This commit is contained in:
Zane Kaminski 2021-05-22 17:40:15 -04:00
parent 49b479949a
commit e02ef0f8d9
12 changed files with 1078 additions and 532 deletions

View File

@ -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

34
entry.s
View File

@ -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:

285
rdisk.c
View File

@ -1,285 +0,0 @@
#include <Memory.h>
#include <Devices.h>
#include <Files.h>
#include <Disks.h>
#include <Errors.h>
#include <Events.h>
#include <OSUtils.h>
#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;
}

195
rdisk.h
View File

@ -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 <Quickdraw.h>
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

361
rombus.c Normal file
View File

@ -0,0 +1,361 @@
#include <Memory.h>
#include <Devices.h>
#include <Files.h>
#include <Disks.h>
#include <Errors.h>
#include <Events.h>
#include <OSUtils.h>
#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;
}

179
rombus.h Normal file
View File

@ -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

220
sdmmc.c Normal file
View File

@ -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<n> is the command sequense of CMD55-CMD<n> */
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;
}

29
sdmmc.h Normal file
View File

@ -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

164
spi.c Normal file
View File

@ -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);
}
}
}

17
spi.h Normal file
View File

@ -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

11
xfer.h Normal file
View File

@ -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

34
xfer.s Normal file
View File

@ -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