aboutsummaryrefslogtreecommitdiff
path: root/SrcShared/Hardware/TRG/EmTRGATA.cpp
blob: fcff3e6c4d0e8ab4662758192168434cb2e1beb1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
/* -*- mode: C++; tab-width: 4 -*- */
/* ===================================================================== *\
	Copyright (c) 2000-2001 Palm, Inc. or its subsidiaries.
	All rights reserved.

	This file is part of the Palm OS Emulator.

	This program 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.
\* ===================================================================== */

#include "EmCommon.h"
#include "EmTRGATA.h"

// ------------------------------------------------------------------------
// This file emulates the ATA Registers on the CF Memory Card.
//
// Address                   Description         
// ---------------------     -------------------- 
// 0x18001000-0x1800100F     ATA Registers
// 0x18001010-0x180013FF     Mirror of the ATA Registers
// 0x18001400-0x18001FFF     Equivalent to the Data-Even/Data-Odd Registers
// ------------------------------------------------------------------------

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::EmRegsCFAta
// ---------------------------------------------------------------------------
EmRegsCFAta::EmRegsCFAta(void)
{
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::~EmRegsCFATA
// ---------------------------------------------------------------------------
EmRegsCFAta::~EmRegsCFAta(void)
{
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::Initialize
// ---------------------------------------------------------------------------
void EmRegsCFAta::Initialize(EmDiskTypeID DiskTypeID)
{
	int	i;

	AtaMode = MODE_DISK_IO;
	DiskIO.Initialize(DiskTypeID);
	for (i=0; i<NUM_IDE_REGS; i++)
		RegMem[i] = i;
	RegMem[6] = 0xA0;
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::Reset
// ---------------------------------------------------------------------------
void EmRegsCFAta::Reset(void)
{
	DiskIO.Reset();
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::Dispose
// ---------------------------------------------------------------------------
void EmRegsCFAta::Dispose(void)
{
    DiskIO.Dispose();
}

//----------------------------------------------------------------------------
// Status and Alternate Status Registers Offsets 7h and Eh
//
// These registers return the CompactFlash Storage Card status when read by
// the host. Reading the Status register does clear a pending interrupt while
// reading the Auxiliary Status register does not. The status bits are
// described as follows:
//
//   D7  D6  D5  D4  D3  D2  D1  D0
//  --- --- --- --- --- --- --- ---
//  BSY RDY DWF DSC DRQ CRR  0  ERR
//
// Bit 7 (BUSY): the busy bit is set when the CompactFlash Storage Card has
// access to the command buffer and registers and the host is locked out
// from accessing the command register and buffer. No other bits in this
// register are valid when this bit is set to a 1.
// Bit 6 (RDY): RDY indicates whether the device is capable of performing
// CompactFlash Storage Card operations. This bit is cleared at power up
// and remains cleared until the CompactFlash Storage Card is ready to
// accept a command.
// Bit 5 (DWF): This bit, if set, indicates a write fault has occurred.
// Bit 4 (DSC): This bit is set when the CompactFlash Storage Card is ready.
// Bit 3 (DRQ): The Data Request is set when the CompactFlash Storage Card
// requires that information be transferred either to or from the host
// through the Data register.
// Bit 2 (CORR): This bit is set when a Correctable data error has been
// encountered and the data has been corrected. This condition does not
// terminate a multi-sector read operation.
// Bit 1 (IDX): This bit is always set to 0.
// Bit 0 (ERR): This bit is set when the previous command has ended in
// some type of error. The bits in the Error register contain additional
// information describing the error. It is recommended that media access
// commands (such as Read Sectors and Write Sectors) that end with an
// error condition should have the address of the first sector in error
// in the command block registers.
//----------------------------------------------------------------------------
uint8 EmRegsCFAta::RegReadStatus(Boolean /*is_alt_reg*/)
{
	uint8 retVal;
	DiskIOStatus   status;
	DiskDataStatus dataStatus;

	DiskIO.GetStatus(&status, &dataStatus);
	if (status == DIO_SUCCESS)
	{
		retVal = (IDE_STS_RDY|IDE_STS_DSC);
		if (dataStatus == DIO_MORE_DATA)
        {
			retVal |= IDE_STS_DRQ;
        }
        else
        {
            DiskParams.Lba += DiskParams.SectorCnt;
            RegMem[IDE_REG_5_LBA_23_16] = (uint8)(DiskParams.Lba >> 16);
            RegMem[IDE_REG_4_LBA_15_8] = (uint8)(DiskParams.Lba >> 8);
            RegMem[IDE_REG_3_LBA_7_0] = (uint8)DiskParams.Lba;
        }
	}
	else
    {
        retVal = (IDE_STS_RDY|IDE_STS_DSC|IDE_STS_ERR);
    }
	return(retVal);
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::GetDiskIOParams
// ---------------------------------------------------------------------------
void EmRegsCFAta::GetDiskIOParams(DiskIOParams * Params)
{
	Params->DriveNum = 0;
	Params->Lba =
	       (((uint32)RegMem[IDE_REG_6_DRV_HEAD] & 0x0F) << 24) +
	        ((uint32)RegMem[IDE_REG_5_LBA_23_16] << 16) +
                ((uint32)RegMem[IDE_REG_4_LBA_15_8]  << 8) +
                 (uint32)RegMem[IDE_REG_3_LBA_7_0];
	Params->SectorCnt = (uint32)RegMem[IDE_REG_2_SECTOR_CNT];
	if (Params->SectorCnt == 0)
		Params->SectorCnt = 256;

    DiskParams = *Params;
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::CmdIdentifyDrive
// ---------------------------------------------------------------------------
void EmRegsCFAta::CmdIdentifyDrive(void)
{
	DiskIO.StartDriveID();
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::CmdReadSectors
// ---------------------------------------------------------------------------
void EmRegsCFAta::CmdReadSectors(void)
{
	DiskIOParams params;

	GetDiskIOParams(&params);
	DiskIO.StartRead(&params);
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::CmdWriteSectors
// ---------------------------------------------------------------------------
void EmRegsCFAta::CmdWriteSectors(void)
{
	DiskIOParams params;

	GetDiskIOParams(&params);
	DiskIO.StartWrite(&params);
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::CmdDriveDiagnostic
// ---------------------------------------------------------------------------
void EmRegsCFAta::CmdDriveDiagnostic(void)
{
	AtaMode = MODE_DRIVE_DIAGNOSTICS;
}

//----------------------------------------------------------------------------
// Data Register Offset 0 (8-bit) and 8-9 (16-bit)
// 
// The Data Register is a 16-bit register, and it is used to transfer data
// blocks between the CompactFlash Storage Card data buffer and the Host.
// This register overlaps the Error Register.  The table below describes the
// combinations of data register access and is provided to assist in
// understanding the overlapped Data Register and Error/Feature Register
// rather than to attempt to define general PCMCIA word and byte access
// modes and operations. See the PCMCIA PC Card Standard Release 2.0 for
// definitions of the Card Accessing Modes for I/O and Memory cycles.
// Note: Because of the overlapped registers, access to the 1F1h, 171h or
// offset 1 are not defined for word (-CE2 = 0 and -CE1 = 0) operations.
// These accesses are treated as accesses to the Word Data Register.
// The duplicated registers at offsets 8, 9 and Dh have no restrictions on
// the operations that can be performed by the socket.
//----------------------------------------------------------------------------
uint8 EmRegsCFAta::Reg0ReadData(void)
{
	DiskIO.ReadNextDataByte(&RegMem[IDE_REG_0_DATA]);
	return(RegMem[IDE_REG_0_DATA]);
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::Reg0WriteData
// ---------------------------------------------------------------------------
void EmRegsCFAta::Reg0WriteData(void)
{
	DiskIO.WriteNextDataByte(RegMem[IDE_REG_0_DATA]);
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::Reg8ReadDataEven
// ---------------------------------------------------------------------------
uint8 EmRegsCFAta::Reg8ReadDataEven(void)
{
	DiskIO.ReadNextDataByte(&RegMem[IDE_REG_8_DATA_EVEN]);
	return(RegMem[IDE_REG_8_DATA_EVEN]);
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::Reg8WriteDataEven
// ---------------------------------------------------------------------------
void EmRegsCFAta::Reg8WriteDataEven(void)
{
	DiskIO.WriteNextDataByte(RegMem[IDE_REG_8_DATA_EVEN]);
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::Reg9ReadDataOdd
// ---------------------------------------------------------------------------
uint8 EmRegsCFAta::Reg9ReadDataOdd(void)
{
	DiskIO.ReadNextDataByte(&RegMem[IDE_REG_9_DATA_ODD]);
	return(RegMem[IDE_REG_9_DATA_ODD]);
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::Reg9WriteDataOdd
// ---------------------------------------------------------------------------
void EmRegsCFAta::Reg9WriteDataOdd(void)
{
	DiskIO.WriteNextDataByte(RegMem[IDE_REG_9_DATA_ODD]);
}

//----------------------------------------------------------------------------
// Error Register -- Offset 1h and Dh (read-only) 
//
// This register contains additional information about the source of
// an error when an error is indicated in bit 0 of the Status register.
// The bits are defined as follows:
//
// Error Register
// This register is also accessed on data bits D15-D8 during a write
// operation to offset 0 with -CE2 low and -CE1 high.
//
// Bit 7 (BBK): this bit is set when a Bad Block is detected.
// Bit 6 (UNC): this bit is set when an Uncorrectable Error is encountered.
// Bit 5: this bit is 0.
// Bit 4 (IDNF): the requested sector ID is in error or cannot be found.
// Bit 3: this bit is 0.
// Bit 2 (Abort) This bit is set if the command has been aborted because of
//    a CompactFlash Storage Card status condition: (Not Ready, Write Fault,
//    etc.) or when an invalid command has been issued.
// Bit 1 This bit is 0.
// Bit 0 (AMNF) This bit is set in case of a general error.
//----------------------------------------------------------------------------
uint8 EmRegsCFAta::RegReadError(Boolean /*is_alt_reg*/)
{
	if (AtaMode == MODE_DRIVE_DIAGNOSTICS)
		return(IDE_DIA_01_NO_ERROR); 
	else
		return DiskIO.GetError();
}


//----------------------------------------------------------------------------
// Sector Count Register (Offset 2h)
//
// This register contains the numbers of sectors of data requested to be
// transferred on a read or write operation between the host and the
// CompactFlash Storage Card. If the value in this register is zero,
// a count of 256 sectors is specified. If the command was successful,
// this register is zero at command completion. If not successfully completed,
// the register contains the number of sectors that need to be transferred
// in order to complete the request.
//----------------------------------------------------------------------------
uint8 EmRegsCFAta::Reg2ReadSectorCount(void)
{
	uint32	cnt;

	cnt = DiskIO.GetSectorCount();
	if (cnt > 0xFF)
		cnt = 0x0;
	return(cnt);
}

//----------------------------------------------------------------------------
// Device Control Register -- Offset Eh
// This register is used to control the CompactFlash Storage Card interrupt
// request and to issue an ATA soft reset to the card. This register can
// be written even if the device is BUSY. The bits are defined as follows:
//
//  D7  D6  D5  D4  D3   D2    D1  D0
// --- --- --- --- --- ------ ---- ---
//  X   X   X   X   1  SW Rst -IEn  0
//
// Bit 7: this bit is an X (don't care).
// Bit 6: this bit is an X (don't care).
// Bit 5: this bit is an X (don't care).
// Bit 4: this bit is an X (don't care).
// Bit 3: this bit is ignored by the CompactFlash Storage Card.
// Bit 2 (SW Rst): this bit is set to 1 in order to force the CompactFlash
// Storage Card to perform an AT Disk controller Soft Reset operation.
// This does not change the PCMCIA Card Configuration Registers (4.3.2
// to 4.3.5) as a hardware Reset does. The Card remains in Reset until this
// bit is reset to 0.
// Bit 1 (-IEn): the Interrupt Enable bit enables interrupts when the bit is
// 0. When the bit is 1, interrupts from the CompactFlash Storage Card are
// disabled. This bit also controls the Int bit in the Configuration and
// Status Register. This bit is set to 0 at power on and Reset.
// Bit 0: this bit is ignored by the CompactFlash Storage Card.
//----------------------------------------------------------------------------
void EmRegsCFAta::RegEWriteDeviceControl(void)
{
	DiskIO.Reset();
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::Reg7WriteCmd
// ---------------------------------------------------------------------------
void EmRegsCFAta::Reg7WriteCmd(void)
{
	AtaMode = MODE_DISK_IO;
    DiskIO.ClearError();
	switch(RegMem[IDE_REG_7_COMMAND])
	{
		case IDE_CMD_EC_IDENTIFY_DRIVE :
        		CmdIdentifyDrive();
        		break;

		case IDE_CMD_20_READ_SECTORS :
		case IDE_CMD_21_READ_SECTORS :
			CmdReadSectors();
			break;

		case IDE_CMD_30_WRITE_SECTORS :
		case IDE_CMD_31_WRITE_SECTORS :
			CmdWriteSectors();
			break;

		case IDE_CMD_90_EXEC_DRIVE_DIAGNOSTIC :
			CmdDriveDiagnostic();
			break;

        case IDE_CMD_C6_SET_MULTIPLE_MODE :
            DiskIO.SetError(IDE_ERR_04_ABORT);
            break;

        default :
            break;
	}
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::ReadByte
// ---------------------------------------------------------------------------
void EmRegsCFAta::ReadByte(uint32 offset,
                           uint8 * val)
{
	*val = 0;
	switch(offset)
	{
		case IDE_REG_0_DATA :
			*val = Reg0ReadData();
			break;
		case IDE_REG_1_ERROR :
			*val = RegReadError(IS_BASE_REG);
			break;
		case IDE_REG_D_ERROR :
			*val = RegReadError(IS_ALT_REG);
			break;
		case IDE_REG_2_SECTOR_CNT :
			*val = Reg2ReadSectorCount();
			break;
		case IDE_REG_7_STATUS :
			*val = RegReadStatus(IS_BASE_REG);
			break;
		case IDE_REG_E_ALT_STATUS :
			*val = RegReadStatus(IS_ALT_REG);
			break;
		case IDE_REG_8_DATA_EVEN :
			*val = Reg8ReadDataEven();
			break;
		case IDE_REG_9_DATA_ODD :
			*val = Reg9ReadDataOdd();
			break;
		default :
			if (offset < NUM_IDE_REGS)
				*val = RegMem[offset];
			else
				*val = 0;
			break;
	}
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::WriteByte
// ---------------------------------------------------------------------------
void EmRegsCFAta::WriteByte(uint32 offset, uint8 val)
{
	RegMem[offset] = val;
	switch(offset)
	{
		case IDE_REG_0_DATA :
			Reg0WriteData();
			break;
		case IDE_REG_7_COMMAND :
			Reg7WriteCmd();
			break;
		case IDE_REG_8_DATA_EVEN :
			Reg8WriteDataEven();
			break;
		case IDE_REG_9_DATA_ODD :
			Reg9WriteDataOdd();
			break;
		case IDE_REG_E_DEVICE_CONTROL :
			RegEWriteDeviceControl();
			break;
	}
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::ReadWord
// ---------------------------------------------------------------------------
void EmRegsCFAta::ReadWord(uint32  offset,
                           _Word * val)
{
	// 16-bit reads of Register 0 are NOT equivalent to 2 8-bit reads
	// of Register 0 and 1 ... instead it reads the Even & Odd Data
	// bytes, so we change the register to be 8
	if (offset == IDE_REG_0_DATA)
		offset = IDE_REG_8_DATA_EVEN;
	ReadByte(offset,   &val->Bytes[0]);
	ReadByte(offset+1, &val->Bytes[1]);
}

// ---------------------------------------------------------------------------
//		¥ EmRegsCFAta::WriteWord
// ---------------------------------------------------------------------------
void EmRegsCFAta::WriteWord(uint32 offset, _Word val)
{
	// 16-bit writes of Register 0 are NOT equivalent to 2 8-bit writes
	// of Register 0 and 1 ... instead it writes the Even & Odd Data
	// bytes, so we change the register to be 8
	if (offset == IDE_REG_0_DATA)
		offset = IDE_REG_8_DATA_EVEN;
	WriteByte(offset,   val.Bytes[0]);
	WriteByte(offset+1, val.Bytes[1]);
}