[SOLVED] FDC / DMA issue

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
BASICFreak
Member
Member
Posts: 284
Joined: Fri Jan 16, 2009 8:34 pm
Location: Louisiana, USA

[SOLVED] FDC / DMA issue

Post by BASICFreak »

Well, I gave it 3 days of me trying to figure this out (even completely scrapping my FDC and DMA driver)

So, now I have new drivers that still do not work...

I initialize the FDC (as far as I can tell) with no issue.
I can seek to any cylinder I choose with no issue.

When I read a sector on bochs I timeout because of no IRQ, and real hardware ST0 tells me "abnormal termination"

Also I don't know if this is right or not but is the FDC's ReadSector command supposed to fire IRQ twice, (it does on my H/W).

Because my code would be more or less difficult to shift through I will upload my functions as my modified DEBUG output.

NOTE: DATA READY is called before _FDC_Read and after _FDC_write in my DEBUG (not in the actual running code both are before)

DMA init:

Code: Select all

_DMA_outb(0xA, 0x6)					MASK DMA CHANNEL 2
_DMA_outb(0xC, 0xFF)					RESET MASTER FF
_DMA_outb(0x4, 0x0)					ADDR LOW
_DMA_outb(0x4, 0x10)					ADDR HIGH
_DMA_outb(0xC, 0xFF)					RESET MASTER FF
_DMA_outb(0x5, 0xFF)					COUNT LOW
_DMA_outb(0x5, 0x23)					COUNT HIGH
_DMA_outb(0x81, 0x0)					ADDR EXT
_DMA_outb(0xA, 0x2)					UNMASK DMA CHANNEL 2
DMA set read:

Code: Select all

_DMA_outb(0xA, 0x6)					DMA MASK CHANNEL 2
_DMA_outb(0xC, 0x46)					(SINGLE TRANSFER | READ)
_DMA_outb(0xB, 0x46)					(SINGLE TRANSFER | READ)
_DMA_outb(0xA, 0x2)					DMA UNMASK CHANNEL 2
FDC READ SECTOR (snippit)

Code: Select all

_FDC_Write(0x3F0, 0x5, 0xE6)			(READ SECTOR | MULTI-TRACK | SKIP | DD)
_FDC_READ(0x3F0, 0x4) = 0x80			DATA READY
_FDC_Write(0x3F0, 0x5, 0x0)			(HEAD << 2) | 1
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x0)			TRACK
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x0)			HEAD
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x1)			SECTOR
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x2)			DTL
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x2)			(SECTOR + 1) OR 18
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x1B)			GAP
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0xFF)			SECTOR SIZE??
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_WAIT_IR()							IT COMPLAINED BIG TIME NOT 
			FDC IRQ RECIVED
_FDC_WAIT_IR()							WAITING FOR THE SECOND IRQ
			FDC IRQ RECIVED
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x40			[ST0]				0100 0000
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x10			[ST1]				0001 0000
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x0			[ST2]				0000 0000
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x0			[CYLINDER]		0000 0000
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x0			[HEAD]			0000 0000
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x1			[SECTOR #]		0000 0001
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x2			[SECTOR SIZE]		0000 0010
_FDC_Write(0x3F0, 0x5, 0x8)			SENSE INT
_FDC_READ(0x3F0, 0x4) = 0x80			DATA READY
...
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x80			[ST0]				1000 0000
_FDC_READ(0x3F0, 0x4) = 0x80			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x80			[CYL]				1000 0000
_FDC_Write(0x3F0, 0x2, 0xC)			MOTOR OFF
And just for completeness:

_FDC_init full DEBUG out:

Code: Select all

_DMA_outb(0xA, 0x6)					MASK DMA CHANNEL 2
_DMA_outb(0xC, 0xFF)					RESET MASTER FF
_DMA_outb(0x4, 0x0)					ADDR LOW
_DMA_outb(0x4, 0x10)					ADDR HIGH
_DMA_outb(0xC, 0xFF)					RESET MASTER FF
_DMA_outb(0x5, 0xFF)					COUNT LOW
_DMA_outb(0x5, 0x23)					COUNT HIGH
_DMA_outb(0x81, 0x0)					ADDR EXT
_DMA_outb(0xA, 0x2)					UNMASK DMA CHANNEL 2
_FDC_Write(0x3F0, 0x2, 0x0)			FDC RESET
FDC IRQ RECIVED
_FDC_Write(0x3F0, 0x2, 0xC)			FDC ENABLE
FDC IRQ RECIVED
_FDC_Write(0x3F0, 0x7, 0x0)			CCR SPEED
_FDC_WAIT_IR()
_FDC_Write(0x3F0, 0x5, 0x8)			FDC SENSE INT
_FDC_READ(0x3F0, 0x4) = 0x80			DATA READY
...
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0xC0			[ST0]				1100 0000
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x0			[CYL]				0000 0000
_FDC_Write(0x3F0, 0x5, 0x8)			FDC SENSE INT
_FDC_READ(0x3F0, 0x4) = 0x80			DATA READY
...
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0xC1			[ST0]				1100 0001
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x0			[CYL]				0000 0000
_FDC_Write(0x3F0, 0x5, 0x8)			FDC SENSE INT
_FDC_READ(0x3F0, 0x4) = 0x80			DATA READY
...
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0xC2			[ST0]				1100 0010
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x0			[CYL]				0000 0000
_FDC_Write(0x3F0, 0x5, 0x8)			FDC SENSE INT
_FDC_READ(0x3F0, 0x4) = 0x80			DATA READY
...
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0xC3			[ST0]				1100 0011
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x0			[CYL]				0000 0000
_FDC_Write(0x3F0, 0x5, 0x13)			FDC CONFIGURE
_FDC_READ(0x3F0, 0x4) = 0x80			DATA READY
_FDC_Write(0x3F0, 0x5, 0x0)			DEFAULT CONFIG
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x10)			POLLING DISABLED
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x0)			precomp_val = 0 ?
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x3)			FDC SPECIFY
_FDC_READ(0x3F0, 0x4) = 0x80			DATA READY
_FDC_Write(0x3F0, 0x5, 0x30)			(3 << 4) | (240 & 0XF)
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x21)			(16 << 1) | 1
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x2, 0x1C)			MOTOR ON
_FDC_Write(0x3F0, 0x5, 0x7)			CALIBRATE
_FDC_READ(0x3F0, 0x4) = 0x80			DATA READY
_FDC_Write(0x3F0, 0x5, 0x0)			DRIVE
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_WAIT_IR()
FDC IRQ RECIVED
_FDC_Write(0x3F0, 0x5, 0x8)			SENSE INT
_FDC_READ(0x3F0, 0x4) = 0x81			DATA READY
...
_FDC_READ(0x3F0, 0x4) = 0xD1			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x20			[ST0]				0010 0000
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x0			[CYL]				0000 0000
_FDC_Write(0x3F0, 0x2, 0xC)			MOTOR OFF
_FDC_ReadSector full DEBUG out:

Code: Select all

_FDC_Write(0x3F0, 0x2, 0x1C)			MOTOR ON
_FDC_Write(0x3F0, 0x5, 0xF)			SEEK
_FDC_READ(0x3F0, 0x4) = 0x80			DATA READY
_FDC_Write(0x3F0, 0x5, 0x0)			HEAD
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x0)			CYLINDER
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
			FDC IRQ RECIVED
_FDC_WAIT_IR()
_FDC_Write(0x3F0, 0x5, 0x8)			SENSE INT
_FDC_READ(0x3F0, 0x4) = 0x81			DATA READY
_FDC_READ(0x3F0, 0x4) = 0xD1			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x20			[ST0]				0010 0000
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x0			[CYL]				0000 0000
_DMA_outb(0xA, 0x6)					DMA MASK CHANNEL 2
_DMA_outb(0xC, 0x46)					(SINGLE TRANSFER | READ)
_DMA_outb(0xB, 0x46)					(SINGLE TRANSFER | READ)
_DMA_outb(0xA, 0x2)					DMA UNMASK CHANNEL 2
_FDC_Write(0x3F0, 0x5, 0xE6)			(READ SECTOR | MULTI-TRACK | SKIP | DD)
_FDC_READ(0x3F0, 0x4) = 0x80			DATA READY
_FDC_Write(0x3F0, 0x5, 0x0)			(HEAD << 2) | 1
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x0)			TRACK
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x0)			HEAD
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x1)			SECTOR
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x2)			DTL
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x2)			(SECTOR + 1) OR 18
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0x1B)			GAP
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_Write(0x3F0, 0x5, 0xFF)			SECTOR SIZE??
_FDC_READ(0x3F0, 0x4) = 0x90			DATA READY
_FDC_WAIT_IR()							IT COMPLAINED BIG TIME NOT 
			FDC IRQ RECIVED
_FDC_WAIT_IR()							WAITING FOR THE SECOND IRQ
			FDC IRQ RECIVED
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x40			[ST0]				0100 0000
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x10			[ST1]				0001 0000
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x0			[ST2]				0000 0000
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x0			[CYLINDER]		0000 0000
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x0			[HEAD]			0000 0000
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x1			[SECTOR #]		0000 0001
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x2			[SECTOR SIZE]		0000 0010
_FDC_Write(0x3F0, 0x5, 0x8)			SENSE INT
_FDC_READ(0x3F0, 0x4) = 0x80			DATA READY
...
_FDC_READ(0x3F0, 0x4) = 0xD0			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x80			[ST0]				1000 0000
_FDC_READ(0x3F0, 0x4) = 0x80			DATA READY
_FDC_READ(0x3F0, 0x5) = 0x80			[CYL]				1000 0000
_FDC_Write(0x3F0, 0x2, 0xC)			MOTOR OFF
I will upload the actual C code if needed, but above has all the port I/Os called by FDC and DMA.

Any help is appreciated, I just can't determine the issue here.

P.S. Hope the tabbing in the code blocks works out decently in all themes.
Last edited by BASICFreak on Fri Jun 27, 2014 1:54 pm, edited 1 time in total.
BOS Source Thanks to GitHub
BOS Expanded Commentary
Both under active development!
Sortie wrote:
  • Don't play the role of an operating systems developer, be one.
  • Be truly afraid of undefined [behavior].
  • Your operating system should be itself, not fight what it is.
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: FDC / DMA issue

Post by SpyderTL »

You might try setting up your DMA Read settings before your turn the FDC motor on.

Also, I'm not sure why you are writing the DMA Read settings (0x46) to both 0xC and 0xB. I'm only sending it to 0xB, and it seems to work for me on most hardware.
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
User avatar
BASICFreak
Member
Member
Posts: 284
Joined: Fri Jan 16, 2009 8:34 pm
Location: Louisiana, USA

Re: FDC / DMA issue

Post by BASICFreak »

SpyderTL wrote:You might try setting up your DMA Read settings before your turn the FDC motor on.

Also, I'm not sure why you are writing the DMA Read settings (0x46) to both 0xC and 0xB. I'm only sending it to 0xB, and it seems to work for me on most hardware.
I wish it were that simple still the same error output. I have another project grabbing my attention at the moment, but I'll be back on it in the next few hours.

Also, I think I saw it in linux 0.92c's source if I'm not mistaken. -> had to look it up to be sure here it is... Exact Segment:

Code: Select all

/* output command byte. I don't know why, but everyone (minix, */
/* sanches & canton) output this twice, first to 12 then to 11 */
 	__asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t"
	"outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:"::
	"a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE)));
And yes I've tried without reg 0xC, but if they did it and I'm not their's works mine don't, I think I'll try what they do..., but still then I must be off somewhere...

Anyways I'll be back later...
BOS Source Thanks to GitHub
BOS Expanded Commentary
Both under active development!
Sortie wrote:
  • Don't play the role of an operating systems developer, be one.
  • Be truly afraid of undefined [behavior].
  • Your operating system should be itself, not fight what it is.
User avatar
BASICFreak
Member
Member
Posts: 284
Joined: Fri Jan 16, 2009 8:34 pm
Location: Louisiana, USA

Re: FDC / DMA issue

Post by BASICFreak »

Well, I got bochs working (incorrectly) by not resetting the FDC after Grub, but did not help real H/W

Changed my DMA_read to be identical to port communication on linux 0.92:

Code: Select all

outb(A, 6)
C, 46
B, 46
4, 0
4, 10
81, 0
5, FF
5, 23
A, 2
I'm going to continue to shift through the linux src code, try to make my I/O identical (so far it looks identical) I must be just one or two bytes off but where...

I hope to get this done before I go to sleep tonight [-o< (but at the same time that's what I said the last 2 days)
BOS Source Thanks to GitHub
BOS Expanded Commentary
Both under active development!
Sortie wrote:
  • Don't play the role of an operating systems developer, be one.
  • Be truly afraid of undefined [behavior].
  • Your operating system should be itself, not fight what it is.
User avatar
BASICFreak
Member
Member
Posts: 284
Joined: Fri Jan 16, 2009 8:34 pm
Location: Louisiana, USA

Re: FDC / DMA issue

Post by BASICFreak »

Well, now on bochs I get:
ST0 = 0
ST1 = 0
ST2 = 0

on real H/W I get the following:
ST0 = 0x40 = Abnormal Termination
ST1 = 0x80 = End of Cylinder
ST2 = 0
But it reads in fine, just needs to be reset after every read

I believe I narrowed down my issue to the Configure or Specify commands
here is what I'm using now to configure:

Code: Select all

	(void) _FDC_Write(_FDC_BASE[0], DATA, 0x13);
	(void) _FDC_Write(_FDC_BASE[0], DATA, 0);
	(void) _FDC_Write(_FDC_BASE[0], DATA, (uint8_t)(1<<4));
	(void) _FDC_Write(_FDC_BASE[0], DATA, 0);
and specify:

Code: Select all

	(void) _FDC_Write(_FDC_BASE[0], DATA, 3);
	(void) _FDC_Write(_FDC_BASE[0], DATA, 0xDf);
	(void) _FDC_Write(_FDC_BASE[0], DATA, 2);
I did not change my configure any, but the specify had DMA turned off (would explain alot).

Anyways can anyone point me in the direction to remove the abnormal termination on H/W? Am I even thinking in the right place?






I'm going to get my FAT-12 driver back up now while I have a chance to get off the FDC for a minute, far too long trying to figure this thing out.
Maybe since switching to Cross-Compiler my clock will load up on H/W [-o< I think I just messed up the stack in the executable though...
BOS Source Thanks to GitHub
BOS Expanded Commentary
Both under active development!
Sortie wrote:
  • Don't play the role of an operating systems developer, be one.
  • Be truly afraid of undefined [behavior].
  • Your operating system should be itself, not fight what it is.
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: FDC / DMA issue

Post by SpyderTL »

The only other difference that I noticed was that I'm only loading one 512 byte block at a time. You might try limiting it to one block and see if that works properly. Either way, it will give you a hint where to look next.

Edit: I'm not seeing any calls to 0xC in Linux 2.2 source or above.

Code: Select all

#define DMA1_MODE_REG           0x0B    /* mode register (w) */
#define DMA1_CLEAR_FF_REG       0x0C    /* clear pointer flip-flop (w) */

static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
{
        if (dmanr<=3)
                dma_outb(mode | dmanr,  DMA1_MODE_REG);
        else
                dma_outb(mode | (dmanr&3),  DMA2_MODE_REG);
}

fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ)?
        DMA_MODE_READ : DMA_MODE_WRITE);
Edit: I also found this in the FDC spec sheet...

Code: Select all

4.2.5 DATA TRANSFER TERMINATION
The 82077AA supports terminal count explicitly
through the TC pin and implicitly through the underrun/
overrun and end-of-track (EOT) functions. For
full sector transfers, the EOT parameter can define
the last sector to be transferred in a single or multisector
transfer. If the last sector to be transferred is
a partial sector, the host can stop transferring the
data in mid-sector, and the 82077AA will continue to
complete the sector as if a hardware TC was received.
The only difference between these implicit
functions and TC is that they return ``abnormal termination''
result status. Such status indications can be
ignored if they were expected.
Still trying to pin down exactly what that means, but the 7th byte that you send the FDC is either a) The number of sectors you want to read, b) the number of the sector (1-18) that you want to be the last sector to read, or c) the sector that you want the FDC to stop sending when it is detected. (basically b+1)

I think the answer is b), but I'm still playing around with this, trying to figure out what is going on. I, too, have to reset the FDC every time I use it, because I'm getting 0xFF for all of the st0-2 status values at the end on real hardware (and AMD SimNow). but the data is being delivered properly, so I've been ignoring it and resetting the FDC every time...
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
User avatar
BASICFreak
Member
Member
Posts: 284
Joined: Fri Jan 16, 2009 8:34 pm
Location: Louisiana, USA

Re: FDC / DMA issue

Post by BASICFreak »

SpyderTL wrote:The only other difference that I noticed was that I'm only loading one 512 byte block at a time. You might try limiting it to one block and see if that works properly. Either way, it will give you a hint where to look next.

Edit: I'm not seeing any calls to 0xC in Linux 2.2 source or above.

...

Still trying to pin down exactly what that means, but the 7th byte that you send the FDC is either a) The number of sectors you want to read, b) the number of the sector (1-18) that you want to be the last sector to read, or c) the sector that you want the FDC to stop sending when it is detected. (basically b+1)

I think the answer is b), but I'm still playing around with this, trying to figure out what is going on. I, too, have to reset the FDC every time I use it, because I'm getting 0xFF for all of the st0-2 status values at the end on real hardware (and AMD SimNow). but the data is being delivered properly, so I've been ignoring it and resetting the FDC every time...
Thanks for the help by the way I no longer have to reset the FDC on H/W anymore :D
I changed DMA count to (sectors to read) * 0x200 and now ST0-2 are 0!!!

I'm about to add write functionality and fix my simi-faulty FAT12 driver (tends to read an extra sector when loading a file inside a dir)

Once I have write I'll post the code if you would like to go through and compare

the 7th byte is (as far as I'm using it for) the number of sectors you want to read.

And I haven't been looking at the higher builds of linux I find them too confusing still, but yet my code is looking more and more like it so it shouldn't be long before I can wrap my brain around it.



BTW even before fixing the having to reset it was 2-300mS faster than the linux driver per sector, but I don't have all the backend to support either the FDC is given all 50% of the CPU time
BOS Source Thanks to GitHub
BOS Expanded Commentary
Both under active development!
Sortie wrote:
  • Don't play the role of an operating systems developer, be one.
  • Be truly afraid of undefined [behavior].
  • Your operating system should be itself, not fight what it is.
User avatar
BASICFreak
Member
Member
Posts: 284
Joined: Fri Jan 16, 2009 8:34 pm
Location: Louisiana, USA

[SOLVED] FDC / DMA issue

Post by BASICFreak »

So to sum things up and mark this as solved...

SKIP mode is a no-no on Bochs for write!!! (It will come back as complete but will not write)

[EDIT] Also Note do not pass Cylinder bounds!!, you never have to reset FDC in my experience (plus you get all the data not just the part before cylinder change...) [/EDIT]

So far my setup never (unless I do something stupid) has to reset FDC on Bochs but every so often on real H/W (figures it's not the most sturdy storage device in the world)

Thanks for all of the help, Here is what I learned and Some of the code I've made.
Hopefully it will help someone out in the future.

And this is the BEST LOOKING code I've made to date :D


Byte lineup FDC sector I/O:

Code: Select all

1. Read/Write [0x46/0x45]
2. (head << 2) | drive
3. track
4. head
5. sector
6. DLT [2]
7. sectorcount
8. GAP [0x1B]
9. 0xFF
DMA Setup:

Code: Select all

dest, src:
0xA, 0x4
0xB, READ/WRITE [0x46/0x4A]
0x4, [ADDR LOW]
0x4, [ADDR HIGH]
0x81, [ADDR EXT]
0x5, [((sectorcount * 0x200) - 1) & 0xFF]
0x5, [(((sectorcount * 0x200) - 1) >> 8 ) & 0xFF]
0xA, 0x2
FDC Reset:

Code: Select all

1. Turn FDC OFF
2. Turn FDC ON
3. Set Speed
4. Wait for IRQ
5. Sense INT (4 times)
6. Configure Command
7. Specify Command
8. Calibrate Drive
9. (Turn Off Drive)
and for some real code:

Code: Select all

error FDC_Specify(uint8_t drive, bool dma, uint8_t steprate, uint8_t loadtime, uint8_t unloadtime)
{
#ifdef DEBUG
	txf(1, "FDC_Specify(0x%x, %s, 0x%x, 0x%x, 0x%x)\n\r", drive, ((dma) ? "TRUE" : "FALSE"), steprate, loadtime, unloadtime);
#endif
	if(drive>3)
		return ERROR_INPUT;
	error errorcode = ERROR_NONE;
	if((errorcode = _FDC_Write(_FDC_BASE[drive], DATA, _FDC_SPECIFY)))
		return errorcode;
	if((errorcode = _FDC_Write(_FDC_BASE[drive], DATA, (uint8_t) (((steprate & 0xf) << 4) | (unloadtime & 0xf)))))
		return errorcode;
	if((errorcode = _FDC_Write(_FDC_BASE[drive], DATA, (uint8_t) ((loadtime << 1) | ((dma) ? 0 : 1)))))
		return errorcode;
	return ERROR_NONE;
}

error FDC_Configure(uint8_t drive, bool impSeek, bool fifo, bool polling, uint8_t threshold)
{
#ifdef DEBUG
	txf(1, "FDC_Configure(0x%x, %s, %s, %s, 0x%s)\n\r", drive, ((impSeek) ? "TRUE" : "FALSE"), ((fifo) ? "TRUE" : "FALSE"), ((polling) ? "TRUE" : "FALSE"), threshold );
#endif
	if(drive>3 || threshold>15)
		return ERROR_INPUT;
	uint8_t databyte = (uint8_t) (impSeek << 6) | threshold;
	if(!fifo)
		databyte |= (uint8_t) (1 << 5);
	if(!polling)
		databyte |= (uint8_t) (1 << 4);
	error errorcode = ERROR_NONE;
	if( (errorcode = _FDC_Write(_FDC_BASE[drive], DATA, 0x13)) )
		return errorcode;
	if( (errorcode = _FDC_Write(_FDC_BASE[drive], DATA, 0)) )
		return errorcode;
	if( (errorcode = _FDC_Write(_FDC_BASE[drive], DATA, databyte)) )
		return errorcode;
	if( (errorcode = _FDC_Write(_FDC_BASE[drive], DATA, 0)) )
		return errorcode;
	return ERROR_NONE;
}

error FDC_Reset(uint8_t drive)
{
#ifdef DEBUG
	txf(1, "FDC_Reset(0x%x)\n\r", drive);
#endif
	if(drive>3)
		return ERROR_INPUT;
	error errorcode = ERROR_NONE;
	if ( (errorcode = DOR_Handler(drive, false, true)) )				// Disable Controller
		return errorcode;
	if ( (errorcode = DOR_Handler(drive, true, false)) )				// Enable Controller
		return errorcode;
	if( (errorcode = FDC_Speed(drive, 0)) )								// Set speed to 500kb/s
		return errorcode;
	if( (errorcode = _FDC_WAIT_IR()) )									// Wait for IRQ
		return errorcode;
	uint8_t st0, cyl;
	for(int i=0; i<4; i++)
		if( (errorcode = _FDC_SENSEINT(&st0, &cyl)))					// Acknolage IRQ x4
			return errorcode;
	if( (errorcode = FDC_Configure(drive, false, true, false, 1)) )			//Configure
		return errorcode;
	if( (errorcode = FDC_Specify(drive, true, 8, 5, 15)) )				// Specify
		return errorcode;
	if( (errorcode = FDC_Calibrate(0)) )								// Calibrate (and turn off motor)
		return errorcode;
	_FDC_RESET_REQUIRED = false;										// We just reset so it is not required ATM
	return ERROR_NONE;
}

error FDC_Seek(uint8_t drive, uint8_t head, uint8_t cylinder)
{
#ifdef DEBUG
	txf(1, "FDC_Reset(0x%x, 0x%x, 0x%x)\n\r", drive, head, cylinder);
#endif
	uint8_t st0, cyl;
	error errorcode = ERROR_NONE;
	for(int i = 0; i < 4; i ++) {
		if((errorcode = _FDC_Write(_FDC_BASE[drive], DATA, _FDC_SEEK)))
			return errorcode;
		if((errorcode = _FDC_Write(_FDC_BASE[drive], DATA, (uint8_t) ((head << 2) | drive))))
			return errorcode;
		if((errorcode = _FDC_Write(_FDC_BASE[drive], DATA, cylinder)))
			return errorcode;
		if((errorcode = _FDC_WAIT_IR()))
			return errorcode;
		if((errorcode = _FDC_SENSEINT(&st0, &cyl)))
			return errorcode;
		if(cyl == cylinder)
			return ERROR_NONE;
	}
	return ERROR_HWFAILURE;
}

error FDC_SectorIO(uint8_t drive, bool write, uint8_t head, uint8_t track, uint8_t sector, uint8_t count)
{
#ifdef DEBUG
	txf(1, "FDC_SectorIO(0x%x, %s, 0x%x, 0x%x, 0x%x, 0x%x)\n\r", drive, ((write) ? "TRUE" : "FALSE"), head, track, sector, count);
#endif
	if(drive>3 || head>1 || track>79 || sector>18)
		return ERROR_INPUT;
	uint8_t st0, cyl;
	error errorcode = ERROR_NONE;
	if((errorcode = _DMA_Setup(DMA_CHANNEL, write, 0x1000, (uint16_t)(count * 0x200))))
		return errorcode;
	if((errorcode = DOR_Handler(drive, true, false)))
		return errorcode;
	if((errorcode = FDC_Seek(drive, head, track)))
		return errorcode;
	if((errorcode = _FDC_Write(_FDC_BASE[drive], DATA, (_FDC_EXT_DDENSITY | ((write) ? _FDC_WRITESECTOR : _FDC_READSECTOR) )    )))
		return errorcode;
	if((errorcode = _FDC_Write(_FDC_BASE[drive], DATA, (uint8_t) ((head << 2) | drive))))
		return errorcode;
	if((errorcode = _FDC_Write(_FDC_BASE[drive], DATA, track)))
		return errorcode;
	if((errorcode = _FDC_Write(_FDC_BASE[drive], DATA, head)))
		return errorcode;
	if((errorcode = _FDC_Write(_FDC_BASE[drive], DATA, sector)))
		return errorcode;
	if((errorcode = _FDC_Write(_FDC_BASE[drive], DATA, _DTL_512)))
		return errorcode;
	if((errorcode = _FDC_Write(_FDC_BASE[drive], DATA, count)))
		return errorcode;
	if((errorcode = _FDC_Write(_FDC_BASE[drive], DATA, 0x1B)))
		return errorcode;
	if((errorcode = _FDC_Write(_FDC_BASE[drive], DATA, 0xFF)))
		return errorcode;
	if((errorcode = _FDC_WAIT_IR()))
		return errorcode;
	for(int i=0; i<7; i++)
	{
		error_data_u8_t errordata = _FDC_Read(_FDC_BASE[drive], DATA);
		if(errordata >> 8)
			return (error) (errordata >> 8);
		if(!i && (errordata & 0xF8))
			_FDC_RESET_REQUIRED = true;
		if((i==1 || i==2) && (errordata & 0xFF))
			_FDC_RESET_REQUIRED = true;
	}
	if((errorcode = _FDC_SENSEINT(&st0, &cyl)))
		return errorcode;
	if((errorcode = DOR_Handler(drive, false, false)))
		return errorcode;
	return ERROR_NONE;
}
And the public function:

Code: Select all

error _FDC_IO(bool write, int start, uint8_t count, void *buffer)
{
	uint8_t *MAINBUFFER = (uint8_t *) 0x1000;
	if (count > 18 || start >= 2880)
		return ERROR_INPUT;
	if (_FDC_RESET_REQUIRED)
		FDC_Reset(0);
	int head, track, sector;
	lbaCHS(start, &head, &track, &sector);
	if(write)
		memcpy(MAINBUFFER, buffer, (size_t)(count * 0x200));
	error temp = FDC_SectorIO(0, write, (uint8_t) head, (uint8_t) track, (uint8_t) sector, count);
	if(temp)
		return temp;
	if(!write)
		memcpy(buffer, MAINBUFFER, (size_t)(count * 0x200));
	return ERROR_NONE;
}
And DMA setup:

Code: Select all

error _DMA_Setup(uint8_t channel, bool write, uint32_t addr, uint16_t count)
{
	if(channel>7 || addr>0xFF0000)
		return ERROR_INPUT;
	error errorcode = ERROR_NONE;
	if((errorcode = _DMA_MASK_CHAN(channel)))
		return errorcode;
	if((errorcode = _DMA_MODEREG_Handle(channel, ((write) ? 0x4A : 0x46))))
		return errorcode;
	if((errorcode = _DMA_set_Addr(channel, addr)))
		return errorcode;
	if((_DMA_set_Count(channel, count)))
		return errorcode;
	if((errorcode = _DMA_UMASK_CHAN(channel)))
		return errorcode;
	return ERROR_NONE;
}
BOS Source Thanks to GitHub
BOS Expanded Commentary
Both under active development!
Sortie wrote:
  • Don't play the role of an operating systems developer, be one.
  • Be truly afraid of undefined [behavior].
  • Your operating system should be itself, not fight what it is.
Post Reply