Cleanup of initial hard drive emulation code.
This commit is contained in:
parent
719cbb7a23
commit
efc3eeaa6f
|
@ -13,9 +13,14 @@ reference/
|
||||||
src/gui/foooked/
|
src/gui/foooked/
|
||||||
ROMs/bin2c
|
ROMs/bin2c
|
||||||
ROMs/from-applewin/
|
ROMs/from-applewin/
|
||||||
res/
|
ROMs/misc/
|
||||||
docs/
|
|
||||||
web/source/
|
|
||||||
ROMs/asimov/
|
ROMs/asimov/
|
||||||
|
res/
|
||||||
|
docs/*.pdf
|
||||||
|
docs/*.jpg
|
||||||
|
docs/redbook/
|
||||||
|
docs/scsi/
|
||||||
|
docs/misc/
|
||||||
|
web/source/
|
||||||
misc/
|
misc/
|
||||||
changes-since-last-commit.txt
|
changes-since-last-commit.txt
|
||||||
|
|
|
@ -29,296 +29,17 @@ static uint8_t ramBank = 0;
|
||||||
static uint8_t deviceID = 7;
|
static uint8_t deviceID = 7;
|
||||||
static bool dmaSwitch = false;
|
static bool dmaSwitch = false;
|
||||||
static uint8_t staticRAM[0x2000] = { 0 };
|
static uint8_t staticRAM[0x2000] = { 0 };
|
||||||
//static char buffer[2048];
|
|
||||||
static uint8_t reg[16];
|
static uint8_t reg[16];
|
||||||
|
|
||||||
// Stuff that will have to GTFO of here
|
// Stuff that will have to GTFO of here
|
||||||
static uint8_t * hdData = NULL;//[(0x10000 * 512) + 0x40];
|
static uint8_t * hdData = NULL;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DVM_DATA_OUT = 0, DVM_DATA_IN = 1, DVM_COMMAND = 2, DVM_STATUS = 3,
|
||||||
|
DVM_MESSAGE_OUT = 6, DVM_MESSAGE_IN = 7, DVM_BUS_FREE = 8,
|
||||||
|
DVM_ARBITRATE = 16, DVM_SELECT = 32
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
$2 clears bit 1 and puts it back
|
|
||||||
$C clears bit 0 & 1 and puts it back
|
|
||||||
$F sets bit 7 and puts it back
|
|
||||||
reads $4, if 0 or <= 4 after anding with $BE, CLC & RTS
|
|
||||||
else, put $81 into $C88F, else SEC & RTS (obv. failure mode)
|
|
||||||
$3 is cleared before going to $CF2F
|
|
||||||
which sets, clears, then sets again bit 7 of $E
|
|
||||||
|
|
||||||
$C bits:
|
|
||||||
0:
|
|
||||||
1:
|
|
||||||
2:
|
|
||||||
3:
|
|
||||||
4:
|
|
||||||
5:
|
|
||||||
6: Physical DMA switch on card
|
|
||||||
7:
|
|
||||||
|
|
||||||
$F bits:
|
|
||||||
0-2: RAM bank # (?)
|
|
||||||
3: Enable RAM bank in bits 0-2 (or make writable maybe?)
|
|
||||||
4-7: ???
|
|
||||||
|
|
||||||
Switches on the card:
|
|
||||||
#1 sets DMA on/off (switch pos UP = OPEN = off)
|
|
||||||
#2-4 sets the computer's SCSI ID number (preset at factory to 7)
|
|
||||||
|
|
||||||
Looks like bits 5-7 of register $E is device ID
|
|
||||||
|
|
||||||
From Apple II SCSI Card Tech. Ref.:
|
|
||||||
|
|
||||||
$0 R Current SCSI data register
|
|
||||||
$0 W Output data register
|
|
||||||
$1 R/W Initiator command register
|
|
||||||
$2 R/W Mode Select register
|
|
||||||
$3 R/W Target command register
|
|
||||||
$4 R SCSI bus status
|
|
||||||
$4 W Select enable register
|
|
||||||
$5 R Bus and Status register
|
|
||||||
$6 R Input data register
|
|
||||||
$7 R Reset parity/interrupts
|
|
||||||
|
|
||||||
$8 R/W PDMA/DACK
|
|
||||||
$9 R SCSI device ID
|
|
||||||
$A W Memory Bank Select register
|
|
||||||
$B W Reset 5380 IC
|
|
||||||
$D W PDMA mode enable
|
|
||||||
$E R Read DRQ status bit through D7 bit
|
|
||||||
|
|
||||||
N.B.: The A2 HS SCSI card wires the A0-A2 lines backwards. So it maps like so: (No, it must be a mistake on the schematic as the code doesn't line up with that interpretation)
|
|
||||||
|
|
||||||
ZP locations:
|
|
||||||
$42 Command number
|
|
||||||
$43 Unit number
|
|
||||||
$44-45 Buffer pointer
|
|
||||||
$46-47 Block number
|
|
||||||
|
|
||||||
0123456789ABCDEF
|
|
||||||
@ABCDEFGHIJKLMNO
|
|
||||||
PQRSTUVWXYZ _
|
|
||||||
|
|
||||||
So the path of execution is:
|
|
||||||
|
|
||||||
$CC00 is written to, is that the bank select writable flag (@ reg. $E)?
|
|
||||||
$CD00 hide bank select?
|
|
||||||
$CD01 restore bank select?
|
|
||||||
$C808 gets slot # (+$20)
|
|
||||||
$C809 gets 0
|
|
||||||
- Bank 11:0
|
|
||||||
$C80B gets set with $98 to signal we've been there already
|
|
||||||
$5D gets flags (6 = running on GS, 5 = bit 6 of reg. $C is set)
|
|
||||||
[could it be that bit 6 of $C is physical DMA enable switch?]
|
|
||||||
$5E is the slot # (+$20)
|
|
||||||
$C80C gets the contents of $5D
|
|
||||||
$C893 gets set with $80 (signal we're in I set mode)
|
|
||||||
$C896 is set with GS Speed Register (0 on non-GS models)
|
|
||||||
$C807 gets set with the SP
|
|
||||||
execution then jumps to...
|
|
||||||
- Bank 15:0
|
|
||||||
$C809 gets $40 (& $BF32 as well!)
|
|
||||||
$C80A gets 0
|
|
||||||
Calls bank 3:0
|
|
||||||
- Bank 3:0 (Look for bootable drive)
|
|
||||||
$C883 gets 0
|
|
||||||
$C815 gets 0
|
|
||||||
$C80D gets 0 (# of drives found?)
|
|
||||||
$C80F gets 0
|
|
||||||
$C8DA gets: Device ID from $E is massaged and changed into a single bit
|
|
||||||
Calls bank 21:3
|
|
||||||
- Bank 21:3
|
|
||||||
Stores $80 (RST) in reg. $1, burns some cycles, stores 0 in reg. $1
|
|
||||||
[Looks like ASSERT /RST]
|
|
||||||
burn cycles, but burn most if $C8DA == 4
|
|
||||||
Clears 32 bytes @ $C92F
|
|
||||||
$C817 gets $40 |_________________
|
|
||||||
$C818 gets 0 | Failure countdown
|
|
||||||
$C8DB gets SCSI ID # from loop (bit field)
|
|
||||||
$4F gets cleared (error flag)
|
|
||||||
Calls $CF5F (send command to device?)
|
|
||||||
So the buffer (@ $C923) looks like so before the call:
|
|
||||||
* 00 00 00 00 00 00 .. .. .. .. .. .. C3 C9 00
|
|
||||||
^$60/1 points here ^$56/7 points here ($62 = $58 = 0)
|
|
||||||
* Puts $C9C3 into $C92F/30, zeroes $C931
|
|
||||||
Then calls bank 16:0
|
|
||||||
- Bank 16:0
|
|
||||||
Stores to $CD00
|
|
||||||
Calls $CDD0
|
|
||||||
Clears bit 1 from reg. $2, bits 0 & 1 from $C
|
|
||||||
[Looks like it clears the DMA MODE bit]
|
|
||||||
* Clears $4F, $C806, $C88F, $C890, $C8EE-F0
|
|
||||||
Sets bit 7 of reg. $F
|
|
||||||
Calls $CECE
|
|
||||||
Gets reg. $4, checks for 0, returns success if so
|
|
||||||
[R is SCSI Bus Status]
|
|
||||||
Masks bits 1-5 & 7, checks for 2 or 4, returns success if so
|
|
||||||
[bit 2 = /I/O, bit 1 = /SEL]
|
|
||||||
Else, $81 -> $C88F, returns failure (set bit 7 of $C806, sets C)
|
|
||||||
Calls $CF42
|
|
||||||
Returns since $C893 has $80 in it
|
|
||||||
Calls $CC24 (Arbitrate phase)
|
|
||||||
Zeroes reg. $3
|
|
||||||
[Target Command, set Data Out]
|
|
||||||
Toggles bit 7 of reg. $E (ON-off-ON)
|
|
||||||
Puts host ID(?) in reg. $0
|
|
||||||
[W: Output Data - sends data on SCSI bus]
|
|
||||||
Loop:
|
|
||||||
Puts 0 in reg. $2, then sets bit 0 of reg. $2
|
|
||||||
[bit 0 is ARBITRATE, requires SCSI device ID in $0]
|
|
||||||
Gets reg. $C, checks bit 4
|
|
||||||
If clear, then toggle reg. $E (ON-off-ON) & count down to failure
|
|
||||||
Check bit 6 of reg. $1, loop back if not set
|
|
||||||
[Initiator Command. bit 6 AIP, if set bus free detected]
|
|
||||||
Check bit 5 of reg. $1, loop back if not clear
|
|
||||||
[Initiator Command, bit 5 LA, if set, bus was lost]
|
|
||||||
Check reg. $0 to see if it's same as what's in $C8DA
|
|
||||||
[R: Current SCSI Data]
|
|
||||||
If not, see if it's >= to EORed value & loop back if it is
|
|
||||||
Checks bit 5 of reg. $1, loop back if not clear
|
|
||||||
[Initiator Command, bit 5 LA, if set, bus was lost]
|
|
||||||
Sets bits 1 & 2 of reg. $1, clear bits 5 & 6 of same
|
|
||||||
[Initiator Command: 1 = ASSERT /ATN, 2 = ASSERT /SEL, clear AIP, LA]
|
|
||||||
Clear C and return if success, set $C88F to $80 & set C if failure
|
|
||||||
Calls $CC7A if succesful:
|
|
||||||
Zeroes out reg. $4
|
|
||||||
[Select Enable: disable interrupts]
|
|
||||||
Stores $C8DA ORed with $C8DB into reg. $0
|
|
||||||
[W: Output Data - writing ?]
|
|
||||||
Set bits 0 & 6 in reg. $1, clear 5 & 6 in reg. $1
|
|
||||||
[W: 0- ASSERT DATA BUS, 6- TEST MODE; 5- unused(?), 6- TEST MODE off]
|
|
||||||
Clear bit 0 in reg. $2
|
|
||||||
[W: Clear ARBITRATE]
|
|
||||||
Puts contents of $C8DC +set bit 7 into $C821
|
|
||||||
Clears bit 3 in reg. $1
|
|
||||||
[W: 3- ASSERT /BSY (0 disconnects from bus)]
|
|
||||||
Calls $CD51
|
|
||||||
Toggle bit 7 of reg. $E (ON-off-ON)
|
|
||||||
Wait for bit 6 of reg. $4 to come on, if not, set C (signal failure)
|
|
||||||
[R: bit 6- /BSY]
|
|
||||||
Clears bit 2 in reg. $1
|
|
||||||
[W: ASSERT /SEL (0 de-asserts)]
|
|
||||||
Clears bits 1, 5, 6 in reg. $1
|
|
||||||
[W: 1- /ATN, 5- unused(?), 6- TEST MODE]
|
|
||||||
Clears bit 0 in reg. $1
|
|
||||||
[W: ASSERT DATA BUS (0 de-asserts)]
|
|
||||||
Signals success (C = 0) or failure (C = 1, $C88F = $81)
|
|
||||||
Calls $CF58
|
|
||||||
Returns since $C893 has $80 in it still
|
|
||||||
Calls $CCE4
|
|
||||||
Checks if bit 4 of reg. $C is set, if not, toggle bit 7 of reg. $E
|
|
||||||
Checks $4, if either of bits 1 & 6 are set, if not, signal failure
|
|
||||||
If only bit 2 or 2 & 6 is set, loop back to beginning of call
|
|
||||||
Clears bit 1 of reg. $2, then restores it to what it was
|
|
||||||
[W: 1- DMA MODE]
|
|
||||||
Checks for bit 5 of reg. $4, if not set, loop back to begin
|
|
||||||
[R: 5- /REQ]
|
|
||||||
Moves $C81F into $C820
|
|
||||||
Restores reg. $4 from Y, masks off bits 2-4 and puts it in $C81F
|
|
||||||
[R: 4- /MSG, 3- /C/D, 2- /I/O]
|
|
||||||
Puts prev. value r. shifted 1 into $C82B
|
|
||||||
Uses that as index into jump table
|
|
||||||
R. shifts again by 1 and stuffs into reg. $3
|
|
||||||
[W: Target Command- writes /MSG, /C/D, /I/O]
|
|
||||||
Calls $CD48
|
|
||||||
Using Y as index, push value pair @ $CFB4 onto stack & return to call
|
|
||||||
Calls a routine from 0-7...
|
|
||||||
0-1 goes to $6E6C or copies $56-8 into $C81C-E, calls bank 18:0
|
|
||||||
- Bank 18:0
|
|
||||||
...
|
|
||||||
Calls bank 20:0 or 1 (0 for read, 1 for write--PIO mode)
|
|
||||||
2 calls bank 17:0 (/C/D)
|
|
||||||
3 calls bank 17:3 (/C/D + /I/O)
|
|
||||||
4-5 signals failure & returns (bit 4: /MSG, no /C/D = failure)
|
|
||||||
6 calls bank 17:2 (/MSG + /C/D)
|
|
||||||
[During init, it comes here...]
|
|
||||||
Gets $C821, compares it to 1, if so, signal failure & return
|
|
||||||
Calls $CE79
|
|
||||||
a
|
|
||||||
7 calls bank 17:1 (/MSG + /C/D + /I/O)
|
|
||||||
If bit 7 of $C806 is clear, loop back to begin
|
|
||||||
Calls $CDA0
|
|
||||||
Does some error checking on $C88F and $C8EC
|
|
||||||
Jumps to $CE18
|
|
||||||
Clears bit 1 from reg. $2, bits 0-1 from reg. $C
|
|
||||||
Moves $C88F into $4F
|
|
||||||
If it's 0 or $8E, or reg. $4 is 0, skip over next
|
|
||||||
Calls $CE6C
|
|
||||||
Moves $C88F into $4F
|
|
||||||
Zeroes out regs. $1, $2, $3, $C
|
|
||||||
Stores to $CD01
|
|
||||||
[Returns to $CC6D in bank 3:0]
|
|
||||||
Calls $CC9F (Function 1 - INQUIRY + more
|
|
||||||
Zeroes $C8CF, $C892
|
|
||||||
Calls $CD0E
|
|
||||||
[12 00 00 00 1E 00 .. .. .. .. .. .. C3 C9 00 .. 1E]
|
|
||||||
Calls bank 16:0 (Do INQUIRY)
|
|
||||||
if $C9C3 (1st byte of INQUIRY data) == $10
|
|
||||||
$C892 <- $80
|
|
||||||
$C8CB <- $06
|
|
||||||
$C8B9 <- $F8
|
|
||||||
$C8CC <- $C0
|
|
||||||
else if == 2 or 6,
|
|
||||||
$C892 <- $40
|
|
||||||
$C8CF |= $0C
|
|
||||||
else (depending on 1st byte),
|
|
||||||
(5=CDROM, 6=DA Tape drive, 7=HD, 8=Scanner, 9=Printer, 3=nonspecific)
|
|
||||||
$C8CB <- 07 06 09 FF FF 05 08
|
|
||||||
$C8B9 <- C0 C0 A0 00 00 C0 A0
|
|
||||||
$C8CC <- F8 F8 78 FF FF B4 70
|
|
||||||
Sets bit 5, clears bit 6 in $C8CC
|
|
||||||
if bits 4-5, 7 are set, set bit 0 of $C8CF
|
|
||||||
Copies 16 bytes of returned data from $C9C3 + $17 to $C8BB
|
|
||||||
$C8CE <- $30
|
|
||||||
$C8CD <- $00
|
|
||||||
Calls bank 21:1 (lock CD-ROM?)
|
|
||||||
Does PREVENT ALLOW MEDIUM REMOVAL if $C8CB == 5
|
|
||||||
$C927 <- $01
|
|
||||||
Calls $CDDD (MODE SENSE/MODE SELECT)
|
|
||||||
Calls $CEA8 (READ CAPACITY)
|
|
||||||
Calls 16:0 with command READ CAPACITY, data returned @ $C9C3 (8 bytes)
|
|
||||||
$C8AB <- $C9C6
|
|
||||||
$C8AA <- $C9C5
|
|
||||||
$C8A9 <- $C9C4
|
|
||||||
if $C8A9 =! 0, set bit 0 of $C8CF
|
|
||||||
$C8A8 <- $C9C3
|
|
||||||
if $C8A8 != 0, set bit 0 of $C8CF
|
|
||||||
$C8AF <- $C9C7, save flags
|
|
||||||
$C8AE <- $C9C8, save flags
|
|
||||||
$C8AD <- $C9C9, save in Y
|
|
||||||
$C8AC <- $C9CA
|
|
||||||
Zeroes error flag ($4F)
|
|
||||||
$C8CF |= 0x0C
|
|
||||||
Calls $CFC7 (bank 4:0 direct)
|
|
||||||
- Bank 4:0
|
|
||||||
Calls $CD65 (READ--reads 512 bytes from LBA set from $C8D2 + 1)
|
|
||||||
Calls $CDDA, sets carry if 1st two bytes are not 'PM'
|
|
||||||
Calls $CD39
|
|
||||||
Calls $CD1A
|
|
||||||
$C8D0 <- $C80F
|
|
||||||
Calls $CDF1
|
|
||||||
[Returns to $CCDB in bank 3:0]
|
|
||||||
Loops back if bit 7 of $C892 is clear
|
|
||||||
Calls $CD05 (bank 21:2 direct--unlock CD-ROM?)
|
|
||||||
Adds 1 to $C8DC
|
|
||||||
Loops back if $C8DC != 8
|
|
||||||
...
|
|
||||||
[Returns to $CC10 in bank 15:0]
|
|
||||||
Checks if call was successful (if not jumps to bank 11:1)
|
|
||||||
execution jumps to...
|
|
||||||
- Bank 11:2 ($CD9A)
|
|
||||||
Puts 1 in $43 (unit #), $44
|
|
||||||
Zeroes out $46-49 (block # [2], ??? [2])
|
|
||||||
Puts $08 in $41, zeroes out $40, $42 (command)
|
|
||||||
Calls bank 9:0
|
|
||||||
- Bank 9:0
|
|
||||||
...
|
|
||||||
Calls bank 16:0
|
|
||||||
|
|
||||||
SCSI Phases
|
|
||||||
-----------
|
|
||||||
|
|
||||||
Selection: In this state, the initiator selects a target unit and get the target to carry out a given function, such as reading or writing data. The initiator outpus the OR value of its SCSI-ID and the SCSI-ID of the target onto the data bus (for example, if the initiator is 2 and the target is 5 then the OR-ed ID on the bus will be 00100100). The target then determines that its ID is on the data bus and sets the /BSY line active. If this does not happen within a given time, then the initiator deactivates the /SEL signal, and the bus will be free. The target determines that it is selected when the /SEL signal and its SCSI ID bit are active and the /BSY and /I/O signals are false. It then asserts the signal within a selection abort time (200µs).
|
|
||||||
*/
|
|
||||||
static bool DATA_BUS = false;
|
static bool DATA_BUS = false;
|
||||||
static bool DMA_MODE = false;
|
static bool DMA_MODE = false;
|
||||||
static bool BSY = false;
|
static bool BSY = false;
|
||||||
|
@ -333,7 +54,7 @@ static bool REQ = false;
|
||||||
static bool DEV_BSY = false;
|
static bool DEV_BSY = false;
|
||||||
static bool DRQ = false;
|
static bool DRQ = false;
|
||||||
static bool DACK = false;
|
static bool DACK = false;
|
||||||
static uint8_t devMode = 8;
|
static uint8_t devMode = DVM_BUS_FREE;
|
||||||
static uint8_t cmdLength;
|
static uint8_t cmdLength;
|
||||||
static uint8_t cmd[256];
|
static uint8_t cmd[256];
|
||||||
static uint32_t bytesToSend;
|
static uint32_t bytesToSend;
|
||||||
|
@ -341,26 +62,30 @@ static uint8_t * buf;
|
||||||
static uint32_t bufPtr;
|
static uint32_t bufPtr;
|
||||||
static uint8_t response;
|
static uint8_t response;
|
||||||
|
|
||||||
|
|
||||||
|
static inline void SetNextState(uint8_t state)
|
||||||
|
{
|
||||||
|
devMode = state;
|
||||||
|
MSG = (state & 0x04 ? true : false);
|
||||||
|
C_D = (state & 0x02 ? true : false);
|
||||||
|
I_O = (state & 0x01 ? true : false);
|
||||||
|
cmdLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void RunDevice(void)
|
static void RunDevice(void)
|
||||||
{
|
{
|
||||||
//WriteLog(" >>> RUNNING HD...\n");
|
|
||||||
// Let's see where it's really going...
|
// Let's see where it's really going...
|
||||||
/* if (mainCPU.pc == 0xCE7E)
|
/* if (mainCPU.pc == 0xCE7E)
|
||||||
dumpDis = true;//*/
|
dumpDis = true;//*/
|
||||||
|
|
||||||
|
// These are SCSI messages sent in response to certain commands
|
||||||
static uint8_t readCapacity[8] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 };
|
static uint8_t readCapacity[8] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00 };
|
||||||
static uint8_t inquireData[30] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'S', 'E', 'A', 'G', 'A', 'T', 'E', ' ', 'P', 'h', 'o', 'n', 'y', '1' };
|
static uint8_t inquireData[30] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'S', 'E', 'A', 'G', 'A', 'T', 'E', ' ', '3', '1', '3', '3', '7', ' ' };
|
||||||
static uint8_t badSense[20] = { 0x70, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
static uint8_t badSense[20] = { 0x70, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
enum {
|
|
||||||
DVM_DATA_OUT = 0, DVM_DATA_IN = 1, DVM_COMMAND = 2, DVM_STATUS = 3,
|
|
||||||
DVM_MESSAGE_OUT = 6, DVM_MESSAGE_IN = 7, DVM_BUS_FREE, DVM_ARBITRATE,
|
|
||||||
DVM_SELECT
|
|
||||||
};
|
|
||||||
|
|
||||||
if (RST)
|
if (RST)
|
||||||
{
|
{
|
||||||
//WriteLog(" >>> DEVICE RESET...\n");
|
|
||||||
devMode = DVM_BUS_FREE;
|
devMode = DVM_BUS_FREE;
|
||||||
DEV_BSY = false;
|
DEV_BSY = false;
|
||||||
return;
|
return;
|
||||||
|
@ -369,40 +94,32 @@ static void RunDevice(void)
|
||||||
switch (devMode)
|
switch (devMode)
|
||||||
{
|
{
|
||||||
case DVM_BUS_FREE:
|
case DVM_BUS_FREE:
|
||||||
if (SEL)//(BSY && SEL)
|
// We never initiate, so this we don't worry about whether or not the
|
||||||
devMode = DVM_ARBITRATE;
|
// bus is free.
|
||||||
|
|
||||||
break;
|
|
||||||
case DVM_ARBITRATE:
|
case DVM_ARBITRATE:
|
||||||
////WriteLog(" >>> ARBITRATE PHASE (BSY=%i SEL=%i DATA_BUS=%i [%02X])\n", BSY, SEL, DATA_BUS, reg[0]);
|
// Likewise, we don't arbitrate either.
|
||||||
if (!BSY && SEL && DATA_BUS && (reg[0] & 0x40))
|
|
||||||
devMode = DVM_SELECT, DEV_BSY = true;
|
|
||||||
else if (!BSY && !SEL)
|
|
||||||
devMode = DVM_BUS_FREE;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DVM_SELECT:
|
case DVM_SELECT:
|
||||||
//WriteLog(" >>> SELECT PHASE\n");
|
// If we're in Selection phase, see if our ID is on the bus, and, if so,
|
||||||
// Preset response code to "Good"
|
// go on to the next phase (since the Target drives the phase dance).
|
||||||
response = 0x00;
|
if ((reg[0] & 0x40) && DATA_BUS)
|
||||||
|
{
|
||||||
|
DEV_BSY = true;
|
||||||
|
|
||||||
if (ATN)
|
// Preset response code to "Good"
|
||||||
{
|
response = 0x00;
|
||||||
MSG = true, C_D = true, I_O = false;
|
|
||||||
devMode = DVM_MESSAGE_OUT;
|
if (ATN)
|
||||||
REQ = true;
|
SetNextState(DVM_MESSAGE_OUT);
|
||||||
}
|
else
|
||||||
else
|
// If no ATN is asserted, go to COMMAND? Dunno, the firmware
|
||||||
{
|
// doesn't ever go there; it *always* starts with MESSAGE OUT.
|
||||||
// If no ATN is asserted, go to COMMAND I guess?
|
SetNextState(DVM_COMMAND);
|
||||||
// Let's try it
|
|
||||||
// errrr, no. this does not work. Or does it???
|
|
||||||
MSG = false, C_D = true, I_O = false;
|
|
||||||
devMode = DVM_COMMAND;
|
|
||||||
cmdLength = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DVM_DATA_OUT:
|
case DVM_DATA_OUT:
|
||||||
//WriteLog(" >>> DATA OUT PHASE (bts=%u)\n", bytesToSend);
|
//WriteLog(" >>> DATA OUT PHASE (bts=%u)\n", bytesToSend);
|
||||||
if (!ACK)
|
if (!ACK)
|
||||||
|
@ -419,22 +136,21 @@ static void RunDevice(void)
|
||||||
if (buf)
|
if (buf)
|
||||||
buf[bufPtr] = reg[0];
|
buf[bufPtr] = reg[0];
|
||||||
|
|
||||||
DRQ = false;
|
DRQ = DACK = false;
|
||||||
DACK = false;
|
|
||||||
bytesToSend--;
|
bytesToSend--;
|
||||||
bufPtr++;
|
bufPtr++;
|
||||||
|
|
||||||
if (bytesToSend == 0)
|
if (bytesToSend == 0)
|
||||||
{
|
{
|
||||||
REQ = false;
|
REQ = false;
|
||||||
MSG = false, C_D = true, I_O = true;
|
SetNextState(DVM_STATUS);
|
||||||
devMode = DVM_STATUS;
|
|
||||||
buf = NULL;
|
buf = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DVM_DATA_IN:
|
case DVM_DATA_IN:
|
||||||
//WriteLog(" >>> DATA IN PHASE (bts=%u)\n", bytesToSend);
|
//WriteLog(" >>> DATA IN PHASE (bts=%u)\n", bytesToSend);
|
||||||
if (!ACK)
|
if (!ACK)
|
||||||
|
@ -444,214 +160,198 @@ static void RunDevice(void)
|
||||||
{
|
{
|
||||||
if (!DACK)
|
if (!DACK)
|
||||||
{
|
{
|
||||||
// We just send zeroes for now...
|
// If there's no buffer set up, send zeroes...
|
||||||
if (buf == NULL)
|
reg[6] = (buf == NULL ? 0 : buf[bufPtr]);
|
||||||
reg[6] = 0;
|
|
||||||
else
|
|
||||||
reg[6] = buf[bufPtr];
|
|
||||||
|
|
||||||
DRQ = true;
|
DRQ = true;
|
||||||
}
|
}
|
||||||
else if (DRQ && DACK)
|
else if (DRQ && DACK)
|
||||||
{
|
{
|
||||||
DRQ = false;
|
DRQ = DACK = false;
|
||||||
DACK = false;
|
|
||||||
bytesToSend--;
|
bytesToSend--;
|
||||||
bufPtr++;
|
bufPtr++;
|
||||||
|
|
||||||
if (bytesToSend == 0)
|
if (bytesToSend == 0)
|
||||||
{
|
{
|
||||||
REQ = false;
|
REQ = false;
|
||||||
MSG = false, C_D = true, I_O = true;
|
SetNextState(DVM_STATUS);
|
||||||
devMode = DVM_STATUS;
|
|
||||||
buf = NULL;
|
buf = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DVM_COMMAND:
|
case DVM_COMMAND:
|
||||||
//WriteLog(" >>> COMMAND PHASE\n");
|
{
|
||||||
if (!ACK)
|
if (!ACK)
|
||||||
REQ = true;
|
REQ = true;
|
||||||
else if (REQ && ACK)
|
else if (REQ && ACK)
|
||||||
{
|
{
|
||||||
cmd[cmdLength++] = reg[0];
|
cmd[cmdLength++] = reg[0];
|
||||||
// WriteLog("HD: Write to target value $%02X\n", reg[0]);
|
|
||||||
REQ = false;
|
REQ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle "Test Unit Ready" command
|
uint8_t cmdType = (cmd[0] & 0xE0) >> 5;
|
||||||
if ((cmd[0] == 0) && (cmdLength == 6))
|
|
||||||
{
|
|
||||||
WriteLog("HD: Received command TEST UNIT READY\n");
|
|
||||||
REQ = false;
|
|
||||||
// Drive next phase
|
|
||||||
MSG = false, C_D = true, I_O = true;
|
|
||||||
devMode = DVM_STATUS;
|
|
||||||
}
|
|
||||||
// Handle "Request Sense" command
|
|
||||||
else if ((cmd[0] == 0x03) && (cmdLength == 6))
|
|
||||||
{
|
|
||||||
WriteLog("HD: Received command REQUEST SENSE [%02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
|
|
||||||
REQ = false;
|
|
||||||
// Drive next phase
|
|
||||||
MSG = false, C_D = false, I_O = true;
|
|
||||||
devMode = DVM_DATA_IN;
|
|
||||||
bytesToSend = cmd[4];
|
|
||||||
|
|
||||||
// Return error for LUNs other than 0
|
if ((cmdType == 0) && (cmdLength == 6))
|
||||||
if ((cmd[1] & 0xE0) != 0)
|
{
|
||||||
|
// Handle "Test Unit Ready" command
|
||||||
|
if (cmd[0] == 0)
|
||||||
{
|
{
|
||||||
buf = badSense;
|
WriteLog("HD: Received command TEST UNIT READY\n");
|
||||||
|
SetNextState(DVM_STATUS);
|
||||||
|
}
|
||||||
|
// Handle "Request Sense" command
|
||||||
|
else if (cmd[0] == 0x03)
|
||||||
|
{
|
||||||
|
WriteLog("HD: Received command REQUEST SENSE [%02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
|
||||||
|
SetNextState(DVM_DATA_IN);
|
||||||
|
bytesToSend = cmd[4];
|
||||||
|
|
||||||
|
// Return error for LUNs other than 0
|
||||||
|
if ((cmd[1] & 0xE0) != 0)
|
||||||
|
{
|
||||||
|
buf = badSense;
|
||||||
|
bufPtr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Handle "Read" (6) command
|
||||||
|
else if (cmd[0] == 0x08)
|
||||||
|
{
|
||||||
|
WriteLog("HD: Received command READ(6) [%02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
|
||||||
|
SetNextState(DVM_DATA_IN);
|
||||||
|
bytesToSend = cmd[4] * 512; // amount is set in blocks
|
||||||
|
uint32_t lba = ((cmd[1] & 0x1F) << 16) | (cmd[2] << 8) | cmd[3];
|
||||||
|
buf = (hdData != NULL ? &hdData[(lba * 512) + 0x40] : NULL);
|
||||||
bufPtr = 0;
|
bufPtr = 0;
|
||||||
}
|
}
|
||||||
}
|
// Handle "Inquire" command
|
||||||
// Handle "Read" (6) command
|
else if (cmd[0] == 0x12)
|
||||||
else if ((cmd[0] == 0x08) && (cmdLength == 6))
|
|
||||||
{
|
|
||||||
WriteLog("HD: Received command READ(6) [%02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
|
|
||||||
REQ = false;
|
|
||||||
// Drive next phase
|
|
||||||
MSG = false, C_D = false, I_O = true;
|
|
||||||
devMode = DVM_DATA_IN;
|
|
||||||
bytesToSend = cmd[4] * 512; // amount is set in blocks
|
|
||||||
}
|
|
||||||
// Handle "Inquire" command
|
|
||||||
else if ((cmd[0] == 0x12) && (cmdLength == 6))
|
|
||||||
{
|
|
||||||
WriteLog("HD: Received command INQUIRE [%02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
|
|
||||||
REQ = false;
|
|
||||||
// Drive next phase
|
|
||||||
MSG = false, C_D = false, I_O = true;
|
|
||||||
devMode = DVM_DATA_IN;
|
|
||||||
bytesToSend = cmd[4];
|
|
||||||
buf = inquireData;
|
|
||||||
bufPtr = 0;
|
|
||||||
|
|
||||||
// Reject all but LUN 0
|
|
||||||
if ((cmd[1] & 0xE0) != 0)
|
|
||||||
{
|
{
|
||||||
|
WriteLog("HD: Received command INQUIRE [%02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
|
||||||
|
SetNextState(DVM_DATA_IN);
|
||||||
|
bytesToSend = cmd[4];
|
||||||
|
buf = inquireData;
|
||||||
|
bufPtr = 0;
|
||||||
|
|
||||||
|
// Reject all but LUN 0
|
||||||
|
if ((cmd[1] & 0xE0) != 0)
|
||||||
|
response = 0x02; // "Check Condition" code
|
||||||
|
}
|
||||||
|
// Handle "Mode Select" command
|
||||||
|
else if (cmd[0] == 0x15)
|
||||||
|
{
|
||||||
|
WriteLog("HD: Received command MODE SELECT [%02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
|
||||||
|
SetNextState(DVM_DATA_OUT);
|
||||||
|
bytesToSend = cmd[4];
|
||||||
|
}
|
||||||
|
// Handle "Mode Sense" command
|
||||||
|
else if (cmd[0] == 0x1A)
|
||||||
|
{
|
||||||
|
WriteLog("HD: Received command MODE SENSE [%02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
|
||||||
|
SetNextState(DVM_DATA_IN);
|
||||||
|
bytesToSend = cmd[4];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteLog("HD: Received unhandled 6 command [%02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
|
||||||
|
// Return failure...
|
||||||
|
SetNextState(DVM_STATUS);
|
||||||
response = 0x02; // Check condition code
|
response = 0x02; // Check condition code
|
||||||
// MSG = false, C_D = false, I_O = false;
|
|
||||||
// DEV_BSY = false;
|
|
||||||
// devMode = DVM_BUS_FREE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Handle "Mode Select" command
|
else if (((cmdType == 1) || (cmdType == 2)) && (cmdLength == 10))
|
||||||
else if ((cmd[0] == 0x15) && (cmdLength == 6))
|
|
||||||
{
|
{
|
||||||
WriteLog("HD: Received command MODE SELECT [%02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
|
// Handle "Read Capacity" command
|
||||||
REQ = false;
|
if (cmd[0] == 0x25)
|
||||||
// Drive next phase
|
{
|
||||||
MSG = false, C_D = false, I_O = false;
|
WriteLog("HD: Received command READ CAPACITY [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9]);
|
||||||
devMode = DVM_DATA_OUT;
|
SetNextState(DVM_DATA_IN);
|
||||||
bytesToSend = cmd[4];
|
bytesToSend = 8;//it's always 8...//cmd[4];
|
||||||
|
// N.B.: We need to hook this up to the actual emulated HD size...
|
||||||
|
buf = readCapacity;
|
||||||
|
bufPtr = 0;
|
||||||
|
}
|
||||||
|
// Handle "Read" (10) command
|
||||||
|
else if (cmd[0] == 0x28)
|
||||||
|
{
|
||||||
|
WriteLog("HD: Received command READ(10) [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9]);
|
||||||
|
// Drive next phase
|
||||||
|
SetNextState(DVM_DATA_IN);
|
||||||
|
bytesToSend = ((cmd[7] << 8) | cmd[8]) * 512; // amount is set in blocks
|
||||||
|
uint32_t lba = (cmd[2] << 24) | (cmd[3] << 16) | (cmd[4] << 8) | cmd[5];
|
||||||
|
buf = (hdData != NULL ? &hdData[(lba * 512) + 0x40] : NULL);
|
||||||
|
bufPtr = 0;
|
||||||
|
}
|
||||||
|
// Handle "Write" (10) command
|
||||||
|
else if (cmd[0] == 0x2A)
|
||||||
|
{
|
||||||
|
WriteLog("HD: Received command WRITE(10) [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9]);
|
||||||
|
// Drive next phase
|
||||||
|
SetNextState(DVM_DATA_OUT);
|
||||||
|
bytesToSend = ((cmd[7] << 8) | cmd[8]) * 512; // amount is set in blocks
|
||||||
|
uint32_t lba = (cmd[2] << 24) | (cmd[3] << 16) | (cmd[4] << 8) | cmd[5];
|
||||||
|
buf = (hdData != NULL ? &hdData[(lba * 512) + 0x40] : NULL);
|
||||||
|
bufPtr = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteLog("HD: Received unhandled 10 command [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9]);
|
||||||
|
// Return failure...
|
||||||
|
SetNextState(DVM_STATUS);
|
||||||
|
response = 0x02; // "Check Condition" code
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Handle "Mode Sense" command
|
else if ((cmdType == 5) && (cmdLength == 12))
|
||||||
else if ((cmd[0] == 0x1A) && (cmdLength == 6))
|
|
||||||
{
|
{
|
||||||
WriteLog("HD: Received command MODE SENSE [%02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
|
WriteLog("HD: Received unhandled 12 command [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9], cmd[10], cmd[11]);
|
||||||
REQ = false;
|
// Return failure...
|
||||||
// Drive next phase
|
SetNextState(DVM_STATUS);
|
||||||
MSG = false, C_D = false, I_O = true;
|
response = 0x02; // "Check Condition" code
|
||||||
devMode = DVM_DATA_IN;
|
|
||||||
bytesToSend = cmd[4];
|
|
||||||
}
|
|
||||||
// Handle "Read Capacity" command
|
|
||||||
else if ((cmd[0] == 0x25) && (cmdLength == 10))
|
|
||||||
{
|
|
||||||
WriteLog("HD: Received command READ CAPACITY [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9]);
|
|
||||||
REQ = false;
|
|
||||||
// Drive next phase
|
|
||||||
MSG = false, C_D = false, I_O = true;
|
|
||||||
devMode = DVM_DATA_IN;
|
|
||||||
bytesToSend = 8;//cmd[4];
|
|
||||||
buf = readCapacity;
|
|
||||||
bufPtr = 0;
|
|
||||||
}
|
|
||||||
// Handle "Read" (10) command
|
|
||||||
else if ((cmd[0] == 0x28) && (cmdLength == 10))
|
|
||||||
{
|
|
||||||
WriteLog("HD: Received command READ(10) [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9]);
|
|
||||||
REQ = false;
|
|
||||||
// Drive next phase
|
|
||||||
MSG = false, C_D = false, I_O = true;
|
|
||||||
devMode = DVM_DATA_IN;
|
|
||||||
bytesToSend = ((cmd[7] << 8) | cmd[8]) * 512; // amount is set in blocks
|
|
||||||
uint32_t lba = (cmd[2] << 24) | (cmd[3] << 16) | (cmd[4] << 8) | cmd[5];
|
|
||||||
buf = (hdData != NULL ? &hdData[(lba * 512) + 0x40] : NULL);
|
|
||||||
bufPtr = 0;
|
|
||||||
}
|
|
||||||
// Handle "Write" (10) command
|
|
||||||
else if ((cmd[0] == 0x2A) && (cmdLength == 10))
|
|
||||||
{
|
|
||||||
WriteLog("HD: Received command WRITE(10) [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9]);
|
|
||||||
REQ = false;
|
|
||||||
// Drive next phase
|
|
||||||
MSG = false, C_D = false, I_O = false;
|
|
||||||
devMode = DVM_DATA_OUT;
|
|
||||||
bytesToSend = ((cmd[7] << 8) | cmd[8]) * 512; // amount is set in blocks
|
|
||||||
uint32_t lba = (cmd[2] << 24) | (cmd[3] << 16) | (cmd[4] << 8) | cmd[5];
|
|
||||||
buf = (hdData != NULL ? &hdData[(lba * 512) + 0x40] : NULL);
|
|
||||||
bufPtr = 0;
|
|
||||||
}
|
|
||||||
else if ((cmdLength == 6) && ((cmd[0] & 0xE0) == 0))
|
|
||||||
{
|
|
||||||
WriteLog("HD: Received unhandled 6 command [%02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
|
|
||||||
}
|
|
||||||
else if ((cmdLength == 10) && (((cmd[0] & 0xE0) == 0x20) || ((cmd[0] & 0xE0) == 0x40)))
|
|
||||||
{
|
|
||||||
WriteLog("HD: Received unhandled 10 command [%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X]\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case DVM_STATUS:
|
case DVM_STATUS:
|
||||||
//WriteLog(" >>> STATUS PHASE\n");
|
|
||||||
if (!ACK)
|
if (!ACK)
|
||||||
{
|
{
|
||||||
// Return A-OK for everything for now...
|
// Return A-OK for everything for now...
|
||||||
reg[0] = 0;
|
reg[0] = 0; // N.B.: This is necessary for some reason...
|
||||||
REQ = true;
|
REQ = true;
|
||||||
}
|
}
|
||||||
else if (REQ && ACK)
|
else if (REQ && ACK)
|
||||||
{
|
{
|
||||||
REQ = false;
|
REQ = false;
|
||||||
// Drive next phase
|
SetNextState(DVM_MESSAGE_IN);
|
||||||
MSG = true, C_D = true, I_O = true;
|
|
||||||
devMode = DVM_MESSAGE_IN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DVM_MESSAGE_OUT:
|
case DVM_MESSAGE_OUT:
|
||||||
//WriteLog(" >>> MESSAGE OUT PHASE\n");
|
if (!ACK)
|
||||||
|
REQ = true;
|
||||||
if (REQ && ACK)
|
if (REQ && ACK)
|
||||||
{
|
{
|
||||||
uint8_t msg = reg[0];
|
// WriteLog("HD: Write to target value $%02X\n", reg[0]);
|
||||||
// WriteLog("HD: Write to target value $%02X\n", msg);
|
|
||||||
REQ = false;
|
REQ = false;
|
||||||
// Drive next phase
|
SetNextState(DVM_COMMAND);
|
||||||
MSG = false, C_D = true, I_O = false;
|
|
||||||
devMode = DVM_COMMAND;
|
|
||||||
cmdLength = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DVM_MESSAGE_IN:
|
case DVM_MESSAGE_IN:
|
||||||
//WriteLog(" >>> MESSAGE IN PHASE\n");
|
|
||||||
if (!ACK)
|
if (!ACK)
|
||||||
{
|
{
|
||||||
// Return A-OK for everything for now...
|
// Return appropriate response
|
||||||
reg[0] = response;
|
reg[0] = response;
|
||||||
REQ = true;
|
REQ = true;
|
||||||
}
|
}
|
||||||
else if (REQ && ACK)
|
else if (REQ && ACK)
|
||||||
{
|
{
|
||||||
REQ = false;
|
REQ = false;
|
||||||
// Drive next phase
|
|
||||||
MSG = false, C_D = false, I_O = false;
|
|
||||||
DEV_BSY = false;
|
DEV_BSY = false;
|
||||||
devMode = DVM_BUS_FREE;
|
SetNextState(DVM_BUS_FREE);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -664,25 +364,6 @@ static uint8_t SlotIOR(uint16_t address)
|
||||||
// This should prolly go somewhere else...
|
// This should prolly go somewhere else...
|
||||||
RunDevice();
|
RunDevice();
|
||||||
|
|
||||||
char SCSIName[16][256] = {
|
|
||||||
"(RO) Current SCSI Data",
|
|
||||||
"Initiator Command",
|
|
||||||
"Mode",
|
|
||||||
"Target Command",
|
|
||||||
"(RO) Current SCSI Bus Status",
|
|
||||||
"(RO) Bus and Status",
|
|
||||||
"(RO) Input Data",
|
|
||||||
"(RO) Reset Parity/Interrupt",
|
|
||||||
"DMA Address LO",
|
|
||||||
"DMA Address HI",
|
|
||||||
"DMA Count LO",
|
|
||||||
"DMA Count HI",
|
|
||||||
"$C",
|
|
||||||
"$D",
|
|
||||||
"Bank/SCSI ID",
|
|
||||||
"$F"
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t response = reg[address & 0x0F];
|
uint8_t response = reg[address & 0x0F];
|
||||||
|
|
||||||
switch (address & 0x0F)
|
switch (address & 0x0F)
|
||||||
|
@ -743,24 +424,16 @@ static uint8_t SlotIOR(uint16_t address)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if (((mainCPU.pc != 0xCD7C) && (mainCPU.pc != 0xCD5F)) || (romBank != 16))
|
#if 0
|
||||||
WriteLog("HD Slot I/O read %s ($%02X <- $%X, PC=%04X:%u)\n", SCSIName[address & 0x0F], response, address & 0x0F, mainCPU.pc, romBank);//*/
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void SlotIOW(uint16_t address, uint8_t byte)
|
|
||||||
{
|
|
||||||
char SCSIName[16][256] = {
|
char SCSIName[16][256] = {
|
||||||
"(WO) Output Data",
|
"(RO) Current SCSI Data",
|
||||||
"Initiator Command",
|
"Initiator Command",
|
||||||
"Mode",
|
"Mode",
|
||||||
"Target Command",
|
"Target Command",
|
||||||
"(WO) Select Enable",
|
"(RO) Current SCSI Bus Status",
|
||||||
"(WO) Start DMA Send",
|
"(RO) Bus and Status",
|
||||||
"(WO) Start DMA Target Receive",
|
"(RO) Input Data",
|
||||||
"(WO) Start DMA Initiator Receive",
|
"(RO) Reset Parity/Interrupt",
|
||||||
"DMA Address LO",
|
"DMA Address LO",
|
||||||
"DMA Address HI",
|
"DMA Address HI",
|
||||||
"DMA Count LO",
|
"DMA Count LO",
|
||||||
|
@ -771,6 +444,16 @@ static void SlotIOW(uint16_t address, uint8_t byte)
|
||||||
"$F"
|
"$F"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (((mainCPU.pc != 0xCD7C) && (mainCPU.pc != 0xCD5F)) || (romBank != 16))
|
||||||
|
WriteLog("HD Slot I/O read %s ($%02X <- $%X, PC=%04X:%u)\n", SCSIName[address & 0x0F], response, address & 0x0F, mainCPU.pc, romBank);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void SlotIOW(uint16_t address, uint8_t byte)
|
||||||
|
{
|
||||||
switch (address & 0x0F)
|
switch (address & 0x0F)
|
||||||
{
|
{
|
||||||
case 0x00:
|
case 0x00:
|
||||||
|
@ -788,9 +471,18 @@ static void SlotIOW(uint16_t address, uint8_t byte)
|
||||||
BSY = (byte & 0x08 ? true : false);
|
BSY = (byte & 0x08 ? true : false);
|
||||||
ACK = (byte & 0x10 ? true : false);
|
ACK = (byte & 0x10 ? true : false);
|
||||||
RST = (byte & 0x80 ? true : false);
|
RST = (byte & 0x80 ? true : false);
|
||||||
|
|
||||||
|
if (!(SEL || BSY || DEV_BSY))
|
||||||
|
devMode = DVM_BUS_FREE;
|
||||||
|
|
||||||
|
if (SEL && (devMode == DVM_ARBITRATE))
|
||||||
|
devMode = DVM_SELECT;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x02:
|
||||||
// Mode register (chip control)
|
// Mode register (chip control)
|
||||||
|
if ((byte & 0x01) && (devMode == DVM_BUS_FREE))
|
||||||
|
devMode = DVM_ARBITRATE;
|
||||||
|
|
||||||
// Dma ReQuest is reset here (as well as by hitting a pin)
|
// Dma ReQuest is reset here (as well as by hitting a pin)
|
||||||
DMA_MODE = (byte & 0x02 ? true : false);
|
DMA_MODE = (byte & 0x02 ? true : false);
|
||||||
|
@ -845,10 +537,33 @@ static void SlotIOW(uint16_t address, uint8_t byte)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* WriteLog("HD Slot I/O write %s ($%02X -> $%X, PC=%04X:%u)\n", SCSIName[address & 0x0F], byte, address & 0x0F, mainCPU.pc, romBank);//*/
|
|
||||||
reg[address & 0x0F] = byte;
|
reg[address & 0x0F] = byte;
|
||||||
|
|
||||||
/* if ((address & 0x0F) == 0x0E)
|
#if 0
|
||||||
|
char SCSIName[16][256] = {
|
||||||
|
"(WO) Output Data",
|
||||||
|
"Initiator Command",
|
||||||
|
"Mode",
|
||||||
|
"Target Command",
|
||||||
|
"(WO) Select Enable",
|
||||||
|
"(WO) Start DMA Send",
|
||||||
|
"(WO) Start DMA Target Receive",
|
||||||
|
"(WO) Start DMA Initiator Receive",
|
||||||
|
"DMA Address LO",
|
||||||
|
"DMA Address HI",
|
||||||
|
"DMA Count LO",
|
||||||
|
"DMA Count HI",
|
||||||
|
"$C",
|
||||||
|
"$D",
|
||||||
|
"Bank/SCSI ID",
|
||||||
|
"$F"
|
||||||
|
};
|
||||||
|
char SCSIPhase[11][256] = { "DATA OUT", "DATA IN", "COMMAND", "STATUS", "ERR4", "ERR5", "MESSAGE OUT", "MESSAGE IN", "BUS FREE", "ARBITRATE", "SELECT" };
|
||||||
|
|
||||||
|
|
||||||
|
WriteLog("HD Slot I/O write %s ($%02X -> $%X, PC=%04X:%u) [%s]\n", SCSIName[address & 0x0F], byte, address & 0x0F, mainCPU.pc, romBank, SCSIPhase[devMode]);
|
||||||
|
|
||||||
|
if ((address & 0x0F) == 0x0E)
|
||||||
{
|
{
|
||||||
if (mainCPU.pc == 0xC78B)
|
if (mainCPU.pc == 0xC78B)
|
||||||
{
|
{
|
||||||
|
@ -862,7 +577,8 @@ static void SlotIOW(uint16_t address, uint8_t byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteLog(" [%02X %02X %02X %02X %02X %02X %02X %02X] [$C81F=$%02X $C80D=$%02X $C80A=$%02X $C887=$%02X $C806=$%02X $C88F=$%02X $C8EC=$%02X $4F=$%02X]\n", reg[0], reg[1], reg[2], reg[3], reg[4], reg[5], reg[6], reg[7], staticRAM[0x1F], staticRAM[0x0D], staticRAM[0x0A], staticRAM[0x87], staticRAM[0x06], staticRAM[0x8F], staticRAM[0xEC], ram[0x4F]);
|
WriteLog(" [%02X %02X %02X %02X %02X %02X %02X %02X] [$C81F=$%02X $C80D=$%02X $C80A=$%02X $C887=$%02X $C806=$%02X $C88F=$%02X $C8EC=$%02X $4F=$%02X]\n", reg[0], reg[1], reg[2], reg[3], reg[4], reg[5], reg[6], reg[7], staticRAM[0x1F], staticRAM[0x0D], staticRAM[0x0A], staticRAM[0x87], staticRAM[0x06], staticRAM[0x8F], staticRAM[0xEC], ram[0x4F]);
|
||||||
}//*/
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// This should prolly go somewhere else...
|
// This should prolly go somewhere else...
|
||||||
RunDevice();
|
RunDevice();
|
||||||
|
|
Loading…
Reference in New Issue