mirror of
https://github.com/AppleWin/AppleWin.git
synced 2025-02-07 01:30:50 +00:00
. Move the 'read block' command into the emulator - to mirror the write command . With emulated time to do the DMA for the r/w block command
This commit is contained in:
parent
d96ed5b8c5
commit
5ed901f720
Binary file not shown.
@ -26,7 +26,7 @@
|
|||||||
;
|
;
|
||||||
|
|
||||||
; Modified by Tom Charlesworth:
|
; Modified by Tom Charlesworth:
|
||||||
; . Updated so it can be assembled by ACME 0.96.4
|
; . Updated so it can be assembled by ACME 0.97
|
||||||
; . Fixed so that ProDOS entrypoint is $c70a (26 Dev 2007) (Bug #12723)
|
; . Fixed so that ProDOS entrypoint is $c70a (26 Dev 2007) (Bug #12723)
|
||||||
; . Modified to support Apple Oasis' entrypoint: $c761 (8 Sept 2012) (Feature #5557)
|
; . Modified to support Apple Oasis' entrypoint: $c761 (8 Sept 2012) (Feature #5557)
|
||||||
; . Added support for SmartPort entrypoint (20 Oct 2012)
|
; . Added support for SmartPort entrypoint (20 Oct 2012)
|
||||||
@ -34,10 +34,11 @@
|
|||||||
; . GH#370 (Robert Hoem, 27 Oct 2016):
|
; . GH#370 (Robert Hoem, 27 Oct 2016):
|
||||||
; . Added a check against open-apple during boot to route boot to slot 6
|
; . Added a check against open-apple during boot to route boot to slot 6
|
||||||
; . This happens after the first two blocks are loaded from the HD.
|
; . This happens after the first two blocks are loaded from the HD.
|
||||||
; . GH#319: smartport return address wrong when crossing page
|
; . GH#319: SmartPort return address wrong when crossing page
|
||||||
|
; . GH#996: Make code slot-independent (so HDD controller card can go into any slot)
|
||||||
|
; . Moved the 512-byte block read into AppleWin's HDD emulation (to mirror the block write command)
|
||||||
; TODO:
|
; TODO:
|
||||||
; . Make code relocatable (so HDD controller card can go into any slot)
|
; . Remove support for Entrypoint_Cs46 (old AppleWin) & Entrypoint_Cs61 (Apple Oasis)
|
||||||
; . Remove support for Entrypoint_C746 (old AppleWin) & Entrypoint_C761 (Apple Oasis)
|
|
||||||
; - provide a utility to convert these to use Entrypoint_ProDOS
|
; - provide a utility to convert these to use Entrypoint_ProDOS
|
||||||
; . Check SmartPort: Is it OK to trash Y and $42,..,$47 ?
|
; . Check SmartPort: Is it OK to trash Y and $42,..,$47 ?
|
||||||
;
|
;
|
||||||
@ -47,31 +48,32 @@
|
|||||||
!sl "hddrvr.labels"
|
!sl "hddrvr.labels"
|
||||||
|
|
||||||
; constants
|
; constants
|
||||||
hd_execute = $c0f0
|
hd_execute = $c080
|
||||||
hd_error = $c0f1
|
hd_error = $c081 ; b7=busy, b0=error
|
||||||
hd_command = $c0f2
|
hd_command = $c082
|
||||||
hd_unitnum = $c0f3
|
hd_unitnum = $c083
|
||||||
hd_memblock = $c0f4
|
hd_memblock = $c084
|
||||||
hd_diskblock = $c0f6
|
hd_diskblock = $c086
|
||||||
hd_nextbyte = $c0f8
|
;hd_nextbyte = $c088 ; legacy read-only port (still supported by AppleWin)
|
||||||
|
|
||||||
command = $42
|
command = $42
|
||||||
unitnum = $43
|
unitnum = $43
|
||||||
memblock = $44
|
memblock = $44
|
||||||
diskblock = $46
|
diskblock = $46
|
||||||
|
|
||||||
slot6 = $c600
|
slot6 = $C600
|
||||||
OS = $0801
|
OS = $0801
|
||||||
BUTTON0 = $C061
|
BUTTON0 = $C061
|
||||||
|
|
||||||
; The Autoboot rom will call this.
|
;======================================
|
||||||
; This is also the entry point for such things as IN#7 and PR#7
|
|
||||||
|
|
||||||
;; code
|
|
||||||
*= $c700 ; org $c700
|
|
||||||
|
|
||||||
!zone code
|
!zone code
|
||||||
|
|
||||||
|
*= $0000 ; org $0000 - position-independent code, so doesn't matter (but the other fixed org positions need to be on the same page)
|
||||||
|
|
||||||
|
; The Autoboot rom will call this.
|
||||||
|
; This is also the entry point for such things as IN#7 and PR#7
|
||||||
|
|
||||||
start
|
start
|
||||||
|
|
||||||
; Autoboot and ProDOS look at the following few opcodes to detect block devices
|
; Autoboot and ProDOS look at the following few opcodes to detect block devices
|
||||||
@ -83,44 +85,23 @@ start
|
|||||||
lda #$3C
|
lda #$3C
|
||||||
bne Bootstrap
|
bne Bootstrap
|
||||||
|
|
||||||
Entrypoint_ProDOS ; $c70a - ProDOS entrypoint
|
Entrypoint_ProDOS ; $Cn0A - ProDOS entrypoint
|
||||||
sec
|
sec
|
||||||
bcs Entrypoint
|
bcs Entrypoint
|
||||||
|
|
||||||
Entrypoint_SmartPort ; $c70d - SmartPort entrypoint
|
Entrypoint_SmartPort ; $Cn0D - SmartPort entrypoint
|
||||||
clc
|
clc
|
||||||
|
|
||||||
Entrypoint ; $c70e - entrypoint?
|
|
||||||
bcs cmdproc
|
|
||||||
bcc SmartPort
|
|
||||||
|
|
||||||
;;
|
Entrypoint ; $Cn0E - entrypoint?
|
||||||
|
bcs GetSlotInX ; C=1: GetSlotInX -> cmdproc
|
||||||
|
|
||||||
Bootstrap
|
; C=0: fall through to SmartPort...
|
||||||
; Lets check to see if there's an image ready
|
|
||||||
lda #$00
|
|
||||||
sta hd_command
|
|
||||||
|
|
||||||
; Slot 7, disk 1
|
|
||||||
lda #$70 ; Slot# << 4
|
|
||||||
sta hd_unitnum
|
|
||||||
lda hd_execute
|
|
||||||
|
|
||||||
; error capturing code. Applewin is picky
|
|
||||||
; about code assigning data to registers and
|
|
||||||
; memory. The safest method is via I/O port
|
|
||||||
ror hd_error ; Post: C=0 or 1
|
|
||||||
bcc hdboot
|
|
||||||
|
|
||||||
; no image ready, boot diskette image instead
|
|
||||||
BootSlot6
|
|
||||||
jmp slot6
|
|
||||||
|
|
||||||
;======================================
|
;======================================
|
||||||
|
|
||||||
; TODO: Is it OK to trash Y and $42,..,$47 ?
|
; TODO: Is it OK to trash Y and $42,..,$47 ?
|
||||||
; Pre: C=0
|
; Pre: C=0, X = Slot# << 4
|
||||||
SmartPort
|
SmartPort ; SmartPort -> GetSlotInX -> cmdproc
|
||||||
pla
|
pla
|
||||||
sta $46
|
sta $46
|
||||||
adc #3 ; Pre: C=0, Post: C=0 or 1
|
adc #3 ; Pre: C=0, Post: C=0 or 1
|
||||||
@ -136,24 +117,7 @@ SmartPort
|
|||||||
lda ($46),y ; cmd
|
lda ($46),y ; cmd
|
||||||
sta $42
|
sta $42
|
||||||
iny
|
iny
|
||||||
bne SmartPort2
|
|
||||||
|
|
||||||
;======================================
|
|
||||||
; 8 unused bytes
|
|
||||||
|
|
||||||
*= $c746 ; org $c746
|
|
||||||
|
|
||||||
Entrypoint_C746 ; Old f/w 'cmdproc' entrypoint
|
|
||||||
; Keep this for any DOSMaster HDD images created with old AppleWin HDD f/w.
|
|
||||||
; DOSMaster hardcodes the entrypoint addr into its bootstrapping code:
|
|
||||||
; - So DOSMaster images are tied to the HDD's controller's f/w
|
|
||||||
sec
|
|
||||||
bcs Entrypoint
|
|
||||||
|
|
||||||
;======================================
|
|
||||||
|
|
||||||
; Pre: Y=2
|
|
||||||
SmartPort2
|
|
||||||
lda ($46),y ; param_l
|
lda ($46),y ; param_l
|
||||||
sta $45
|
sta $45
|
||||||
iny
|
iny
|
||||||
@ -164,31 +128,76 @@ SmartPort2
|
|||||||
lda ($45),y ; unit
|
lda ($45),y ; unit
|
||||||
sta $43
|
sta $43
|
||||||
iny
|
iny
|
||||||
|
|
||||||
lda ($45),y ; memblock_l
|
lda ($45),y ; memblock_l
|
||||||
sta $44
|
sta $44
|
||||||
iny
|
iny
|
||||||
bne SmartPort3
|
lda ($45),y ; memblock_h
|
||||||
|
pha
|
||||||
|
iny
|
||||||
|
|
||||||
|
lda ($45),y ; diskblock_l
|
||||||
|
pha
|
||||||
|
iny
|
||||||
|
|
||||||
|
bne SmartPort2
|
||||||
|
|
||||||
;======================================
|
;======================================
|
||||||
; 1 unused byte
|
; 2 unused bytes
|
||||||
|
|
||||||
*= $c761 ; org $c761
|
|
||||||
|
|
||||||
Entrypoint_C761 ; Apple Oasis HDD controller entrypoint
|
@checkCs46
|
||||||
|
*= $0046 ; org $0046
|
||||||
|
!warn "Cs46 padding = ", * - @checkCs46
|
||||||
|
|
||||||
|
Entrypoint_Cs46 ; Old f/w 'cmdproc' entrypoint
|
||||||
|
; Keep this for any DOSMaster HDD images created with old AppleWin HDD f/w.
|
||||||
|
; DOSMaster hardcodes the entrypoint addr into its bootstrapping code:
|
||||||
|
; - So DOSMaster images are tied to the HDD's controller's f/w
|
||||||
|
sec
|
||||||
|
bcs Entrypoint ; or directly to GetSlotInX
|
||||||
|
|
||||||
|
;======================================
|
||||||
|
|
||||||
|
Bootstrap
|
||||||
|
; Lets check to see if there's an image ready
|
||||||
|
; Slot n, disk 1
|
||||||
|
clc
|
||||||
|
bcc GetSlotInX ; Post: X = Slot# << 4
|
||||||
|
Bootstrap2
|
||||||
|
lda #$00
|
||||||
|
sta hd_unitnum,x ; b7=0 => disk 1
|
||||||
|
sta hd_command,x
|
||||||
|
lda hd_execute,x
|
||||||
|
ror hd_error,x ; Post: C=0 or 1
|
||||||
|
bcc hdboot
|
||||||
|
|
||||||
|
; no image ready, boot diskette image instead
|
||||||
|
BootSlot6
|
||||||
|
jmp slot6
|
||||||
|
|
||||||
|
;======================================
|
||||||
|
; 2 unused bytes
|
||||||
|
|
||||||
|
@checkCs61
|
||||||
|
*= $0061 ; org $0061
|
||||||
|
!warn "Cs61 padding = ", * - @checkCs61
|
||||||
|
|
||||||
|
Entrypoint_Cs61 ; Apple Oasis HDD controller entrypoint
|
||||||
; Keep this for any DOSMaster HDD images created with Apple Oasis HDD f/w.
|
; Keep this for any DOSMaster HDD images created with Apple Oasis HDD f/w.
|
||||||
; DOSMaster hardcodes the entrypoint addr into its bootstrapping code:
|
; DOSMaster hardcodes the entrypoint addr into its bootstrapping code:
|
||||||
; - So DOSMaster images are tied to the HDD's controller's f/w
|
; - So DOSMaster images are tied to the HDD's controller's f/w
|
||||||
sec
|
sec
|
||||||
bcs Entrypoint
|
bcs Entrypoint ; or directly to GetSlotInX
|
||||||
|
|
||||||
;======================================
|
;======================================
|
||||||
|
|
||||||
; image ready. Lets boot from it.
|
; image ready. Lets boot from it.
|
||||||
; we want to load block 1 from s7,d1 to $800 then jump there
|
; we want to load block 1 from disk 1 to $800 then jump there
|
||||||
|
; Pre: X = Slot# << 4
|
||||||
|
; C = 0
|
||||||
hdboot
|
hdboot
|
||||||
lda #$70 ; Slot# << 4
|
|
||||||
sta unitnum
|
|
||||||
lda #$0
|
lda #$0
|
||||||
|
sta unitnum ; b7=0 => disk 1
|
||||||
sta memblock
|
sta memblock
|
||||||
sta diskblock
|
sta diskblock
|
||||||
sta diskblock+1
|
sta diskblock+1
|
||||||
@ -196,101 +205,109 @@ hdboot
|
|||||||
sta memblock+1
|
sta memblock+1
|
||||||
lda #$1
|
lda #$1
|
||||||
sta command
|
sta command
|
||||||
jsr cmdproc
|
bne cmdproc
|
||||||
|
hdboot2
|
||||||
bcs BootSlot6
|
bcs BootSlot6
|
||||||
|
|
||||||
goload
|
bit BUTTON0 ; button 0 pressed?
|
||||||
bit BUTTON0 ; button 0 pressed?
|
|
||||||
bmi BootSlot6
|
bmi BootSlot6
|
||||||
|
|
||||||
; X=device
|
; Pre: X = Slot# << 4
|
||||||
ldx #$70 ; Slot# << 4
|
|
||||||
jmp OS
|
jmp OS
|
||||||
|
|
||||||
; entry point for ProDOS' block driver
|
|
||||||
; simple really. Copy the command from $42..$47
|
|
||||||
; to our I/O ports then execute command
|
|
||||||
cmdproc
|
|
||||||
clc
|
|
||||||
lda $42
|
|
||||||
sta hd_command
|
|
||||||
lda $43
|
|
||||||
sta hd_unitnum
|
|
||||||
lda $44
|
|
||||||
sta hd_memblock
|
|
||||||
lda $45
|
|
||||||
sta hd_memblock+1
|
|
||||||
lda $46
|
|
||||||
sta hd_diskblock
|
|
||||||
lda $47
|
|
||||||
sta hd_diskblock+1
|
|
||||||
lda hd_execute
|
|
||||||
|
|
||||||
; check for error
|
|
||||||
pha
|
|
||||||
lda command
|
|
||||||
cmp #1
|
|
||||||
bne skipSread
|
|
||||||
jsr sread
|
|
||||||
skipSread
|
|
||||||
ror hd_error ; Post: C=0 or 1
|
|
||||||
pla
|
|
||||||
rts
|
|
||||||
|
|
||||||
|
|
||||||
; if there's no error, then lets read the block into memory
|
|
||||||
; because Applewin is picky about memory management, here's what I did:
|
|
||||||
; on read, hd_nextbyte = buffer[0], therefore we'll read that byte 256 times (in which
|
|
||||||
; the emulated code increments the buffer by 1 on each read) to (memblock),y
|
|
||||||
; increment memblock+1 and read the second 256 bytes via hd_nextbyte.
|
|
||||||
;
|
|
||||||
; if I could figure out how to consistently get applewin to update it's memory regions all
|
|
||||||
; this code can be moved into the emulation code (although, this is how I'd build the hardware
|
|
||||||
; anyway...)
|
|
||||||
|
|
||||||
sread
|
|
||||||
tya
|
|
||||||
pha
|
|
||||||
ldy #0
|
|
||||||
loop1
|
|
||||||
lda hd_nextbyte
|
|
||||||
sta (memblock),y
|
|
||||||
iny
|
|
||||||
bne loop1
|
|
||||||
inc memblock+1
|
|
||||||
ldy #0
|
|
||||||
loop2
|
|
||||||
lda hd_nextbyte
|
|
||||||
sta (memblock),y
|
|
||||||
iny
|
|
||||||
bne loop2
|
|
||||||
dec memblock+1 ; restore memblock+1 ($45) to original value (for Epyx's California Games)
|
|
||||||
pla
|
|
||||||
tay
|
|
||||||
rts
|
|
||||||
|
|
||||||
;======================================
|
;======================================
|
||||||
|
|
||||||
SmartPort3
|
SmartPort2
|
||||||
lda ($45),y ; memblock_h
|
|
||||||
pha
|
|
||||||
iny
|
|
||||||
lda ($45),y ; diskblock_l
|
|
||||||
pha
|
|
||||||
iny
|
|
||||||
lda ($45),y ; diskblock_h
|
lda ($45),y ; diskblock_h
|
||||||
sta $47
|
sta $47
|
||||||
|
|
||||||
pla
|
pla
|
||||||
sta $46
|
sta $46
|
||||||
pla
|
pla
|
||||||
sta $45
|
sta $45
|
||||||
|
|
||||||
iny
|
sec
|
||||||
bne cmdproc
|
; fall through...
|
||||||
|
|
||||||
;======================================
|
;======================================
|
||||||
; 18 unused bytes
|
|
||||||
|
; Pre:
|
||||||
|
; C=0 => via Bootstrap
|
||||||
|
; C=1 => via Entrypoint / SmartPort2
|
||||||
|
; Post:
|
||||||
|
; X = Slot# << 4
|
||||||
|
GetSlotInX
|
||||||
|
php
|
||||||
|
sei ; disable ints, in case an int handler races our $0000/RTS and stack accesses!
|
||||||
|
|
||||||
|
; NB. need RAM that's guaranteed to be both read & writeable:
|
||||||
|
; . can't use $0200-$BFFF, due to eg. RAMRD=0/RAMWRT=1 combination
|
||||||
|
; . can't use LC as ROM might be enabled.
|
||||||
|
; So use ZP (specifically $0000) as whatever the state of ALTZP, both read & write will be to the same physical memory location.
|
||||||
|
lda $00 ; save $00
|
||||||
|
ldx #$60 ; opcode RTS
|
||||||
|
stx $00
|
||||||
|
jsr $0000 ; RTS immediately (NB. can't use $FF58, since LC RAM may be switched in)
|
||||||
|
sta $00 ; restore $00
|
||||||
|
tsx
|
||||||
|
lda $0100,x ; $Cn
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
asl
|
||||||
|
tax ; X=$n0
|
||||||
|
|
||||||
|
plp ; + restore int status
|
||||||
|
bcc Bootstrap2
|
||||||
|
; otherwise fall through for Entrypoint / SmartPort...
|
||||||
|
|
||||||
|
;--------------------------------------
|
||||||
|
|
||||||
|
; entry point for ProDOS' block driver
|
||||||
|
; simple really. Copy the command from $42..$47
|
||||||
|
; to our I/O ports then execute command
|
||||||
|
|
||||||
|
; Pre:
|
||||||
|
; C=0 => via Bootstrap (hdboot)
|
||||||
|
; C=1 => via GetSlotInX (eg. Entrypoint / SmartPort2)
|
||||||
|
; X = Slot# << 4
|
||||||
|
; Post:
|
||||||
|
; C = hd_error.b0
|
||||||
|
; A = result of hd_execute
|
||||||
|
; X = Slot# << 4
|
||||||
|
cmdproc
|
||||||
|
php
|
||||||
|
|
||||||
|
lda command
|
||||||
|
sta hd_command,x
|
||||||
|
lda unitnum
|
||||||
|
sta hd_unitnum,x
|
||||||
|
lda memblock
|
||||||
|
sta hd_memblock,x
|
||||||
|
lda memblock+1
|
||||||
|
sta hd_memblock+1,x
|
||||||
|
lda diskblock
|
||||||
|
sta hd_diskblock,x
|
||||||
|
lda diskblock+1
|
||||||
|
sta hd_diskblock+1,x
|
||||||
|
lda hd_execute,x ; A = result of hd_execute (NB. instantaneous 512 byte r/w!)
|
||||||
|
|
||||||
|
- rol hd_error,x ; b7=busy doing DMA?
|
||||||
|
bcs -
|
||||||
|
|
||||||
|
plp ; restore C from start of cmdproc
|
||||||
|
bcs done
|
||||||
|
ror hd_error,x ; Post: C=0 or 1
|
||||||
|
lda #0
|
||||||
|
beq hdboot2
|
||||||
|
|
||||||
|
done
|
||||||
|
ror hd_error,x ; Post: C=0 or 1
|
||||||
|
rts
|
||||||
|
|
||||||
|
;======================================
|
||||||
|
|
||||||
|
; 33 unused bytes
|
||||||
|
|
||||||
!zone data
|
!zone data
|
||||||
|
|
||||||
@ -309,7 +326,10 @@ SmartPort3
|
|||||||
|
|
||||||
; datablock. This starts near the end of the firmware (at offset $FC)
|
; datablock. This starts near the end of the firmware (at offset $FC)
|
||||||
;; data
|
;; data
|
||||||
*= $c7fc ; org $c7fc
|
@checkCsFC
|
||||||
|
*= $00FC ; org $00FC
|
||||||
|
!warn "CsFC padding = ", * - @checkCsFC
|
||||||
|
|
||||||
!word $7fff ; how many blocks are on the device.
|
!word $7fff ; how many blocks are on the device.
|
||||||
!byte $D7 ; specifics about the device (number of drives, read/write/format capability, etc)
|
!byte $D7 ; specifics about the device (number of drives, read/write/format capability, etc)
|
||||||
!byte <Entrypoint_ProDOS ; entry point offset for ProDOS (must be $0a)
|
!byte <Entrypoint_ProDOS ; entry point offset for ProDOS (must be $0a)
|
||||||
|
Binary file not shown.
@ -178,11 +178,17 @@ void Disk2InterfaceCard::LoadLastDiskImage(const int drive)
|
|||||||
char pathname[MAX_PATH];
|
char pathname[MAX_PATH];
|
||||||
|
|
||||||
std::string& regSection = RegGetConfigSlotSection(m_slot);
|
std::string& regSection = RegGetConfigSlotSection(m_slot);
|
||||||
if (RegLoadString(regSection.c_str(), regKey.c_str(), TRUE, pathname, MAX_PATH, TEXT("")))
|
if (RegLoadString(regSection.c_str(), regKey.c_str(), TRUE, pathname, MAX_PATH, TEXT("")) && (pathname[0] != 0))
|
||||||
{
|
{
|
||||||
m_saveDiskImage = false;
|
m_saveDiskImage = false;
|
||||||
InsertDisk(drive, pathname, IMAGE_USE_FILES_WRITE_PROTECT_STATUS, IMAGE_DONT_CREATE);
|
ImageError_e error = InsertDisk(drive, pathname, IMAGE_USE_FILES_WRITE_PROTECT_STATUS, IMAGE_DONT_CREATE);
|
||||||
m_saveDiskImage = true;
|
m_saveDiskImage = true;
|
||||||
|
|
||||||
|
if (error != eIMAGE_ERROR_NONE)
|
||||||
|
{
|
||||||
|
NotifyInvalidImage(drive, pathname, error);
|
||||||
|
EjectDisk(drive);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +125,9 @@ HarddiskInterfaceCard::HarddiskInterfaceCard(UINT slot) :
|
|||||||
// . ProDOS will write to Command before switching drives
|
// . ProDOS will write to Command before switching drives
|
||||||
m_command = 0;
|
m_command = 0;
|
||||||
|
|
||||||
|
// Interface busy doing DMA for r/w when current cycle is earlier than this cycle
|
||||||
|
m_notBusyCycle = 0;
|
||||||
|
|
||||||
m_saveDiskImage = true; // Save the DiskImage name to Registry
|
m_saveDiskImage = true; // Save the DiskImage name to Registry
|
||||||
|
|
||||||
// if created by user in Config->Disk, then MemInitializeIO() won't be called
|
// if created by user in Config->Disk, then MemInitializeIO() won't be called
|
||||||
@ -190,7 +193,20 @@ void HarddiskInterfaceCard::CleanupDrive(const int iDrive)
|
|||||||
|
|
||||||
void HarddiskInterfaceCard::NotifyInvalidImage(TCHAR* pszImageFilename)
|
void HarddiskInterfaceCard::NotifyInvalidImage(TCHAR* pszImageFilename)
|
||||||
{
|
{
|
||||||
// TC: TO DO
|
// TC: TO DO - see Disk2InterfaceCard::NotifyInvalidImage()
|
||||||
|
|
||||||
|
char szBuffer[MAX_PATH + 128];
|
||||||
|
|
||||||
|
StringCbPrintf(
|
||||||
|
szBuffer,
|
||||||
|
MAX_PATH + 128,
|
||||||
|
TEXT("Unable to open the file %s."),
|
||||||
|
pszImageFilename);
|
||||||
|
|
||||||
|
GetFrame().FrameMessageBox(
|
||||||
|
szBuffer,
|
||||||
|
g_pAppTitle.c_str(),
|
||||||
|
MB_ICONEXCLAMATION | MB_SETFOREGROUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
@ -206,11 +222,17 @@ void HarddiskInterfaceCard::LoadLastDiskImage(const int drive)
|
|||||||
char pathname[MAX_PATH];
|
char pathname[MAX_PATH];
|
||||||
|
|
||||||
std::string& regSection = RegGetConfigSlotSection(m_slot);
|
std::string& regSection = RegGetConfigSlotSection(m_slot);
|
||||||
if (RegLoadString(regSection.c_str(), regKey.c_str(), TRUE, pathname, MAX_PATH, TEXT("")))
|
if (RegLoadString(regSection.c_str(), regKey.c_str(), TRUE, pathname, MAX_PATH, TEXT("")) && (pathname[0] != 0))
|
||||||
{
|
{
|
||||||
m_saveDiskImage = false;
|
m_saveDiskImage = false;
|
||||||
Insert(drive, pathname);
|
bool res = Insert(drive, pathname);
|
||||||
m_saveDiskImage = true;
|
m_saveDiskImage = true;
|
||||||
|
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
NotifyInvalidImage(pathname);
|
||||||
|
CleanupDrive(drive);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,10 +331,10 @@ void HarddiskInterfaceCard::Destroy(void)
|
|||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
// Pre: pathname likely to include path (but can also just be filename)
|
// Pre: pathname likely to include path (but can also just be filename)
|
||||||
BOOL HarddiskInterfaceCard::Insert(const int iDrive, const std::string& pathname)
|
bool HarddiskInterfaceCard::Insert(const int iDrive, const std::string& pathname)
|
||||||
{
|
{
|
||||||
if (pathname.empty())
|
if (pathname.empty())
|
||||||
return FALSE;
|
return false;
|
||||||
|
|
||||||
if (m_hardDiskDrive[iDrive].m_imageloaded)
|
if (m_hardDiskDrive[iDrive].m_imageloaded)
|
||||||
Unplug(iDrive);
|
Unplug(iDrive);
|
||||||
@ -429,8 +451,8 @@ bool HarddiskInterfaceCard::IsDriveUnplugged(const int iDrive)
|
|||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
#define DEVICE_OK 0x00
|
#define DEVICE_OK 0x00
|
||||||
#define DEVICE_UNKNOWN_ERROR 0x28
|
|
||||||
#define DEVICE_IO_ERROR 0x27
|
#define DEVICE_IO_ERROR 0x27
|
||||||
|
#define DEVICE_NOT_CONNECTED 0x28 // No device detected/connected
|
||||||
|
|
||||||
BYTE __stdcall HarddiskInterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles)
|
BYTE __stdcall HarddiskInterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles)
|
||||||
{
|
{
|
||||||
@ -438,6 +460,9 @@ BYTE __stdcall HarddiskInterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BY
|
|||||||
HarddiskInterfaceCard* pCard = (HarddiskInterfaceCard*)MemGetSlotParameters(slot);
|
HarddiskInterfaceCard* pCard = (HarddiskInterfaceCard*)MemGetSlotParameters(slot);
|
||||||
HardDiskDrive* pHDD = &(pCard->m_hardDiskDrive[pCard->m_unitNum >> 7]); // bit7 = drive select
|
HardDiskDrive* pHDD = &(pCard->m_hardDiskDrive[pCard->m_unitNum >> 7]); // bit7 = drive select
|
||||||
|
|
||||||
|
CpuCalcCycles(nExecutedCycles);
|
||||||
|
const UINT CYCLES_FOR_DMA_RW_BLOCK = HD_BLOCK_SIZE;
|
||||||
|
|
||||||
BYTE r = DEVICE_OK;
|
BYTE r = DEVICE_OK;
|
||||||
pHDD->m_status_next = DISK_STATUS_READ;
|
pHDD->m_status_next = DISK_STATUS_READ;
|
||||||
|
|
||||||
@ -466,7 +491,31 @@ BYTE __stdcall HarddiskInterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BY
|
|||||||
{
|
{
|
||||||
pHDD->m_error = 0;
|
pHDD->m_error = 0;
|
||||||
r = 0;
|
r = 0;
|
||||||
|
pCard->m_notBusyCycle = g_nCumulativeCycles + (UINT64)CYCLES_FOR_DMA_RW_BLOCK;
|
||||||
pHDD->m_buf_ptr = 0;
|
pHDD->m_buf_ptr = 0;
|
||||||
|
|
||||||
|
// Apple II's MMU could be setup so that read & write memory is different,
|
||||||
|
// so can't use 'mem' (like we can for HDD block writes)
|
||||||
|
const UINT PAGE_SIZE = 256;
|
||||||
|
WORD dstAddr = pHDD->m_memblock;
|
||||||
|
UINT remaining = HD_BLOCK_SIZE;
|
||||||
|
BYTE* pSrc = pHDD->m_buf;
|
||||||
|
|
||||||
|
while (remaining)
|
||||||
|
{
|
||||||
|
memdirty[dstAddr >> 8] = 0xFF;
|
||||||
|
LPBYTE page = memwrite[dstAddr >> 8];
|
||||||
|
|
||||||
|
// handle both page-aligned & non-page aligned destinations
|
||||||
|
UINT size = PAGE_SIZE - (dstAddr & 0xff);
|
||||||
|
if (size > remaining) size = remaining; // clip the last memcpy for the unaligned case
|
||||||
|
|
||||||
|
memcpy(page + (dstAddr & 0xff), pSrc, size);
|
||||||
|
pSrc += size;
|
||||||
|
dstAddr += size;
|
||||||
|
|
||||||
|
remaining -= size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -501,7 +550,7 @@ BYTE __stdcall HarddiskInterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BY
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memmove(pHDD->m_buf, mem+pHDD->m_memblock, HD_BLOCK_SIZE);
|
memcpy(pHDD->m_buf, mem + pHDD->m_memblock, HD_BLOCK_SIZE);
|
||||||
|
|
||||||
if (bRes)
|
if (bRes)
|
||||||
bRes = ImageWriteBlock(pHDD->m_imagehandle, pHDD->m_diskblock, pHDD->m_buf);
|
bRes = ImageWriteBlock(pHDD->m_imagehandle, pHDD->m_diskblock, pHDD->m_buf);
|
||||||
@ -510,6 +559,7 @@ BYTE __stdcall HarddiskInterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BY
|
|||||||
{
|
{
|
||||||
pHDD->m_error = 0;
|
pHDD->m_error = 0;
|
||||||
r = 0;
|
r = 0;
|
||||||
|
pCard->m_notBusyCycle = g_nCumulativeCycles + (UINT64)CYCLES_FOR_DMA_RW_BLOCK;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -527,16 +577,19 @@ BYTE __stdcall HarddiskInterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BY
|
|||||||
{
|
{
|
||||||
pHDD->m_status_next = DISK_STATUS_OFF;
|
pHDD->m_status_next = DISK_STATUS_OFF;
|
||||||
pHDD->m_error = 1;
|
pHDD->m_error = 1;
|
||||||
r = DEVICE_UNKNOWN_ERROR;
|
r = DEVICE_NOT_CONNECTED; // GH#452
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x1: // m_error
|
case 0x1: // m_error
|
||||||
pHDD->m_status_next = DISK_STATUS_OFF; // TODO: FIXME: ??? YELLOW ??? WARNING
|
if (pHDD->m_error & 0x7f)
|
||||||
if (pHDD->m_error)
|
pHDD->m_error = 1; // Firmware requires that b0=1 for an error
|
||||||
{
|
else
|
||||||
_ASSERT(pHDD->m_error & 1);
|
pHDD->m_error = 0;
|
||||||
pHDD->m_error |= 1; // Firmware requires that b0=1 for an error
|
|
||||||
}
|
if (g_nCumulativeCycles <= pCard->m_notBusyCycle)
|
||||||
|
pHDD->m_error |= 0x80; // Firmware requires that b7=1 for busy (eg. busy doing r/w DMA operation)
|
||||||
|
else
|
||||||
|
pHDD->m_status_next = DISK_STATUS_OFF; // TODO: FIXME: ??? YELLOW ??? WARNING
|
||||||
|
|
||||||
r = pHDD->m_error;
|
r = pHDD->m_error;
|
||||||
break;
|
break;
|
||||||
@ -558,7 +611,7 @@ BYTE __stdcall HarddiskInterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BY
|
|||||||
case 0x7:
|
case 0x7:
|
||||||
r = (BYTE)(pHDD->m_diskblock & 0xFF00 >> 8);
|
r = (BYTE)(pHDD->m_diskblock & 0xFF00 >> 8);
|
||||||
break;
|
break;
|
||||||
case 0x8:
|
case 0x8: // Legacy: continue to support this I/O port for old HDD firmware
|
||||||
r = pHDD->m_buf[pHDD->m_buf_ptr];
|
r = pHDD->m_buf[pHDD->m_buf_ptr];
|
||||||
if (pHDD->m_buf_ptr < sizeof(pHDD->m_buf)-1)
|
if (pHDD->m_buf_ptr < sizeof(pHDD->m_buf)-1)
|
||||||
pHDD->m_buf_ptr++;
|
pHDD->m_buf_ptr++;
|
||||||
@ -649,8 +702,10 @@ bool HarddiskInterfaceCard::ImageSwap(void)
|
|||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
// Unit version history:
|
// Unit version history:
|
||||||
// 2: Updated $Csnn firmware to fix GH#319
|
// 2: Updated $C7nn firmware to fix GH#319
|
||||||
static const UINT kUNIT_VERSION = 2;
|
// 3: Updated $Csnn firmware to fix GH#996 (now slot-independent code)
|
||||||
|
// Added: Not Busy Cycle
|
||||||
|
static const UINT kUNIT_VERSION = 3;
|
||||||
|
|
||||||
#define SS_YAML_VALUE_CARD_HDD "Generic HDD"
|
#define SS_YAML_VALUE_CARD_HDD "Generic HDD"
|
||||||
|
|
||||||
@ -667,6 +722,7 @@ static const UINT kUNIT_VERSION = 2;
|
|||||||
#define SS_YAML_KEY_STATUS_PREV "Status Prev"
|
#define SS_YAML_KEY_STATUS_PREV "Status Prev"
|
||||||
#define SS_YAML_KEY_BUF_PTR "Buffer Offset"
|
#define SS_YAML_KEY_BUF_PTR "Buffer Offset"
|
||||||
#define SS_YAML_KEY_BUF "Buffer"
|
#define SS_YAML_KEY_BUF "Buffer"
|
||||||
|
#define SS_YAML_KEY_NOT_BUSY_CYCLE "Not Busy Cycle"
|
||||||
|
|
||||||
std::string HarddiskInterfaceCard::GetSnapshotCardName(void)
|
std::string HarddiskInterfaceCard::GetSnapshotCardName(void)
|
||||||
{
|
{
|
||||||
@ -700,6 +756,7 @@ void HarddiskInterfaceCard::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
|
|||||||
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
|
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
|
||||||
yamlSaveHelper.Save("%s: %d # b7=unit\n", SS_YAML_KEY_CURRENT_UNIT, m_unitNum);
|
yamlSaveHelper.Save("%s: %d # b7=unit\n", SS_YAML_KEY_CURRENT_UNIT, m_unitNum);
|
||||||
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_COMMAND, m_command);
|
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_COMMAND, m_command);
|
||||||
|
yamlSaveHelper.SaveHexUint64(SS_YAML_KEY_NOT_BUSY_CYCLE, m_notBusyCycle);
|
||||||
|
|
||||||
SaveSnapshotHDDUnit(yamlSaveHelper, HARDDISK_1);
|
SaveSnapshotHDDUnit(yamlSaveHelper, HARDDISK_1);
|
||||||
SaveSnapshotHDDUnit(yamlSaveHelper, HARDDISK_2);
|
SaveSnapshotHDDUnit(yamlSaveHelper, HARDDISK_2);
|
||||||
@ -777,12 +834,15 @@ bool HarddiskInterfaceCard::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT sl
|
|||||||
if (version < 1 || version > kUNIT_VERSION)
|
if (version < 1 || version > kUNIT_VERSION)
|
||||||
throw std::string("Card: wrong version");
|
throw std::string("Card: wrong version");
|
||||||
|
|
||||||
if (version == 1 && (regs.pc >> 8) == (0xC0|slot))
|
if (version <= 2 && (regs.pc >> 8) == (0xC0|slot))
|
||||||
throw std::string("HDD card: 6502 is running old HDD firmware");
|
throw std::string("HDD card: 6502 is running old HDD firmware");
|
||||||
|
|
||||||
m_unitNum = yamlLoadHelper.LoadUint(SS_YAML_KEY_CURRENT_UNIT); // b7=unit
|
m_unitNum = yamlLoadHelper.LoadUint(SS_YAML_KEY_CURRENT_UNIT); // b7=unit
|
||||||
m_command = yamlLoadHelper.LoadUint(SS_YAML_KEY_COMMAND);
|
m_command = yamlLoadHelper.LoadUint(SS_YAML_KEY_COMMAND);
|
||||||
|
|
||||||
|
if (version >= 3)
|
||||||
|
m_notBusyCycle = yamlLoadHelper.LoadUint64(SS_YAML_KEY_NOT_BUSY_CYCLE);
|
||||||
|
|
||||||
// Unplug all HDDs first in case HDD-2 is to be plugged in as HDD-1
|
// Unplug all HDDs first in case HDD-2 is to be plugged in as HDD-1
|
||||||
for (UINT i=0; i<NUM_HARDDISKS; i++)
|
for (UINT i=0; i<NUM_HARDDISKS; i++)
|
||||||
{
|
{
|
||||||
|
@ -94,7 +94,7 @@ public:
|
|||||||
const std::string& HarddiskGetFullPathName(const int iDrive);
|
const std::string& HarddiskGetFullPathName(const int iDrive);
|
||||||
void GetFilenameAndPathForSaveState(std::string& filename, std::string& path);
|
void GetFilenameAndPathForSaveState(std::string& filename, std::string& path);
|
||||||
bool Select(const int iDrive);
|
bool Select(const int iDrive);
|
||||||
BOOL Insert(const int iDrive, const std::string& pathname);
|
bool Insert(const int iDrive, const std::string& pathname);
|
||||||
void Unplug(const int iDrive);
|
void Unplug(const int iDrive);
|
||||||
bool IsDriveUnplugged(const int iDrive);
|
bool IsDriveUnplugged(const int iDrive);
|
||||||
void LoadLastDiskImage(const int iDrive);
|
void LoadLastDiskImage(const int iDrive);
|
||||||
@ -125,6 +125,7 @@ private:
|
|||||||
|
|
||||||
BYTE m_unitNum; // b7=unit
|
BYTE m_unitNum; // b7=unit
|
||||||
BYTE m_command;
|
BYTE m_command;
|
||||||
|
UINT64 m_notBusyCycle;
|
||||||
|
|
||||||
bool m_saveDiskImage; // Save the DiskImage name to Registry
|
bool m_saveDiskImage; // Save the DiskImage name to Registry
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user