Esempio n. 1
0
File: mem.c Progetto: Frankz/umdkv2
// Direct-write a sequence of bytes to the specified PHYSICAL address. Bear in mind that the
// mapping from logical to physical addresses are done via the SSF2 registers; the mapping is
// 1:1 only for the lowest 512KiB, and is fixed for only the lowest 512KiB and the top 512KiB.
// The area to be written must have an even start address and length. The MegaDrive need not
// be suspended at the monitor, but overwriting the code that the MD is executing is obviously
// a recipe for disaster.
//
int umdkPhysicalWriteBytes(
	struct FLContext *handle, uint32 address, const uint32 count, const uint8 *const data,
	const char **error)
{
	int retVal = 0;
	FLStatus status;
	uint8 command[8];
	uint32 wordAddr;
	uint32 wordCount;

	// Next verify that the write is to an even address, and has even length
	CHECK_STATUS(address&1, 2, cleanup, "umdkPhysicalWriteBytes(): Address must be even!");
	CHECK_STATUS(count&1, 3, cleanup, "umdkPhysicalWriteBytes(): Count must be even!");

	// Get word-count and word-addres
	wordAddr = address / 2;
	wordCount = count / 2;

	// Prepare the write command
	prepMemCtrlCmd(0x00, wordAddr, command);
	prepMemCtrlCmd(0x80, wordCount, command+4);

	// Do the write
	status = flWriteChannelAsync(handle, 0x00, 8, command, error);
	CHECK_STATUS(status, 4, cleanup);
	status = flWriteChannelAsync(handle, 0x00, count, data, error);
	CHECK_STATUS(status, 5, cleanup);
cleanup:
	return retVal;
}
Esempio n. 2
0
File: mem.c Progetto: Frankz/umdkv2
// Direct-write a binary file to the specified address. The area of memory to be written must reside
// entirely within one of the two direct-writable memory areas (0x000000-0x07FFFF and
// 0x400000-0x47FFFF, mapped to SDRAM pages 0 and 31 respectively) and must have an even start
// address and length. The MegaDrive need not be suspended at the monitor.
//
int umdkDirectWriteFile(
	struct FLContext *handle, uint32 address, const char *fileName,
	const char **error)
{
	int retVal = 0;
	FLStatus status;
	uint8 command[8];
	uint32 wordAddr;
	size_t byteCount;
	size_t wordCount;
	uint8 *const fileData = flLoadFile(fileName, &byteCount);
	CHECK_STATUS(!fileData, 1, cleanup, "umdkDirectWriteFile(): Cannot read from %s!", fileName);

	// Verify the write is in a legal range
	if ( isInside(MONITOR, 0x80000, address, byteCount) ) {
		// Write is to the UMDKv2-reserved 512KiB of address-space at 0x400000. The mapping for this
		// is fixed to the top 512KiB of SDRAM, so we need to transpose the MD virtual address to
		// get the correct SDRAM physical address.
		address += 0xb80000;
	} else if ( !isInside(0, 0x80000, address, byteCount) ) {
		// The only other region of the address-space which is directly host-addressable is the
		// bottom 512KiB of address-space, which has a logical-physical mapping that is guaranteed
		// by SEGA to be 1:1 (i.e no transpose necessary). So any attempt to directly access memory
		// anywhere else is an error.
		CHECK_STATUS(
			true, 1, cleanup,
			"umdkDirectWriteFile(): Illegal direct-write to 0x%06X-0x%06X range!",
			address, address+byteCount-1
		);
	}

	// Next verify that the write is to an even address, and has even length
	CHECK_STATUS(address&1, 2, cleanup, "umdkDirectWriteFile(): Address must be even!");
	CHECK_STATUS(byteCount&1, 3, cleanup, "umdkDirectWriteFile(): File must have even length!");

	// Get word-count and word-address
	wordAddr = address / 2;
	wordCount = byteCount / 2;

	// Prepare the write command
	prepMemCtrlCmd(0x00, wordAddr, command);
	prepMemCtrlCmd(0x80, wordCount, command+4);

	// Do the write
	status = flWriteChannelAsync(handle, 0x00, 8, command, error);
	CHECK_STATUS(status, 4, cleanup);
	status = flWriteChannelAsync(handle, 0x00, byteCount, fileData, error);
	CHECK_STATUS(status, 5, cleanup);
cleanup:
	flFreeFile(fileData);
	return retVal;
}
// Write some bytes to the specified channel, synchronously.
//
DLLEXPORT(FLStatus) flWriteChannel(
	struct FLContext *handle, uint8 chan, size_t count, const uint8 *data, const char **error)
{
	FLStatus retVal = FL_SUCCESS, fStatus;
	fStatus = flWriteChannelAsync(handle, chan, count, data, error);
	CHECK_STATUS(fStatus, fStatus, cleanup, "flWriteChannel()");
	fStatus = flAwaitAsyncWrites(handle, error);
	CHECK_STATUS(fStatus, fStatus, cleanup, "flWriteChannel()");
cleanup:
	return retVal;
}
Esempio n. 4
0
File: mem.c Progetto: Frankz/umdkv2
// Asynchronously direct-read a sequence of bytes from the specified address. The area of memory to
// be read must reside entirely within one of the two direct-readable memory areas
// (0x000000-0x07FFFF and 0x400000-0x47FFFF, mapped to SDRAM pages 0 and 31 respectively). Unlike
// umdkDirectReadBytes(), this function must be given an even start address and count. The
// MegaDrive need not be suspended at the monitor. This does an asynchronous read, so each call to
// this function must match a later call to FPGALink's flReadChannelAsyncAwait(), to retrieve the
// actual data.
//
int umdkDirectReadBytesAsync(
	struct FLContext *handle, uint32 address, const uint32 count, const char **error)
{
	int retVal = 0;
	FLStatus status;
	uint8 command[8];

	// First verify the read is in a legal range
	if ( isInside(MONITOR, 0x80000, address, count) ) {
		// Read is from the UMDKv2-reserved 512KiB of address-space at 0x400000. The mapping for this
		// is fixed to the top 512KiB of SDRAM, so we need to transpose the MD virtual address to
		// get the correct SDRAM physical address.
		address += 0xb80000;
	} else if ( !isInside(0, 0x80000, address, count) ) {
		// The only other region of the address-space which is directly host-addressable is the
		// bottom 512KiB of address-space, which has a logical-physical mapping that is guaranteed
		// by SEGA to be 1:1 (i.e no transpose necessary). So any attempt to directly access memory
		// anywhere else is an error.
		CHECK_STATUS(
			true, 1, cleanup,
			"umdkDirectReadBytesAsync(): Illegal direct-read from 0x%06X-0x%06X range!",
			address, address+count-1
		);
	}

	// Next verify that the read is to an even address, and has even length
	CHECK_STATUS(address&1, 2, cleanup, "umdkDirectReadBytesAsync(): Address must be even!");
	CHECK_STATUS(count&1, 3, cleanup, "umdkDirectReadBytesAsync(): Count must be even!");

	// Prepare the read command
	prepMemCtrlCmd(0x00, address/2, command);
	prepMemCtrlCmd(0x40, count/2, command+4);
	
	// Send the read request
	status = flWriteChannelAsync(handle, 0x00, 8, command, error);
	CHECK_STATUS(status, 8, cleanup);
	
	// Submit the read
	status = flReadChannelAsyncSubmit(handle, 0x00, count, NULL, error);
	CHECK_STATUS(status, 9, cleanup);
cleanup:
	return retVal;
}
Esempio n. 5
0
File: mem.c Progetto: Frankz/umdkv2
// Tell the monitor to continue execution with the (possibly new) register/memory context, until
// a breakpoint is hit. If there is no breakpoint in the execution-path, this function will wait
// forever.
//
int umdkContWait(
	struct FLContext *handle, bool debug, struct Registers *regs, const char **error)
{
	int retVal = 0, status, i;
	uint8 tmpData[65536];
	size_t scrapSize;
	uint32 vbAddr, actualLength;
	uint16 oldOp;
	union RegUnion {
		struct Registers reg;
		uint32 longs[18];
		uint8 bytes[18*4];
	} *const u = (union RegUnion *)regs;
	const uint8 *recvData;
	FILE *file = NULL;

	if ( debug ) {
		// Read RAM
		status = umdkReadBytes(handle, 0xFF0000, 65536, tmpData, error);
		CHECK_STATUS(status, status, cleanup);
		
		// Save it
		file = fopen("ramBefore.bin", "wb");
		CHECK_STATUS(!file, 13, cleanup, "umdkContWait(): Unable to open ramBefore.bin for writing!");
		fwrite(tmpData, 1, 65536, file);
		fclose(file);
		file = NULL;
		
		// Open trace log
		file = fopen("trace.log", "wb");
		CHECK_STATUS(!file, 13, cleanup, "umdkContWait(): Unable to open trace.log for writing!");
	}

	// Get address of VDP vertical interrupt routine and its first opcode
	status = umdkDirectReadLong(handle, VB_VEC, &vbAddr, error);
	CHECK_STATUS(status, status, cleanup);
	status = umdkDirectReadWord(handle, vbAddr, &oldOp, error);
	CHECK_STATUS(status, status, cleanup);

	// Write monitor address to illegal instruction vector
	status = umdkDirectWriteLong(handle, IL_VEC, MONITOR, error);
	CHECK_STATUS(status, status, cleanup);

	if ( debug ) {
		// Disable tracing (if any) & clear junk from trace FIFO
		tmpData[0] = 0x00;
		status = flWriteChannel(handle, 0x01, 1, tmpData, error);
		CHECK_STATUS(status, 25, cleanup);
		status = flReadChannel(handle, 0x03, 1, tmpData, error);
		CHECK_STATUS(status, 20, cleanup);
		scrapSize = tmpData[0] << 8;
		status = flReadChannel(handle, 0x04, 1, tmpData, error);
		CHECK_STATUS(status, 20, cleanup);
		scrapSize |= tmpData[0];
		while ( scrapSize ) {
			// Clear junk from FIFO
			status = flReadChannel(handle, 0x02, scrapSize, tmpData, error);
			CHECK_STATUS(status, 20, cleanup);
			
			// Verify no junk remaining
			status = flReadChannel(handle, 0x03, 1, tmpData, error);
			CHECK_STATUS(status, 20, cleanup);
			scrapSize = tmpData[0] << 8;
			status = flReadChannel(handle, 0x04, 1, tmpData, error);
			CHECK_STATUS(status, 20, cleanup);
			scrapSize |= tmpData[0];
		}
		
		// Enable tracing
		tmpData[0] = 0x02;
		status = flWriteChannelAsync(handle, 0x01, 1, tmpData, error);
		CHECK_STATUS(status, 25, cleanup);
	}

	// Set up the continue command and execute it
	status = umdkDirectWriteWord(handle, CB_INDEX, CMD_CONT, error);
	CHECK_STATUS(status, status, cleanup);
	status = umdkDirectWriteWord(handle, CB_FLAG, CF_CMD, error);
	CHECK_STATUS(status, status, cleanup);

	if ( debug ) {
		// Submit 1st read for some trace data
		status = flReadChannelAsyncSubmit(handle, 2, 22528, NULL, error);
		CHECK_STATUS(status, 28, cleanup);
	}

	// Submit 1st read for the command status flag
	status = umdkDirectReadBytesAsync(handle, CB_FLAG, 2, error);
	CHECK_STATUS(status, status, cleanup);
	do {
		// If interrupted (escape or ctrl-c in gdb), induce a suspend at the next vblank
		if ( isInterrupted() ) {
			status = umdkDirectWriteWord(handle, vbAddr, ILLEGAL, error);
			CHECK_STATUS(status, status, cleanup);
		}

		if ( debug ) {
			// Submit a read for some trace data
			status = flReadChannelAsyncSubmit(handle, 2, 22528, NULL, error);
			CHECK_STATUS(status, 28, cleanup);
		}

		// Submit a read for the command status flag
		status = umdkDirectReadBytesAsync(handle, CB_FLAG, 2, error);
		CHECK_STATUS(status, status, cleanup);

		if ( debug ) {
			// Await the requested trace data
			status = flReadChannelAsyncAwait(handle, &recvData, &actualLength, &actualLength, error);
			CHECK_STATUS(status, status, cleanup);

			// Write it to the trace-log
			fwrite(recvData, 1, actualLength, file);
		}

		// Await the requested command status flag
		status = flReadChannelAsyncAwait(handle, &recvData, &actualLength, &actualLength, error);
		CHECK_STATUS(status, status, cleanup);
	} while ( recvData[0] != 0x00 || recvData[1] != CF_READY );

	if ( debug ) {
		// Await the final block of trace-data
		status = flReadChannelAsyncAwait(handle, &recvData, &actualLength, &actualLength, error);
		CHECK_STATUS(status, status, cleanup);
		
		// Write it to the trace-log
		fwrite(recvData, 1, actualLength, file);
		fclose(file);
		file = NULL;
	}
	
	// Await the final command-flag
	status = flReadChannelAsyncAwait(handle, &recvData, &actualLength, &actualLength, error);
	CHECK_STATUS(status, status, cleanup);

	// Restore old opcode to vbAddr
	status = umdkDirectWriteWord(handle, vbAddr, oldOp, error);
	CHECK_STATUS(status, status, cleanup);

	// Read saved registers, if necessary
	if ( regs ) {
		status = umdkDirectReadBytes(handle, CB_REGS, 18*4, u->bytes, error);
		CHECK_STATUS(status, status, cleanup);
		for ( i = 0; i < 18; i++ ) {
			u->longs[i] = bigEndian32(u->longs[i]);
		}
	}

	if ( debug ) {
		// Read RAM
		status = umdkReadBytes(handle, 0xFF0000, 65536, tmpData, error);
		CHECK_STATUS(status, status, cleanup);
		
		// Save it
		file = fopen("ramAfter.bin", "wb");
		CHECK_STATUS(!file, 13, cleanup, "umdkContWait(): Unable to open ramAfter.bin for writing!");
		fwrite(tmpData, 1, 65536, file);
		fclose(file);
		file = NULL;
	}
cleanup:
	if ( file ) {
		fclose(file);
	}
	return retVal;
}
Esempio n. 6
0
File: mem.c Progetto: Frankz/umdkv2
// Synchronously direct-read a sequence of bytes from the specified address. The area of memory to
// be read must reside entirely within one of the two direct-readable memory areas
// (0x000000-0x07FFFF and 0x400000-0x47FFFF, mapped to SDRAM pages 0 and 31 respectively). It need
// not have an even start address or length. The MegaDrive need not be suspended at the monitor.
//
int umdkDirectReadBytes(
	struct FLContext *handle, uint32 address, const uint32 count, uint8 *const data,
	const char **error)
{
	int retVal = 0;
	FLStatus status;
	uint8 command[8];
	uint32 wordAddr;
	uint32 wordCount;
	uint8 *tmpBuf = NULL;

	// First verify the read is in a legal range
	if ( isInside(MONITOR, 0x80000, address, count) ) {
		// Read is from the UMDKv2-reserved 512KiB of address-space at 0x400000. The mapping for this
		// is fixed to the top 512KiB of SDRAM, so we need to transpose the MD virtual address to
		// get the correct SDRAM physical address.
		address += 0xb80000;
	} else if ( !isInside(0, 0x80000, address, count) ) {
		// The only other region of the address-space which is directly host-addressable is the
		// bottom 512KiB of address-space, which has a logical-physical mapping that is guaranteed
		// by SEGA to be 1:1 (i.e no transpose necessary). So any attempt to directly access memory
		// anywhere else is an error.
		CHECK_STATUS(
			true, 1, cleanup,
			"umdkDirectReadBytes(): Illegal direct-read from 0x%06X-0x%06X range!",
			address, address+count-1
		);
	}

	// Reads from odd addresses or for odd lengths need to be done via a temporary buffer
	if ( address & 1 ) {
		// Odd address
		tmpBuf = (uint8*)malloc(count);
		CHECK_STATUS(!tmpBuf, 2, cleanup, "umdkDirectReadBytes(): Allocation error!");
		wordAddr = address / 2;
		wordCount = 1 + count / 2;
		
		// Prepare the read command
		prepMemCtrlCmd(0x00, wordAddr, command);
		prepMemCtrlCmd(0x40, wordCount, command+4);
		
		// Send the read request
		status = flWriteChannelAsync(handle, 0x00, 8, command, error);
		CHECK_STATUS(status, 3, cleanup);
		
		// Receive the data
		status = flReadChannel(handle, 0x00, 2*wordCount, tmpBuf, error);
		CHECK_STATUS(status, 4, cleanup);
		memcpy(data, tmpBuf+1, count);
	} else {
		// Even address
		if ( count & 1 ) {
			// Even address, odd count
			tmpBuf = (uint8*)malloc(count);
			CHECK_STATUS(!tmpBuf, 5, cleanup, "umdkDirectReadBytes(): Allocation error!");
			wordAddr = address / 2;
			wordCount = 1 + count / 2;
			
			// Prepare the read command
			prepMemCtrlCmd(0x00, wordAddr, command);
			prepMemCtrlCmd(0x40, wordCount, command+4);
			
			// Send the read request
			status = flWriteChannelAsync(handle, 0x00, 8, command, error);
			CHECK_STATUS(status, 6, cleanup);
			
			// Receive the data
			status = flReadChannel(handle, 0x00, 2*wordCount, tmpBuf, error);
			CHECK_STATUS(status, 7, cleanup);
			memcpy(data, tmpBuf, count);
		} else {
			// Even address, even count
			wordAddr = address / 2;
			wordCount = count / 2;
			
			// Prepare the read command
			prepMemCtrlCmd(0x00, wordAddr, command);
			prepMemCtrlCmd(0x40, wordCount, command+4);
			
			// Send the read request
			status = flWriteChannelAsync(handle, 0x00, 8, command, error);
			CHECK_STATUS(status, 8, cleanup);
			
			// Receive the data
			status = flReadChannel(handle, 0x00, count, data, error);
			CHECK_STATUS(status, 9, cleanup);
		}
	}
cleanup:
	free(tmpBuf);
	return retVal;
}