Oz-DOS and Format command support (#88, PR #1337)

Support FORMAT cmd:
. HDC firmware: byte $FE, b3=1 (format supported)
. HDC firmware: allow both SmartPort and BLK FORMAT cmd (and check that SP FORMAT only has 1 parameter)

SmartPort Controller:
. Format will just zero all blocks (if not write-protected)
. Write cmd: if write-protected return NOWRITE
. SP Status cmd: 'General Status': set format-allowed & write-protected flags

If HDD image is read-only then support as write-protected.
. On Insert() setup m_bWriteProtected flag correctly
This commit is contained in:
TomCh 2024-11-02 11:39:49 +00:00 committed by GitHub
parent 5ddb2357aa
commit 964a5d5198
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 142 additions and 79 deletions

View File

@ -243,7 +243,7 @@ Cn_BLK php
ldy #0
- lda BLK_Cmd,y
sta IO_BlkCmdFifo,x ; BLK_Cmd's are $0x
sta IO_BlkCmdFifo,x ; BLK_Cmd's are $0x (NB. not range-checked unlike SP cmds)
iny ; BLK_UnitNum's are DSSS0000 : if SSS does NOT match physical slot...
; ...hardware should handle the remap by adding +2 to the REAL dev_ID
cpy #6 ; that way, a BLK controller can support 4 devices (see $CnFE byte below)
@ -276,7 +276,9 @@ Cn_BLK_Done lsr ; Post: C=0 or 1
Cn_SP lda (Ptr1),y ; CMD byte
cmp #SP_Cmd_format
bcs Cn_SP_E_BADCALL ; only STATUS, READBLOCK & WRITEBLOCK supported
beq +
bcs Cn_SP_E_BADCALL ; only STATUS, READBLOCK, WRITEBLOCK & FORMAT supported
+ ; C=1 if FORMAT cmd [*1]
ldx Slot_n0
@ -293,15 +295,25 @@ Cn_SP lda (Ptr1),y ; CMD byte
pla
sta Ptr1 ; Now Ptr1 = Param list
ldy #0 ; Param Cnt
ldy #0 ; Param Idx (in bytes)
lda (Ptr1),y
cmp #3 ; STATUS, READBLOCK & WRITEBLOCK = all 3 parameters
sec
!if 1 { ; (This parameter-checking code could be removed to free up some space)
bcs @format ; NB. C-flag untouched from above [*1]
cmp #3 ; STATUS, READBLOCK & WRITEBLOCK: all have 3 parameters
beq +
bne Cn_SP_E_BADCNT
@format cmp #1 ; FORMAT: has 1 parameter
bne Cn_SP_E_BADCNT
+
}
- iny ; UnitNum (B), MemPtr (L/H), DiskBlock (L/M/H) -> IO (R,W)
lda (Ptr1),y ; UnitNum (B), MemPtr (L/H), StatusCode (B) -> IO (S)
; Parameter-1: Parameter-2: Parameter-3:
; UnitNum (B), MemPtr (L/H), StatusCode (B) -> IO (STATUS)
; UnitNum (B), MemPtr (L/H), DiskBlock (L/M/H) -> IO (READ,WRITE)
; UnitNum (B) -> IO (FORMAT)
- iny ; Always copy 6 more bytes to the FIFO regardless of the command
lda (Ptr1),y
sta IO_SPCmdFifo,x ; UnitNum Range is 0 (smartport controller itself), 1,2,3.....
cpy #6 ; blockNums are 24-bit for SP calls
bcc -
@ -364,7 +376,8 @@ Cn_SP_E_BADCNT ldx #E_BADCNT
; $C7 = Removable, Interruptable, #Volumes=1, Supports write/read/status
; $D7 = Removable, Interruptable, #Volumes=2, Supports write/read/status
; $F7 = Removable, Interruptable, #Volumes=4, Supports write/read/status
; $BF = Removable, Interruptable, #Volumes=4, Supports format/write/read/status (KEGS / IIGS)
; $FF = Removable, Interruptable, #Volumes=4, Supports format/write/read/status
; $BF = Removable, , #Volumes=4, Supports format/write/read/status (KEGS / IIGS)
;
; $CnFF = offset to BLK entry point
;--------------------------------------
@ -372,8 +385,8 @@ Cn_SP_E_BADCNT ldx #E_BADCNT
*= $00FB ; org $00FB
!warn "CsFB padding = ", * - @checkCsFB
;--------------------------------------
!byte $00 ; Smart port ID Type byte
!byte $00 ; SmartPort ID Type byte
!word $0000 ; how many blocks are on the device. Zero means use status call
!byte $F7 ; specifics about the device (number of drives, read/write/format capability, etc)
!byte $FF ; specifics about the device (number of drives, read/write/format capability, etc)
!byte <Cn_Entry_BLK ; entry point offset for ProDOS (must be $0a)
;--------------------------------------

Binary file not shown.

View File

@ -73,6 +73,10 @@ ImageError_e ImageOpen( const std::string & pszImageFilename,
*ppImageInfo = NULL;
Err = eIMAGE_ERROR_UNSUPPORTED_HDV;
}
if (Err == eIMAGE_ERROR_NONE)
*pWriteProtected = pImageInfo->bWriteProtected;
return Err;
}

View File

@ -82,16 +82,16 @@ Memory map SmartPort device (IO addr + s*$10):
; C088 (r) NEXT BYTE (legacy read-only port - still supported)
C089 (r) LOW BYTE OF DISK IMAGE SIZE IN BLOCKS
C08A (r) HIGH BYTE OF DISK IMAGE SIZE IN BLOCKS
C089 (w) a 6-deep FIFO to write: command, unitNum, memPtr(2), blockNum(2)
C08A (w) a 7-deep FIFO to write: command, unitNum, memPtr(2), blockNum(3); first byte gets OR'd with $80 (ie. to indicate it's an SP command)
C089 (w) a 6-deep FIFO to write: command, unitNum, memPtr(2), blockNum(2); for BLK driver
C08A (w) a 7-deep FIFO to write: command, unitNum, memPtr(2), blockNum(3); for SP: first byte gets OR'd with $80 (ie. to indicate it's an SP command)
*/
/*
Hard drive emulation in AppleWin - for the HDDRVR v1 & v2 firmware
Concept
To emulate a 32mb hard drive connected to an Apple IIe via AppleWin.
Designed to work with Autoboot Rom and Prodos.
To emulate a 32MiB hard drive connected to an Apple IIe via AppleWin.
Designed to work with Autoboot ROM and ProDOS.
Overview
1. Hard drive image file
@ -130,8 +130,8 @@ Overview
patching prodos (to detect DELETE FILE calls).
4. FORMAT
Ignored. This would be used for low level formatting of the device
(as in the case of a tape or SCSI drive, perhaps).
This is used for low level formatting of the device. (GH#88)
(Also in the case of a tape or SCSI drive, perhaps.)
3. Bugs
The only thing I've noticed is that Copy II+ 7.1 seems to crash or stall
@ -409,6 +409,12 @@ bool HarddiskInterfaceCard::Insert(const int iDrive, const std::string& pathname
if (m_hardDiskDrive[iDrive].m_imageloaded)
Unplug(iDrive);
const DWORD dwAttributes = GetFileAttributes(pathname.c_str());
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
m_hardDiskDrive[iDrive].m_bWriteProtected = false; // File doesn't exist - so ImageOpen() below will fail
else
m_hardDiskDrive[iDrive].m_bWriteProtected = (dwAttributes & FILE_ATTRIBUTE_READONLY) ? true : false;
// Check if image is being used by the other HDD, and unplug it in order to be swapped
{
const std::string & pszOtherPathname = HarddiskGetFullPathName(!iDrive);
@ -517,11 +523,12 @@ void HarddiskInterfaceCard::Unplug(const int iDrive)
#if 0 // Enable HDD command logging
#define LOG_DISK(format, ...) LOG(format, __VA_ARGS__)
#define DEBUG_SKIP_BUSY_STATUS 1
#else
#define LOG_DISK(...)
#define DEBUG_SKIP_BUSY_STATUS 0
#endif
#define DEBUG_SKIP_BUSY_STATUS 0
// ProDOS BLK & SmartPort commands
//
@ -553,6 +560,7 @@ const UINT SP_Cmd_busyStatus = SP_Cmd_base + 0x3F; // AppleWin vendor-specific c
#define BADCTL 0x21
#define DEVICE_IO_ERROR 0x27
#define DEVICE_NOT_CONNECTED 0x28 // No device detected/connected
#define NOWRITE 0x2B // Disk write protected
#define ERRORCODE_MASK 0x3F // limit to just 6 bits (as 'error' byte uses b0 & b7 for other status)
#define STATUS_OK 0x00
@ -655,6 +663,7 @@ BYTE HarddiskInterfaceCard::CmdExecute(HardDiskDrive* pHDD)
}
const UINT CYCLES_FOR_DMA_RW_BLOCK = HD_BLOCK_SIZE;
const UINT CYCLES_FOR_FORMATTING_1_BLOCK = 100; // Arbitrary
const UINT PAGE_SIZE = 256;
pHDD->m_error = DEVICE_OK;
@ -671,7 +680,7 @@ BYTE HarddiskInterfaceCard::CmdExecute(HardDiskDrive* pHDD)
break;
case SP_Cmd_status:
pHDD->m_error = SmartPortCmdStatus(pHDD);
LOG_DISK("ST: %02X\n", pHDD->m_error);
LOG_DISK("ST: %02X (statusCode: %02X)\n", pHDD->m_error, m_statusCode);
break;
case BLK_Cmd_Read:
case SP_Cmd_readblock:
@ -744,8 +753,15 @@ BYTE HarddiskInterfaceCard::CmdExecute(HardDiskDrive* pHDD)
case BLK_Cmd_Write:
case SP_Cmd_writeblock:
{
LOG_DISK("WR: %08X (from addr: %04X)\n", pHDD->m_diskblock, pHDD->m_memblock);
pHDD->m_status_next = DISK_STATUS_WRITE; // or DISK_STATUS_PROT if we ever enable write-protect on HDD
LOG_DISK("WR: %08X (from addr: %04X) %s\n", pHDD->m_diskblock, pHDD->m_memblock, pHDD->m_bWriteProtected ? "write-protected" : "");
if (pHDD->m_bWriteProtected)
{
pHDD->m_status_next = DISK_STATUS_PROT;
pHDD->m_error = NOWRITE;
}
else
{
pHDD->m_status_next = DISK_STATUS_WRITE;
bool bRes = true;
const bool bAppendBlocks = (pHDD->m_diskblock * HD_BLOCK_SIZE) >= ImageGetImageSize(pHDD->m_imagehandle);
bool breakpointHit = false;
@ -817,10 +833,39 @@ BYTE HarddiskInterfaceCard::CmdExecute(HardDiskDrive* pHDD)
{
pHDD->m_error = DEVICE_IO_ERROR;
}
} // if (pHDD->m_bWriteProtected)
}
break;
case BLK_Cmd_Format:
pHDD->m_error = DEVICE_IO_ERROR; // Not supported
case SP_Cmd_format:
LOG_DISK("FORMAT: write-protected=%d\n", pHDD->m_bWriteProtected);
if (pHDD->m_bWriteProtected)
{
pHDD->m_error = NOWRITE;
}
else
{
const UINT numBlocks = GetImageSizeInBlocks(pHDD->m_imagehandle);
memset(pHDD->m_buf, 0, HD_BLOCK_SIZE);
bool res = false;
m_notBusyCycle = g_nCumulativeCycles;
for (UINT block = 0; block < numBlocks; block++)
{
// Inefficient (especially for gzip/zip files!)
res = ImageWriteBlock(pHDD->m_imagehandle, block, pHDD->m_buf);
_ASSERT(res);
if (!res)
break;
m_notBusyCycle += (UINT64)CYCLES_FOR_FORMATTING_1_BLOCK;
#if DEBUG_SKIP_BUSY_STATUS
m_notBusyCycle = 0;
#endif
}
pHDD->m_error = res ? DEVICE_OK : DEVICE_IO_ERROR;
}
break;
default:
_ASSERT(0);
@ -1070,7 +1115,8 @@ BYTE HarddiskInterfaceCard::SmartPortCmdStatus(HardDiskDrive* pHDD)
// general status:
// . b7=block device, b6=write allowed, b5=read allowed, b4=device online or disk in drive,
// . b3=format allowed, b2=media write protected (block devices only), b1=device currently interrupting (//c only), b0=device currently open (char device only)
const BYTE generalStatus = isImageLoaded ? 0xF0 : 0xE0; // Loaded: b#11110000: bwrl---- / Not loaded: b#11100000: bwr-----
BYTE generalStatus = isImageLoaded ? 0xF8 : 0xE8; // Loaded: b#11111000: bwrlf--- / Not loaded: b#11101000: bwr-f---
if (pHDD->m_bWriteProtected) generalStatus |= (1 << 2);
mem[statusListAddr++] = generalStatus;
const UINT imageSizeInBlocks = isImageLoaded ? GetImageSizeInBlocks(pHDD->m_imagehandle) : 0;