FDC Experimental Code

This commit is contained in:
Peter Weingartner 2022-05-05 13:40:24 -04:00
parent ce1f4b3219
commit fcd89cc069
12 changed files with 16209 additions and 10548 deletions

View file

@ -4,7 +4,7 @@
# and where the MCP will run (ram or flash) # and where the MCP will run (ram or flash)
# #
UNIT := a2560k UNIT := a2560k
MEMORY := flash MEMORY := ram
# CPU_WDC65816 0x16 /* CPU code for the Western Design Center 65816 */ # CPU_WDC65816 0x16 /* CPU code for the Western Design Center 65816 */
# CPU_M68000 0x20 /* CPU code for the Motorola 68000 */ # CPU_M68000 0x20 /* CPU code for the Motorola 68000 */
@ -32,6 +32,13 @@ export VBCC_CPU = 68040 # VBCC CPU flag
export MODEL_NUMBER = 11 # A2560K export MODEL_NUMBER = 11 # A2560K
export cpu = m68040 export cpu = m68040
else ifeq ($(UNIT),genx)
export CPU_NUMBER = 6 # M68040V
export VASM_CPU = -m68040 # VASM CPU flag
export VBCC_CPU = 68040 # VBCC CPU flag
export MODEL_NUMBER = 4 # GenX
export cpu = m68040
else ifeq ($(UNIT),a2560u) else ifeq ($(UNIT),a2560u)
export CPU_NUMBER = 0 # M680SEC00 export CPU_NUMBER = 0 # M680SEC00
export VASM_CPU = -m68000 # VASM CPU flag export VASM_CPU = -m68000 # VASM CPU flag

View file

@ -411,19 +411,28 @@ short cli_test_seek(short screen, int argc, const char * argv[]) {
/* /*
* Test the FDC interface by reading the MBR * Test the FDC interface by reading the MBR
*
* TEST FDC [DMA]
*/ */
short cli_test_fdc(short screen, int argc, const char * argv[]) { short cli_test_fdc(short screen, int argc, const char * argv[]) {
unsigned char buffer[512]; unsigned char buffer[512];
char message[80];
unsigned long lba = 0;
short i; short i;
short scancode; short scancode;
short n = 0; short n = 0;
short result; short result;
if (argc > 1) {
if ((strcmp(argv[1], "DMA") == 0) || ((strcmp(argv[1], "dma") == 0)) {
fdc_set_dma(1);
}
// lba = (unsigned long)cli_eval_number(argv[1]);
}
bdev_ioctrl(BDEV_FDC, FDC_CTRL_MOTOR_ON, 0, 0); bdev_ioctrl(BDEV_FDC, FDC_CTRL_MOTOR_ON, 0, 0);
result = fdc_init(); result = bdev_init(BDEV_FDC);
//result = bdev_init(BDEV_FDC);
if (result != 0) { if (result != 0) {
sprintf(buffer, "Could not initialize FDC: %s\n", sys_err_message(result)); sprintf(buffer, "Could not initialize FDC: %s\n", sys_err_message(result));
sys_chan_write(screen, buffer, strlen(buffer)); sys_chan_write(screen, buffer, strlen(buffer));
@ -434,10 +443,11 @@ short cli_test_fdc(short screen, int argc, const char * argv[]) {
buffer[i] = 0xAA; buffer[i] = 0xAA;
} }
n = bdev_read(BDEV_FDC, 0, buffer, 512); n = bdev_read(BDEV_FDC, lba, buffer, 512);
if (n < 0) { if (n < 0) {
dump_buffer(screen, buffer, 512, 1); dump_buffer(screen, buffer, 512, 1);
err_print(screen, "Unable to read MBR", n); sprintf(message, "Unable to read sector %d: %s\n", lba, err_message(n));
print(screen, message);
bdev_ioctrl(BDEV_FDC, FDC_CTRL_MOTOR_OFF, 0, 0); bdev_ioctrl(BDEV_FDC, FDC_CTRL_MOTOR_OFF, 0, 0);
return n; return n;
} }

View file

@ -15,6 +15,7 @@
#include "timers.h" #include "timers.h"
#include "fdc.h" #include "fdc.h"
#include "fdc_reg.h" #include "fdc_reg.h"
#include "interrupt.h"
#include "syscalls.h" #include "syscalls.h"
/* /*
@ -68,6 +69,7 @@ static short fdc_heads_per_cylinder = 2; /* How many heads are supported? */
static short fdc_sectors_per_track = 18; /* How many sectors per track */ static short fdc_sectors_per_track = 18; /* How many sectors per track */
static short fdc_cylinders = 80; /* How many cylinders */ static short fdc_cylinders = 80; /* How many cylinders */
static short fdc_bytes_per_sector = 512; /* How many bytes are in a sector */ static short fdc_bytes_per_sector = 512; /* How many bytes are in a sector */
static short fdc_use_dma = 0; /* If 0: used polled I/O, if anything else, use DMA */
/* /*
* Convert a logical block address to cylinder-head-sector addressing * Convert a logical block address to cylinder-head-sector addressing
@ -84,6 +86,23 @@ void lba_2_chs(unsigned long lba, unsigned char * cylinder, unsigned char * head
*sector = (unsigned char)((lba % fdc_sectors_per_track) + 1); *sector = (unsigned char)((lba % fdc_sectors_per_track) + 1);
} }
/**
* Set whether to use DMA or polled I/O for exchanging data
*
* @param dma 0 for polled I/O, anything else for DMA
*/
void fdc_set_dma(short dma) {
fdc_use_dma = dma;
}
/**
* Flag that the disk has changed
*/
void fdc_media_change() {
// Indicate that the disk has changed
fdc_stat = FDC_STAT_NOINIT;
}
/* /*
* Wait for the FDC to ready * Wait for the FDC to ready
* *
@ -434,7 +453,11 @@ short fdc_specify() {
} }
/* Set head load time to maximum, and no DMA */ /* Set head load time to maximum, and no DMA */
if (fdc_use_dma) {
*FDC_DATA = 0x0B; *FDC_DATA = 0x0B;
} else {
*FDC_DATA = 0x0A;
}
return 0; return 0;
} }
@ -480,7 +503,7 @@ short fdc_configure() {
return DEV_TIMEOUT; return DEV_TIMEOUT;
} }
/* Implied seek, enable FIFO, enable POLL, FIFO threshold = 4 bytes */ /* Implied seek, enable FIFO, enable POLL, FIFO threshold = 8 bytes */
*FDC_DATA = 0x47; *FDC_DATA = 0x47;
if (fdc_wait_write()) { if (fdc_wait_write()) {
@ -613,6 +636,95 @@ void fdc_log_transaction(p_fdc_trans trans) {
} }
} }
/*
* Issue a command to the floppy drive controller using DMA
*
* This routine supports transactions with variable number of parameters and results
* It can also support commands with an execution phase (read or write) and those
* without an exectution phase.
*
* Inputs:
* transaction = a pointer to an s_fdc_trans structure, containing the information
* needed for the transaction
*
* Returns:
* 0 on success, negative number on error
*/
short fdc_command_dma(p_fdc_trans transaction) {
volatile unsigned char * fdc_dma_buffer = (unsigned char *)0xFEC02400;
short abort = 0;
short i;
short result = 0;
unsigned char msr;
unsigned long target_jiffies;
TRACE("fdc_command");
// fdc_log_transaction(transaction);
if (fdc_wait_while_busy()) {
/* Timed out waiting for the FDC to be free */
log(LOG_ERROR, "fdc_command: fdc_wait_while_busy timeout");
return DEV_TIMEOUT;
}
result = fdc_out(transaction->command); /* Send the command byte */
if (result < 0) {
log(LOG_ERROR, "fdc_command: timeout sending command");
return result;
}
for (i = 0; i < transaction->parameter_count; i++) {
if ((result = fdc_out(transaction->parameters[i])) < 0) {
log(LOG_ERROR, "fdc_command: timeout sending parameters");
return result;
}
}
/* Check to see if there is an execution phase...
* that is, there is data to transfer one way or the other
*/
switch (transaction->direction) {
case FDC_TRANS_WRITE:
/* We're writing to the FDC */
break;
case FDC_TRANS_READ:
/* Wait for DMA to complete */
target_jiffies = timers_jiffies() + fdc_timeout;
while ((*PENDING_GRP1 & SPIO_FDC_INT16) == 0) {
if (timers_jiffies() < target_jiffies) {
return DEV_TIMEOUT;
}
}
/* Copy the data from the DMA buffer */
for (i = 0; i < 512; i++) {
transaction->data[i] = fdc_dma_buffer[i];
}
break;
default:
break;
}
/* Result phase: read the result bytes */
for (i = 0; i < transaction->result_count; i++) {
if ((result = fdc_in(&transaction->results[i])) < 0) {
log(LOG_ERROR, "fdc_command: timeout getting results");
return result;
}
}
/* Wait until the FDC is not busy */
result = fdc_wait_while_busy();
return result;
}
/* /*
* Issue a command to the floppy drive controller * Issue a command to the floppy drive controller
* *
@ -877,6 +989,16 @@ short fdc_read(long lba, unsigned char * buffer, short size) {
fdc_motor_on(); fdc_motor_on();
/* Check if the disk has changed and recalibrate if it has */
// if (*FDC_DIR & 0x80) {
// fdc_stat = FDC_STAT_NOINIT;
// if (fdc_recalibrate()) {
// return DEV_NOMEDIA;
// } else {
// return ERR_MEDIA_CHANGE;
// }
// }
trans.retries = 1; //FDC_DEFAULT_RETRIES; trans.retries = 1; //FDC_DEFAULT_RETRIES;
trans.command = 0x40 | FDC_CMD_READ_DATA; /* MFM read command */ trans.command = 0x40 | FDC_CMD_READ_DATA; /* MFM read command */
trans.direction = FDC_TRANS_READ; /* We're going to read from the drive */ trans.direction = FDC_TRANS_READ; /* We're going to read from the drive */
@ -896,16 +1018,22 @@ short fdc_read(long lba, unsigned char * buffer, short size) {
trans.result_count = 7; /* Expect 7 result bytes */ trans.result_count = 7; /* Expect 7 result bytes */
while (trans.retries > 0) { while (trans.retries > 0) {
if (fdc_use_dma) {
result = fdc_command_dma(&trans); /* Issue the transaction */
log_num(LOG_ERROR, "fdc_command_dma: ", result);
} else {
result = fdc_cmd_asm(trans.command, trans.parameter_count, &trans.parameters, buffer, trans.result_count, &trans.results); result = fdc_cmd_asm(trans.command, trans.parameter_count, &trans.parameters, buffer, trans.result_count, &trans.results);
log_num(LOG_ERROR, "fdc_cmd_asm: ", result); log_num(LOG_ERROR, "fdc_cmd_asm: ", result);
}
// result = fdc_command(&trans); /* Issue the transaction */ if ((result == 0)) { //} && ((trans.results[0] & 0xC0) == 0)) {
if ((result == 0) && ((trans.results[0] & 0xC0) == 0)) {
sprintf(message, "fdc_read: success? ST0 = %02x ST1 = %02x ST2 = %02x", trans.results[0], trans.results[1], trans.results[2]);
log(LOG_ERROR, message);
return size; return size;
} else { } else {
sprintf(message, "fdc_read: retry ST0 = %02x ST1 = %02x ST2 = %02x", trans.results[0], trans.results[1], trans.results[2]); sprintf(message, "fdc_read: retry ST0=%02X ST1=%02X ST2=%02X C=%02X H=%02X R=%02X N=%02X",
trans.results[0], trans.results[1], trans.results[2], trans.results[3], trans.results[4], trans.results[5], trans.results[6]);
log(LOG_ERROR, message);
sprintf(message, "fdc_read: retry EXTRA0=%02X EXTRA1=%02X",
trans.results[7], trans.results[8]);
log(LOG_ERROR, message); log(LOG_ERROR, message);
} }
fdc_init(); fdc_init();
@ -993,20 +1121,17 @@ short fdc_ioctrl(short command, unsigned char * buffer, short size) {
* 0 on success, any negative number is an error code * 0 on success, any negative number is an error code
*/ */
short fdc_init() { short fdc_init() {
unsigned char version;
// if (fdc_version(&version) < 0) {
// log(LOG_ERROR, "Unable to get FDC version");
// return DEV_TIMEOUT;
// }
//
// log_num(LOG_ERROR, "FDC version: ", version);
if (fdc_reset() < 0) { if (fdc_reset() < 0) {
log(LOG_ERROR, "Unable to reset the FDC"); log(LOG_ERROR, "Unable to reset the FDC");
return DEV_TIMEOUT; return DEV_TIMEOUT;
} }
// Recalibrate the drive
if (fdc_recalibrate()) {
log(LOG_ERROR, "Unable to recalibrate the drive");
return ERR_GENERAL;
}
fdc_stat &= ~FDC_STAT_NOINIT; fdc_stat &= ~FDC_STAT_NOINIT;
return 0; return 0;
} }

View file

@ -52,6 +52,13 @@ extern short fdc_install();
*/ */
extern short fdc_init(); extern short fdc_init();
/**
* Set whether to use DMA or polled I/O for exchanging data
*
* @param dma 0 for polled I/O, anything else for DMA
*/
extern void fdc_set_dma(short dma);
/* /*
* Read a block from the FDC * Read a block from the FDC
* *

View file

@ -76,7 +76,11 @@ DRESULT disk_read (
result = bdev_read(pdrv, sector, buff, 512); result = bdev_read(pdrv, sector, buff, 512);
if (result < 0) { if (result < 0) {
log_num(LOG_ERROR, "disk_read error: ", result); log_num(LOG_ERROR, "disk_read error: ", result);
if (result == ERR_MEDIA_CHANGE) {
return RES_NOTRDY;
} else {
return RES_PARERR; return RES_PARERR;
}
} else { } else {
sector++; sector++;
} }

5405
src/foenixmcp.s68 Normal file

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -47,5 +47,6 @@
#define ERR_NOT_SUPPORTED -37 /* Device does not support the file or operation */ #define ERR_NOT_SUPPORTED -37 /* Device does not support the file or operation */
#define ERR_BAD_ARGUMENT -38 /* An invalid argument was provided */ #define ERR_BAD_ARGUMENT -38 /* An invalid argument was provided */
#define ERR_MEDIA_CHANGE -39 /* Removable media has changed */
#endif #endif

View file

@ -62,7 +62,8 @@ const char * err_messages[] = {
"too many open files", "too many open files",
"file system invalid parameter", "file system invalid parameter",
"not supported", "not supported",
"bad argument" "bad argument",
"media changed"
}; };
/* /*
@ -71,7 +72,7 @@ const char * err_messages[] = {
const char * err_message(short err_number) { const char * err_message(short err_number) {
short index = 0 - err_number; short index = 0 - err_number;
if (index < 39) { if (index < 40) {
return err_messages[index]; return err_messages[index];
} else { } else {
return "unknown error"; return "unknown error";
@ -89,7 +90,7 @@ const char * err_message(short err_number) {
void err_print(short channel, const char * message, short err_number) { void err_print(short channel, const char * message, short err_number) {
char buffer[80]; char buffer[80];
if ((err_number < 0) && (err_number > -38)) { if ((err_number < 0) && (err_number > -40)) {
sprintf(buffer, "%s: %s\n", message, err_message(err_number)); sprintf(buffer, "%s: %s\n", message, err_message(err_number));
} else { } else {
sprintf(buffer, "%s: #%d\n", message, err_number); sprintf(buffer, "%s: #%d\n", message, err_number);

View file

@ -3,6 +3,7 @@
;;; ;;;
xdef _fdc_cmd_asm xdef _fdc_cmd_asm
xref _timers_jiffies
code code
@ -52,16 +53,14 @@ FDC_CCR = $FEC023F7 ; Write - Configuration Control Register
; @param buffer the buffer to fill with any read data (a2) ; @param buffer the buffer to fill with any read data (a2)
; @param resultc the count of result bytes expected ; @param resultc the count of result bytes expected
; @param results the buffer to fill with result bytes (a3) ; @param results the buffer to fill with result bytes (a3)
_fdc_cmd_asm link a6,#0 ; Set up the stack frame _fdc_cmd_asm ; Save our registers
; Save our registers
; TODO: save only those affected ; TODO: save only those affected
movem d4-d7/a4-a5,-(a7) movem d4-d7/a4-a5,-(a7)
; Clear the buffer ; Clear the buffer
move.w #$0,d0 move.w #$0,d0
clr_buffer move.b #$55,(a2,d0) clr_buffer move.b #0,(a2,d0)
addq.w #1,d0 addq.w #1,d0
cmp.w #512,d0 cmp.w #512,d0
bne clr_buffer bne clr_buffer
@ -69,7 +68,7 @@ clr_buffer move.b #$55,(a2,d0)
; Clear the results ; Clear the results
move.w #$0,d0 move.w #$0,d0
clr_results move.b #$AA,(a3,d0) clr_results move.b #0,(a3,d0)
addq.w #1,d0 addq.w #1,d0
cmp.w #10,d0 cmp.w #10,d0
bne clr_results bne clr_results
@ -102,33 +101,69 @@ snd_arg move.b (a1,d4),FDC_DATA ; Send the next argument byte
; Receive data bytes ; Receive data bytes
get_data move.b FDC_MSR,d0
btst #5,d0
bne result_phase
move.w #0,d4 ; Counter = 0 move.w #0,d4 ; Counter = 0
get_data ; TODO: should be checking NONDMA here... not sure why that fails here
wait_data move.b FDC_MSR,d0 wait_data move.b FDC_MSR,d0
btst #7,d0 ; Is RQM = 1 btst #7,d0 ; Is RQM = 1
beq wait_data ; No: wait until it is beq wait_data ; No: wait until it is
move.b FDC_DATA,(a2,d4) ; Move the data byte to the data buffer move.b FDC_DATA,(a2,d4) ; Move the data byte to the data buffer
addq.w #1,d4
move.b FDC_MSR,d0 ; Validate we're still in execution phase
btst #5,d0
beq result_phase ; If not, go to result phase
addq.w #1,d4 ; Move to the next byte
cmp.l #512,d4 cmp.l #512,d4
bne get_data ; And check to see if there is more data bne wait_data ; Keep looping if we are not done with the buffer
; Receive result bytes ; Receive result bytes
result_phase move.w #0,d4 ; Counter = 0 result_phase ; Start by waiting?
wait_result move.b FDC_MSR,d0 ; Get the MSR jsr _timers_jiffies ; Wait 5 jiffies? Just adding some delay
btst #7,d0 ; Is RQM set? move.l d0,d4
beq wait_result ; No: wait until it is addq.l #2,d4 ; Put the target jiffy count in D4
and.b #FDC_MSR_DIO|FDC_MSR_CMDBSY,d0
cmp.b #FDC_MSR_DIO|FDC_MSR_CMDBSY,d0
bne fdc_success ; If not BUSY and ready for READ, we're done
move.b FDC_DATA,(a3)+ ; Move the data byte to the result buffer wait_delay jsr _timers_jiffies ; Wait until we reach the target time
cmp.l d0,d4
bgt wait_delay
move.w #0,d4 ; Counter = 0
wait_result move.b FDC_MSR,d0 ; Get the MSR
andi.b #$D0,d0
cmp.b #FDC_MSR_RQM,d0
beq fdc_success ; If just RQM, we're done, and the command is done
cmp.b #$90,d0
beq fdc_error_2 ; If busy and DIO=0, it wants input... something's wrong
btst #7,d0 ; Check RQM
beq wait_result ; If RQM=0, keep waiting
move.b FDC_DATA,(a3,d4) ; Move the data byte to the result buffer
addq.w #1,d4 addq.w #1,d4
cmp.w d4,d3 ; Have we reached the end? cmp.w d4,d3 ; Have we reached the end?
beq fdc_success ; Yes, quit bne wait_result ; No: keep looping
bra wait_result ; And try to fetch another byte
chk_done ; Make sure the results are not an error
wait_done move.b FDC_MSR,d0 ; Get the MSR
btst #7,d0 ; Is RQM set?
beq wait_done ; No: wait until it is
addq.b #1,(2,a3)
btst #4,d0 ; Check CMDBUSY
beq fdc_success ; If it's 0, we're done
bra wait_done
fdc_error_2 move.l #$fffffffe,d0
bra fdc_cmd_exit
fdc_error move.l #$ffffffff,d0 ; Return -1 for error fdc_error move.l #$ffffffff,d0 ; Return -1 for error
bra fdc_cmd_exit bra fdc_cmd_exit
@ -138,5 +173,4 @@ fdc_success move.l #0,d0 ; Return 0 for success
; Restore our registers ; Restore our registers
; TODO: restore what we saved ; TODO: restore what we saved
fdc_cmd_exit movem (a7)+,d4-d7/a4-a5 fdc_cmd_exit movem (a7)+,d4-d7/a4-a5
unlk a6 ; Restore our stack frame
rts rts

21067
src/mapfile

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,6 @@
#define VER_MAJOR 0 #define VER_MAJOR 0
#define VER_MINOR 53 #define VER_MINOR 53
#define VER_BUILD 7 #define VER_BUILD 8
#endif #endif