//
// First 1K is the driver ROM, repeated four times. After that, there are 31 1K
// chunks that are addressed in the $CC00-$CFFF address range; $C800-$CBFF is a
-// 1K RAM space (internally, it's an 8K static RAM).
+// 1K RAM space (8K static RAM, bank switched).
//
#include "harddrive.h"
#include "apple2.h"
#include "dis65c02.h"
#include "fileio.h"
-#include "firmware.h"
+#include "firmware/a2hs-scsi.h"
#include "log.h"
#include "mmu.h"
#include "settings.h"
#include "v65c02.h" // For dumpDis...
-static uint8_t bank = 0;
+static uint8_t romBank = 0;
static uint8_t ramBank = 0;
static uint8_t deviceID = 7;
static bool dmaSwitch = false;
Switches on the card:
#1 sets DMA on/off (switch pos UP = OPEN = off)
-#2-4 sets the computer's SCSI ID number (preset at factor to 7)
+#2-4 sets the computer's SCSI ID number (preset at factory to 7)
Looks like bits 5-7 of register $E is device ID
static uint32_t bytesToSend;
static uint8_t * buf;
static uint32_t bufPtr;
-
+static uint8_t response;
static void RunDevice(void)
{
static uint8_t readCapacity[8] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 };
static uint8_t inquireData[30] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'S', 'E', 'A', 'G', 'A', 'T', 'E', ' ', 'P', 'h', 'o', 'n', 'y', '1' };
+ static uint8_t badSense[20] = { 0x70, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
enum {
DVM_DATA_OUT = 0, DVM_DATA_IN = 1, DVM_COMMAND = 2, DVM_STATUS = 3,
if (RST)
{
-WriteLog(" >>> DEVICE RESET...\n");
+//WriteLog(" >>> DEVICE RESET...\n");
devMode = DVM_BUS_FREE;
DEV_BSY = false;
return;
break;
case DVM_ARBITRATE:
-//WriteLog(" >>> ARBITRATE PHASE (BSY=%i SEL=%i DATA_BUS=%i [%02X])\n", BSY, SEL, DATA_BUS, reg[0]);
+////WriteLog(" >>> ARBITRATE PHASE (BSY=%i SEL=%i DATA_BUS=%i [%02X])\n", BSY, SEL, DATA_BUS, reg[0]);
if (!BSY && SEL && DATA_BUS && (reg[0] & 0x40))
devMode = DVM_SELECT, DEV_BSY = true;
else if (!BSY && !SEL)
break;
case DVM_SELECT:
-WriteLog(" >>> SELECT PHASE\n");
+//WriteLog(" >>> SELECT PHASE\n");
+ // Preset response code to "Good"
+ response = 0x00;
+
if (ATN)
{
MSG = true, C_D = true, I_O = false;
break;
case DVM_DATA_OUT:
-WriteLog(" >>> DATA OUT PHASE\n");
+//WriteLog(" >>> DATA OUT PHASE (bts=%u)\n", bytesToSend);
if (!ACK)
REQ = true;
{
if (!DACK)
{
- // We just send zeroes for now...
- reg[6] = 0;
DRQ = true;
}
else if (DRQ && DACK)
{
+ if (buf)
+ buf[bufPtr] = reg[0];
+
DRQ = false;
DACK = false;
bytesToSend--;
+ bufPtr++;
if (bytesToSend == 0)
{
REQ = false;
MSG = false, C_D = true, I_O = true;
devMode = DVM_STATUS;
+ buf = NULL;
}
}
}
break;
case DVM_DATA_IN:
-WriteLog(" >>> DATA IN PHASE (bts=%u)\n", bytesToSend);
+//WriteLog(" >>> DATA IN PHASE (bts=%u)\n", bytesToSend);
if (!ACK)
REQ = true;
break;
case DVM_COMMAND:
-WriteLog(" >>> COMMAND PHASE\n");
+//WriteLog(" >>> COMMAND PHASE\n");
if (!ACK)
REQ = true;
else if (REQ && ACK)
{
cmd[cmdLength++] = reg[0];
- WriteLog("HD: Write to target value $%02X\n", reg[0]);
+// WriteLog("HD: Write to target value $%02X\n", reg[0]);
REQ = false;
}
MSG = false, C_D = false, I_O = true;
devMode = DVM_DATA_IN;
bytesToSend = cmd[4];
+
+ // Return error for LUNs other than 0
+ if ((cmd[1] & 0xE0) != 0)
+ {
+ buf = badSense;
+ bufPtr = 0;
+ }
}
// Handle "Read" (6) command
else if ((cmd[0] == 0x08) && (cmdLength == 6))
bytesToSend = cmd[4];
buf = inquireData;
bufPtr = 0;
+
+ // Reject all but LUN 0
+ if ((cmd[1] & 0xE0) != 0)
+ {
+ response = 0x02; // Check condition code
+// MSG = false, C_D = false, I_O = false;
+// DEV_BSY = false;
+// devMode = DVM_BUS_FREE;
+ }
}
// Handle "Mode Select" command
else if ((cmd[0] == 0x15) && (cmdLength == 6))
devMode = DVM_DATA_IN;
bytesToSend = ((cmd[7] << 8) | cmd[8]) * 512; // amount is set in blocks
uint32_t lba = (cmd[2] << 24) | (cmd[3] << 16) | (cmd[4] << 8) | cmd[5];
- buf = &hdData[(lba * 512) + 0x40];
+ buf = (hdData != NULL ? &hdData[(lba * 512) + 0x40] : NULL);
+ bufPtr = 0;
+ }
+ // Handle "Write" (10) command
+ else if ((cmd[0] == 0x2A) && (cmdLength == 10))
+ {
+ WriteLog("HD: Received command WRITE(10) [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9]);
+ REQ = false;
+ // Drive next phase
+ MSG = false, C_D = false, I_O = false;
+ devMode = DVM_DATA_OUT;
+ bytesToSend = ((cmd[7] << 8) | cmd[8]) * 512; // amount is set in blocks
+ uint32_t lba = (cmd[2] << 24) | (cmd[3] << 16) | (cmd[4] << 8) | cmd[5];
+ buf = (hdData != NULL ? &hdData[(lba * 512) + 0x40] : NULL);
bufPtr = 0;
}
else if ((cmdLength == 6) && ((cmd[0] & 0xE0) == 0))
break;
case DVM_STATUS:
-WriteLog(" >>> STATUS PHASE\n");
+//WriteLog(" >>> STATUS PHASE\n");
if (!ACK)
{
// Return A-OK for everything for now...
break;
case DVM_MESSAGE_OUT:
-WriteLog(" >>> MESSAGE OUT PHASE\n");
+//WriteLog(" >>> MESSAGE OUT PHASE\n");
if (REQ && ACK)
{
uint8_t msg = reg[0];
- WriteLog("HD: Write to target value $%02X\n", msg);
+// WriteLog("HD: Write to target value $%02X\n", msg);
REQ = false;
// Drive next phase
MSG = false, C_D = true, I_O = false;
break;
case DVM_MESSAGE_IN:
-WriteLog(" >>> MESSAGE IN PHASE\n");
+//WriteLog(" >>> MESSAGE IN PHASE\n");
if (!ACK)
{
// Return A-OK for everything for now...
- reg[0] = 0;
+ reg[0] = response;
REQ = true;
}
else if (REQ && ACK)
case 0x04:
// (RO) Current SCSI Bus Status register: Bits from hi to lo:
// /RST, /BSY, /REQ, /MSG, /C/D, /I/O, /SEL, /DBP
-if (((mainCPU.pc != 0xCD7C) && (mainCPU.pc != 0xCD5F)) || (bank != 16))
- WriteLog(" [%02X %02X %02X %02X %02X %02X %02X %02X] [$C81F=$%02X $C80D=$%02X $C80A=$%02X $C887=$%02X $C806=$%02X $C88F=$%02X $C8EC=$%02X $4F=$%02X]\n", reg[0], reg[1], reg[2], reg[3], reg[4], reg[5], reg[6], reg[7], staticRAM[0x1F], staticRAM[0x0D], staticRAM[0x0A], staticRAM[0x87], staticRAM[0x06], staticRAM[0x8F], staticRAM[0xEC], ram[0x4F]);
+/*if (((mainCPU.pc != 0xCD7C) && (mainCPU.pc != 0xCD5F)) || (romBank != 16))
+ WriteLog(" [%02X %02X %02X %02X %02X %02X %02X %02X] [$C81F=$%02X $C80D=$%02X $C80A=$%02X $C887=$%02X $C806=$%02X $C88F=$%02X $C8EC=$%02X $4F=$%02X]\n", reg[0], reg[1], reg[2], reg[3], reg[4], reg[5], reg[6], reg[7], staticRAM[0x1F], staticRAM[0x0D], staticRAM[0x0A], staticRAM[0x87], staticRAM[0x06], staticRAM[0x8F], staticRAM[0xEC], ram[0x4F]);//*/
response = (RST ? 0x80 : 0) | (BSY | DEV_BSY ? 0x40 : 0) | (REQ ? 0x20 : 0) | (MSG ? 0x10 : 0) | (C_D ? 0x08 : 0) | (I_O ? 0x04 : 0) | (SEL ? 0x02 : 0);
break;
response = 0x10 | (dmaSwitch ? 0x40 : 0);
break;
case 0x0E:
- response = bank | (deviceID << 5);
+ response = romBank | (deviceID << 5);
break;
}
- if (((mainCPU.pc != 0xCD7C) && (mainCPU.pc != 0xCD5F)) || (bank != 16))
- WriteLog("HD Slot I/O read %s ($%02X <- $%X, PC=%04X:%u)\n", SCSIName[address & 0x0F], response, address & 0x0F, mainCPU.pc, bank);
+/* if (((mainCPU.pc != 0xCD7C) && (mainCPU.pc != 0xCD5F)) || (romBank != 16))
+ WriteLog("HD Slot I/O read %s ($%02X <- $%X, PC=%04X:%u)\n", SCSIName[address & 0x0F], response, address & 0x0F, mainCPU.pc, romBank);//*/
return response;
}
// Mode register (chip control)
// Dma ReQuest is reset here (as well as by hitting a pin)
-// if ((byte & 0x02) == 0)
-// DRQ = false;
DMA_MODE = (byte & 0x02 ? true : false);
if (!DMA_MODE)
// ???
break;
case 0x0E:
- // Bottom 5 bits of $E set the ROM bank...
- bank = byte & 0x1F;
-// WriteLog("HD: Setting bank %u\n", bank);
+ // Bottom 5 bits of $E set the ROM bank
+ romBank = byte & 0x1F;
break;
case 0x0F:
- // ??? RAM bank? Seems to be
+ // Bottom 3 bits of $F set the RAM bank
ramBank = byte & 0x07;
break;
}
- WriteLog("HD Slot I/O write %s ($%02X -> $%X, PC=%04X:%u)\n", SCSIName[address & 0x0F], byte, address & 0x0F, mainCPU.pc, bank);
+/* WriteLog("HD Slot I/O write %s ($%02X -> $%X, PC=%04X:%u)\n", SCSIName[address & 0x0F], byte, address & 0x0F, mainCPU.pc, romBank);//*/
reg[address & 0x0F] = byte;
- if ((address & 0x0F) == 0x0E)
+/* if ((address & 0x0F) == 0x0E)
{
if (mainCPU.pc == 0xC78B)
{
uint16_t sp = mainCPU.sp;
uint16_t pc = ram[0x100 + sp + 1] | (ram[0x100 + sp + 2] << 8);
- WriteLog(" *** Returning to bank %u, $%04X\n", bank, pc + 1);
+ WriteLog(" *** Returning to bank %u, $%04X\n", romBank, pc + 1);
}
else if (mainCPU.pc == 0xC768)
{
}
WriteLog(" [%02X %02X %02X %02X %02X %02X %02X %02X] [$C81F=$%02X $C80D=$%02X $C80A=$%02X $C887=$%02X $C806=$%02X $C88F=$%02X $C8EC=$%02X $4F=$%02X]\n", reg[0], reg[1], reg[2], reg[3], reg[4], reg[5], reg[6], reg[7], staticRAM[0x1F], staticRAM[0x0D], staticRAM[0x0A], staticRAM[0x87], staticRAM[0x06], staticRAM[0x8F], staticRAM[0xEC], ram[0x4F]);
- }
+ }//*/
// This should prolly go somewhere else...
RunDevice();
static uint8_t SlotROM(uint16_t address)
{
- return hd2ROM[address];
+ return a2hsScsiROM[address];
}
if (address < 0x400)
return staticRAM[(ramBank * 0x400) + address];
else
- return hd2ROM[(bank * 0x400) + address - 0x400];
+ return a2hsScsiROM[(romBank * 0x400) + address - 0x400];
}
if (address < 0x400)
staticRAM[(ramBank * 0x400) + address] = byte;
else
- {
- WriteLog("Unhandled HD 1K ROM write ($%02X) @ $C%03X...\n", byte, address + 0x800);
+// {
+ WriteLog("HD: Unhandled HD 1K ROM write ($%02X) @ $C%03X...\n", byte, address + 0x800);
- if ((mainCPU.pc == 0xCDDD) && (bank == 11))
- dumpDis = true;
- }
+/* if ((mainCPU.pc == 0xCDDD) && (romBank == 11))
+ dumpDis = true;//*/
+// }
}
SlotData hd = { SlotIOR, SlotIOW, SlotROM, 0, SlotIOExtraR, SlotIOExtraW };
InstallSlotHandler(slot, &hd);
+ // If this fails to read the file, the pointer is set to NULL
uint32_t size = 0;
hdData = ReadFile(settings.hdPath, &size);
- WriteLog("Read Hard Drive image file, %u bytes ($%X)\n", size, size);
+ if (hdData)
+ WriteLog("HD: Read Hard Drive image file, %u bytes ($%X)\n", size - 0x40, size - 0x40);
+ else
+ WriteLog("HD: Could not read Hard Drive image file!\n");
}