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
|
/*
DMA Controller (8237A)
*/
#include "headers/types.h" //Basic types!
#include "headers/hardware/ports.h" //Port support!
typedef void (*DMAWriteBHandler)(byte *EOP, byte data); //Write handler to DMA hardware!
typedef byte (*DMAReadBHandler)(byte *EOP); //Read handler from DMA hardware!
typedef void (*DMAWriteWHandler)(byte *EOP, word data); //Write handler to DMA hardware!
typedef word (*DMAReadWHandler)(byte *EOP); //Read handler from DMA hardware!
typedef struct
{
DMAModeRegister ModeRegister; //Our mode register!
word CurrentAddressRegister; //Start address register!
word BaseAddressRegister; //Start address base register when resetting (base)! Written together with the start address!
word CurrentCountRegister; //Count register set by the user and counting!
word BaseCountRegister; //Current count register when resetting (base)! Written together with the counter!
byte PageAddressRegister; //Upper 8 bits of the 24-bit transfer memory address!
DMAWriteBHandler WriteBHandler; //Write handler 8-bit!
DMAReadBHandler ReadBHandler; //Read handler 8-bit
DMAWriteWHandler WriteWHandler; //Write handler 16-bit!
DMAReadWHandler ReadWHandler; //Read handler 16-bit!
} DMAChannelTYPE; //Contains all info about an DMA channel!
typedef union
{
struct
{
byte SEL : 2; //Which channel are we?
byte TransferType : 2; //00=Self test, 1=Write to memory, 2=Read from memory, 3=Invalid.
byte Auto : 1; //After the transfer has completed, Reset to the address and count values originally programmed.
byte Down : 1; //Top-down processing if set, else increment addresses.
byte Mode : 2; //Mode: 0=Transfer on Demand, 1=Single DMA Transfer, 2=Block DMA transfer, 3=Cascade Mode (Used to
cascade another DMA controller).
}; //The mode register!
byte ModeRegisterB; //Mode register for all 4 channels!
} DMAModeRegister;
typedef struct
{
//Public registers
DMAChannelTYPE DMAChannel[4]; //4 DMA Channels per Controller!
union
{
struct
{
byte TransferComplete : 4; //Transfer complete for 4 channels (high to low, bit 0=TC0.)
byte RequestPending : 4; //Request pending for 4 channels (high to low, bit 0=REQ0.)
};
byte StatusRegister; //Status register for a DMA controller!
}; //A Status register!
byte CommandRegister; //Command Register
byte RequestRegister; //Request Register!
byte MultiChannelMaskRegister; //MultiChennel Mask Register, bit0-3=channel 0-3; 0=unmask (enabled), 1=mask (disabled)
//Internal registers!
byte FlipFlop; //Current flipflop: Cannot be accessed by software!
byte IntermediateRegister; //Intermediate register!
//Master reset register doesn't store!
//MaskResetRegister doesn't store!
} DMAControllerTYPE; //Contains a DMA Controller's registers!
DMAControllerTYPE DMAController[2]; //We have 2 DMA Controllers!
void initDMAControllers() //Init function for BIOS!
{
memset(&DMAController[0],0,sizeof(DMAController)); //Init DMA Controller channels 0-3 (0 unused: for DRAM Refresh)
memset(&DMAController[1],0,sizeof(DMAController)); //Init DMA Controller channels 4-7 (4 unused: for DMA Controller coupling)
}
//Easy sets of high and low nibbles (word data)!
#define SETHIGH(b,v) b=((b&0xFF)|(v<<8))
#define SETLOW(b,v) b = ((b&0xFF00)|v)
void DMA_WriteIO(word port, byte value) //Handles OUT instructions to I/O ports.
{
byte controller = (port>=0xC0)?1:0; //What controller?
byte reg = port; //What register is selected, default to 1:1 mapping?
if (controller) //16-bit register (second DMA controller)?
{
reg -= 0xC0; //Take the base!
reg >>= 1; //Every port is on a offset of 2!
//Now reg is on 1:1 mapping too!
}
byte channel; //Which channel to use?
switch (port) //What port?
{
//Extra 8 bits for addresses:
case 0x87: //
DMAController[0].DMAChannel[0].PageAddressRegister = value; //Set!
break;
case 0x83: //
DMAController[0].DMAChannel[1].PageAddressRegister = value; //Set!
break;
case 0x81: //
DMAController[0].DMAChannel[2].PageAddressRegister = value; //Set!
break;
case 0x82: //
DMAController[0].DMAChannel[3].PageAddressRegister = value; //Set!
break;
//Extra 8 bits for addresses:
case 0x8F: //
DMAController[1].DMAChannel[0].PageAddressRegister = value; //Set!
break;
case 0x8B: //
DMAController[1].DMAChannel[1].PageAddressRegister = value; //Set!
break;
case 0x89: //
DMAController[1].DMAChannel[2].PageAddressRegister = value; //Set!
break;
case 0x8A: //
DMAController[1].DMAChannel[3].PageAddressRegister = value; //Set!
break;
default: //Unknown port?
break;
default: //Non-page register!
switch (reg) //What register is selected?
{
case 0x00:
case 0x02:
case 0x04:
case 0x06: //Address register?
channel = port>>1; //What channel?
if (DMAController[controller].FlipFlop) //High?
{
SETHIGH(DMAController[controller].DMAChannel[channel].CurrentAddressRegister,value); //Set high
nibble!
SETHIGH(DMAController[controller].DMAChannel[channel].BaseAddressRegister,value); //Set high
nibble!
}
else //Low?
{
SETLOW(DMAController[controller].DMAChannel[channel].CurrentAddressRegister,value); //Set low
nibble!
SETLOW(DMAController[controller].DMAChannel[channel].BaseAddressRegister,value); //Set low
nibble!
}
DMAController[controller].FlipFlop = !DMAController[controller].FlipFlop; //Flipflop!
break;
case 0x01:
case 0x03:
case 0x05:
case 0x07: //Count register?
channel = (port-1)>>1; //What channel?
if (DMAController[controller].FlipFlop) //High?
{
SETHIGH(DMAController[controller].DMAChannel[channel].CurrentCountRegister,value); //Set high
nibble!
SETHIGH(DMAController[controller].DMAChannel[channel].BaseCountRegister,value); //Set high
nibble!
}
else //Low?
{
SETLOW(DMAController[controller].DMAChannel[channel].CurrentCountRegister,value); //Set low
nibble!
SETLOW(DMAController[controller].DMAChannel[channel].BaseCountRegister,value); //Set low nibble!
}
DMAController[controller].FlipFlop = !DMAController[controller].FlipFlop; //Flipflop!
break;
case 0x08: //Command register!
DMAController[controller].CommandRegister = value; //Set!
break;
case 0x09: //Request register!
DMAController[controller].RequestRegister = value; //Set!
break;
case 0x0A: //Single Channel Mask Register!
DMAController[controller].MultiChannelMaskRegister &= ~(1<<(value&3)); //Turn off the channel!
DMAController[controller].MultiChannelMaskRegister |= ((value&4)>>2)<<(value&3)); //Mask it if needed!
break;
case 0x0B: //Mode Register!
DMAController[controller].ModeRegisters[value&0x3].ModeRegister = value; //Set!
break;
case 0x0C: //Flip-Flop Reset Register!
DMAController[controller].FlipFlop = 0; //Reset!
break;
case 0x0D: //Master Reset Register!
DMAController[controller].FlipFlop = 0; //Reset!
DMAController[controller].StatusRegister = 0; //Reset!
DMAController[controller].MultiChannelMaskRegister |= 0xF; //Set the masks!
break;
case 0x0E: //Mask Reset Register!
DMAController[controller].MultiChannelMaskRegister &= ~0xF; //Clear the masks!
break;
case 0x0F: //MultiChannel Mask Register!
DMAController[controller].MultiChannelMaskRegister = value; //Set!
break;
}
break;
}
}
|