printf("[AMIGA] PISCSI Interface Enabled.\n");
piscsi_enabled = 1;
piscsi_init();
- //ac_z2_type[ac_z2_pic_count] = ACTYPE_PISCSI;
- //ac_z2_pic_count++;
+ ac_z2_type[ac_z2_pic_count] = ACTYPE_PISCSI;
+ ac_z2_pic_count++;
adjust_ranges_amiga(cfg);
}
if (piscsi_enabled) {
* structures which require absolute pointers to ROM code or data.
*----- We'll store Version and Revision in serial number
-VERSION EQU 37 ; also the high word of serial number
-REVISION EQU 1 ; also the low word of serial number
+VERSION EQU 37 ; also the high word of serial number
+REVISION EQU 1 ; also the low word of serial number
* See the Addison-Wesley Amiga Hardware Manual for more info.
-
-MANUF_ID EQU 2011 ; CBM assigned (2011 for hackers only)
-PRODUCT_ID EQU 1 ; Manufacturer picks product ID
-
-BOARDSIZE EQU $10000 ; How much address space board decodes
-SIZE_FLAG EQU 3 ; Autoconfig 3-bit flag for BOARDSIZE
- ; 0=$800000(8meg) 4=$80000(512K)
- ; 1=$10000(64K) 5=$100000(1meg)
- ; 2=$20000(128K) 6=$200000(2meg)
- ; 3=$40000(256K) 7=$400000(4meg)
- CODE
-
-AllocMem EQU -198
+
+MANUF_ID EQU 2011 ; CBM assigned (2011 for hackers only)
+PRODUCT_ID EQU 1 ; Manufacturer picks product ID
+
+BOARDSIZE EQU $10000 ; How much address space board decodes
+SIZE_FLAG EQU 3 ; Autoconfig 3-bit flag for BOARDSIZE
+ ; 0=$800000(8meg) 4=$80000(512K)
+ ; 1=$10000(64K) 5=$100000(1meg)
+ ; 2=$20000(128K) 6=$200000(2meg)
+ ; 3=$40000(256K) 7=$400000(4meg)
+ CODE
+
+; Exec stuff
+AllocMem EQU -198
+InitResident EQU -102
+FindResident EQU -96
+OpenLibrary EQU -552
+CloseLibrary EQU -414
+
+; Expansion stuff
+MakeDosNode EQU -144
+AddDosNode EQU -150
+AddBootNode EQU -36
+
+; PiSCSI stuff
+PiSCSIAddr1 EQU $80000010
+PiSCSIDebugMe EQU $80000020
+PiSCSIDriver EQU $80000040
+PiSCSINextPart EQU $80000044
+PiSCSIGetPart EQU $80000048
+PiSCSIGetPrio EQU $8000004C
******* RomStart ***************************************************
**********************************************************************
******* Strings referenced in Diag Copy area ************************
-DevName: dc.b 'PiSCSI Snake Controller',0 ; Name string
-IdString dc.b 'PISCSI v0.1',0 ; Id string
+DevName: dc.b 'pi-scsi.device',0,0 ; Name string
+IdString dc.b 'PISCSI v0.8',0 ; Id string
-DosName: dc.b 'dos.library',0 ; DOS library name
+DosName: dc.b 'dos.library',0 ; DOS library name
+ExpansionName: dc.b "expansion.library",0
+LibName: dc.b "pi-scsi.device",0,0
DosDevName: dc.b 'ABC',0 ; dos device name for MakeDosNode()
; (dos device will be ABC:)
nop
nop
nop
- move.l #1,$80000020
+ move.l #1,PiSCSIDebugMe
+ move.l a3,PiSCSIAddr1
nop
nop
nop
BootEntry:
align 2
- move.l #2,$80000020
+ move.l #2,PiSCSIDebugMe
nop
nop
nop
nop
lea DosName(PC),a1 ; 'dos.library',0
- jsr _LVOFindResident(a6) ; find the DOS resident tag
+ jsr FindResident(a6) ; find the DOS resident tag
move.l d0,a0 ; in order to bootstrap
move.l RT_INIT(A0),a0 ; set vector to DOS INIT
jsr (a0) ; and initialize DOS
; BootNode, and Enqueue() on eb_MountList.
;
align 2
- move.w #$00B8,$dff09a
- move.l #3,$80000020
- nop
- nop
- nop
- nop
+ move.l a6,-(a7) ; Push A6 to stack
+ ;move.w #$00B8,$dff09a ; Disable interrupts during init
+ move.l #3,PiSCSIDebugMe
+
+ move.l #11,PiSCSIDebugMe
+ movea.l 4,a6
+ lea LibName(pc),a1
+ jsr FindResident(a6)
+ move.l #10,PiSCSIDebugMe
+ cmp.l #0,d0
+ bne.s SkipDriverLoad ; Library is already loaded, jump straight to partitions
- move.l #4,$80000020
+ move.l #4,PiSCSIDebugMe
movea.l 4,a6
move.l #$40000,d0
moveq #0,d1
- jsr AllocMem(a6)
+ jsr AllocMem(a6) ; Allocate memory for the PiStorm to copy the driver to
- move.l d0,$80000040
- nop
- nop
+ move.l d0,PiSCSIDriver ; Copy the PiSCSI driver to allocated memory and patch offsets
- move.l #5,$80000020
+ move.l #5,PiSCSIDebugMe
move.l d0,a1
move.l #0,d1
movea.l 4,a6
add.l #$02c,a1
- nop
- nop
- nop
- jsr -102(a6)
- nop
- nop
+ jsr InitResident(a6) ; Initialize the PiSCSI driver
+
+SkipDriverLoad:
+ lea ExpansionName(pc),a1
+ moveq #0,d0
+ jsr OpenLibrary(a6) ; Open expansion.library to make this work, somehow
+ move.l d0,a6
+
+PartitionLoop:
+ move.l #9,PiSCSIDebugMe
+ move.l PiSCSIGetPart,d0 ; Get the available partition in the current slot
+ beq.s EndPartitions ; If the next partition returns 0, there's no additional partitions
+ move.l d0,a0
+ jsr MakeDosNode(a6)
+ move.l #7,PiSCSIDebugMe
+ move.l d0,a0
+ move.l PiSCSIGetPrio,d0
+ move.l #0,d1
+ move.l PiSCSIAddr1,a1
+ jsr AddBootNode(a6)
+ move.l #8,PiSCSIDebugMe
+ move.l #1,PiSCSINextPart ; Switch to the next partition
+ bra.w PartitionLoop
+
+
+EndPartitions:
+ move.l a6,a1
+ movea.l 4,a6
+ jsr CloseLibrary(a6)
+ move.l #6,PiSCSIDebugMe
- moveq.l #1,d0 ; indicate "success"
+ move.l (a7)+,a6 ; Pop A6 from stack
- move.w #$80B8,$dff09a
+ ;move.w #$80B8,$dff09a ; Re-enable interrupts
+ moveq.l #1,d0 ; indicate "success"
rts
END
#define DEVICE_NAME "pi-scsi.device"
#define DEVICE_DATE "(3 Feb 2021)"
#define DEVICE_ID_STRING "PiSCSI " XSTR(DEVICE_VERSION) "." XSTR(DEVICE_REVISION) " " DEVICE_DATE
-#define DEVICE_VERSION 1
-#define DEVICE_REVISION 0
+#define DEVICE_VERSION 43
+#define DEVICE_REVISION 20
#define DEVICE_PRIORITY 0
#pragma pack(4)
for (int i = 0; i < NUM_UNITS; i++) {
uint16_t r = 0;
- WRITESHORT(PISCSI_CMD_DRVNUM, i);
+ WRITESHORT(PISCSI_CMD_DRVNUM, (i * 10));
dev_base->units[i].regs_ptr = PISCSI_OFFSET;
READSHORT(PISCSI_CMD_DRVTYPE, r);
dev_base->units[i].enabled = r;
}
iotd->iotd_Req.io_Error = io_err;
- //dev_base->open_count++;
+ ((struct Library *)dev_base->pi_dev)->lib_OpenCnt++;
}
static uint8_t* __attribute__((used)) close(struct Library *dev asm("a6"), struct IOExtTD *iotd asm("a1"))
{
- //dev_base->open_count--;
+ ((struct Library *)dev_base->pi_dev)->lib_OpenCnt--;
return 0;
}
break;
}
+ WRITESHORT(PISCSI_CMD_DRVNUM, u->unit_num);
READLONG(PISCSI_CMD_BLOCKS, maxblocks);
if (block + blocks > maxblocks || blocks == 0) {
err = IOERR_BADADDRESS;
err = IOERR_BADLENGTH;
break;
}
-
+
+ WRITESHORT(PISCSI_CMD_DRVNUM, u->unit_num);
READLONG(PISCSI_CMD_BLOCKS, blocks);
((uint32_t*)data)[0] = blocks - 1;
((uint32_t*)data)[1] = PISCSI_BLOCK_SIZE;
data[2] = 0;
data[3] = 8;
+ WRITESHORT(PISCSI_CMD_DRVNUM, u->unit_num);
READLONG(PISCSI_CMD_BLOCKS, maxblocks);
(blocks = (maxblocks - 1) & 0xFFFFFF);
PISCSI_CMD_ADDR4 = 0x1C,
PISCSI_CMD_DEBUGME = 0x20,
PISCSI_CMD_DRIVER = 0x40,
+ PISCSI_CMD_NEXTPART = 0x44,
+ PISCSI_CMD_GETPART = 0x48,
+ PISCSI_CMD_GETPRIO = 0x4C,
PISCSI_CMD_WRITE64 = 0x50,
PISCSI_CMD_READ64 = 0x52,
PISCSI_DBG_MSG = 0x1000,
#include "../../../config_file/config_file.h"
#include "../../../gpio/ps_protocol.h"
-// Comment this line to restore debug output:
-//#define printf(...)
+#define BE(val) be32toh(val)
+
+// Comment these lines to restore debug output:
+#define printf(...)
+#define stop_cpu_emulation(...)
#ifdef FAKESTORM
#define lseek64 lseek
uint32_t piscsi_rom_size = 0;
uint8_t *piscsi_rom_ptr;
+uint32_t rom_partitions[128];
+uint32_t rom_partition_prio[128];
+uint32_t rom_cur_partition = 0;
+
extern unsigned char ac_piscsi_rom[];
static const char *op_type_names[4] = {
void piscsi_find_partitions(struct piscsi_dev *d) {
int fd = d->fd;
- char *block = malloc(512);
int cur_partition = 0;
uint8_t tmp;
+ for (int i = 0; i < 16; i++) {
+ if (d->pb[i]) {
+ free(d->pb[i]);
+ d->pb[i] = NULL;
+ }
+ }
+
if (!d->rdb || d->rdb->rdb_PartitionList == 0) {
printf("[PISCSI] No partitions on disk.\n");
return;
}
+ char *block = malloc(512);
+
lseek(fd, be32toh(d->rdb->rdb_PartitionList) * 512, SEEK_SET);
next_partition:;
read(fd, block, 512);
struct PartitionBlock *pb = (struct PartitionBlock *)block;
tmp = pb->pb_DriveName[0];
pb->pb_DriveName[tmp + 1] = 0x00;
- printf("Partition %d: %s\n", cur_partition, pb->pb_DriveName + 1);
+ printf("[PISCSI] Partition %d: %s\n", cur_partition, pb->pb_DriveName + 1);
+ printf("Checksum: %.8X HostID: %d\n", BE(pb->pb_ChkSum), BE(pb->pb_HostID));
+ printf("Flags: %d (%.8X) Devflags: %d (%.8X)\n", BE(pb->pb_Flags), BE(pb->pb_Flags), BE(pb->pb_DevFlags), BE(pb->pb_DevFlags));
d->pb[cur_partition] = pb;
if (d->pb[cur_partition]->pb_Next != 0xFFFFFFFF) {
block = malloc(512);
lseek64(fd, next * 512, SEEK_SET);
cur_partition++;
- printf("Next partition at block %d.\n", be32toh(pb->pb_Next));
+ printf("[PISCSI] Next partition at block %d.\n", be32toh(pb->pb_Next));
goto next_partition;
}
- printf("No more partitions on disk.\n");
+ printf("[PISCSI] No more partitions on disk.\n");
+ d->num_partitions = cur_partition + 1;
return;
}
uint32_t first = be32toh(*((uint32_t *)&block[0]));
if (first == RDB_IDENTIFIER)
goto rdb_found;
- else {
- printf("Block %d is not RDB, looking for %.8X, found %.8X\n", i, RDB_IDENTIFIER, first);
- }
}
goto no_rdb_found;
rdb_found:;
break;
case DBG_IOCMD_UNHANDLED:
printf("[PISCSI] WARN: IO command %.4X (%s) is unhandled by driver.\n", piscsi_dbg[0], io_cmd_name(piscsi_dbg[0]));
+ break;
}
}
case PISCSI_CMD_READ:
d = &devs[val];
if (d->fd == -1) {
- printf ("[PISCSI] BUG: Attempted read from unmapped drive %d.\n", piscsi_cur_drive);
+ printf ("[PISCSI] BUG: Attempted read from unmapped drive %d.\n", val);
break;
}
case PISCSI_CMD_WRITE:
d = &devs[val];
if (d->fd == -1) {
- printf ("[PISCSI] BUG: Attempted write to unmapped drive %d.\n", piscsi_cur_drive);
+ printf ("[PISCSI] BUG: Attempted write to unmapped drive %d.\n", val);
break;
}
break;
}
case PISCSI_CMD_DRVNUM:
- if (val != 0) {
- if (val < 10) // Kludge for GiggleDisk
- piscsi_cur_drive = val;
- else if (val >= 10 && val % 10 != 0)
- piscsi_cur_drive = 255;
- else
- piscsi_cur_drive = val / 10;
- }
+ if (val % 10 != 0)
+ piscsi_cur_drive = 255;
else
- piscsi_cur_drive = val;
+ piscsi_cur_drive = val / 10;
printf("[PISCSI] (%s) Drive number set to %d (%d)\n", op_type_names[type], piscsi_cur_drive, val);
break;
case PISCSI_CMD_DEBUGME:
if (r != -1) {
uint32_t addr = val - cfg->map_offset[r];
uint8_t *dst_data = cfg->map_data[r];
+ uint8_t cur_partition = 0;
memcpy(dst_data + addr, piscsi_rom_ptr + 0x400, 0x3C00);
piscsi_hinfo.base_offset = val;
reloc_hunks(piscsi_hreloc, dst_data + addr, &piscsi_hinfo);
stop_cpu_emulation(1);
- }
- else {
- for (int i = 0; i < 0x3C00; i++) {
- uint8_t src = piscsi_rom_ptr[0x400 + i];
- write8(addr + i, src);
+
+ #define PUTNODELONG(val) *(uint32_t *)&dst_data[p_offs] = htobe32(val); p_offs += 4;
+ #define PUTNODELONGBE(val) *(uint32_t *)&dst_data[p_offs] = val; p_offs += 4;
+
+ for (int i = 0; i < 128; i++) {
+ rom_partitions[i] = 0;
+ rom_partition_prio[i] = 0;
+ }
+ rom_cur_partition = 0;
+
+ uint32_t data_addr = addr + 0x3F00;
+ sprintf((char *)dst_data + data_addr, "pi-scsi.device");
+ uint32_t addr2 = addr + 0x4000;
+ for (int i = 0; i < NUM_UNITS; i++) {
+ piscsi_find_partitions(&devs[i]);
+ if (devs[i].num_partitions) {
+ uint32_t p_offs = addr2;
+ printf("[PISCSI] Adding %d partitions for unit %d\n", devs[i].num_partitions, i);
+ for (uint32_t j = 0; j < devs[i].num_partitions; j++) {
+ printf("Partition %d: %s\n", j, devs[i].pb[j]->pb_DriveName + 1);
+ sprintf((char *)dst_data + p_offs, "%s", devs[i].pb[j]->pb_DriveName + 1);
+ p_offs += 0x20;
+ PUTNODELONG(addr2 + cfg->map_offset[r]);
+ PUTNODELONG(data_addr + cfg->map_offset[r]);
+ PUTNODELONG((i * 10));
+ PUTNODELONG(0);
+ uint32_t nodesize = (be32toh(devs[i].pb[j]->pb_Environment[0]) + 1) * 4;
+ memcpy(dst_data + p_offs, devs[i].pb[j]->pb_Environment, nodesize);
+
+ struct pihd_dosnode_data *dat = (struct pihd_dosnode_data *)(&dst_data[addr2+0x20]);
+
+ if (BE(devs[i].pb[j]->pb_Flags) & 0x01) {
+ printf("Partition is bootable.\n");
+ rom_partition_prio[cur_partition] = 0;
+ dat->priority = 0;
+ }
+ else {
+ printf("Partition is not bootable.\n");
+ rom_partition_prio[cur_partition] = -128;
+ dat->priority = htobe32(-128);
+ }
+
+ printf("DOSNode Data:\n");
+ printf("Name: %s Device: %s\n", dst_data + addr2, dst_data + data_addr);
+ printf("Unit: %d Flags: %d Pad1: %d\n", BE(dat->unit), BE(dat->flags), BE(dat->pad1));
+ printf("Node len: %d Block len: %d\n", BE(dat->node_len) * 4, BE(dat->block_len) * 4);
+ printf("H: %d SPB: %d BPS: %d\n", BE(dat->surf), BE(dat->secs_per_block), BE(dat->blocks_per_track));
+ printf("Reserved: %d Prealloc: %d\n", BE(dat->reserved_blocks), BE(dat->pad2));
+ printf("Interleaved: %d Buffers: %d Memtype: %d\n", BE(dat->interleave), BE(dat->buffers), BE(dat->mem_type));
+ printf("Lowcyl: %d Highcyl: %d Prio: %d\n", BE(dat->lowcyl), BE(dat->highcyl), BE(dat->priority));
+ printf("Maxtransfer: %.8X Mask: %.8X\n", BE(dat->maxtransfer), BE(dat->transfer_mask));
+ printf("DOSType: %.8X\n", BE(dat->dostype));
+
+ rom_partitions[cur_partition] = addr2 + 0x20 + cfg->map_offset[r];
+ cur_partition++;
+ addr2 += 0x100;
+ p_offs = addr2;
+ }
+ }
}
}
+
break;
}
+ case PISCSI_CMD_NEXTPART:
+ printf("[PISCSI] Switch partition %d -> %d\n", rom_cur_partition, rom_cur_partition + 1);
+ rom_cur_partition++;
+ break;
case PISCSI_DBG_VAL1: case PISCSI_DBG_VAL2: case PISCSI_DBG_VAL3: case PISCSI_DBG_VAL4:
case PISCSI_DBG_VAL5: case PISCSI_DBG_VAL6: case PISCSI_DBG_VAL7: case PISCSI_DBG_VAL8: {
int i = ((addr & 0xFFFF) - PISCSI_DBG_VAL1) / 4;
}
switch (addr & 0xFFFF) {
+ case PISCSI_CMD_ADDR1: case PISCSI_CMD_ADDR2: case PISCSI_CMD_ADDR3: case PISCSI_CMD_ADDR4: {
+ int i = ((addr & 0xFFFF) - PISCSI_CMD_ADDR1) / 4;
+ return piscsi_u32[i];
+ break;
+ }
case PISCSI_CMD_DRVTYPE:
if (devs[piscsi_cur_drive].fd == -1) {
printf("[PISCSI] %s Read from DRVTYPE %d, drive not attached.\n", op_type_names[type], piscsi_cur_drive);
return blox;
break;
}
+ case PISCSI_CMD_GETPART: {
+ printf("[PISCSI] Get ROM partition %d offset: %.8X\n", rom_cur_partition, rom_partitions[rom_cur_partition]);
+ return rom_partitions[rom_cur_partition];
+ break;
+ }
+ case PISCSI_CMD_GETPRIO:
+ printf("[PISCSI] Get partition %d boot priority: %d\n", rom_cur_partition, rom_partition_prio[rom_cur_partition]);
+ return rom_partition_prio[rom_cur_partition];
+ break;
default:
printf("[PISCSI] Unhandled %s register read from %.8X\n", op_type_names[type], addr);
break;
uint64_t fs;
int32_t fd;
uint32_t lba;
+ uint32_t num_partitions;
// Will parse max eight partitions per disk
struct PartitionBlock *pb[16];
struct RigidDiskBlock *rdb;
};
-/*
-dosnode: \
// .long 0 /* dos disk name */
// .long 0 /* device file name */
// .long 0 /* unit */
// .long 0 /* flags */
-// .long 16 /* length of node? */
-// .long 128 /* longs in a block */
-// .long 0
-// .long 4 /* surfaces */
-// .long 1 /* sectors per block */
-// .long 256 /* blocks per track */
-// .long 2 /* reserved bootblocks 256 = 128KB */
-// .long 0
-// .long 0
-// .long 2 /* lowcyl FIXME */
-// /*.long 2047*/ /* hicyl */
-// .long 10 /* buffers */
-// .long 0 /* MEMF_ANY */
-// .long 0x0001fe00 /* MAXTRANS */
-// .long 0x7ffffffe /* Mask */
-// .long -1 /* boot prio */
-// .long 0x444f5303 /* dostype: DOS3 */1
+struct DosEnvec {
+ uint32_t de_TableSize; /* Size of Environment vector */
+ uint32_t de_SizeBlock; /* in longwords: standard value is 128 */
+ uint32_t de_SecOrg; /* not used; must be 0 */
+ uint32_t de_Surfaces; /* # of heads (surfaces). drive specific */
+ uint32_t de_SectorPerBlock; /* not used; must be 1 */
+ uint32_t de_BlocksPerTrack; /* blocks per track. drive specific */
+ uint32_t de_Reserved; /* DOS reserved blocks at start of partition. */
+ uint32_t de_PreAlloc; /* DOS reserved blocks at end of partition */
+ uint32_t de_Interleave; /* usually 0 */
+ uint32_t de_LowCyl; /* starting cylinder. typically 0 */
+ uint32_t de_HighCyl; /* max cylinder. drive specific */
+ uint32_t de_NumBuffers; /* Initial # DOS of buffers. */
+ uint32_t de_BufMemType; /* type of mem to allocate for buffers */
+ uint32_t de_MaxTransfer; /* Max number of bytes to transfer at a time */
+ uint32_t de_Mask; /* Address Mask to block out certain memory */
+ int32_t de_BootPri; /* Boot priority for autoboot */
+ uint32_t de_DosType; /* ASCII (HEX) string showing filesystem type;
+ * 0X444F5300 is old filesystem,
+ * 0X444F5301 is fast file system */
+ uint32_t de_Baud; /* Baud rate for serial handler */
+ uint32_t de_Control; /* Control word for handler/filesystem */
+ uint32_t de_BootBlocks; /* Number of blocks containing boot code */
+
+};
struct pihd_dosnode_data {
uint32_t name_ptr;
uint32_t blocks_per_track;
uint32_t reserved_blocks;
uint32_t pad2;
- uint32_t pad3;
+ uint32_t interleave;
uint32_t lowcyl;
uint32_t highcyl;
uint32_t buffers;
This driver and interface is work in progress, do not use it in conjunction with any critical data that you need to survive.
+# Making changes to the driver
+
+If you make changes to the driver, you can always test these on the Amiga as a regular file in `DEVS:`, but the Z2 device has to be disabled for this to work properly.
+
+If you use the boot ROM, the separate `pi-scsi.device` driver file currently has to match the one in `piscsi.rom`. This is due to an oversight, and will probably be addressed at some point...
+
+Steps to create an updated boot ROM, all of these are done in the `device_driver_amiga` directory:
+
+* (Optional) If you've made changes to bootrom.s, first run `./build.sh`.
+* (Optional) If you've had build.sh create a new `bootrom` file, you need to chop off the first few bytes of it, since VASM adds a single hunk to the beginning of it. Simply delete all bytes up until you bump into the value `0x90`, this is the first value in the boot ROM identifier.
+* Compile the new `pi-scsi.device` using `./build2.sh`.
+* (Optional) If you haven't previously compiled the `makerom` binary, or the code for it has been updated since last time, simply run `gcc makerom.c -o makerom`
+* Run `./makerom` to assemble the boot ROM file, it's automatically in the correct place for the emulator to find it.
+
# Instructions
In a perfect world, the PiSCSI boot ROM would automatically detect drives/partitions and add them as boot nodes to be available during early startup, but this is not yet possible.
If the MountList has several partitions listed in it, it must be split up into separate files for all partitions to be mounted.
-Once you've edited a MountList file, simply copy/move it to `SYS:Devs:DOSDrivers`, and the drive will be mounted automatically the next time you boot into Workbench.
+Once you've edited a MountList file, simply copy/move it to `SYS:Devs/DOSDrivers`, and the drive will be mounted automatically the next time you boot into Workbench.
If you don't want it to be mounted automatically, simply use the `Mount` command from CLI.