This commit is contained in:
Jeff Epler 2022-01-13 09:39:53 -06:00
parent 5b021bb35a
commit 6f085764b9
3 changed files with 93 additions and 0 deletions

View file

@ -23,6 +23,9 @@
#define clr_debug_led() ((void)0)
#endif
#define MFM_IO_MMIO (1)
#include "mfm_impl.h"
/**************************************************************************/
/*!
@brief Create a hardware interface to a floppy drive
@ -271,6 +274,36 @@ void Adafruit_Floppy::step(bool dir, uint8_t times) {
/**************************************************************************/
int8_t Adafruit_Floppy::track(void) { return _track; }
/**************************************************************************/
/*!
@brief Capture and decode one track of MFM data
@param sectors A pointer to an array of memory we can use to store into, 512*n_sectors bytes
@param n_sectors The number of sectors (e.g., 18 for a standard 3.5", 1.44MB format)
@param sector_validity An array of values set to 1 if the sector was captured, 0 if not captured (no IDAM, CRC error, etc)
@return Number of sectors we actually captured
*/
/**************************************************************************/
uint32_t Adafruit_Floppy::read_track_mfm(uint8_t *sectors, size_t n_sectors, uint8_t *sector_validity) {
mfm_io_t io;
#ifdef BUSIO_USE_FAST_PINIO
io.index_port = indexPort;
io.index_mask = indexMask;
io.data_port = dataPort;
io.data_mask = dataMask;
#elif defined(ARDUINO_ARCH_RP2040)
io.index_port = &sio_hw->gpio_in;
io.index_mask = 1u << _indexpin;
io.data_port = &sio_hw->gpio_in;
io.data_mask = 1u << _rddatapin;
#endif
noInterrupts();
int result = read_track(io, n_sectors, buf, sector_validity);
Interrupts();
return result;
}
/**************************************************************************/
/*!
@brief Capture one track's worth of flux transitions, between two falling

View file

@ -36,6 +36,7 @@ public:
int8_t track(void);
void step(bool dir, uint8_t times);
uint32_t read_track_mfm(uint8_t *sectors, size_t n_sectors, uint8_t *sector_validity);
uint32_t capture_track(uint8_t *pulses, uint32_t max_pulses)
__attribute__((optimize("O3")));
void print_pulse_bins(uint8_t *pulses, uint32_t num_pulses,

View file

@ -7,8 +7,66 @@
#include <stdbool.h>
#include <stddef.h>
#pragma GCC push_options
#pragma GCC optimize("-O3")
typedef struct mfm_io mfm_io_t;
#ifndef MFM_IO_MMIO
#define MFM_IO_MMIO (0)
#endif
// If you have a memory mapped peripheral, define MFM_IO_MMIO to get an implementation of the mfm_io functions.
// then, just populate the fields with the actual registers to use
#if MFM_IO_MMIO
struct mfm_io {
volatile uint32_t *index_port;
uint32_t index_mask;
volatile uint32_t *data_port;
uint32_t data_mask;
unsigned index_state;
unsigned index_count;
};
#define READ_DATA() (!!(*io->data_port & io->data_mask))
#define READ_INDEX() (!!(*io->index_port & io->index_mask))
__attribute__((always_inline))
static inline mfm_io_symbol_t mfm_io_read_symbol(mfm_io_t *io) {
unsigned pulse_count = 3;
while (!READ_DATA()) {
pulse_count++;
}
unsigned index_state = (io->index_state << 1) | READ_INDEX();
if ((index_state & 3) == 2) { // a zero-to-one transition
io->index_count++;
}
io->index_state = index_state;
while (READ_DATA()) {
pulse_count++;
}
mfm_io_symbol_t result = pulse_10;
if (pulse_count > T2_5) {
result++;
}
if (pulse_count > T3_5) {
result++;
}
return result;
}
static void mfm_io_reset_sync_count(mfm_io_t *io) {
io->index_count = 0;
}
__attribute__((optimize("O3"), always_inline))
inline static int mfm_io_get_sync_count(mfm_io_t *io) {
return io->index_count;
}
#endif
typedef enum { pulse_10, pulse_100, pulse_1000 } mfm_io_symbol_t;
typedef enum { odd=0, even=1 } mfm_state_t;
@ -189,3 +247,4 @@ static int read_track(mfm_io_t io, int n_sectors, void *data, uint8_t *validity)
}
return n_valid;
}
#pragma GCC pop_options