Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
8db8423634
21 changed files with 391 additions and 284 deletions
|
@ -657,6 +657,10 @@
|
||||||
RelativePath=".\source\AY8910.h"
|
RelativePath=".\source\AY8910.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Card.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\source\Card.h"
|
RelativePath=".\source\Card.h"
|
||||||
>
|
>
|
||||||
|
|
|
@ -144,6 +144,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="source\6821.cpp" />
|
<ClCompile Include="source\6821.cpp" />
|
||||||
<ClCompile Include="source\AY8910.cpp" />
|
<ClCompile Include="source\AY8910.cpp" />
|
||||||
|
<ClCompile Include="source\Card.cpp" />
|
||||||
<ClCompile Include="source\CardManager.cpp" />
|
<ClCompile Include="source\CardManager.cpp" />
|
||||||
<ClCompile Include="source\CmdLine.cpp" />
|
<ClCompile Include="source\CmdLine.cpp" />
|
||||||
<ClCompile Include="source\Configuration\About.cpp" />
|
<ClCompile Include="source\Configuration\About.cpp" />
|
||||||
|
|
|
@ -238,6 +238,9 @@
|
||||||
<ClCompile Include="source\SNESMAX.cpp">
|
<ClCompile Include="source\SNESMAX.cpp">
|
||||||
<Filter>Source Files\Emulator</Filter>
|
<Filter>Source Files\Emulator</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\Card.cpp">
|
||||||
|
<Filter>Source Files\Emulator</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="source\CommonVICE\6510core.h">
|
<ClInclude Include="source\CommonVICE\6510core.h">
|
||||||
|
|
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,38 @@
|
||||||
!sl "hddrvr.labels"
|
!sl "hddrvr.labels"
|
||||||
|
|
||||||
; constants
|
; constants
|
||||||
hd_execute = $c0f0
|
hd_execute = $c080
|
||||||
hd_error = $c0f1
|
hd_status = $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)
|
||||||
|
|
||||||
|
; Notes on accesses to I/O registers:
|
||||||
|
; . ROR ABS16,X and ROL ABS16,X - only used for $C081+s*$10 STATUS register:
|
||||||
|
; 6502: double read (old data), write (old data), write (new data). The writes are harmless as writes to STATUS are ignored.
|
||||||
|
; 65C02: double read (old data), write (new data). The write is harmless as writes to STATUS are ignored.
|
||||||
|
; . STA ABS16,X does a false-read. This is harmless for writable I/O registers, since the false-read has no side effect.
|
||||||
|
|
||||||
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 +91,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?
|
Entrypoint ; $Cn0E - entrypoint?
|
||||||
bcs cmdproc
|
bcs GetSlotInX ; C=1: GetSlotInX -> cmdproc
|
||||||
bcc SmartPort
|
|
||||||
|
|
||||||
;;
|
; C=0: fall through to SmartPort...
|
||||||
|
|
||||||
Bootstrap
|
|
||||||
; 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 +123,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 +134,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
|
@checkCs46
|
||||||
|
*= $0046 ; org $0046
|
||||||
|
!warn "Cs46 padding = ", * - @checkCs46
|
||||||
|
|
||||||
Entrypoint_C761 ; Apple Oasis HDD controller entrypoint
|
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_status,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,88 +211,19 @@ 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
|
||||||
|
|
||||||
|
@ -286,11 +232,88 @@ SmartPort3
|
||||||
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_status.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_status,x ; b7=busy doing DMA?
|
||||||
|
bcs -
|
||||||
|
|
||||||
|
plp ; restore C from start of cmdproc
|
||||||
|
bcs done
|
||||||
|
ror hd_status,x ; Post: C=0 or 1
|
||||||
|
lda #0
|
||||||
|
beq hdboot2
|
||||||
|
|
||||||
|
done
|
||||||
|
ror hd_status,x ; Post: C=0 or 1
|
||||||
|
rts
|
||||||
|
|
||||||
|
;======================================
|
||||||
|
|
||||||
|
; 33 unused bytes
|
||||||
|
|
||||||
!zone data
|
!zone data
|
||||||
|
|
||||||
|
@ -309,7 +332,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.
54
source/Card.cpp
Normal file
54
source/Card.cpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
AppleWin : An Apple //e emulator for Windows
|
||||||
|
|
||||||
|
Copyright (C) 2021, Tom Charlesworth, Michael Pohoreski
|
||||||
|
|
||||||
|
AppleWin is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
AppleWin is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with AppleWin; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "StdAfx.h"
|
||||||
|
#include "Card.h"
|
||||||
|
|
||||||
|
#include "Tfe/tfe.h"
|
||||||
|
#include "Mockingboard.h"
|
||||||
|
#include "ParallelPrinter.h"
|
||||||
|
#include "z80emu.h"
|
||||||
|
|
||||||
|
|
||||||
|
void DummyCard::InitializeIO(LPBYTE pCxRomPeripheral)
|
||||||
|
{
|
||||||
|
switch (QueryType())
|
||||||
|
{
|
||||||
|
case CT_GenericPrinter:
|
||||||
|
PrintLoadRom(pCxRomPeripheral, m_slot);
|
||||||
|
break;
|
||||||
|
case CT_Uthernet:
|
||||||
|
tfe_InitializeIO(pCxRomPeripheral, m_slot);
|
||||||
|
break;
|
||||||
|
case CT_GenericClock:
|
||||||
|
break; // nothing to do
|
||||||
|
case CT_MockingboardC:
|
||||||
|
case CT_Phasor:
|
||||||
|
// only in slot 4
|
||||||
|
if (m_slot == SLOT4)
|
||||||
|
{
|
||||||
|
MB_InitializeIO(pCxRomPeripheral, SLOT4, SLOT5);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CT_Z80:
|
||||||
|
Z80_InitializeIO(pCxRomPeripheral, m_slot);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,10 +31,10 @@ enum SLOTS { SLOT0=0, SLOT1, SLOT2, SLOT3, SLOT4, SLOT5, SLOT6, SLOT7, NUM_SLOTS
|
||||||
class Card
|
class Card
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Card(void) : m_type(CT_Empty), m_slot(SLOT0) {}
|
|
||||||
Card(SS_CARDTYPE type, UINT slot) : m_type(type), m_slot(slot) {}
|
Card(SS_CARDTYPE type, UINT slot) : m_type(type), m_slot(slot) {}
|
||||||
virtual ~Card(void) {}
|
virtual ~Card(void) {}
|
||||||
|
|
||||||
|
virtual void InitializeIO(LPBYTE pCxRomPeripheral) = 0;
|
||||||
virtual void Init(void) = 0;
|
virtual void Init(void) = 0;
|
||||||
virtual void Reset(const bool powerCycle) = 0;
|
virtual void Reset(const bool powerCycle) = 0;
|
||||||
SS_CARDTYPE QueryType(void) { return m_type; }
|
SS_CARDTYPE QueryType(void) { return m_type; }
|
||||||
|
@ -51,11 +51,12 @@ private:
|
||||||
class EmptyCard : public Card
|
class EmptyCard : public Card
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EmptyCard(void) {}
|
EmptyCard(UINT slot) : Card(CT_Empty, slot) {}
|
||||||
virtual ~EmptyCard(void) {}
|
virtual ~EmptyCard(void) {}
|
||||||
|
|
||||||
virtual void Init(void) {};
|
virtual void InitializeIO(LPBYTE pCxRomPeripheral) {}
|
||||||
virtual void Reset(const bool powerCycle) {};
|
virtual void Init(void) {}
|
||||||
|
virtual void Reset(const bool powerCycle) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -66,6 +67,7 @@ public:
|
||||||
DummyCard(SS_CARDTYPE type, UINT slot) : Card(type, slot) {}
|
DummyCard(SS_CARDTYPE type, UINT slot) : Card(type, slot) {}
|
||||||
virtual ~DummyCard(void) {}
|
virtual ~DummyCard(void) {}
|
||||||
|
|
||||||
virtual void Init(void) {};
|
virtual void InitializeIO(LPBYTE pCxRomPeripheral);
|
||||||
virtual void Reset(const bool powerCycle) {};
|
virtual void Init(void) {}
|
||||||
|
virtual void Reset(const bool powerCycle) {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,7 +48,7 @@ void CardManager::InsertInternal(UINT slot, SS_CARDTYPE type)
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case CT_Empty:
|
case CT_Empty:
|
||||||
m_slot[slot] = new EmptyCard;
|
m_slot[slot] = new EmptyCard(slot);
|
||||||
break;
|
break;
|
||||||
case CT_Disk2:
|
case CT_Disk2:
|
||||||
m_slot[slot] = new Disk2InterfaceCard(slot);
|
m_slot[slot] = new Disk2InterfaceCard(slot);
|
||||||
|
@ -153,7 +153,7 @@ void CardManager::InsertAuxInternal(SS_CARDTYPE type)
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case CT_Empty:
|
case CT_Empty:
|
||||||
m_aux = new EmptyCard;
|
m_aux = new EmptyCard(SLOT_AUX);
|
||||||
break;
|
break;
|
||||||
case CT_80Col:
|
case CT_80Col:
|
||||||
m_aux = new DummyCard(type, SLOT_AUX);
|
m_aux = new DummyCard(type, SLOT_AUX);
|
||||||
|
@ -191,3 +191,14 @@ void CardManager::RemoveAux(void)
|
||||||
{
|
{
|
||||||
InsertAux(CT_Empty);
|
InsertAux(CT_Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CardManager::InitializeIO(LPBYTE pCxRomPeripheral)
|
||||||
|
{
|
||||||
|
for (UINT i = 0; i < NUM_SLOTS; ++i)
|
||||||
|
{
|
||||||
|
if (m_slot[i])
|
||||||
|
{
|
||||||
|
m_slot[i]->InitializeIO(pCxRomPeripheral);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -57,6 +57,8 @@ public:
|
||||||
class CSuperSerialCard* GetSSC(void) { return m_pSSC; }
|
class CSuperSerialCard* GetSSC(void) { return m_pSSC; }
|
||||||
bool IsSSCInstalled(void) { return m_pSSC != NULL; }
|
bool IsSSCInstalled(void) { return m_pSSC != NULL; }
|
||||||
|
|
||||||
|
void InitializeIO(LPBYTE pCxRomPeripheral);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InsertInternal(UINT slot, SS_CARDTYPE type);
|
void InsertInternal(UINT slot, SS_CARDTYPE type);
|
||||||
void InsertAuxInternal(SS_CARDTYPE type);
|
void InsertAuxInternal(SS_CARDTYPE type);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,7 @@ public:
|
||||||
virtual void Init(void) {};
|
virtual void Init(void) {};
|
||||||
virtual void Reset(const bool powerCycle);
|
virtual void Reset(const bool powerCycle);
|
||||||
|
|
||||||
void InitializeIO(LPBYTE pCxRomPeripheral);
|
virtual void InitializeIO(LPBYTE pCxRomPeripheral);
|
||||||
void Destroy(void); // no, doesn't "destroy" the disk image. DiskIIManagerShutdown()
|
void Destroy(void); // no, doesn't "destroy" the disk image. DiskIIManagerShutdown()
|
||||||
|
|
||||||
void Boot(void);
|
void Boot(void);
|
||||||
|
|
|
@ -14,7 +14,7 @@ public:
|
||||||
virtual void Init(void) {};
|
virtual void Init(void) {};
|
||||||
virtual void Reset(const bool powerCycle) {};
|
virtual void Reset(const bool powerCycle) {};
|
||||||
|
|
||||||
void InitializeIO(LPBYTE pCxRomPeripheral);
|
virtual void InitializeIO(LPBYTE pCxRomPeripheral);
|
||||||
|
|
||||||
static BYTE __stdcall IORead(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
|
static BYTE __stdcall IORead(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
|
||||||
|
|
||||||
|
|
|
@ -42,54 +42,64 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
#include "../resource/resource.h"
|
#include "../resource/resource.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Memory map:
|
Memory map (for slot 7):
|
||||||
|
|
||||||
C0F0 (r) EXECUTE AND RETURN STATUS
|
C0F0 (r) EXECUTE AND RETURN STATUS
|
||||||
C0F1 (r) STATUS (or ERROR)
|
C0F1 (r) STATUS (or ERROR): b7=busy, b0=error
|
||||||
C0F2 (r/w) COMMAND
|
C0F2 (r/w) COMMAND
|
||||||
C0F3 (r/w) UNIT NUMBER
|
C0F3 (r/w) UNIT NUMBER
|
||||||
C0F4 (r/w) LOW BYTE OF MEMORY BUFFER
|
C0F4 (r/w) LOW BYTE OF MEMORY BUFFER
|
||||||
C0F5 (r/w) HIGH BYTE OF MEMORY BUFFER
|
C0F5 (r/w) HIGH BYTE OF MEMORY BUFFER
|
||||||
C0F6 (r/w) LOW BYTE OF BLOCK NUMBER
|
C0F6 (r/w) LOW BYTE OF BLOCK NUMBER
|
||||||
C0F7 (r/w) HIGH BYTE OF BLOCK NUMBER
|
C0F7 (r/w) HIGH BYTE OF BLOCK NUMBER
|
||||||
C0F8 (r) NEXT BYTE
|
C0F8 (r) NEXT BYTE (legacy read-only port - still supported)
|
||||||
|
|
||||||
|
Firmware notes:
|
||||||
|
. ROR ABS16,X and ROL ABS16,X - only used for $C081+s*$10 STATUS register:
|
||||||
|
6502: double read (old data), write (old data), write (new data). The writes are harmless as writes to STATUS are ignored.
|
||||||
|
65C02: double read (old data), write (new data). The write is harmless as writes to STATUS are ignored.
|
||||||
|
. STA ABS16,X does a false-read. This is harmless for writable I/O registers, since the false-read has no side effect.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Hard drive emulation in Applewin.
|
Hard drive emulation in AppleWin.
|
||||||
|
|
||||||
Concept
|
Concept
|
||||||
To emulate a 32mb hard drive connected to an Apple IIe via Applewin.
|
To emulate a 32mb hard drive connected to an Apple IIe via AppleWin.
|
||||||
Designed to work with Autoboot Rom and Prodos.
|
Designed to work with Autoboot Rom and Prodos.
|
||||||
|
|
||||||
Overview
|
Overview
|
||||||
1. Hard drive image file
|
1. Hard drive image file
|
||||||
The hard drive image file (.HDV) will be formatted into blocks of 512
|
The hard drive image file (.HDV) will be formatted into blocks of 512
|
||||||
bytes, in a linear fashion. The internal formatting and meaning of each
|
bytes, in a linear fashion. The internal formatting and meaning of each
|
||||||
block to be decided by the Apple's operating system (ProDos). To create
|
block to be decided by the Apple's operating system (ProDOS). To create
|
||||||
an empty .HDV file, just create a 0 byte file (I prefer the debug method).
|
an empty .HDV file, just create a 0 byte file.
|
||||||
|
|
||||||
2. Emulation code
|
2. Emulation code
|
||||||
There are 4 commands Prodos will send to a block device.
|
There are 4 commands ProDOS will send to a block device.
|
||||||
Listed below are each command and how it's handled:
|
Listed below are each command and how it's handled:
|
||||||
|
|
||||||
1. STATUS
|
1. STATUS
|
||||||
In the emulation's case, returns only a DEVICE OK (0) or DEVICE I/O ERROR (8).
|
In the emulation's case, returns only a DEVICE OK (0), DEVICE I/O ERROR ($27) or DEVICE NOT CONNECTED ($28)
|
||||||
DEVICE I/O ERROR only returned if no HDV file is selected.
|
DEVICE NOT CONNECTED only returned if no HDV file is selected.
|
||||||
|
|
||||||
2. READ
|
2. READ
|
||||||
Loads requested block into a 512 byte buffer by attempting to seek to
|
Loads requested block into a 512 byte buffer by attempting to seek to
|
||||||
location in HDV file.
|
location in HDV file.
|
||||||
If seek fails, returns a DEVICE I/O ERROR. Resets hd_buf_ptr used by HD_NEXTBYTE
|
If seek fails, returns a DEVICE I/O ERROR. Resets m_buf_ptr used by legacy HD_NEXTBYTE
|
||||||
|
Copies requested block from a 512 byte buffer to the Apple's memory.
|
||||||
|
Sets STATUS.busy=1 until the DMA operation completes.
|
||||||
Returns a DEVICE OK if read was successful, or a DEVICE I/O ERROR otherwise.
|
Returns a DEVICE OK if read was successful, or a DEVICE I/O ERROR otherwise.
|
||||||
|
|
||||||
3. WRITE
|
3. WRITE
|
||||||
Copies requested block from the Apple's memory to a 512 byte buffer
|
Copies requested block from the Apple's memory to a 512 byte buffer
|
||||||
then attempts to seek to requested block.
|
then attempts to seek to requested block.
|
||||||
If the seek fails (usually because the seek is beyond the EOF for the
|
If the seek fails (usually because the seek is beyond the EOF for the
|
||||||
HDV file), the Emulation will attempt to "grow" the HDV file to accomodate.
|
HDV file), the emulation will attempt to "grow" the HDV file to accommodate.
|
||||||
Once the file can accomodate, or if the seek did not fail, the buffer is
|
Once the file can accommodate, or if the seek did not fail, the buffer is
|
||||||
written to the HDV file. NOTE: A2PC will grow *AND* shrink the HDV file.
|
written to the HDV file. NOTE: A2PC will grow *AND* shrink the HDV file.
|
||||||
|
Sets STATUS.busy=1 until the DMA operation completes.
|
||||||
I didn't see the point in shrinking the file as this behaviour would require
|
I didn't see the point in shrinking the file as this behaviour would require
|
||||||
patching prodos (to detect DELETE FILE calls).
|
patching prodos (to detect DELETE FILE calls).
|
||||||
|
|
||||||
|
@ -99,9 +109,9 @@ Overview
|
||||||
|
|
||||||
3. Bugs
|
3. Bugs
|
||||||
The only thing I've noticed is that Copy II+ 7.1 seems to crash or stall
|
The only thing I've noticed is that Copy II+ 7.1 seems to crash or stall
|
||||||
occasionally when trying to calculate how many free block are available
|
occasionally when trying to calculate how many free blocks are available
|
||||||
when running a catalog. This might be due to the great number of blocks
|
when running a catalog. This might be due to the great number of blocks
|
||||||
available. Also, DDD pro will not optimise the disk correctally (it's
|
available. Also, DDD pro will not optimise the disk correctly (it's
|
||||||
doing a disk defragment of some sort, and when it requests a block outside
|
doing a disk defragment of some sort, and when it requests a block outside
|
||||||
the range of the image file, it starts getting I/O errors), so don't
|
the range of the image file, it starts getting I/O errors), so don't
|
||||||
bother. Any program that preforms a read before write to an "unwritten"
|
bother. Any program that preforms a read before write to an "unwritten"
|
||||||
|
@ -125,6 +135,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
|
||||||
|
@ -149,7 +162,7 @@ void HarddiskInterfaceCard::Reset(const bool powerCycle)
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
void HarddiskInterfaceCard::InitializeIO(const LPBYTE pCxRomPeripheral)
|
void HarddiskInterfaceCard::InitializeIO(LPBYTE pCxRomPeripheral)
|
||||||
{
|
{
|
||||||
const DWORD HARDDISK_FW_SIZE = APPLE_SLOT_SIZE;
|
const DWORD HARDDISK_FW_SIZE = APPLE_SLOT_SIZE;
|
||||||
|
|
||||||
|
@ -190,7 +203,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 +232,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 +341,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 +461,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 +470,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 +501,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 +560,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 +569,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 +587,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
|
||||||
|
if (pHDD->m_error & 0x7f)
|
||||||
|
pHDD->m_error = 1; // Firmware requires that b0=1 for an error
|
||||||
|
else
|
||||||
|
pHDD->m_error = 0;
|
||||||
|
|
||||||
|
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
|
pHDD->m_status_next = DISK_STATUS_OFF; // TODO: FIXME: ??? YELLOW ??? WARNING
|
||||||
if (pHDD->m_error)
|
|
||||||
{
|
|
||||||
_ASSERT(pHDD->m_error & 1);
|
|
||||||
pHDD->m_error |= 1; // Firmware requires that b0=1 for an error
|
|
||||||
}
|
|
||||||
|
|
||||||
r = pHDD->m_error;
|
r = pHDD->m_error;
|
||||||
break;
|
break;
|
||||||
|
@ -558,7 +621,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 +712,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 +732,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 +766,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 +844,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++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -88,13 +88,13 @@ public:
|
||||||
virtual void Init(void) {}
|
virtual void Init(void) {}
|
||||||
virtual void Reset(const bool powerCycle);
|
virtual void Reset(const bool powerCycle);
|
||||||
|
|
||||||
void InitializeIO(const LPBYTE pCxRomPeripheral);
|
virtual void InitializeIO(LPBYTE pCxRomPeripheral);
|
||||||
void Destroy(void);
|
void Destroy(void);
|
||||||
const std::string& GetFullName(const int iDrive);
|
const std::string& GetFullName(const int iDrive);
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ LanguageCardUnit::~LanguageCardUnit(void)
|
||||||
SetMemMainLanguageCard(NULL);
|
SetMemMainLanguageCard(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LanguageCardUnit::InitializeIO(void)
|
void LanguageCardUnit::InitializeIO(LPBYTE pCxRomPeripheral)
|
||||||
{
|
{
|
||||||
RegisterIoHandler(kSlot0, &LanguageCardUnit::IO, &LanguageCardUnit::IO, NULL, NULL, this, NULL);
|
RegisterIoHandler(kSlot0, &LanguageCardUnit::IO, &LanguageCardUnit::IO, NULL, NULL, this, NULL);
|
||||||
}
|
}
|
||||||
|
@ -276,7 +276,7 @@ UINT Saturn128K::GetActiveBank(void)
|
||||||
return m_uSaturnActiveBank;
|
return m_uSaturnActiveBank;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Saturn128K::InitializeIO(void)
|
void Saturn128K::InitializeIO(LPBYTE pCxRomPeripheral)
|
||||||
{
|
{
|
||||||
RegisterIoHandler(kSlot0, &Saturn128K::IO, &Saturn128K::IO, NULL, NULL, this, NULL);
|
RegisterIoHandler(kSlot0, &Saturn128K::IO, &Saturn128K::IO, NULL, NULL, this, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ public:
|
||||||
virtual void Init(void) {};
|
virtual void Init(void) {};
|
||||||
virtual void Reset(const bool powerCycle) {};
|
virtual void Reset(const bool powerCycle) {};
|
||||||
|
|
||||||
virtual void InitializeIO(void);
|
virtual void InitializeIO(LPBYTE pCxRomPeripheral);
|
||||||
virtual void SetMemorySize(UINT banks) {} // No-op for //e and slot-0 16K LC
|
virtual void SetMemorySize(UINT banks) {} // No-op for //e and slot-0 16K LC
|
||||||
virtual UINT GetActiveBank(void) { return 0; } // Always 0 as only 1x 16K bank
|
virtual UINT GetActiveBank(void) { return 0; } // Always 0 as only 1x 16K bank
|
||||||
virtual void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper) { _ASSERT(0); } // Not used for //e
|
virtual void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper) { _ASSERT(0); } // Not used for //e
|
||||||
|
@ -71,7 +71,7 @@ public:
|
||||||
Saturn128K(UINT banks);
|
Saturn128K(UINT banks);
|
||||||
virtual ~Saturn128K(void);
|
virtual ~Saturn128K(void);
|
||||||
|
|
||||||
virtual void InitializeIO(void);
|
virtual void InitializeIO(LPBYTE pCxRomPeripheral);
|
||||||
virtual void SetMemorySize(UINT banks);
|
virtual void SetMemorySize(UINT banks);
|
||||||
virtual UINT GetActiveBank(void);
|
virtual UINT GetActiveBank(void);
|
||||||
virtual void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
|
virtual void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
|
||||||
|
|
|
@ -1720,84 +1720,11 @@ void MemInitializeIO(void)
|
||||||
InitIoHandlers();
|
InitIoHandlers();
|
||||||
|
|
||||||
if (g_pLanguageCard)
|
if (g_pLanguageCard)
|
||||||
g_pLanguageCard->InitializeIO();
|
g_pLanguageCard->InitializeIO(NULL);
|
||||||
else
|
else
|
||||||
RegisterIoHandler(LanguageCardUnit::kSlot0, IO_Null, IO_Null, NULL, NULL, NULL, NULL);
|
RegisterIoHandler(LanguageCardUnit::kSlot0, IO_Null, IO_Null, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
if (GetCardMgr().QuerySlot(SLOT1) == CT_GenericPrinter)
|
GetCardMgr().InitializeIO(pCxRomPeripheral);
|
||||||
PrintLoadRom(pCxRomPeripheral, SLOT1); // $C100 : Parallel printer f/w
|
|
||||||
|
|
||||||
if (GetCardMgr().QuerySlot(SLOT2) == CT_SSC)
|
|
||||||
dynamic_cast<CSuperSerialCard&>(GetCardMgr().GetRef(SLOT2)).InitializeIO(pCxRomPeripheral); // $C200 : SSC
|
|
||||||
|
|
||||||
if (GetCardMgr().QuerySlot(SLOT3) == CT_Uthernet)
|
|
||||||
{
|
|
||||||
// Slot 3 contains the Uthernet card (which can coexist with an 80-col+Ram card in AUX slot)
|
|
||||||
// . Uthernet card has no ROM and only IO mapped at $C0Bx
|
|
||||||
tfe_InitializeIO(pCxRomPeripheral, SLOT3);
|
|
||||||
}
|
|
||||||
else if (GetCardMgr().QuerySlot(SLOT3) == CT_FourPlay)
|
|
||||||
{
|
|
||||||
dynamic_cast<FourPlayCard&>(GetCardMgr().GetRef(SLOT3)).InitializeIO(pCxRomPeripheral);
|
|
||||||
}
|
|
||||||
else if (GetCardMgr().QuerySlot(SLOT3) == CT_SNESMAX)
|
|
||||||
{
|
|
||||||
dynamic_cast<SNESMAXCard&>(GetCardMgr().GetRef(SLOT3)).InitializeIO(pCxRomPeripheral);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apple//e: Auxiliary slot contains Extended 80 Column card or RamWorksIII card
|
|
||||||
|
|
||||||
if (GetCardMgr().QuerySlot(SLOT4) == CT_MouseInterface)
|
|
||||||
{
|
|
||||||
dynamic_cast<CMouseInterface&>(GetCardMgr().GetRef(SLOT4)).InitializeIO(pCxRomPeripheral); // $C400 : Mouse f/w
|
|
||||||
}
|
|
||||||
else if (GetCardMgr().QuerySlot(SLOT4) == CT_MockingboardC || GetCardMgr().QuerySlot(SLOT4) == CT_Phasor)
|
|
||||||
{
|
|
||||||
MB_InitializeIO(pCxRomPeripheral, SLOT4, SLOT5);
|
|
||||||
}
|
|
||||||
else if (GetCardMgr().QuerySlot(SLOT4) == CT_Z80)
|
|
||||||
{
|
|
||||||
Z80_InitializeIO(pCxRomPeripheral, SLOT4); // $C400 : Z80 card
|
|
||||||
}
|
|
||||||
// else if (GetCardMgr().QuerySlot(SLOT4) == CT_GenericClock)
|
|
||||||
// {
|
|
||||||
// LoadRom_Clock_Generic(pCxRomPeripheral, SLOT4);
|
|
||||||
// }
|
|
||||||
else if (GetCardMgr().QuerySlot(SLOT4) == CT_FourPlay)
|
|
||||||
{
|
|
||||||
dynamic_cast<FourPlayCard&>(GetCardMgr().GetRef(SLOT4)).InitializeIO(pCxRomPeripheral);
|
|
||||||
}
|
|
||||||
else if (GetCardMgr().QuerySlot(SLOT4) == CT_SNESMAX)
|
|
||||||
{
|
|
||||||
dynamic_cast<SNESMAXCard&>(GetCardMgr().GetRef(SLOT4)).InitializeIO(pCxRomPeripheral);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetCardMgr().QuerySlot(SLOT5) == CT_Z80)
|
|
||||||
{
|
|
||||||
Z80_InitializeIO(pCxRomPeripheral, SLOT5); // $C500 : Z80 card
|
|
||||||
}
|
|
||||||
else if (GetCardMgr().QuerySlot(SLOT5) == CT_SAM)
|
|
||||||
{
|
|
||||||
dynamic_cast<SAMCard&>(GetCardMgr().GetRef(SLOT5)).InitializeIO(pCxRomPeripheral);
|
|
||||||
}
|
|
||||||
else if (GetCardMgr().QuerySlot(SLOT5) == CT_FourPlay)
|
|
||||||
{
|
|
||||||
dynamic_cast<FourPlayCard&>(GetCardMgr().GetRef(SLOT5)).InitializeIO(pCxRomPeripheral);
|
|
||||||
}
|
|
||||||
else if (GetCardMgr().QuerySlot(SLOT5) == CT_SNESMAX)
|
|
||||||
{
|
|
||||||
dynamic_cast<SNESMAXCard&>(GetCardMgr().GetRef(SLOT5)).InitializeIO(pCxRomPeripheral);
|
|
||||||
}
|
|
||||||
else if (GetCardMgr().QuerySlot(SLOT5) == CT_Disk2)
|
|
||||||
{
|
|
||||||
dynamic_cast<Disk2InterfaceCard&>(GetCardMgr().GetRef(SLOT5)).InitializeIO(pCxRomPeripheral); // $C500 : Disk][ card
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetCardMgr().QuerySlot(SLOT6) == CT_Disk2)
|
|
||||||
dynamic_cast<Disk2InterfaceCard&>(GetCardMgr().GetRef(SLOT6)).InitializeIO(pCxRomPeripheral); // $C600 : Disk][ card
|
|
||||||
|
|
||||||
if (GetCardMgr().QuerySlot(SLOT7) == CT_GenericHDD)
|
|
||||||
dynamic_cast<HarddiskInterfaceCard&>(GetCardMgr().GetRef(SLOT7)).InitializeIO(pCxRomPeripheral);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by:
|
// Called by:
|
||||||
|
|
|
@ -14,7 +14,7 @@ public:
|
||||||
virtual void Init(void) {};
|
virtual void Init(void) {};
|
||||||
virtual void Reset(const bool powerCycle) {};
|
virtual void Reset(const bool powerCycle) {};
|
||||||
|
|
||||||
void InitializeIO(LPBYTE pCxRomPeripheral);
|
virtual void InitializeIO(LPBYTE pCxRomPeripheral);
|
||||||
// void Uninitialize();
|
// void Uninitialize();
|
||||||
void Reset();
|
void Reset();
|
||||||
UINT GetSlot(void) { return m_slot; }
|
UINT GetSlot(void) { return m_slot; }
|
||||||
|
|
|
@ -14,7 +14,7 @@ public:
|
||||||
virtual void Init(void) {};
|
virtual void Init(void) {};
|
||||||
virtual void Reset(const bool powerCycle) {};
|
virtual void Reset(const bool powerCycle) {};
|
||||||
|
|
||||||
void InitializeIO(LPBYTE pCxRomPeripheral);
|
virtual void InitializeIO(LPBYTE pCxRomPeripheral);
|
||||||
|
|
||||||
static BYTE __stdcall IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
|
static BYTE __stdcall IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,10 @@ public:
|
||||||
}
|
}
|
||||||
virtual ~SNESMAXCard(void) {}
|
virtual ~SNESMAXCard(void) {}
|
||||||
|
|
||||||
virtual void Init(void) {};
|
virtual void Init(void) {}
|
||||||
virtual void Reset(const bool powerCycle) {};
|
virtual void Reset(const bool powerCycle) {}
|
||||||
|
|
||||||
void InitializeIO(LPBYTE pCxRomPeripheral);
|
virtual void InitializeIO(LPBYTE pCxRomPeripheral);
|
||||||
|
|
||||||
static BYTE __stdcall IORead(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
|
static BYTE __stdcall IORead(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
|
||||||
static BYTE __stdcall IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
|
static BYTE __stdcall IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
|
||||||
|
|
Loading…
Add table
Reference in a new issue