// Read some bytes from the specified channel, synchronously.
// TODO: Deal with early-termination properly - it should not be treated like an error.
//       This will require changes in usbBulkRead(). Async API is already correct.
//
DLLEXPORT(FLStatus) flReadChannel(
	struct FLContext *handle, uint8 chan, size_t count, uint8 *buffer,
	const char **error)
{
	FLStatus retVal = FL_SUCCESS, fStatus;
	const uint8 *data;
	uint32 requestLength, actualLength;
	CHECK_STATUS(
		count == 0, FL_PROTOCOL_ERR, cleanup,
		"flReadChannel(): Zero-length reads are illegal!");
	CHECK_STATUS(
		!handle->isCommCapable, FL_PROTOCOL_ERR, cleanup,
		"flReadChannel(): This device does not support CommFPGA");
	if ( count >= 0x10000 ) {
		fStatus = flReadChannelAsyncSubmit(handle, chan, 0x10000, buffer, error);
		CHECK_STATUS(fStatus, fStatus, cleanup, "flReadChannel()");
		count -= 0x10000;
		buffer += 0x10000;
		while ( count >= 0x10000 ) {
			fStatus = flReadChannelAsyncSubmit(handle, chan, 0x10000, buffer, error);
			CHECK_STATUS(fStatus, fStatus, cleanup, "flReadChannel()");
			count -= 0x10000;
			buffer += 0x10000;
			fStatus = flReadChannelAsyncAwait(handle, &data, &requestLength, &actualLength, error);
			CHECK_STATUS(fStatus, fStatus, cleanup, "flReadChannel()");
			CHECK_STATUS(
				actualLength != requestLength,
				FL_EARLY_TERM, cleanup, "flReadChannel()");
		}
		if ( count ) {
			fStatus = flReadChannelAsyncSubmit(handle, chan, (uint32)count, buffer, error);
			CHECK_STATUS(fStatus, fStatus, cleanup, "flReadChannel()");
			fStatus = flReadChannelAsyncAwait(handle, &data, &requestLength, &actualLength, error);
			CHECK_STATUS(fStatus, fStatus, cleanup, "flReadChannel()");
			CHECK_STATUS(
				actualLength != requestLength,
				FL_EARLY_TERM, cleanup, "flReadChannel()");
		}
	} else {
		fStatus = flReadChannelAsyncSubmit(handle, chan, (uint32)count, buffer, error);
		CHECK_STATUS(fStatus, fStatus, cleanup, "flReadChannel()");
	}
	fStatus = flReadChannelAsyncAwait(handle, &data, &requestLength, &actualLength, error);
	CHECK_STATUS(fStatus, fStatus, cleanup, "flReadChannel()");
	CHECK_STATUS(
		actualLength != requestLength,
		FL_EARLY_TERM, cleanup, "flReadChannel()");
cleanup:
	return retVal;
}
Пример #2
0
// 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;
}
Пример #3
0
// 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;
}