mirror of
https://github.com/una1veritas/mac-floppy-emu.git
synced 2024-09-22 20:56:18 +00:00
236 lines
5.7 KiB
C++
236 lines
5.7 KiB
C++
|
/*
|
||
|
Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved.
|
||
|
|
||
|
Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported
|
||
|
license. (CC BY-NC 3.0) The terms of the license may be viewed at
|
||
|
http://creativecommons.org/licenses/by-nc/3.0/
|
||
|
|
||
|
Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/
|
||
|
|
||
|
Permissions beyond the scope of this license may be available at www.bigmessowires.com
|
||
|
or from mailto:steve@bigmessowires.com.
|
||
|
*/
|
||
|
|
||
|
#ifdef ARDUINO
|
||
|
|
||
|
#include <stdint.h>
|
||
|
|
||
|
#include <SPI.h>
|
||
|
#include <SD_SPI.h>
|
||
|
#include "noklcd.h"
|
||
|
|
||
|
#else
|
||
|
|
||
|
#include <math.h>
|
||
|
|
||
|
#include <avr/io.h>
|
||
|
#include <avr/pgmspace.h>
|
||
|
#include <avr/interrupt.h>
|
||
|
#include <util/delay.h>
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include "portmacros.h"
|
||
|
#include "noklcd.h"
|
||
|
#include "millitimer.h"
|
||
|
#include "SdFat.h"
|
||
|
#include "SdBaseFile.h"
|
||
|
#include "micro.h"
|
||
|
#include "ports.h"
|
||
|
#include "diskmenu.h"
|
||
|
#include "cardtest.h"
|
||
|
|
||
|
#ifdef ENABLE_ORIGINAL_COMPILER_WORKAROUND
|
||
|
|
||
|
// work-around for compiler bug
|
||
|
#undef PROGMEM
|
||
|
#define PROGMEM __attribute__(( section(".progmem.data") ))
|
||
|
#undef PSTR
|
||
|
#define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); &__c[0];}))
|
||
|
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#define STATUS_LED_PORT B
|
||
|
#define STATUS_LED_PIN 3
|
||
|
|
||
|
#define TEXTBUF_SIZE 22
|
||
|
extern char textBuf[];
|
||
|
extern uint8_t sectorBuf[512];
|
||
|
|
||
|
void CardTest()
|
||
|
{
|
||
|
LcdClear();
|
||
|
|
||
|
//SdFat sd;
|
||
|
SDClass sd(4);
|
||
|
|
||
|
if (!sd.init(SPI_HALF_SPEED))
|
||
|
{
|
||
|
snprintf(textBuf, TEXTBUF_SIZE, "SD card error %d:%d", sd.card()->errorCode(), sd.card()->errorData());
|
||
|
LcdGoto(0,0);
|
||
|
LcdTinyString(textBuf, TEXT_NORMAL);
|
||
|
while(1);
|
||
|
}
|
||
|
|
||
|
cid_t cid;
|
||
|
|
||
|
uint32_t cardSize = sd.card()->cardSize();
|
||
|
cardSize /= (2L*1024L);
|
||
|
|
||
|
sd.card()->readCID(&cid);
|
||
|
|
||
|
snprintf(textBuf, TEXTBUF_SIZE, "CID %d %c%c%c%c%c %lu MB", cid.mid, cid.pnm[0], cid.pnm[1], cid.pnm[2], cid.pnm[3], cid.pnm[4], cardSize);
|
||
|
LcdGoto(0,0);
|
||
|
LcdTinyString(textBuf, TEXT_NORMAL);
|
||
|
|
||
|
csd_t csd;
|
||
|
sd.card()->readCSD(&csd);
|
||
|
|
||
|
uint8_t writeBlockPow; // write block length, log2
|
||
|
uint8_t sectorSizeCnt; // minimum erasable size, in write blocks
|
||
|
|
||
|
if (csd.v1.csd_ver == 1)
|
||
|
{
|
||
|
csd1_t* c = &csd.v1;
|
||
|
|
||
|
writeBlockPow = 4*c->write_bl_len_high + c->write_bl_len_low;
|
||
|
sectorSizeCnt = 2*c->sector_size_high + c->sector_size_low;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
csd2_t* c = &csd.v2;
|
||
|
|
||
|
writeBlockPow = 4*c->write_bl_len_high + c->write_bl_len_low;
|
||
|
sectorSizeCnt = 2*c->sector_size_high + c->sector_size_low;
|
||
|
}
|
||
|
|
||
|
sectorSizeCnt += 1; // these all seem to be 2**n - 1?
|
||
|
|
||
|
uint32_t writeBlock=1;
|
||
|
for (uint8_t i=0; i<writeBlockPow; i++)
|
||
|
{
|
||
|
writeBlock *= 2;
|
||
|
}
|
||
|
uint32_t sectorSize = writeBlock * sectorSizeCnt;
|
||
|
sectorSize /= 1024;
|
||
|
|
||
|
snprintf(textBuf, TEXTBUF_SIZE, "BLK %luB ERASE %luK", writeBlock, sectorSize);
|
||
|
LcdGoto(0,1);
|
||
|
LcdTinyString(textBuf, TEXT_NORMAL);
|
||
|
|
||
|
LcdGoto(0,2);
|
||
|
|
||
|
SdBaseFile f;
|
||
|
if (!f.open("TESTFILE.DAT", O_RDWR))
|
||
|
{
|
||
|
LcdTinyStringP(PSTR("TESTFILE.DAT missing"), TEXT_NORMAL);
|
||
|
while(1);
|
||
|
}
|
||
|
|
||
|
// get address of file on SD
|
||
|
uint32_t imageFirstBlock, imageLastBlock;
|
||
|
if (!f.contiguousRange(&imageFirstBlock, &imageLastBlock))
|
||
|
{
|
||
|
LcdTinyStringP(PSTR("file not contiguous"), TEXT_NORMAL);
|
||
|
while(1);
|
||
|
}
|
||
|
|
||
|
if (f.fileSize() < (unsigned long)1024 * 1024)
|
||
|
{
|
||
|
LcdTinyStringP(PSTR("file too small"), TEXT_NORMAL);
|
||
|
while(1);
|
||
|
}
|
||
|
|
||
|
f.close();
|
||
|
|
||
|
LcdTinyStringP(PSTR("Testing..."), TEXT_NORMAL);
|
||
|
|
||
|
uint32_t writeCount = 0;
|
||
|
uint32_t writeTotalTime = 0;
|
||
|
uint32_t worstTime = 0;
|
||
|
uint32_t above20Count = 0;
|
||
|
|
||
|
for (int trial=0; trial<3; trial++)
|
||
|
{
|
||
|
uint32_t b = 0;
|
||
|
for (uint32_t cnt=0; cnt<1600 && b<1600; cnt++)
|
||
|
{
|
||
|
if (!sd.card()->readBlock(imageFirstBlock + b, sectorBuf))
|
||
|
{
|
||
|
LcdGoto(0,2);
|
||
|
LcdTinyStringP(PSTR("SD read error"), TEXT_NORMAL);
|
||
|
while(1);
|
||
|
}
|
||
|
|
||
|
// alter the data, to prevent any kind of compression/optimization on the card
|
||
|
for (uint16_t i=0; i<512; i++)
|
||
|
{
|
||
|
sectorBuf[i] ^= sectorBuf[i+1];
|
||
|
}
|
||
|
|
||
|
// blink the LED
|
||
|
if ((writeCount & 0x7) == 0)
|
||
|
PORT(STATUS_LED_PORT) ^= (1<<STATUS_LED_PIN);
|
||
|
|
||
|
uint32_t t0;
|
||
|
|
||
|
_delay_ms(3);
|
||
|
|
||
|
// write it
|
||
|
t0 = millis();
|
||
|
|
||
|
if (!sd.card()->writeBlock(imageFirstBlock + b, sectorBuf))
|
||
|
{
|
||
|
LcdGoto(0,2);
|
||
|
LcdTinyStringP(PSTR("SD write error"), TEXT_NORMAL);
|
||
|
while(1);
|
||
|
}
|
||
|
|
||
|
uint32_t writeTime = millis() - t0;
|
||
|
|
||
|
// update stats
|
||
|
writeCount++;
|
||
|
writeTotalTime += writeTime;
|
||
|
if (writeTime > 20)
|
||
|
above20Count++;
|
||
|
if (writeTime > worstTime)
|
||
|
worstTime = writeTime;
|
||
|
|
||
|
// pseudo-interleave
|
||
|
if ((cnt & 1) == 0)
|
||
|
b += 6;
|
||
|
else
|
||
|
b -= 5;
|
||
|
|
||
|
_delay_ms(3);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint32_t avg = (writeTotalTime + (writeCount >> 1))/ writeCount;
|
||
|
|
||
|
LcdGoto(0,2);
|
||
|
LcdTinyStringP(PSTR("AVG.ms/MAX.ms/LONG.%"), TEXT_NORMAL);
|
||
|
|
||
|
snprintf(textBuf, TEXTBUF_SIZE, "512B RRWI %lu/%lu/%lu", avg, worstTime, above20Count*100/writeCount);
|
||
|
LcdGoto(0,3);
|
||
|
LcdTinyString(textBuf, TEXT_NORMAL);
|
||
|
|
||
|
// Card: actual capacity, block size, erase size, best test result (random read-write interleaved) average/max/percent "long" over 20ms
|
||
|
// ----------------------------------------------------------
|
||
|
// PNY class 10 8GB: 7708 MB, 512B block, 64K erase. 512B RRWI 10/189/1 (random read-write interleave)
|
||
|
// SanDisk unrated Ultra II 2GB: 1938 MB, 1024B block, 32K erase. 512B RRWI 7/79/0
|
||
|
// Transcend unrated 2GB: 1875 MB, 1024B block, 128K erase. 512B RRWI 3/103/0
|
||
|
// SanDisk unrated 128MB: 120 MB, 512B block, 16K erase. 512B RRWI 5/94/1
|
||
|
|
||
|
// enabling the TACH stuff seems to cause some cards to get errors during this test. Coupling between traces? Why doesn't it happen during normal operation?
|
||
|
|
||
|
// Transcend unrated 2GB: Finder consistently "goes to sleep" after copying first 19 tracks, but worked twice after 3 tries. Maybe it's too fast?
|
||
|
|
||
|
|
||
|
|
||
|
while(1);
|
||
|
}
|