FDC Experimental Code
This commit is contained in:
parent
ce1f4b3219
commit
fcd89cc069
|
@ -4,7 +4,7 @@
|
|||
# and where the MCP will run (ram or flash)
|
||||
#
|
||||
UNIT := a2560k
|
||||
MEMORY := flash
|
||||
MEMORY := ram
|
||||
|
||||
# CPU_WDC65816 0x16 /* CPU code for the Western Design Center 65816 */
|
||||
# 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 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)
|
||||
export CPU_NUMBER = 0 # M680SEC00
|
||||
export VASM_CPU = -m68000 # VASM CPU flag
|
||||
|
|
|
@ -411,19 +411,28 @@ short cli_test_seek(short screen, int argc, const char * argv[]) {
|
|||
|
||||
/*
|
||||
* Test the FDC interface by reading the MBR
|
||||
*
|
||||
* TEST FDC [DMA]
|
||||
*/
|
||||
short cli_test_fdc(short screen, int argc, const char * argv[]) {
|
||||
unsigned char buffer[512];
|
||||
char message[80];
|
||||
unsigned long lba = 0;
|
||||
short i;
|
||||
short scancode;
|
||||
short n = 0;
|
||||
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);
|
||||
|
||||
result = fdc_init();
|
||||
|
||||
//result = bdev_init(BDEV_FDC);
|
||||
result = bdev_init(BDEV_FDC);
|
||||
if (result != 0) {
|
||||
sprintf(buffer, "Could not initialize FDC: %s\n", sys_err_message(result));
|
||||
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;
|
||||
}
|
||||
|
||||
n = bdev_read(BDEV_FDC, 0, buffer, 512);
|
||||
n = bdev_read(BDEV_FDC, lba, buffer, 512);
|
||||
if (n < 0) {
|
||||
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);
|
||||
return n;
|
||||
}
|
||||
|
|
161
src/dev/fdc.c
161
src/dev/fdc.c
|
@ -15,6 +15,7 @@
|
|||
#include "timers.h"
|
||||
#include "fdc.h"
|
||||
#include "fdc_reg.h"
|
||||
#include "interrupt.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_cylinders = 80; /* How many cylinders */
|
||||
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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
@ -434,7 +453,11 @@ short fdc_specify() {
|
|||
}
|
||||
|
||||
/* Set head load time to maximum, and no DMA */
|
||||
*FDC_DATA = 0x0B;
|
||||
if (fdc_use_dma) {
|
||||
*FDC_DATA = 0x0B;
|
||||
} else {
|
||||
*FDC_DATA = 0x0A;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -480,7 +503,7 @@ short fdc_configure() {
|
|||
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;
|
||||
|
||||
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
|
||||
*
|
||||
|
@ -877,6 +989,16 @@ short fdc_read(long lba, unsigned char * buffer, short size) {
|
|||
|
||||
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.command = 0x40 | FDC_CMD_READ_DATA; /* MFM read command */
|
||||
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 */
|
||||
|
||||
while (trans.retries > 0) {
|
||||
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);
|
||||
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);
|
||||
log_num(LOG_ERROR, "fdc_cmd_asm: ", result);
|
||||
}
|
||||
|
||||
// result = fdc_command(&trans); /* Issue the transaction */
|
||||
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);
|
||||
if ((result == 0)) { //} && ((trans.results[0] & 0xC0) == 0)) {
|
||||
return size;
|
||||
} 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);
|
||||
}
|
||||
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
|
||||
*/
|
||||
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) {
|
||||
log(LOG_ERROR, "Unable to reset the FDC");
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,13 @@ extern short fdc_install();
|
|||
*/
|
||||
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
|
||||
*
|
||||
|
|
|
@ -76,7 +76,11 @@ DRESULT disk_read (
|
|||
result = bdev_read(pdrv, sector, buff, 512);
|
||||
if (result < 0) {
|
||||
log_num(LOG_ERROR, "disk_read error: ", result);
|
||||
return RES_PARERR;
|
||||
if (result == ERR_MEDIA_CHANGE) {
|
||||
return RES_NOTRDY;
|
||||
} else {
|
||||
return RES_PARERR;
|
||||
}
|
||||
} else {
|
||||
sector++;
|
||||
}
|
||||
|
|
5405
src/foenixmcp.s68
Normal file
5405
src/foenixmcp.s68
Normal file
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
@ -47,5 +47,6 @@
|
|||
|
||||
#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_MEDIA_CHANGE -39 /* Removable media has changed */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -62,7 +62,8 @@ const char * err_messages[] = {
|
|||
"too many open files",
|
||||
"file system invalid parameter",
|
||||
"not supported",
|
||||
"bad argument"
|
||||
"bad argument",
|
||||
"media changed"
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -71,7 +72,7 @@ const char * err_messages[] = {
|
|||
const char * err_message(short err_number) {
|
||||
short index = 0 - err_number;
|
||||
|
||||
if (index < 39) {
|
||||
if (index < 40) {
|
||||
return err_messages[index];
|
||||
} else {
|
||||
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) {
|
||||
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));
|
||||
} else {
|
||||
sprintf(buffer, "%s: #%d\n", message, err_number);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
;;;
|
||||
|
||||
xdef _fdc_cmd_asm
|
||||
xref _timers_jiffies
|
||||
|
||||
code
|
||||
|
||||
|
@ -52,16 +53,14 @@ FDC_CCR = $FEC023F7 ; Write - Configuration Control Register
|
|||
; @param buffer the buffer to fill with any read data (a2)
|
||||
; @param resultc the count of result bytes expected
|
||||
; @param results the buffer to fill with result bytes (a3)
|
||||
_fdc_cmd_asm link a6,#0 ; Set up the stack frame
|
||||
|
||||
; Save our registers
|
||||
_fdc_cmd_asm ; Save our registers
|
||||
; TODO: save only those affected
|
||||
movem d4-d7/a4-a5,-(a7)
|
||||
|
||||
; Clear the buffer
|
||||
|
||||
move.w #$0,d0
|
||||
clr_buffer move.b #$55,(a2,d0)
|
||||
clr_buffer move.b #0,(a2,d0)
|
||||
addq.w #1,d0
|
||||
cmp.w #512,d0
|
||||
bne clr_buffer
|
||||
|
@ -69,7 +68,7 @@ clr_buffer move.b #$55,(a2,d0)
|
|||
; Clear the results
|
||||
|
||||
move.w #$0,d0
|
||||
clr_results move.b #$AA,(a3,d0)
|
||||
clr_results move.b #0,(a3,d0)
|
||||
addq.w #1,d0
|
||||
cmp.w #10,d0
|
||||
bne clr_results
|
||||
|
@ -102,33 +101,69 @@ snd_arg move.b (a1,d4),FDC_DATA ; Send the next argument byte
|
|||
|
||||
; Receive data bytes
|
||||
|
||||
get_data move.b FDC_MSR,d0
|
||||
btst #5,d0
|
||||
bne result_phase
|
||||
|
||||
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
|
||||
btst #7,d0 ; Is RQM = 1
|
||||
beq wait_data ; No: wait until it is
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
result_phase move.w #0,d4 ; Counter = 0
|
||||
wait_result move.b FDC_MSR,d0 ; Get the MSR
|
||||
btst #7,d0 ; Is RQM set?
|
||||
beq wait_result ; No: wait until it is
|
||||
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
|
||||
result_phase ; Start by waiting?
|
||||
jsr _timers_jiffies ; Wait 5 jiffies? Just adding some delay
|
||||
move.l d0,d4
|
||||
addq.l #2,d4 ; Put the target jiffy count in D4
|
||||
|
||||
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
|
||||
cmp.w d4,d3 ; Have we reached the end?
|
||||
beq fdc_success ; Yes, quit
|
||||
bra wait_result ; And try to fetch another byte
|
||||
bne wait_result ; No: keep looping
|
||||
|
||||
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
|
||||
bra fdc_cmd_exit
|
||||
|
@ -138,5 +173,4 @@ fdc_success move.l #0,d0 ; Return 0 for success
|
|||
; Restore our registers
|
||||
; TODO: restore what we saved
|
||||
fdc_cmd_exit movem (a7)+,d4-d7/a4-a5
|
||||
unlk a6 ; Restore our stack frame
|
||||
rts
|
||||
|
|
21067
src/mapfile
21067
src/mapfile
File diff suppressed because it is too large
Load diff
|
@ -7,6 +7,6 @@
|
|||
|
||||
#define VER_MAJOR 0
|
||||
#define VER_MINOR 53
|
||||
#define VER_BUILD 7
|
||||
#define VER_BUILD 8
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue