Page 1 of 1

[solved] FDC FIFO error

Posted: Tue Aug 09, 2016 6:12 am
by onlyonemac
Hi,

I'm trying to read form a floppy disk. The code works on QEMU but fails with st1 = 0x10, which is apparently a FIFO error.

Code: Select all

static void floppy_read_sectors(uint8_t track, uint8_t head, uint8_t start_sector, uint8_t sector_count, uint32_t buffer)
{
	fdc_motor_on();
	fdc_do_command(FDC_CMD_SEEK, (uint8_t[]){ 0, track }, NULL);
	fdc_do_command(FDC_CMD_SENSE, NULL, fdc_results);
	dma_setup(buffer, ((uint16_t) sector_count) * 512, FALSE);
	fdc_do_command(FDC_CMD_READ, (uint8_t[]){ head << 2, track, head, start_sector + 1, 2, sector_count, 0x1B, 0xFF }, fdc_results);
	fdc_motor_off();
}
(Yes I know I'm not waiting for the motor to spin up but for now the seek gives an adequate delay.)

Code: Select all

static void fdc_motor_on()
{
	outb(FDC_REGISTER_DOR, 0x1C);
}

static void fdc_motor_off()
{
	outb(FDC_REGISTER_DOR, 0x0C);
}

Code: Select all

static void fdc_do_command(fdc_command command, uint8_t* parameters, uint8_t* results)
{
	uint32_t	current_parameter;
	uint32_t	parameter_count;
	uint32_t	current_result;
	uint32_t	result_count;
	uint32_t	irq_expected;

	while ((inb(FDC_REGISTER_MSR) & 0xC0) != 0x80)
	{
		// wait
	}

	switch (command)
	{
		case FDC_CMD_READ:
		case FDC_CMD_WRITE:
			parameter_count = 8;
			result_count = 7;
			irq_expected = TRUE;
			break;
		case FDC_CMD_SEEK:
			parameter_count = 2;
			result_count = 0;
			irq_expected = TRUE;
			break;
		case FDC_CMD_RECALIBRATE:
			parameter_count = 1;
			result_count = 0;
			irq_expected = TRUE;
			break;
		case FDC_CMD_SENSE:
			parameter_count = 0;
			result_count = 2;
			irq_expected = FALSE;
			break;
		case FDC_CMD_CONFIGURE:
			parameter_count = 3;
			result_count = 0;
			irq_expected = FALSE;
			break;
		case FDC_CMD_SPECIFY:
			parameter_count = 2;
			result_count = 0;
			irq_expected = FALSE;
			break;
		case FDC_CMD_LOCK:
		case FDC_CMD_UNLOCK:
			parameter_count = 0;
			result_count = 1;
			irq_expected = FALSE;
			break;
		case FDC_CMD_VERSION:
			parameter_count = 0;
			result_count = 1;
			irq_expected = FALSE;
			break;
	}

	if (irq_expected == TRUE)
	{
		instance->irq = FALSE;
	}
	outb(FDC_REGISTER_FIFO, command);
	current_parameter = 0;
	while (current_parameter < parameter_count)
	{
		while ((inb(FDC_REGISTER_MSR) & 0xC0) != 0x80)
		{
			// wait
		}
		outb(FDC_REGISTER_FIFO, parameters[current_parameter]);
		current_parameter++;
	}
	if (irq_expected == TRUE)
	{
		fdc_wait_for_irq();
	}
	current_result = 0;
	while (current_result < result_count)
	{
		while ((inb(FDC_REGISTER_MSR) & 0xC0) != 0xC0)
		{
			// wait
		}
		results[current_result] = inb(FDC_REGISTER_FIFO);
		current_result++;
	}
}

Code: Select all

static void dma_setup(uint32_t address, uint16_t length, uint8_t direction)	// direction = FALSE to read from disk; direction = TRUE to write to disk
{
	outb(0x0B, direction == FALSE ? 0x06 : 0x0A);
	outb(0x0C, 0x00);
	outb(0x04, address & 0x000000FF);
	outb(0x04, (address & 0x0000FF00) >> 8);
	outb(0x0C, 0x00);
	outb(0x05, (length - 1) & 0x00FF);
	outb(0x05, ((length - 1) & 0xFF00) >> 8);
	outb(0x81, (address & 0x00FF0000) >> 16);
}
Here's the code that I'm using to initialise the FDC - I'm guessing that the FIFO is not configured correctly?

Code: Select all

fdc_motor_off();
fdc_do_command(FDC_CMD_CONFIGURE, (uint8_t[]){ 0, 0x17, 0 }, NULL);
fdc_do_command(FDC_CMD_LOCK, NULL, fdc_results);
fdc_reset();
fdc_motor_on();
fdc_do_command(FDC_CMD_RECALIBRATE, (uint8_t[]){ 0 }, NULL);
fdc_do_command(FDC_CMD_SENSE, NULL, fdc_results);
fdc_motor_off();

Code: Select all

static void fdc_reset()
{
	instance->irq = FALSE;
	outb(FDC_REGISTER_DSR, 0x80);
	fdc_wait_for_irq();
	fdc_do_command(FDC_CMD_SPECIFY, (uint8_t[]){ (8 << 4) | 5, 15 << 1 }, NULL);
}
Thanks,

onlyonemac

Re: FDC FIFO error

Posted: Tue Aug 09, 2016 6:27 am
by sleephacker
st1 = 0x10 could also be a DMA error, to quote the datasheet on bit 4 in st1:
Becomes set if the 82077AA does not receive CPU or DMA
service within the required time interval, resulting in data
overrun or underrun
I also noticed that you didn't mask DMA channel 2 while setting up the transfer, which I believe is required before doing anything, so that might be the problem.

Re: FDC FIFO error

Posted: Tue Aug 09, 2016 7:50 am
by onlyonemac
sleephacker wrote:I also noticed that you didn't mask DMA channel 2 while setting up the transfer, which I believe is required before doing anything, so that might be the problem.
I thought that was only necessary if you were setting up the FDC first, and you didn't want the DMA trying to do the transfer before you'd finished setting it up, but I will try that anyway.

Re: FDC FIFO error

Posted: Tue Aug 09, 2016 7:55 am
by onlyonemac
Yes, it's working now. :-)