Project

General

Profile

Feature #73 » atx.patch

foft, 09/01/2018 01:43 PM

View differences:

atx.c 2018-09-01 14:35:20.121479335 +0200
//
//*****************************************************************************
#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#include "avrlibtypes.h"
#include "atx_eclaire.h"
#include "atx.h"
#include "fat.h"
// number of angular units in a full disk rotation
#define AU_FULL_ROTATION 26042
......
u16 gBytesPerSector; // number of bytes per sector
u08 gSectorsPerTrack; // number of sectors in each track
struct atxTrackInfo gTrackInfo[2][40]; // pre-calculated info for each track and drive
// support slot D1 and D2 only because of insufficient RAM!
u16 gLastAngle = 0;
u08 gCurrentHeadTrack = 1;
struct atxTrackInfo gTrackInfo[40]; // pre-calculated info for each track
u16 gLastAngle;
u08 gCurrentHeadTrack;
#define FILE_ACCESS_READ 0
void longbyteswap(u32 * x);
void byteswap(u16 * x);
void byteswapatxfileheader(struct atxFileHeader * header)
{
// only swap the used entries
byteswap(&header->version);
byteswap(&header->minVersion);
longbyteswap(&header->startData);
}
void byteswapatxtrackheader(struct atxTrackHeader * header)
{
// only swap the used entries
longbyteswap(&header->size); // used
byteswap(&header->sectorCount); // used
longbyteswap(&header->headerSize); // used
}
void byteswapatxsectorlistheader(struct atxSectorListHeader * header)
{
longbyteswap(&header->next);
}
void byteswapatxsectorheader(struct atxSectorHeader * header)
{
byteswap(&header->timev);
longbyteswap(&header->data);
}
u16 loadAtxFile(u08 drive) {
void byteswapatxtrackchunk(struct atxTrackChunk *header)
{
byteswap(&header->data);
longbyteswap(&header->size);
}
u16 loadAtxFile() {
struct atxFileHeader *fileHeader;
struct atxTrackHeader *trackHeader;
// read the file header
faccess_offset(FILE_ACCESS_READ, 0, sizeof(struct atxFileHeader));
byteswapatxfileheader((struct atxFileHeader *) atari_sector_buffer);
// validate the ATX file header
fileHeader = (struct atxFileHeader *) atari_sector_buffer;
......
fileHeader->signature[3] != 'X' ||
fileHeader->version != ATX_VERSION ||
fileHeader->minVersion != ATX_VERSION) {
return 0;
}
......
break;
}
trackHeader = (struct atxTrackHeader *) atari_sector_buffer;
gTrackInfo[drive][trackHeader->trackNumber].offset = startOffset;
byteswapatxtrackheader(trackHeader);
gTrackInfo[trackHeader->trackNumber].offset = startOffset;
startOffset += trackHeader->size;
}
return gBytesPerSector;
}
u16 loadAtxSector(u08 drive, u16 num, unsigned short *sectorSize, u08 *status) {
u16 loadAtxSector(u16 num, unsigned short *sectorSize, u08 *status) {
struct atxTrackHeader *trackHeader;
struct atxSectorListHeader *slHeader;
struct atxSectorHeader *sectorHeader;
......
u16 headPosition = getCurrentHeadPosition();
// read the track header
u32 currentFileOffset = gTrackInfo[drive][tgtTrackNumber - 1].offset;
u32 currentFileOffset = gTrackInfo[tgtTrackNumber - 1].offset;
faccess_offset(FILE_ACCESS_READ, currentFileOffset, sizeof(struct atxTrackHeader));
trackHeader = (struct atxTrackHeader *) atari_sector_buffer;
byteswapatxtrackheader(trackHeader);
u16 sectorCount = trackHeader->sectorCount;
// if there are no sectors in this track or the track number doesn't match, return error
......
currentFileOffset += trackHeader->headerSize;
faccess_offset(FILE_ACCESS_READ, currentFileOffset, sizeof(struct atxSectorListHeader));
slHeader = (struct atxSectorListHeader *) atari_sector_buffer;
byteswapatxsectorlistheader(slHeader);
// sector list header is variable length, so skip any extra header bytes that may be present
currentFileOffset += slHeader->next - sectorCount * sizeof(struct atxSectorHeader);
......
for (i=0; i < sectorCount; i++) {
if (faccess_offset(FILE_ACCESS_READ, currentFileOffset, sizeof(struct atxSectorHeader))) {
sectorHeader = (struct atxSectorHeader *) atari_sector_buffer;
byteswapatxsectorheader(sectorHeader);
// if the sector number matches the one we're looking for...
if (sectorHeader->number == tgtSectorNumber) {
// check if it's the next sector that the head would encounter angularly...
......
// if an extended data record exists for this track, iterate through all track chunks to search
// for those records (note that we stop looking for chunks when we hit the 8-byte terminator; length == 0)
if (extendedDataRecords > 0) {
currentFileOffset = gTrackInfo[drive][tgtTrackNumber - 1].offset + trackHeader->headerSize;
currentFileOffset = gTrackInfo[tgtTrackNumber - 1].offset + trackHeader->headerSize;
do {
faccess_offset(FILE_ACCESS_READ, currentFileOffset, sizeof(struct atxTrackChunk));
extSectorData = (struct atxTrackChunk *) atari_sector_buffer;
byteswapatxtrackchunk(extSectorData);
if (extSectorData->size > 0) {
// if the target sector has a weak data flag, grab the start weak offset within the sector data
if (extSectorData->sectorIndex == tgtSectorIndex && extSectorData->type == 0x10) {
......
*sectorSize = gBytesPerSector;
// read the data (re-using tgtSectorIndex variable here to reduce stack consumption)
tgtSectorIndex = tgtSectorOffset ? (u16) faccess_offset(FILE_ACCESS_READ, gTrackInfo[drive][tgtTrackNumber - 1].offset + tgtSectorOffset, gBytesPerSector) : (u16) 0;
tgtSectorIndex = tgtSectorOffset ? (u16) faccess_offset(FILE_ACCESS_READ, gTrackInfo[tgtTrackNumber - 1].offset + tgtSectorOffset, gBytesPerSector) : (u16) 0;
tgtSectorIndex = hasError ? (u16) 0 : tgtSectorIndex;
// if a weak offset is defined, randomize the appropriate data
......
return ret;
}
void waitForAngularPosition(u16 pos) {
// if the position is less than the current timer, we need to wait for a rollover
// to occur
if (pos < TCNT1 / 2) {
TIFR1 |= _BV(OCF1A);
while (!(TIFR1 & _BV(OCF1A)));
}
// wait for the timer to reach the target position
while (TCNT1 / 2 < pos);
}
u16 getCurrentHeadPosition() {
// TCNT1 is a variable driven by an Atmel timer that ticks every 4 microseconds. A full
// rotation of the disk is represented in an ATX file by an angular positional value
// between 1-26042 (or 8 microseconds based on 288 rpms). So, TCNT1 / 2 always gives the
// current angular position of the drive head on the track any given time assuming the
// disk is spinning continously.
return TCNT1 / 2;
}
(3-3/4)