Created DMA driver

This commit is contained in:
Arnau Camprubí 2022-08-25 20:37:50 +02:00
pare 92b14a5331
commit 44c78007d8
S'han modificat 4 arxius amb 201 adicions i 1 eliminacions

Veure arxiu

@ -0,0 +1,94 @@
#include <stdint.h>
#include "dma.h"
#include "io.h"
void i686_dma_set_address(uint8_t channel, uint16_t addr){
if(channel > 8) return;
uint16_t port = 0;
switch(channel){
case 0: port = i686_DMA0_CHAN0_ADDR_REG; break;
case 1: port = i686_DMA0_CHAN1_ADDR_REG; break;
case 2: port = i686_DMA0_CHAN2_ADDR_REG; break;
case 3: port = i686_DMA0_CHAN3_ADDR_REG; break;
case 4: port = i686_DMA1_CHAN4_ADDR_REG; break;
case 5: port = i686_DMA1_CHAN5_ADDR_REG; break;
case 6: port = i686_DMA1_CHAN6_ADDR_REG; break;
case 7: port = i686_DMA1_CHAN7_ADDR_REG; break;
}
i686_outw(port, addr);
}
void i686_dma_set_count(uint8_t channel, uint16_t count){
if(channel > 8) return;
uint16_t port = 0;
switch(channel){
case 0: port = i686_DMA0_CHAN0_COUNT_REG; break;
case 1: port = i686_DMA0_CHAN1_COUNT_REG; break;
case 2: port = i686_DMA0_CHAN2_COUNT_REG; break;
case 3: port = i686_DMA0_CHAN3_COUNT_REG; break;
case 4: port = i686_DMA1_CHAN4_COUNT_REG; break;
case 5: port = i686_DMA1_CHAN5_COUNT_REG; break;
case 6: port = i686_DMA1_CHAN6_COUNT_REG; break;
case 7: port = i686_DMA1_CHAN7_COUNT_REG; break;
}
i686_outw(port, count);
}
void i686_dma_set_external_page_register(uint8_t reg, uint8_t val){
uint16_t port = 0;
switch(reg){
case 1: port = i686_DMA_PAGE_CHAN1_ADDRBYTE2; break;
case 2: port = i686_DMA_PAGE_CHAN2_ADDRBYTE2; break;
case 3: port = i686_DMA_PAGE_CHAN3_ADDRBYTE2; break;
// 4 is not valid
case 5: port = i686_DMA_PAGE_CHAN5_ADDRBYTE2; break;
case 6: port = i686_DMA_PAGE_CHAN6_ADDRBYTE2; break;
case 7: port = i686_DMA_PAGE_CHAN7_ADDRBYTE2; break;
default: return;
}
}
void i686_dma_set_mode(uint8_t channel, uint8_t mode){
int dma = (channel < 4) ? 0 : 1;
int chan = (dma == 0) ? channel : channel-4;
i686_dma_mask_channel(channel);
i686_outb((channel < 4) ? i686_DMA0_MODE_REG : i686_DMA1_MODE_REG, chan | mode);
i686_dma_unmask_all(dma);
}
void i686_dma_set_read(uint8_t channel){
i686_dma_set_mode(channel, i686_DMA_MODE_READ_TRANSFER | i686_DMA_MODE_TRANSFER_SINGLE | i686_DMA_MODE_MASK_AUTO);
}
void i686_dma_set_write(uint8_t channel){
i686_dma_set_mode(channel, i686_DMA_MODE_WRITE_TRANSFER | i686_DMA_MODE_TRANSFER_SINGLE | i686_DMA_MODE_MASK_AUTO);
}
void i686_dma_mask_channel(uint8_t channel){
if(channel <= 4) i686_outb(i686_DMA0_CHANMASK_REG, (1 << (channel-1)));
else i686_outb(i686_DMA1_CHANMASK_REG, (1 << (channel-5)));
}
void i686_dma_unmask_channel(uint8_t channel){
i686_outb(channel <= 4 ? i686_DMA0_CHANMASK_REG : i686_DMA1_CHANMASK_REG, channel);
}
void i686_dma_reset_flipflop(int dma){
if(dma > 2) return;
i686_outb((dma == 0) ? i686_DMA0_CLEARBYTE_FLIPFLOP_REG : i686_DMA1_CLEARBYTE_FLIPFLOP_REG, 0xFF);
}
void i686_dma_reset(int dma){
i686_outb(i686_DMA0_TEMP_REG, 0xFF);
}
void i686_dma_unmask_all(int dma){
i686_outb(i686_DMA1_UNMASK_ALL_REG, 0xFF);
}

Veure arxiu

@ -0,0 +1,85 @@
#pragma once
#include <stdint.h>
#define i686_DMA0_STATUS_REG 0x08
#define i686_DMA0_COMMAND_REG 0x08
#define i686_DMA0_REQUEST_REG 0x09
#define i686_DMA0_CHANMASK_REG 0x0A
#define i686_DMA0_MODE_REG 0x0B
#define i686_DMA0_CLEARBYTE_FLIPFLOP_REG 0x0C
#define i686_DMA0_TEMP_REG 0x0D
#define i686_DMA0_MASTER_CLEAR_REG 0x0D
#define i686_DMA0_CLEAR_MASK_REG 0x0E
#define i686_DMA0_MASK_REG 0x0F
#define i686_DMA0_CHAN0_ADDR_REG 0x00
#define i686_DMA0_CHAN0_COUNT_REG 0x01
#define i686_DMA0_CHAN1_ADDR_REG 0x02
#define i686_DMA0_CHAN1_COUNT_REG 0x03
#define i686_DMA0_CHAN2_ADDR_REG 0x04
#define i686_DMA0_CHAN2_COUNT_REG 0x05
#define i686_DMA0_CHAN3_ADDR_REG 0x06
#define i686_DMA0_CHAN3_COUNT_REG 0x07
#define i686_DMA1_STATUS_REG 0xD0
#define i686_DMA1_COMMAND_REG 0xD0
#define i686_DMA1_REQUEST_REG 0xD2
#define i686_DMA1_CHANMASK_REG 0xD4
#define i686_DMA1_MODE_REG 0xD6
#define i686_DMA1_CLEARBYTE_FLIPFLOP_REG 0xD8
#define i686_DMA1_INTER_REG 0xDA
#define i686_DMA1_UNMASK_ALL_REG 0xDC
#define i686_DMA1_MASK_REG 0xDE
#define i686_DMA1_CHAN4_ADDR_REG 0xC0
#define i686_DMA1_CHAN4_COUNT_REG 0xC2
#define i686_DMA1_CHAN5_ADDR_REG 0xC4
#define i686_DMA1_CHAN5_COUNT_REG 0xC6
#define i686_DMA1_CHAN6_ADDR_REG 0xC8
#define i686_DMA1_CHAN6_COUNT_REG 0xCA
#define i686_DMA1_CHAN7_ADDR_REG 0xCC
#define i686_DMA1_CHAN7_COUNT_REG 0xCE
#define i686_DMA_PAGE_EXTRA0 0x80
#define i686_DMA_PAGE_CHAN2_ADDRBYTE2 0x81
#define i686_DMA_PAGE_CHAN3_ADDRBYTE2 0x82
#define i686_DMA_PAGE_CHAN1_ADDRBYTE2 0x83
#define i686_DMA_PAGE_EXTRA1 0x84
#define i686_DMA_PAGE_EXTRA2 0x85
#define i686_DMA_PAGE_EXTRA3 0x86
#define i686_DMA_PAGE_CHAN6_ADDRBYTE2 0x87
#define i686_DMA_PAGE_CHAN7_ADDRBYTE2 0x88
#define i686_DMA_PAGE_CHAN5_ADDRBYTE2 0x89
#define i686_DMA_PAGE_EXTRA4 0x8C
#define i686_DMA_PAGE_EXTRA5 0x8D
#define i686_DMA_PAGE_EXTRA6 0x8E
#define i686_DMA_PAGE_DRAM_REFRESH 0x8F
#define i686_DMA_CMD_MASK_MEMTOMEM 0x01
#define i686_DMA_CMD_MASK_CHAN0ADDRHOLD 0x02
#define i686_DMA_CMD_MASK_ENABLE 0x04
#define i686_DMA_CMD_MASK_TIMING 0x08
#define i686_DMA_CMD_MASK_PRIORITY 0x10
#define i686_DMA_CMD_MASK_WRITESEL 0x20
#define i686_DMA_CMD_MASK_DREQ 0x40
#define i686_DMA_CMD_MASK_DACK 0x80
#define i686_DMA_MODE_MASK_SEL 0x03
#define i686_DMA_MODE_MASK_TRA 0x0C
#define i686_DMA_MODE_MASK_TEST 0x00
#define i686_DMA_MODE_READ_TRANSFER 0x04
#define i686_DMA_MODE_WRITE_TRANSFER 0x08
#define i686_DMA_MODE_MASK_AUTO 0x10
#define i686_DMA_MODE_MASK_IDEC 0x20
#define i686_DMA_MODE_MASK 0xC0
#define i686_DMA_MODE_TRANSFER_ON_DEMAND 0x00
#define i686_DMA_MODE_TRANSFER_SINGLE 0x40
#define i686_DMA_MODE_TRANSFER_BLOCK 0x80
#define i686_DMA_MODE_TRANSFER_CASCADE 0xC0
void i686_dma_set_address(uint8_t channel, uint16_t addr);
void i686_dma_set_count(uint8_t channel, uint16_t count);
void i686_dma_set_external_page_register(uint8_t reg, uint8_t val);
void i686_dma_set_mode(uint8_t channel, uint8_t mode);
void i686_dma_set_read(uint8_t channel);
void i686_dma_set_write(uint8_t channel);
void i686_dma_mask_channel(uint8_t channel);
void i686_dma_unmask_channel(uint8_t channel);
void i686_dma_reset_flipflop(int dma);
void i686_dma_reset(int dma);
void i686_dma_unmask_all(int dma);

Veure arxiu

@ -2,6 +2,7 @@
#include "fdc.h"
#include "isr.h"
#include "io.h"
#include "dma.h"
#include "../../lib/time.h"
#include "../../lib/debug.h"
@ -20,7 +21,7 @@ static inline void wait_irq(){
void i686_fdc_initialize_dma(){
i686_outb(0x0A, 0x06); // Mask DMA channel 2
i686_outb(0xD8, 0xFF); // Reset master flip-flop
i686_outw(0x04, 0x1000); // Address = 0x1000
i686_outw(0x04, i686_FDC_DMA_BUFFER); // Address = 0x1000
i686_outb(0xD8, 0xFF); // Reset master flip-flop
i686_outb(0x05, 0xFF); // Count to 0x23FF (bytes in 2.5" floppy disk track)
i686_outb(0x05, 0x23);
@ -97,6 +98,9 @@ int i686_fdc_motor(bool b){
void i686_fdc_read_sector_imp(uint8_t head, uint8_t track, uint8_t sector){
uint32_t st0, cyl;
// Initialize the DMA
i686_dma_initialize_floppy((uint8_t *)i686_FDC_DMA_BUFFER, 512);
// Set DMA for read
i686_fdc_dma_read();
@ -239,3 +243,17 @@ void i686_fdc_initialize(){
// Set drive info
i686_fdc_drive_data(13, 1, 0x0F, true);
}
void i686_dma_initialize_floppy(uint8_t *buffer, unsigned length){
i686_dma_reset(1);
i686_dma_mask_channel(i686_FDC_DMA_CHANNEL);
i686_dma_reset_flipflop(1);
i686_dma_set_address(i686_FDC_DMA_CHANNEL, (unsigned)buffer);
i686_dma_reset_flipflop(1);
i686_dma_set_count(i686_FDC_DMA_CHANNEL, length);
i686_dma_set_read(i686_FDC_DMA_CHANNEL);
i686_dma_unmask_all(1);
}

Veure arxiu

@ -48,6 +48,8 @@
#define i686_FDC_SECTOR_DTL_512 2
#define i686_FDC_SECTOR_DTL_1024 4
#define i686_FDC_SECTORS_PER_TRACK 18
#define i686_FDC_DMA_BUFFER 0x1000
#define i686_FDC_DMA_CHANNEL 2
void i686_fdc_initialize_dma();
void i686_fdc_dma_read();
@ -68,3 +70,4 @@ void i686_fdc_enable();
void i686_fdc_reset();
void i686_fdc_set_working_drive(int drive);
void i686_fdc_initialize();
void i686_dma_initialize_floppy(uint8_t *buffer, unsigned length);