diff --git a/Makefile b/Makefile index dcb2124..b5f5fcd 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,15 @@ # path to RETRO68 -RETRO68=/Users/zane/Retro68-build/toolchain +RETRO68=~/Retro68-build/toolchain -PREFIX=$(RETRO68)/m68k-apple-macos -AS=$(RETRO68)/bin/m68k-apple-macos-as -CC=$(RETRO68)/bin/m68k-apple-macos-gcc -LD=$(RETRO68)/bin/m68k-apple-macos-ld -OBJCOPY=$(RETRO68)/bin/m68k-apple-macos-objcopy -OBJDUMP=$(RETRO68)/bin/m68k-apple-macos-objdump +PREFIX=$(RETRO68)/bin/m68k-apple-macos +AS=$(PREFIX)-as +CC=$(PREFIX)-gcc +LD=$(PREFIX)-ld +OBJCOPY=$(PREFIX)-objcopy +OBJDUMP=$(PREFIX)-objdump +CFLAGS=-march=68030 -c -Os -all: bin/rom16M_swap.bin obj/rdisk1M5.s obj/rdisk7M5.s obj/driver1M5.s obj/driver7M5.s obj/entry_rel.sym obj/driver_abs.sym +all: bin/rom16M_swap.bin obj/rdisk7M5.s obj/driver7M5.s obj/entry_rel.sym obj/driver_abs.sym obj: mkdir obj @@ -24,56 +25,42 @@ obj/entry_rel.sym: obj obj/entry.o $(OBJDUMP) -t obj/entry.o > $@ -obj/rdisk1M5.o: rdisk.c obj - $(CC) -DRDiskSize=1572864 -c -Os $< -o $@ - obj/rdisk7M5.o: rdisk.c obj - $(CC) -DRDiskSize=7864320 -c -Os $< -o $@ - -obj/rdisk1M5.s: obj obj/rdisk1M5.o - $(OBJDUMP) -d obj/rdisk1M5.o > $@ + $(CC) -Wall -DRDiskSize=7864320 $(CFLAGS) $< -o $@ obj/rdisk7M5.s: obj obj/rdisk7M5.o - $(OBJDUMP) -d obj/rdisk1M5.o > $@ + $(OBJDUMP) -d obj/rdisk7M5.o > $@ + + +obj/spi.o: spi.c obj + $(CC) -Wall $(CFLAGS) $< -o $@ + +obj/spi.s: obj obj/spi.o + $(OBJDUMP) -d obj/spi.o > $@ + + +obj/sdmmc.o: sdmmc.c obj + $(CC) -Wall $(CFLAGS) -Os $< -o $@ + +obj/sdmmc.s: obj obj/sdmmc.o + $(OBJDUMP) -d obj/sdmmc.o > $@ -obj/driver1M5.o: obj obj/entry.o obj/rdisk1M5.o - $(LD) -Ttext=40851D70 -o $@ obj/entry.o obj/rdisk1M5.o obj/driver7M5.o: obj obj/entry.o obj/rdisk7M5.o - $(LD) -Ttext=40851D70 -o $@ obj/entry.o obj/rdisk7M5.o - -obj/driver1M5.s: obj obj/driver1M5.o - $(OBJDUMP) -d obj/driver1M5.o > $@ + $(LD) -Ttext=40851D70 -o $@ obj/entry.o obj/rdisk7M5.o obj/spi.o obj/sdmmc.o obj/driver7M5.s: obj obj/driver7M5.o $(OBJDUMP) -d obj/driver7M5.o > $@ -obj/driver_abs.sym: obj obj/driver1M5.o - $(OBJDUMP) -t obj/driver1M5.o > $@ +obj/driver_abs.sym: obj obj/driver7M5.o + $(OBJDUMP) -t obj/driver7M5.o > $@ -bin/driver1M5.bin: bin obj/driver1M5.o - $(OBJCOPY) -O binary obj/driver1M5.o $@ - bin/driver7M5.bin: bin obj/driver7M5.o $(OBJCOPY) -O binary obj/driver7M5.o $@ - -bin/rom2M.bin: baserom.bin RDisk1M5.dsk bin bin/driver1M5.bin obj/driver_abs.sym obj/entry_rel.sym - cp baserom.bin $@ # Copy base rom - # Patch driver - dd if=bin/driver1M5.bin of=$@ bs=1 seek=335248 skip=32 conv=notrunc # Copy driver code - printf '\x78' | dd of=$@ bs=1 seek=335168 count=1 conv=notrunc # Set resource flags - printf '\x4F' | dd of=$@ bs=1 seek=335216 count=1 conv=notrunc # Set driver flags - cat obj/entry_rel.sym | grep "DOpen" | cut -c5-8 | xxd -r -p - | dd of=$@ bs=1 seek=335224 count=2 conv=notrunc - cat obj/entry_rel.sym | grep "DPrime" | cut -c5-8 | xxd -r -p - | dd of=$@ bs=1 seek=335226 count=2 conv=notrunc - cat obj/entry_rel.sym | grep "DControl" | cut -c5-8 | xxd -r -p - | dd of=$@ bs=1 seek=335228 count=2 conv=notrunc - cat obj/entry_rel.sym | grep "DStatus" | cut -c5-8 | xxd -r -p - | dd of=$@ bs=1 seek=335230 count=2 conv=notrunc - cat obj/entry_rel.sym | grep "DClose" | cut -c5-8 | xxd -r -p - | dd of=$@ bs=1 seek=335232 count=2 conv=notrunc - dd if=RDisk1M5.dsk of=$@ bs=1024 seek=512 count=1536 conv=notrunc # copy disk image - -bin/rom8M.bin: baserom.bin RDisk7M5.dsk bin bin/driver7M5.bin obj/driver_abs.sym obj/entry_rel.sym +bin/rom8M.bin: bin baserom.bin RDisk7M5.dsk bin bin/driver7M5.bin obj/driver_abs.sym obj/entry_rel.sym cp baserom.bin $@ # Copy base rom # Patch driver dd if=bin/driver7M5.bin of=$@ bs=1 seek=335248 skip=32 conv=notrunc # Copy driver code @@ -86,15 +73,15 @@ bin/rom8M.bin: baserom.bin RDisk7M5.dsk bin bin/driver7M5.bin obj/driver_abs.sym cat obj/entry_rel.sym | grep "DClose" | cut -c5-8 | xxd -r -p - | dd of=$@ bs=1 seek=335232 count=2 conv=notrunc dd if=RDisk7M5.dsk of=$@ bs=1024 seek=512 count=7680 conv=notrunc # copy disk image -bin/rom8M_swap.bin: bin/rom8M.bin +bin/rom8M_swap.bin: bin bin/rom8M.bin dd if=bin/rom8M.bin of=$@ conv=swab # swap bytes -bin/rom2M_swap.bin: bin/rom2M.bin - dd if=bin/rom2M.bin of=$@ conv=swab # swap bytes +bin/iisi_swap.bin: bin iisi.bin + dd if=iisi.bin of=$@ conv=swab # swap bytes -bin/rom16M_swap.bin: bin/rom2M_swap.bin bin/rom8M_swap.bin +bin/rom16M_swap.bin: bin/iisi_swap.bin bin/rom8M_swap.bin cat bin/rom8M_swap.bin > $@ - cat bin/rom2M_swap.bin >> $@ + cat bin/iisi_swap.bin >> $@ .PHONY: clean diff --git a/entry.s b/entry.s index a64a11b..ea864cf 100644 --- a/entry.s +++ b/entry.s @@ -4,33 +4,57 @@ .EQU kioResult, 16 .EQU kcsCode, 26 .EQU JIODone, 0x08FC +.GLOBAL RDiskSig +.GLOBAL RDiskDBGNamePos +.GLOBAL RDiskDBGDisPos +.GLOBAL RDiskDBGDisByte +.GLOBAL RDiskCDRNamePos +.GLOBAL RDiskCDRDisPos +.GLOBAL RDiskCDRDisByte dc.l 0x00000000, 0x00000000, 0x00000000, 0x00000000 dc.l 0x00000000, 0x00000000, 0x00000000, 0x00000000 + +RDiskSig: .ascii "\5RDisk\0" .align 4 +RDiskDBGDisPos: +dc.l 0x00000031 +RDiskCDRDisPos: +dc.l 0x00012CAF +RDiskDBGNameAddr: +dc.l 0x4088002A +RDiskCDRNameAddr: +dc.l 0x40892C96 +RDiskDBGDisByte: +dc.b 0x44 +RDiskCDRDisByte: +dc.b 0x44 +RDiskRAMRequired: +.ascii "16" +.align 4 DOpen: movem.l %A0-%A1, -(%SP) - bsr RDiskOpen + bsr RDOpen movem.l (%SP)+, %A0-%A1 rts DClose: movem.l %A0-%A1, -(%SP) - bsr RDiskClose + bsr RDClose movem.l (%SP)+, %A0-%A1 rts DPrime: movem.l %A0-%A1, -(%SP) - bsr RDiskPrime + bsr RDPrime movem.l (%SP)+, %A0-%A1 bra.b IOReturn DControl: movem.l %A0-%A1, -(%SP) - bsr RDiskControl + bsr RDCtl movem.l (%SP)+, %A0-%A1 cmpi.w #killCode, kcsCode(%A0) bne.b IOReturn @@ -38,7 +62,7 @@ DControl: DStatus: movem.l %A0-%A1, -(%SP) - bsr RDiskStatus + bsr RDStat movem.l (%SP)+, %A0-%A1 IOReturn: diff --git a/rdisk.c b/rdisk.c deleted file mode 100644 index 3a55e8b..0000000 --- a/rdisk.c +++ /dev/null @@ -1,285 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "rdisk.h" - -// Decode keyboard/PRAM settings -static void RDiskDecodeSettings(RDiskStorage_t *c, Ptr unmount, Ptr mount, Ptr ram) { - // Decode settings - if (RDiskIsRPressed()) { // R boots from ROM disk - *unmount = 0; // Don't unmount so we boot from this drive - *mount = 0; // No need to mount later since we are boot disk - *ram = RDiskIsAPressed(); // A enables RAM disk - } else { - // Read PRAM - char legacy_startup, legacy_ram; - RDiskReadXPRAM(1, 4, &legacy_startup); - RDiskReadXPRAM(1, 5, &legacy_ram); - if (legacy_startup & 1) { // Boot from ROM disk - *unmount = 0; // Don't unmount so we boot from this drive - *mount = 0; // No need to mount later since we are boot disk - *ram = legacy_ram & 1; - } else if (legacy_startup & 2) { // Mount ROM disk - *unmount = 1; // Unmount to not boot from our disk - *mount = 1; // Mount in accRun - *ram = legacy_ram & 1; - } else { - *unmount = 1; // Unmount - *mount = 0; // Don't mount again - *ram = 0; // Don't allocate RAM disk - } - } -} - -// Switch to 32-bit mode and copy -#pragma parameter RDiskCopy24(__A0, __A1, __D0) -void RDiskCopy24(Ptr sourcePtr, Ptr destPtr, unsigned long byteCount) { - char mode = true32b; - SwapMMUMode(&mode); - BlockMove(sourcePtr, destPtr, byteCount); - SwapMMUMode(&mode); -} - -// Figure out the first available drive number >= 5 -static int RDiskFindDrvNum() { - DrvQElPtr dq; - int drvNum = 5; - for (dq = (DrvQElPtr)(GetDrvQHdr())->qHead; dq; dq = (DrvQElPtr)dq->qLink) { - if (dq->dQDrive >= drvNum) { drvNum = dq->dQDrive + 1; } - } - return drvNum; -} - -#pragma parameter __D0 RDiskOpen(__A0, __A1) -OSErr RDiskOpen(IOParamPtr p, DCtlPtr d) { - int drvNum; - RDiskStorage_t *c; - char legacy_startup, legacy_ram; - - // Do nothing if already opened - if (d->dCtlStorage) { return noErr; } - - // Do nothing if inhibited - RDiskReadXPRAM(1, 4, &legacy_startup); - RDiskReadXPRAM(1, 5, &legacy_ram); - if ((legacy_startup & 0x07) == 0x04) { return noErr; } - - // Allocate storage struct - d->dCtlStorage = NewHandleSysClear(sizeof(RDiskStorage_t)); - if (!d->dCtlStorage) { return openErr; } - - // Lock our storage struct and get master pointer - HLock(d->dCtlStorage); - c = *(RDiskStorage_t**)d->dCtlStorage; - - // Find first available drive number - drvNum = RDiskFindDrvNum(); - - // Set drive status - //c->status.track = 0; - c->status.writeProt = -1; // nonzero is write protected - c->status.diskInPlace = 8; // 8 is nonejectable disk - c->status.installed = 1; // drive installed - //c->status.sides = 0; - //c->status.qType = 1; - c->status.dQDrive = drvNum; - //c->status.dQFSID = 0; - c->status.dQRefNum = d->dCtlRefNum; - c->status.driveSize = RDiskSize / 512; - //c->status.driveS1 = (RDiskSize / 512) >> 16; - - // Decompress icon - #ifdef RDISK_COMPRESS_ICON_ENABLE - char *src = &RDiskIconCompressed[0]; - char *dst = &c->icon[0]; - UnpackBits(&src, &dst, RDISK_ICON_SIZE); - #endif - - // Add drive to drive queue and return - RDiskAddDrive(c->status.dQRefNum, drvNum, (DrvQElPtr)&c->status.qLink); - return noErr; -} - -// Init is called at beginning of first prime (read/write) call -static void RDiskInit(IOParamPtr p, DCtlPtr d, RDiskStorage_t *c) { - char unmountEN, mountEN, ramEN; - // Mark init done - c->initialized = 1; - // Decode settings - RDiskDecodeSettings(c, &unmountEN, &mountEN, &ramEN); - - // If RAM disk enabled, try to allocate RAM disk buffer if not already - if (ramEN & !c->ramdisk) { - if (*MMU32bit) { // 32-bit mode - unsigned long minBufPtr, newBufPtr; - // Compute if there is enough high memory - minBufPtr = ((unsigned long)*MemTop / 2) + 1024; - newBufPtr = (unsigned long)*BufPtr - RDiskSize; - if (newBufPtr > minBufPtr && (unsigned long)*BufPtr > newBufPtr) { - // Allocate RAM disk buffer by lowering BufPtr - *BufPtr = (Ptr)newBufPtr; - // Set RAM disk buffer pointer. - c->ramdisk = *BufPtr; - // Copy ROM disk image to RAM disk - BlockMove(RDiskBuf, c->ramdisk, RDiskSize); - // Clearing write protect marks RAM disk enabled - c->status.writeProt = 0; - } - } else { // 24-bit mode - // Put RAM disk just past 8MB - c->ramdisk = (Ptr)(8 * 1024 * 1024); - // Copy ROM disk image to RAM disk - copy24(RDiskBuf, c->ramdisk, RDiskSize); - // Clearing write protect marks RAM disk enabled - c->status.writeProt = 0; - //FIXME: what if we don't have enough RAM? - // Will this wrap around and overwrite low memory? - // That's not the worst, since the system would just crash, - // but it would be better to switch to read-only status - } - } - - // Unmount if not booting from ROM disk - if (unmountEN) { c->status.diskInPlace = 0; } - - // If mount enabled, enable accRun to post disk inserted event later - if (mountEN) { - d->dCtlDelay = 150; // Set accRun delay (150 ticks is 2.5 sec.) - d->dCtlFlags |= dNeedTimeMask; // Enable accRun - } -} - -#pragma parameter __D0 RDiskPrime(__A0, __A1) -OSErr RDiskPrime(IOParamPtr p, DCtlPtr d) { - RDiskStorage_t *c; - char cmd; - Ptr disk; - - // Return disk offline error if dCtlStorage null - if (!d->dCtlStorage) { return notOpenErr; } - // Dereference dCtlStorage to get pointer to our context - c = *(RDiskStorage_t**)d->dCtlStorage; - - // Initialize if this is the first prime call - if (!c->initialized) { RDiskInit(p, d, c); } - - // Return disk offline error if virtual disk not inserted - if (!c->status.diskInPlace) { return offLinErr; } - - // Get pointer to RAM or ROM disk buffer - disk = (c->ramdisk ? c->ramdisk : RDiskBuf) + d->dCtlPosition; - // Bounds checking - if (d->dCtlPosition >= RDiskSize || p->ioReqCount >= RDiskSize || - d->dCtlPosition + p->ioReqCount >= RDiskSize) { return paramErr; } - - // Service read or write request - cmd = p->ioTrap & 0x00FF; - if (cmd == aRdCmd) { // Read - // Read from disk into buffer. - if (*MMU32bit) { BlockMove(disk, p->ioBuffer, p->ioReqCount); } - else { copy24(disk, StripAddress(p->ioBuffer), p->ioReqCount); } - } else if (cmd == aWrCmd) { // Write - // Fail if write protected or RAM disk buffer not set up - if (c->status.writeProt || !c->ramdisk) { return wPrErr; } - // Write from buffer into disk. - if (*MMU32bit) { BlockMove(p->ioBuffer, disk, p->ioReqCount); } - else { copy24(StripAddress(p->ioBuffer), disk, p->ioReqCount); } - } else { return noErr; } //FIXME: Fail if cmd isn't read or write? - - // Update count and position/offset, then return - d->dCtlPosition += p->ioReqCount; - p->ioActCount = p->ioReqCount; - return noErr; -} - -#pragma parameter __D0 RDiskControl(__A0, __A1) -OSErr RDiskControl(CntrlParamPtr p, DCtlPtr d) { - RDiskStorage_t *c; - // Fail if dCtlStorage null - if (!d->dCtlStorage) { return notOpenErr; } - // Dereference dCtlStorage to get pointer to our context - c = *(RDiskStorage_t**)d->dCtlStorage; - // Handle control request based on csCode - switch (p->csCode) { - case killCode: - return noErr; - case kFormat: - if (!c->status.diskInPlace || c->status.writeProt || - !c->ramdisk) { return controlErr; } - long zero[32]; - for (int i = 0; i < 32; i++) { zero[i] = 0; } - for (int i = 0; i < 32; i++) { - copy24((Ptr)zero, c->ramdisk + i * sizeof(zero), sizeof(zero)); - } - return noErr; - case kVerify: - if (!c->status.diskInPlace) { return controlErr; } - return noErr; - case kEject: - // "Reinsert" disk if ejected illegally - if (c->status.diskInPlace) { - PostEvent(diskEvt, c->status.dQDrive); - } - return controlErr; // Eject not allowed so return error - case accRun: - d->dCtlFlags &= ~dNeedTimeMask; // Disable accRun - c->status.diskInPlace = 8; // 8 is nonejectable disk - PostEvent(diskEvt, c->status.dQDrive); // Post disk inserted event - return noErr; - case kDriveIcon: case kMediaIcon: // Get icon - #ifdef RDISK_COMPRESS_ICON_ENABLE - *(Ptr*)p->csParam = (Ptr)c->icon; - #else - *(Ptr*)p->csParam = (Ptr)RDiskIcon; - #endif - return noErr; - case kDriveInfo: - // high word (bytes 2 & 3) clear - // byte 1 = primary + fixed media + internal - // byte 0 = drive type (0x10 is RAM disk) / (0x11 is ROM disk) - if (c->status.writeProt) { *(long*)p->csParam = 0x00000410; } - else { *(long*)p->csParam = 0x00000411; } - return noErr; - case 24: // Return SCSI partition size - *(long*)p->csParam = RDiskSize / 512; - return noErr; - case 2351: // Post-boot - c->initialized = 1; // Skip initialization - d->dCtlDelay = 30; // Set accRun delay (30 ticks is 0.5 sec.) - d->dCtlFlags |= dNeedTimeMask; // Enable accRun - return noErr; - default: return controlErr; - } -} - -#pragma parameter __D0 RDiskStatus(__A0, __A1) -OSErr RDiskStatus(CntrlParamPtr p, DCtlPtr d) { - RDiskStorage_t *c; - // Fail if dCtlStorage null - if (!d->dCtlStorage) { return notOpenErr; } - // Dereference dCtlStorage to get pointer to our context - c = *(RDiskStorage_t**)d->dCtlStorage; - // Handle status request based on csCode - switch (p->csCode) { - case kDriveStatus: - BlockMove(*d->dCtlStorage, &p->csParam, sizeof(DrvSts2)); - return noErr; - default: return statusErr; - } -} - -#pragma parameter __D0 RDiskClose(__A0, __A1) -OSErr RDiskClose(IOParamPtr p, DCtlPtr d) { - // If dCtlStorage not null, dispose of it - if (!d->dCtlStorage) { return noErr; } - RDiskStorage_t *c = *(RDiskStorage_t**)d->dCtlStorage; - HUnlock(d->dCtlStorage); - DisposeHandle(d->dCtlStorage); - d->dCtlStorage = NULL; - return noErr; -} diff --git a/rdisk.h b/rdisk.h deleted file mode 100644 index 689ee88..0000000 --- a/rdisk.h +++ /dev/null @@ -1,195 +0,0 @@ -#ifndef RDISK_H -#define RDISK_H - -//#define RDiskSize (0x00180000L) -#define RDiskBuf ((char*)0x40880000) -#define BufPtr ((Ptr*)0x10C) -#define MemTop ((Ptr*)0x108) -#define MMU32bit ((char*)0xCB2) - -#pragma parameter __D0 RDiskReadXPRAM(__D0, __D1, __A0) -OSErr RDiskReadXPRAM(short numBytes, short whichByte, Ptr dest) = {0x4840, 0x3001, 0xA051}; - -#pragma parameter __D0 RDiskAddDrive(__D1, __D0, __A0) -OSErr RDiskAddDrive(short drvrRefNum, short drvNum, DrvQElPtr dq) = {0x4840, 0x3001, 0xA04E}; - -static inline char RDiskIsRPressed() { return *((char*)0x175) & 0x80; } -static inline char RDiskIsAPressed() { return *((char*)0x174) & 0x01; } - -typedef void (*RDiskCopy_t)(Ptr, Ptr, unsigned long); -#define copy24(s, d, b) { RDiskCopy_t copy24 = (RDiskCopy_t)RDiskCopy24; copy24(s, d, b); } - -//#define RDISK_COMPRESS_ICON_ENABLE -#define RDISK_ICON_SIZE (285) -typedef struct RDiskStorage_s { - DrvSts2 status; - char initialized; - Ptr ramdisk; - #ifdef RDISK_COMPRESS_ICON_ENABLE - char icon[RDISK_ICON_SIZE]; - #endif -} RDiskStorage_t; - -#define PackBits_Repeat(count) (-1 * (count - 1)) -#define PackBits_Literal(count) (count - 1) - -#define RDISK_COMPRESSED_ICON_SIZE (87) -#ifdef RDISK_COMPRESS_ICON_ENABLE -#include -const char const RDiskIconCompressed[RDISK_COMPRESSED_ICON_SIZE] = { - PackBits_Repeat(76), 0b00000000, /* - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, */ - PackBits_Repeat(4), 0b11111111, /* - 0b11111111, 0b11111111, 0b11111111, 0b11111111, */ - PackBits_Literal(36), - 0b10000000, 0b00000000, 0b00000000, 0b00000001, - 0b10001111, 0b00011110, 0b00111100, 0b01111001, - 0b10001001, 0b00010010, 0b00100100, 0b01001001, - 0b10001001, 0b00010010, 0b00100100, 0b01001001, - 0b10001001, 0b00010010, 0b00100100, 0b01001001, - 0b10001111, 0b00011110, 0b00111100, 0b01111001, - 0b11000000, 0b00000000, 0b00000000, 0b00000001, - 0b01010101, 0b01010101, 0b11010101, 0b01010101, - 0b01111111, 0b11111111, 0b01111111, 0b11111111, - PackBits_Repeat(12), 0b00000000, /* - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, */ - - PackBits_Repeat(76), 0b00000000, /* - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, */ - PackBits_Repeat(32), 0b11111111, /* - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, */ - PackBits_Literal(1), 0b01111111, - PackBits_Repeat(3), 0b11111111, /* - 0b01111111, 0b11111111, 0b11111111, 0b11111111, */ - PackBits_Literal(1), 0b01111111, - PackBits_Repeat(3), 0b11111111, /* - 0b01111111, 0b11111111, 0b11111111, 0b11111111, */ - PackBits_Repeat(12), 0b00000000, /* - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, */ - PackBits_Literal(29), - 27, 'G', 'a', 'r', 'r', 'e', 't', 't', '\'', 's', ' ', - 'W', 'o', 'r', 'k', 's', 'h', 'o', 'p', ' ', - 'R', 'O', 'M', ' ', 'D', 'i', 's', 'k', 0 -}; -#else -const char const RDiskIcon[RDISK_ICON_SIZE] = { - // Icon - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b10000000, 0b00000000, 0b00000000, 0b00000001, - 0b10001111, 0b00011110, 0b00111100, 0b01111001, - 0b10001001, 0b00010010, 0b00100100, 0b01001001, - 0b10001001, 0b00010010, 0b00100100, 0b01001001, - 0b10001001, 0b00010010, 0b00100100, 0b01001001, - 0b10001111, 0b00011110, 0b00111100, 0b01111001, - 0b11000000, 0b00000000, 0b00000000, 0b00000001, - 0b01010101, 0b01010101, 0b11010101, 0b01010101, - 0b01111111, 0b11111111, 0b01111111, 0b11111111, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - // Mask - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b11111111, 0b11111111, 0b11111111, 0b11111111, - 0b01111111, 0b11111111, 0b11111111, 0b11111111, - 0b01111111, 0b11111111, 0b11111111, 0b11111111, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 0b00000000, 0b00000000, 0b00000000, 0b00000000, - 27, 'G', 'a', 'r', 'r', 'e', 't', 't', '\'', 's', ' ', - 'W', 'o', 'r', 'k', 's', 'h', 'o', 'p', ' ', - 'R', 'O', 'M', ' ', 'D', 'i', 's', 'k', 0 -}; -#endif - -#endif diff --git a/rombus.c b/rombus.c new file mode 100644 index 0000000..7a295ab --- /dev/null +++ b/rombus.c @@ -0,0 +1,361 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "rdisk.h" + +// Decode keyboard/PRAM settings +static void RDDecodeSettings(Ptr recoveryEN, Ptr unmountEN, Ptr mountEN) { + // Read PRAM + char legacy_startup; + RBReadXPRAM(1, 4, &legacy_startup); + + // Decode settings: boot from recovery, unmount (don't boot), mount (after boot) + if (RBIsRPressed()) { // R boots from ROM recovery + *recoveryEN = 1; // Enable recovery partition + *unmountEN = 0; // Unmount SD so we don't boot from it + *mountEN = 1; // Mount SD later + } else { + *recoveryEN = 0; // Disable recovery partition + if (legacy_startup & 0x10) { // Boot from SD disk + *unmountEN = 0; // Don't unmount so we boot from this drive + *mountEN = 0; // No need to mount later since we are boot disk + } else if (legacy_startup & 0x20) { // Mount SD disk under other boot volume + *unmountEN = 1; // Unmount to not boot from our disk + *mountEN = 1; // Mount in accRun + } else { + *unmountEN = 1; // Unmount + *mountEN = 0; // Don't mount again + } + } +} + +// Switch to 32-bit mode and copy +#pragma parameter C24(__A0, __A1, __D0) +void __attribute__ ((noinline)) C24(Ptr sourcePtr, Ptr destPtr, unsigned long byteCount) { + signed char mode = true32b; + SwapMMUMode(&mode); + BlockMove(sourcePtr, destPtr, byteCount); + SwapMMUMode(&mode); +} + +// Switch to 32-bit mode and get +#pragma parameter __D0 G24(__A2) +char __attribute__ ((noinline)) G24(Ptr pos) { + long ret; + signed char mode = true32b; + SwapMMUMode(&mode); + ret = *pos; // Peek + SwapMMUMode(&mode); + return ret; +} + +// Switch to 32-bit mode and set +#pragma parameter S24(__A2, __D3) +void __attribute__ ((noinline)) S24(Ptr pos, char patch) { + signed char mode = true32b; + SwapMMUMode(&mode); + *pos = patch; // Poke + SwapMMUMode(&mode); +} + +// Figure out the first available drive number >= 5 +static int RBFindDrvNum() { + DrvQElPtr dq; + int drvNum = 5; + for (dq = (DrvQElPtr)(GetDrvQHdr())->qHead; dq; dq = (DrvQElPtr)dq->qLink) { + if (dq->dQDrive >= drvNum) { drvNum = dq->dQDrive + 1; } + } + return drvNum; +} + +static void RBOpenRDisk(RDiskStorage_t *c) { + int drvNum; + + // Find first available drive number for ROM recovery + drvNum = RBFindDrvNum(); + + // Set ROM recovery drive status + //c->rStatus.track = 0; + c->rStatus.writeProt = -1; // nonzero is write protected + c->rStatus.diskInPlace = 8; // 8 is nonejectable disk + c->rStatus.installed = 1; // drive installed + //c->rStatus.sides = 0; + //c->rStatus.qType = 1; + c->rStatus.dQDrive = drvNum; + //c->rStatus.dQFSID = 0; + c->rStatus.dQRefNum = d->dCtlRefNum; + c->rStatus.driveSize = RDiskSize / 512; + //c->rStatus.driveS1 = (RDiskSize / 512) >> 16; + + // Decompress icon + #ifdef RDISK_COMPRESS_ICON_ENABLE + char *src = &RDiskIconCompressed[0]; + char *dst = &c->rIcon[0]; + UnpackBits(&src, &dst, RDISK_ICON_SIZE); + #endif + + // Add RDisk to drive queue and return + RDiskAddDrive(c->rStatus.dQRefNum, drvNum, (DrvQElPtr)&c->rStatus.qLink); +} + +static void RBOpenSDisk(RDiskStorage_t *c) { + int drvNum; + + // Find first available drive number for SD disk + drvNum = RBFindDrvNum(); + + // Set SD disk drive status + //c->rStatus.track = 0; + c->rStatus.writeProt = 0; // 0 is writable + c->rStatus.diskInPlace = 8; // 8 is nonejectable disk + c->rStatus.installed = 1; // drive installed + //c->rStatus.sides = 0; + c->rStatus.qType = 1; + c->rStatus.dQDrive = drvNum; + //c->rStatus.dQFSID = 0; + c->rStatus.dQRefNum = d->dCtlRefNum; + c->rStatus.driveSize = SDiskSize / 512; + c->rStatus.driveS1 = (SDiskSize / 512) >> 16; + + // Decompress icon + #ifdef SDISK_COMPRESS_ICON_ENABLE + char *src = &SDiskIconCompressed[0]; + char *dst = &c->sIcon[0]; + UnpackBits(&src, &dst, SDISK_ICON_SIZE); + #endif + + // Add SDisk to drive queue and return + RDiskAddDrive(c->rstatus.dQRefNum, drvNum, (DrvQElPtr)&c->sStatus.qLink); +} + +#pragma parameter __D0 RBOpen(__A0, __A1) +OSErr RBOpen(IOParamPtr p, DCtlPtr d) { + RDiskStorage_t *c; + char legacy_startup; + + // Do nothing if already opened + if (d->dCtlStorage) { return noErr; } + + // Do nothing if inhibited + RBReadXPRAM(1, 4, &legacy_startup); + if (legacy_startup & 0x40) { return noErr; } + + // Allocate storage struct + d->dCtlStorage = NewHandleSysClear(sizeof(RDiskStorage_t)); + if (!d->dCtlStorage) { return openErr; } + + // Lock our storage struct and get master pointer + HLock(d->dCtlStorage); + c = *(RDiskStorage_t**)d->dCtlStorage; + + // Create RDisk and SDisk entries in drive queue, then return + RBOpenRDisk(c); + RBOpenSDisk(c); + return noErr; +} + +// Init is called at beginning of first prime (read/write) call +static void RBInit(IOParamPtr p, DCtlPtr d, RDiskStorage_t *c) { + char recoveryEN, unmountEN, mountEN; + // Mark init done + c->initialized = 1; + // Decode settings + RDDecodeSettings(&recoveryEN, &unmountEN, &mountEN); + + // Unmount if not booting from ROM disk + if (!recoveryEN) { c->rStatus.diskInPlace = 0; } + + // Unmount if not booting from ROM disk + if (unmountEN) { c->SStatus.diskInPlace = 0; } + + // If mount enabled, enable accRun to post disk inserted event later + if (mountEN) { + d->dCtlDelay = 150; // Set accRun delay (150 ticks is 2.5 sec.) + d->dCtlFlags |= dNeedTimeMask; // Enable accRun + } +} + +static OSErr RDPrime(IOParamPtr p, DCtlPtr d) { + // Get pointer to correct position in ROM disk buffer + Ptr disk = RDiskBuf + d->dCtlPosition; + + // Return disk offline error if virtual disk not inserted + if (!c->rStatus.diskInPlace) { return offLinErr; } + + // Bounds checking + if (d->dCtlPosition >= RDiskSize || p->ioReqCount >= RDiskSize || + d->dCtlPosition + p->ioReqCount >= RDiskSize) { return paramErr; } + + // Service read or write request + cmd = p->ioTrap & 0x00FF; + if (cmd == aRdCmd) { + if (*MMU32bit) { BlockMove(disk, p->ioBuffer, p->ioReqCount); } + else { copy24(disk, StripAddress(p->ioBuffer), p->ioReqCount); } + } else if (cmd == aWrCmd) { return wPrErr; + } else { return noErr; } //FIXME: Fail if cmd isn't read or write? + + // Update count and position/offset, then return + d->dCtlPosition += p->ioReqCount; + p->ioActCount = p->ioReqCount; + return noErr; +} + +static OSErr SDPrime(IOParamPtr p, DCtlPtr d) { + +} + +#pragma parameter __D0 RBPrime(__A0, __A1) +OSErr RBPrime(IOParamPtr p, DCtlPtr d) { + RDiskStorage_t *c; + char cmd; + + // Return disk offline error if dCtlStorage null + if (!d->dCtlStorage) { return notOpenErr; } + // Dereference dCtlStorage to get pointer to our context + c = *(RDiskStorage_t**)d->dCtlStorage; + + // Initialize if this is the first prime call + if (!c->initialized) { RBInit(p, d, c); } + + if (p->ioVRefNum == c->sStatus.dQDrive) { + return SDPrime(p, d, c); + } else if (p->ioVRefNum == c->rStatus.dQDrive) { + return RDPrime(p, d, c); + } else { return nsvErr; } +} + +static OSErr RDCtl(CntrlParamPtr p, DCtlPtr d, RDiskStorage_t *c) { + // Handle control request based on csCode + switch (p->csCode) { + case kFormat: return controlErr; + case kVerify: + if (!c->rStatus.diskInPlace) { return controlErr; } + return noErr; + case kEject: + // "Reinsert" disk if ejected illegally + if (c->rStatus.diskInPlace) { + PostEvent(diskEvt, c->status.dQDrive); + } + return controlErr; // Eject not allowed so return error + case kDriveIcon: case kMediaIcon: // Get icon + #ifdef RDISK_COMPRESS_ICON_ENABLE + *(Ptr*)p->csParam = (Ptr)c->rIcon; + #else + *(Ptr*)p->csParam = (Ptr)RDiskIcon; + #endif + return noErr; + case kDriveInfo: + // high word (bytes 2 & 3) clear + // byte 1 = primary + fixed media + internal + // byte 0 = drive type (0x11 is ROM disk) + *(long*)p->csParam = 0x00000411; + return noErr; + case 24: // Return SCSI partition size + *(long*)p->csParam = RDiskSize / 512; + return noErr; + default: return controlErr; + } +} + +static OSErr SDCtl(CntrlParamPtr p, DCtlPtr d, RDiskStorage_t *c) { + // Handle control request based on csCode + switch (p->csCode) { + case kFormat: + // FIXME: implement SD format + return controlErr; + case kVerify: + // FIXME: implement SD verify + return noErr; + case kEject: + // "Reinsert" disk if ejected illegally + if (c->sStatus.diskInPlace) { + PostEvent(diskEvt, c->sStatus.dQDrive); + } + return controlErr; // Eject not allowed so return error + case kDriveIcon: case kMediaIcon: // Get icon + #ifdef SDISK_COMPRESS_ICON_ENABLE + *(Ptr*)p->csParam = (Ptr)c->sIcon; + #else + *(Ptr*)p->csParam = (Ptr)SDiskIcon; + #endif + return noErr; + case kDriveInfo: + // high word (bytes 2 & 3) clear + // byte 1 = primary + fixed media + internal + // byte 0 = drive type (0x01 is unspecified drive) + *(long*)p->csParam = 0x00000401; + return noErr; + case 24: // Return SCSI partition size + *(long*)p->csParam = SDiskSize / 512; + return noErr; + default: return controlErr; + } +} + +#pragma parameter __D0 RBCtl(__A0, __A1) +OSErr RBCtl(CntrlParamPtr p, DCtlPtr d) { + RDiskStorage_t *c; + // Fail if dCtlStorage null + if (!d->dCtlStorage) { return notOpenErr; } + // Dereference dCtlStorage to get pointer to our context + c = *(RDiskStorage_t**)d->dCtlStorage; + // Handle control request based on csCode + switch (p->csCode) { + case killCode: + return noErr; + case accRun: + d->dCtlFlags &= ~dNeedTimeMask; // Disable accRun + c->sStatus.diskInPlace = 8; // 8 is nonejectable disk + PostEvent(diskEvt, c->sStatus.dQDrive); // Post disk inserted event + return noErr; + case 2351: // Post-boot + c->initialized = 1; // Skip initialization + d->dCtlDelay = 30; // Set accRun delay (30 ticks is 0.5 sec.) + d->dCtlFlags |= dNeedTimeMask; // Enable accRun + return noErr; + } + + // Otherwise, dispatch to correct drive + if (p->ioVRefNum == c->sStatus.dQDrive) { + return SDCtl(p, d, c); + } else if (p->ioVRefNum == c->rStatus.dQDrive) { + return RDCtl(p, d, c); + } else { return nsvErr; } +} + +#pragma parameter __D0 RBStat(__A0, __A1) +OSErr RBStat(CntrlParamPtr p, DCtlPtr d) { + RDiskStorage_t *c; + // Fail if dCtlStorage null + if (!d->dCtlStorage) { return notOpenErr; } + // Dereference dCtlStorage to get pointer to our context + c = *(RDiskStorage_t**)d->dCtlStorage; + // Handle status request based on csCode + switch (p->csCode) { + case kDriveStatus: + // Otherwise, copy correct drive status + if (p->ioVRefNum == c->sStatus.dQDrive) { + BlockMove(&c->sStatus, &p->csParam, sizeof(DrvSts2)); + } else if (p->ioVRefNum == c->rStatus.dQDrive) { + BlockMove(&c->rStatus, &p->csParam, sizeof(DrvSts2)); + } else { return nsvErr; } + return noErr; + default: return statusErr; + } +} + +#pragma parameter __D0 RBClose(__A0, __A1) +OSErr RBClose(IOParamPtr p, DCtlPtr d) { + // If dCtlStorage not null, dispose of it + if (!d->dCtlStorage) { return noErr; } + //RDiskStorage_t *c = *(RDiskStorage_t**)d->dCtlStorage; + HUnlock(d->dCtlStorage); + DisposeHandle(d->dCtlStorage); + d->dCtlStorage = NULL; + return noErr; +} diff --git a/rombus.h b/rombus.h new file mode 100644 index 0000000..0e02990 --- /dev/null +++ b/rombus.h @@ -0,0 +1,179 @@ +#ifndef ROMBUS_H +#define ROMBUS_H + +#define RDiskBuf ((char*)0x408C0000) +#define SDiskSize (0x80000000L) +#define BufPtr ((Ptr*)0x10C) +#define MemTop ((Ptr*)0x108) +#define MMU32bit ((char*)0xCB2) + +#pragma parameter __D0 RBReadXPRAM(__D0, __D1, __A0) +OSErr RBReadXPRAM(short numBytes, short whichByte, Ptr dest) = {0x4840, 0x3001, 0xA051}; + +#pragma parameter __D0 RBAddDrive(__D1, __D0, __A0) +OSErr RBAddDrive(short drvrRefNum, short drvNum, DrvQElPtr dq) = {0x4840, 0x3001, 0xA04E}; + +static inline char RBIsRPressed() { return *((char*)0x175) & 0x80; } + +typedef struct RBStorage_s { + DrvSts2 sStatus; + DrvSts2 rStatus; + char initialized; +} RBStorage_t; + +typedef void (*RDiskCopy_t)(Ptr, Ptr, unsigned long); +#define copy24(s, d, b) { RDiskCopy_t f = C24; f(s, d, b); } + +typedef char (*RDiskPeek_t)(Ptr); +#define peek24(a, d) { RDiskPeek_t f = G24; d = f(a); } + +typedef void (*RDiskPoke_t)(Ptr, char); +#define poke24(a, d) { RDiskPoke_t f = S24; f(a, d); } + +#define RDISK_ICON_SIZE (285) +const char RDiskIcon[RDISK_ICON_SIZE] = { + // Icon + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b11111111, 0b11111111, 0b11111111, 0b11111111, + 0b10000000, 0b00000000, 0b00000000, 0b00000001, + 0b10001111, 0b00011110, 0b00111100, 0b01111001, + 0b10001001, 0b00010010, 0b00100100, 0b01001001, + 0b10001001, 0b00010010, 0b00100100, 0b01001001, + 0b10001001, 0b00010010, 0b00100100, 0b01001001, + 0b10001111, 0b00011110, 0b00111100, 0b01111001, + 0b11000000, 0b00000000, 0b00000000, 0b00000001, + 0b01010101, 0b01010101, 0b11010101, 0b01010101, + 0b01111111, 0b11111111, 0b01111111, 0b11111111, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + // Mask + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b11111111, 0b11111111, 0b11111111, 0b11111111, + 0b11111111, 0b11111111, 0b11111111, 0b11111111, + 0b11111111, 0b11111111, 0b11111111, 0b11111111, + 0b11111111, 0b11111111, 0b11111111, 0b11111111, + 0b11111111, 0b11111111, 0b11111111, 0b11111111, + 0b11111111, 0b11111111, 0b11111111, 0b11111111, + 0b11111111, 0b11111111, 0b11111111, 0b11111111, + 0b11111111, 0b11111111, 0b11111111, 0b11111111, + 0b01111111, 0b11111111, 0b11111111, 0b11111111, + 0b01111111, 0b11111111, 0b11111111, 0b11111111, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 27, 'G', 'a', 'r', 'r', 'e', 't', 't', '\'', 's', ' ', + 'W', 'o', 'r', 'k', 's', 'h', 'o', 'p', ' ', + 'R', 'O', 'M', ' ', 'D', 'i', 's', 'k', 0 +}; + +#define SDISK_ICON_SIZE (283) +const char const SDiskIcon[SDISK_ICON_SIZE] = { + // Icon + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000001, 0b11111111, 0b11111111, 0b11110000, + 0b00000001, 0b00000000, 0b00000000, 0b00010000, + 0b00000001, 0b00000001, 0b10000000, 0b11010000, + 0b00000001, 0b01101101, 0b10110110, 0b11010000, + 0b00000001, 0b01101101, 0b10110110, 0b11010000, + 0b00000001, 0b01101101, 0b10110110, 0b11010000, + 0b00000001, 0b01101101, 0b10110110, 0b11010000, + 0b00000001, 0b01101101, 0b10110110, 0b11010000, + 0b00000001, 0b00000000, 0b00000000, 0b00010000, + 0b00000001, 0b00000000, 0b00000000, 0b00010000, + 0b00000010, 0b00000000, 0b00000000, 0b00010000, + 0b00000100, 0b00000000, 0b00000000, 0b00010000, + 0b00001000, 0b00000000, 0b00000000, 0b00010000, + 0b00001000, 0b00000000, 0b00000000, 0b00010000, + 0b00001000, 0b00000000, 0b00000000, 0b00010000, + 0b00001000, 0b00000000, 0b00000000, 0b00010000, + 0b00001110, 0b00000000, 0b00000000, 0b00010000, + 0b00000010, 0b00000000, 0b00000000, 0b00010000, + 0b00000010, 0b00000000, 0b00000000, 0b00010000, + 0b00000010, 0b00000000, 0b00000000, 0b00010000, + 0b00000100, 0b00000000, 0b00000000, 0b00010000, + 0b00001000, 0b00000000, 0b00000000, 0b00010000, + 0b00001000, 0b00000000, 0b00000000, 0b00010000, + 0b00001000, 0b00000000, 0b00000000, 0b00010000, + 0b00001000, 0b00000000, 0b00000000, 0b00010000, + 0b00001000, 0b00000000, 0b00000000, 0b00010000, + 0b00001000, 0b00000000, 0b00000000, 0b00010000, + 0b00001000, 0b00000000, 0b00000000, 0b00010000, + 0b00001000, 0b00000000, 0b00000000, 0b00010000, + 0b00001111, 0b11111111, 0b11111111, 0b11110000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + // Mask + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 0b00000001, 0b11111111, 0b11111111, 0b11110000, + 0b00000001, 0b11111111, 0b11111111, 0b11110000, + 0b00000001, 0b11111111, 0b11111111, 0b11110000, + 0b00000001, 0b11111111, 0b11111111, 0b11110000, + 0b00000001, 0b11111111, 0b11111111, 0b11110000, + 0b00000001, 0b11111111, 0b11111111, 0b11110000, + 0b00000001, 0b11111111, 0b11111111, 0b11110000, + 0b00000001, 0b11111111, 0b11111111, 0b11110000, + 0b00000001, 0b11111111, 0b11111111, 0b11110000, + 0b00000001, 0b11111111, 0b11111111, 0b11110000, + 0b00000011, 0b11111111, 0b11111111, 0b11110000, + 0b00000111, 0b11111111, 0b11111111, 0b11110000, + 0b00001111, 0b11111111, 0b11111111, 0b11110000, + 0b00001111, 0b11111111, 0b11111111, 0b11110000, + 0b00001111, 0b11111111, 0b11111111, 0b11110000, + 0b00001111, 0b11111111, 0b11111111, 0b11110000, + 0b00001111, 0b11111111, 0b11111111, 0b11110000, + 0b00000011, 0b11111111, 0b11111111, 0b11110000, + 0b00000011, 0b11111111, 0b11111111, 0b11110000, + 0b00000011, 0b11111111, 0b11111111, 0b11110000, + 0b00000111, 0b11111111, 0b11111111, 0b11110000, + 0b00001111, 0b11111111, 0b11111111, 0b11110000, + 0b00001111, 0b11111111, 0b11111111, 0b11110000, + 0b00001111, 0b11111111, 0b11111111, 0b11110000, + 0b00001111, 0b11111111, 0b11111111, 0b11110000, + 0b00001111, 0b11111111, 0b11111111, 0b11110000, + 0b00001111, 0b11111111, 0b11111111, 0b11110000, + 0b00001111, 0b11111111, 0b11111111, 0b11110000, + 0b00001111, 0b11111111, 0b11111111, 0b11110000, + 0b00001111, 0b11111111, 0b11111111, 0b11110000, + 0b00000000, 0b00000000, 0b00000000, 0b00000000, + 25, 'G', 'a', 'r', 'r', 'e', 't', 't', '\'', 's', ' ', + 'W', 'o', 'r', 'k', 's', 'h', 'o', 'p', ' ', + 'R', 'O', 'M', 'B', 'U', 'S', 0 +}; + +#endif \ No newline at end of file diff --git a/sdmmc.c b/sdmmc.c new file mode 100644 index 0000000..048f678 --- /dev/null +++ b/sdmmc.c @@ -0,0 +1,220 @@ +#include "sdmmc.h" + + +/*-------------------------------------------------------------------------- + + Module Private Functions + +---------------------------------------------------------------------------*/ + +#define INIT_PORT() init_port() /* Initialize MMC control port (CS/CLK/DI:output, DO:input) */ +#define DLY_US(n) dly_us(n) /* Delay n microseconds */ +#define FORWARD(d) forward(d) /* Data in-time processing function (depends on the project) */ + +/* Definitions for MMC/SDC command */ +#define CMD0 (0x40+0) /* GO_IDLE_STATE */ +#define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */ +#define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */ +#define CMD8 (0x40+8) /* SEND_IF_COND */ +#define CMD16 (0x40+16) /* SET_BLOCKLEN */ +#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */ +#define CMD24 (0x40+24) /* WRITE_BLOCK */ +#define CMD55 (0x40+55) /* APP_CMD */ +#define CMD58 (0x40+58) /* READ_OCR */ + +/* Card type flags (CardType) */ +#define CT_MMC 0x01 /* MMC ver 3 */ +#define CT_SD1 0x02 /* SD ver 1 */ +#define CT_SD2 0x04 /* SD ver 2 */ +#define CT_SDC (CT_SD1|CT_SD2) /* SD */ +#define CT_BLOCK 0x08 /* Block addressing */ + + + +static char CardType; /* 0:MMC, 1:SDv1, 2:SDv2, 3:Block addressing */ + + +/*-----------------------------------------------------------------------*/ +/* Send a command packet to MMC */ +/*-----------------------------------------------------------------------*/ +static char send_cmd(char cmd, long arg) +{ + char n, res; + + if (cmd & 0x80) { /* ACMD is the command sequense of CMD55-CMD */ + cmd &= 0x7F; + res = send_cmd(CMD55, 0); + if (res > 1) return res; + } + + /* Select the card */ + CS_H(); spi_rx(); + CS_L(); spi_rx(); + + /* Send a command packet */ + spi_tx(cmd); /* Start + Command index */ + s((BYTE)(arg >> 24)); /* Argument[31..24] */ + spi_tx((BYTE)(arg >> 16)); /* Argument[23..16] */ + spi_tx((BYTE)(arg >> 8)); /* Argument[15..8] */ + spi_tx((BYTE)arg); /* Argument[7..0] */ + n = 0x01; /* Dummy CRC + Stop */ + if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */ + if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */ + spi_tx(n); + + /* Receive a command response */ + n = 10; /* Wait for a valid response in timeout of 10 attempts */ + do { + res = spi_rx(); + } while ((res & 0x80) && --n); + + return res; /* Return with the response value */ +} + + + +/*-------------------------------------------------------------------------- + + Public Functions + +---------------------------------------------------------------------------*/ + + +/*-----------------------------------------------------------------------*/ +/* Initialize Disk Drive */ +/*-----------------------------------------------------------------------*/ +sdstatus_t sdmmc_init() +{ + char n, cmd, ty, buf[4]; + uint tmr; + + CS_H(); + spi_skip(10); /* Dummy clocks */ + + ty = 0; + if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */ + if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2 */ + for (n = 0; n < 4; n++) buf[n] = spi_rx(); /* Get trailing return value of R7 resp */ + if (buf[2] == 0x01 && buf[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */ + for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state (ACMD41 with HCS bit) */ + if (send_cmd(ACMD41, 1UL << 30) == 0) break; + DLY_US(1000); + } + if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ + for (n = 0; n < 4; n++) buf[n] = spi_rx(); + ty = (buf[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 (HC or SC) */ + } + } + } else { /* SDv1 or MMCv3 */ + if (send_cmd(ACMD41, 0) <= 1) { + ty = CT_SD1; cmd = ACMD41; /* SDv1 */ + } else { + ty = CT_MMC; cmd = CMD1; /* MMCv3 */ + } + for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state */ + if (send_cmd(cmd, 0) == 0) break; + DLY_US(1000); + } + if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */ + ty = 0; + } + } + CardType = ty; + release_spi(); + + return ty ? 0 : STA_NOINIT; +} + + +/*-----------------------------------------------------------------------*/ +/* Read partial sector */ +/*-----------------------------------------------------------------------*/ +sdresult_t sdmmc_readp(Ptr buf, long sector, uint offset, uint count) +{ + DRESULT res; + char d; + uint bc, tmr; + + + if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ + + res = RES_ERROR; + if (send_cmd(CMD17, sector) == 0) { /* READ_SINGLE_BLOCK */ + + tmr = 1000; + do { /* Wait for data packet in timeout of 100ms */ + DLY_US(100); + d = spi_rx(); + } while (d == 0xFF && --tmr); + + if (d == 0xFE) { /* A data packet arrived */ + bc = 514 - offset - count; + + /* Skip leading bytes */ + if (offset) spi_skip(offset); + + /* Receive a part of the sector */ + if (buff) { /* Store data to the memory */ + do + *buff++ = spi_rx(); + while (--count); + } else { /* Forward data to the outgoing stream */ + do { + d = spi_rx(); + FORWARD(d); + } while (--count); + } + + /* Skip trailing bytes and CRC */ + spi_skip(bc); + + res = RES_OK; + } + } + + release_spi(); + + return res; +} + + +/*-----------------------------------------------------------------------*/ +/* Write partial sector */ +/*-----------------------------------------------------------------------*/ +sdresult_t sdmmc_writep(const Ptr buf, long sc) +{ + DRESULT res; + UINT bc, tmr; + static UINT wc; + + res = RES_ERROR; + + if (buff) { /* Send data bytes */ + bc = (UINT)sc; + while (bc && wc) { /* Send data bytes to the card */ + spi_tx(*buff++); + wc--; bc--; + } + res = RES_OK; + } else { + if (sc) { /* Initiate sector write transaction */ + if (!(CardType & CT_BLOCK)) sc *= 512; /* Convert to byte address if needed */ + if (send_cmd(CMD24, sc) == 0) { /* WRITE_SINGLE_BLOCK */ + spi_tx(0xFF); spi_tx(0xFE); /* Data block header */ + wc = 512; /* Set byte counter */ + res = RES_OK; + } + } else { /* Finalize sector write transaction */ + bc = wc + 2; + while (bc--) spi_tx(0); /* Fill left bytes and CRC with zeros */ + if ((spi_rx() & 0x1F) == 0x05) { /* Receive data resp and wait for end of write process in timeout of 300ms */ + for (tmr = 10000; spi_rx() != 0xFF && tmr; tmr--) /* Wait for ready (max 1000ms) */ + DLY_US(100); + if (tmr) res = RES_OK; + } + release_spi(); + } + } + + return res; +} diff --git a/sdmmc.h b/sdmmc.h new file mode 100644 index 0000000..e2a49b6 --- /dev/null +++ b/sdmmc.h @@ -0,0 +1,29 @@ +#ifndef SDMMC_H +#define SDMMC_H + + +/* Status of Disk Functions */ +typedef char sdstatus_t; + +#define STA_NOINIT 0x01 /* Drive not initialized */ +#define STA_NODISK 0x02 /* No medium in the drive */ + + +/* Results of Disk Functions */ +typedef enum sdmmc_result_e { + RES_OK = 0, /* 0: Function succeeded */ + RES_ERROR, /* 1: Disk error */ + RES_NOTRDY, /* 2: Not ready */ + RES_PARERR /* 3: Invalid parameter */ +} sdresult_t; + + +/*---------------------------------------*/ +/* Prototypes for disk control functions */ +/*---------------------------------------*/ +sdstatus_t sdmmc_init(); +sdresult_t sdmmc_readp(Ptr buf, long sector, uint offset, uint count); +sdresult_t sdmmc_writep(const Ptr buf, long sc); + + +#endif diff --git a/spi.c b/spi.c new file mode 100644 index 0000000..4b918ff --- /dev/null +++ b/spi.c @@ -0,0 +1,164 @@ +#include "spi.h" + +/*-------------------------------------------------------------------------*/ +/* Platform dependent macros and functions needed to be modified */ +/*-------------------------------------------------------------------------*/ +#define CS_H() bset(P0) /* Set MMC CS "high" */ +#define CS_L() bclr(P0) /* Set MMC CS "low" */ +#define CK_H() bset(P1) /* Set MMC SCLK "high" */ +#define CK_L() bclr(P1) /* Set MMC SCLK "low" */ +#define DI_H() bset(P2) /* Set MMC DI "high" */ +#define DI_L() bclr(P2) /* Set MMC DI "low" */ +#define DO btest(P3) /* Test MMC DO (high:true, low:false) */ + + +// Command listing +/* T16: Transfer 16-bit + * First, the 16-bit value encoded in the address bits A[17:2] is latched. + * The data output mux is set to the current RXR and the cycle completes. + * Shortly after /AS rises, the SPI transfer engine begins + * transferring the latched value. + */ +/* T16S: Transfer 16-bit Swapped + * Same as T16L but read data is byte-swapped. + */ +/* MERT: Measure Elapsed time and Reset Timer + * The elapsed time since the last MERT command is returned in D[31:24] + * and the timer is reset. + */ +/* SKIP1: Skip Clocks with MOSI "1" + * + */ +/* SKIP0: Skip Clocks with MOSI "0" + * + */ +/* T8S: Transfer 8-bit Swapped + * Same as T8 but read data is byte-swapped. + */ +/* T8: Transfer 8-bit + * First, the 8-bit value encoded in the address bits A[9:2] is latched. + * The data output mux is set to the current RXR and the cycle completes. + * Shortly after /AS rises, the SPI transfer engine begins + * transferring the latched value. + */ +/* WRC: Write Command + * The command encoded in address bits A[9:2] is sent to the command target + * corresponding to the address bits A[15:10]. + * Command targets: + * $00 - Set bitbang + * A[2] - SCS value + */ +/* RDRXR: Read Receive Data Register + * The the current RXR is returned in D[31:16] and the cycle completes. + */ +/* RDRXRS: Read Receive Data Register Swapped + * Same as RDRXR but read data is byte-swapped. + */ +/* MAGIC: Write Command + * Write sequence $FF $00 $55 $AA $C1 $AD + * to enable registers at $40890000-$4097FFFF. + * Write anything else to disable them. + * Always reads 0xC1AD + */ + +// SPI controller address map: +// 40940000-4097FFFF (256 kB, D[31:16]) T16S. Write transfer data in A[17:2]. +// 40900000-4093FFFF (256 kB, D[31:16]) T16. Write transfer data in A[17:2]. +// 408C0000-408FFFFF (320 kB) reserved +// 408A0000-408AFFFF ( 64 kB, D[31:24]) WRC. Write port address in A[15:10] and data in A[9:2]. +// 40891C00-4089FFFF ( 55 kB) reserved +// 40892000-408923FF ( 1 kB, D[31:24]) MERT. +// 40891C00-40891FFF ( 1 kB) SKIP1. Write bytes to skip in A[9:2]. +// 40891800-40891BFF ( 1 kB) SKIP0. Write bytes to skip in A[9:2]. +// 40891400-408917FF ( 1 kB, D[31:16]) T8S. Write transfer data in A[9:2]. +// 40891000-408913FF ( 1 kB, D[31:16]) T8. Write transfer data in A[9:2]. +// 40890C00-40890FFF ( 1 kB, D[31:16]) RDRXRS. +// 40890800-40890BFF ( 1 kB, D[31:16]) RDRXR. +// 40890400-408907FF ( 1 kB) reserved +// 40890000-408903FF ( 1 kB, D[31:24]) MAGIC. Write magic numbers in A[9:2]. +// 40880000-408FFFFF ( 64 kB, D[31:00]) ROMBUS driver data + +#define RB_T16S(x) (*(volatile int*) (0x40940000 + ((x && 0xFFFF)<<02)) ) +#define RB_T16(x) (*(volatile int*) (0x40900000 + ((x && 0xFFFF)<<02)) ) +#define RB_RDS(a) (*(volatile char*) (0x408B0000 + ((a && 0x003F)<<10)) ) +#define RB_WRC(a,d) (*(volatile char*) (0x408A0000 + ((a && 0x003F)<<10) + + ((d && 0x00FF)<<02)) ) +#define RB_MERT(x) (*(volatile char*) (0x40892000 + ((x && 0xFFFF)<<02)) ) +#define RB_SKIP1(n) (*(volatile char*) (0x40891C00 + ((x && 0xFFFF)<<02)) ) +#define RB_SKIP0(n) (*(volatile char*) (0x40891800 + ((x && 0xFFFF)<<02)) ) +#define RB_T8S(x) (*(volatile int*) (0x40891400 + ((x && 0xFFFF)<<02)) ) +#define RB_T8(x) (*(volatile int*) (0x40891000 + ((x && 0xFFFF)<<02)) ) +#define RB_RDRXRS (*(volatile int*) (0x40890C00 + ((x && 0xFFFF)<<02)) ) +#define RB_RDRXR (*(volatile int*) (0x40890800 + ((x && 0xFFFF)<<02)) ) +#define RB_WRMOSI(x) (*(volatile char*) (0x40890400 + ((x && 0x0001)<<02)) ) +#define RB_MAGIC(x) (*(volatile char*) (0x40890000 + ((x && 0xFFFF)<<02)) ) + +#define SPI_GET_MISO(d) (d & 1) + +void spi_select() { + ret = *SPI_CMD_SEL0; + ret = *SPI_CMD_SEL1; + ret = *SPI_CMD_SEL2; + ret = *SPI_CMD_SEL3; +} +void spi_deselect() { + ret = *SPI_CMD_DES0; + ret = *SPI_CMD_DES1; + ret = *SPI_CMD_DES2; + ret = *SPI_CMD_DES3; +} + +void spi_tx_slow(char d) { + for (int i = 0; i < 8; i++) { + *SPI_CMD_BBA((0 & 0x02) | (d & 0x01)); + *SPI_CMD_BBA((1 & 0x02) | (d & 0x01)); + d >>= 1; + } + *SPI_CMD_BBA((0 & 0x02) | (0 & 0x01)); +} + +char spi_rx_slow() { + char ret = 0; + for (int i = 0; i < 8; i++) { + *SPI_CMD_BBA((0 & 0x02) | (1 & 0x01)); + *SPI_CMD_BBA((1 & 0x02) | (1 & 0x01)); + ret = (ret << 1) + (*SPI_CMD_BBA((1 & 0x02) | (1 & 0x01)) & 1); + } + return ret; +} + +void spi_skip_slow(int n) { + while (n-- > 0) { + for (int i = 0; i < 8; i++) { + *SPI_CMD_BBA((0 & 0x02) | (1 & 0x01)); + *SPI_CMD_BBA((1 & 0x02) | (1 & 0x01)); + } + } + *SPI_CMD_BBA((0 & 0x02) | (1 & 0x01)); +} + +void spi_tx_8(char d) { + *SPI_CMD_SH8(d); +} + +char spi_rx_8() { + *SPI_CMD_SH8(0xFF); + return *SPI_CMD_RD & 0xFF; +} + +void spi_tx_16(int d) { + *SPI_CMD_SH16(d); +} + +int spi_rx_16() { + *SPI_CMD_SH16(0xFFFF); + return *SPI_CMD_RD & 0xFFFF; +} + +void spi_skip(int n) { + while (n-- > 0) { + for (int i = 0; i < 8; i++) { + *SPI_CMD_SH8(0xFF); + } + } +} diff --git a/spi.h b/spi.h new file mode 100644 index 0000000..70ee2c5 --- /dev/null +++ b/spi.h @@ -0,0 +1,17 @@ +#ifndef SPI_H +#define SPI_H + +void spi_select(); +void spi_deselect(); + +void spi_tx_slow(char d); +char spi_rx_slow(); +void spi_skip_slow(int n); + +void spi_tx_8(char d); +char spi_rx_8(); +void spi_tx_16(int d); +int spi_rx_16(); +void spi_skip(int n); + +#endif diff --git a/xfer.h b/xfer.h new file mode 100644 index 0000000..bc81450 --- /dev/null +++ b/xfer.h @@ -0,0 +1,11 @@ +#ifndef RDISK_H +#define RDISK_H + +#pragma parameter xfer_s_256(__A0, __A1) +void xfer_s_256(Ptr srcreg, Ptr destmem); + +#pragma parameter xfer_s(__D0, __A0, __A1) +void xfer_s(uint8_t numBytes, Ptr srcreg, Ptr destmem); + + +#endif diff --git a/xfer.s b/xfer.s new file mode 100644 index 0000000..2c9b1d6 --- /dev/null +++ b/xfer.s @@ -0,0 +1,34 @@ + .macro xfer_in from, to + move.w (%A0), (%A1)+ + nop + nop + nop + .if \to-\from + xfer_in "(\from+1)" + .else + + .endif + .endm + + +;pragma parameter xfer_s_256(__A0, __A1) +;void xfer_s_256(Ptr srcreg, Ptr destmem); +xfer_256: + movem.l %D0/%A1-%A2, -(%SP) +xfer_256_loop: + xfer_s_in 0, 255 +xfer_256_end: + movem.l (%SP)+, %D0/%A1-%A2 + + +;pragma parameter xfer_s(__D0, __A0, __A1) +;void xfer_s(uint8_t numBytes, Ptr srcreg, Ptr destmem); +xfer: + movem.l %D0/%A1-%A2, -(%SP) + andi.l #0xFF, %D0 + subi.l #256, %D0 + neg.l %D0 + lsl.l #2, %D0 + addi.l #xfer_256, %D0 + movea.l %D0, %A2 + jmp %A2