Table based CRC and a few race protections
This commit is contained in:
@@ -13,10 +13,11 @@ BIN=bin/$(SKETCH).ino.bin
|
||||
|
||||
$(BIN): $(SKETCH).ino datastream.h
|
||||
#arduino-cli compile --fqbn $(BOARD) --board-options "freq=300,arch=riscv" --output-dir bin --build-path build
|
||||
arduino-cli compile --fqbn $(BOARD) --board-options "freq=300" --output-dir bin --build-path build
|
||||
arduino-cli compile --fqbn $(BOARD) --board-options "freq=300,opt=Fast" --output-dir bin --build-path build
|
||||
|
||||
upload: $(BIN)
|
||||
arduino-cli upload --fqbn $(BOARD) -p $(PORT) --input-dir bin
|
||||
umount /pi
|
||||
|
||||
clean:
|
||||
rm -rf build bin
|
||||
@@ -26,3 +27,6 @@ watch:
|
||||
|
||||
datastream.h: datastream.pio
|
||||
${PIOASM} datastream.pio datastream.h
|
||||
|
||||
install:
|
||||
mount /pi && cp bin/Test.ino.uf2 /pi && umount /pi
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#include <CLI.h>
|
||||
#include <SdFat.h>
|
||||
#include "datastream.h"
|
||||
#include <errno.h>
|
||||
#include <pico/platform.h>
|
||||
|
||||
|
||||
CLIClient *console;
|
||||
|
||||
#define SDIO_CLK 16
|
||||
#define SDIO_CMD 17
|
||||
@@ -37,9 +42,10 @@ int dma;
|
||||
|
||||
uint32_t loadtime;
|
||||
|
||||
uint32_t current_head = 0;
|
||||
uint32_t current_cyl = 0;
|
||||
uint32_t current_sector = 0;
|
||||
volatile uint32_t current_head = 0;
|
||||
volatile uint32_t current_cyl = 0;
|
||||
volatile uint32_t current_sector = 0;
|
||||
volatile uint32_t target_cyl = 0;
|
||||
|
||||
#define POLY16 0x1021
|
||||
#define POLY32 0xa00805
|
||||
@@ -57,8 +63,11 @@ uint32_t current_sector = 0;
|
||||
|
||||
SdFs sd;
|
||||
FsFile mounted_file;
|
||||
uint8_t *track_buffer;
|
||||
|
||||
struct disk_format {
|
||||
char *name;
|
||||
char *comment;
|
||||
uint16_t cyls;
|
||||
uint8_t heads;
|
||||
uint8_t sectors;
|
||||
@@ -82,24 +91,13 @@ struct disk_format {
|
||||
float clock_div;
|
||||
};
|
||||
|
||||
|
||||
struct disk_format RD54 = {
|
||||
1225, // Cyl
|
||||
15, // Heads
|
||||
17, // Sectors,
|
||||
SECTOR_512, // Bytes per sector
|
||||
10, // Index width - how long the index pulse is low
|
||||
290, // Track pregap - Time between index pulse and first sync byte
|
||||
1100, // Track postgap - Time between last sync byte and index pulse
|
||||
41, // Header postgap - Time between header sync byte and data sync byte
|
||||
911, // Data postgap - Time between data sync byte and header sync byte of next sector
|
||||
5000000, // Data Rate
|
||||
OPT_HEADER_CRC16 | OPT_DATA_CRC32,
|
||||
0x1021, // Header CRC polynomial
|
||||
0xa00805, // Data CRC polynomial
|
||||
|
||||
struct format_list {
|
||||
struct disk_format *fmt;
|
||||
struct format_list *next;
|
||||
};
|
||||
|
||||
struct format_list *formats = NULL;
|
||||
|
||||
struct encoded_sector {
|
||||
uint16_t header[10];
|
||||
uint16_t data[520];
|
||||
@@ -128,6 +126,16 @@ struct cylinder cyl_data;
|
||||
|
||||
struct disk_format *format;
|
||||
|
||||
bool _sd_is_open = false;
|
||||
bool open_sd_if_needed() {
|
||||
if (_sd_is_open) return true;
|
||||
if (!sd.begin(SdioConfig(SDIO_CLK, SDIO_CMD, SDIO_DAT0, 1.5))) {
|
||||
sd.initErrorPrint();
|
||||
return false;;
|
||||
}
|
||||
_sd_is_open = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void bindump(uint16_t v) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
@@ -152,19 +160,28 @@ uint16_t crc16(uint8_t val, uint16_t crc, uint16_t poly)
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t crc32(uint8_t val, uint32_t crc, uint32_t poly)
|
||||
{
|
||||
static uint32_t CRCTable[256];
|
||||
|
||||
int j;
|
||||
crc = crc ^ (val << 24);
|
||||
for (j = 1; j <= 8; j++) {
|
||||
if (crc & 0x80000000) {
|
||||
crc = (crc << 1) ^ poly;
|
||||
} else {
|
||||
crc = crc << 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
static void CRC32_init(uint32_t poly) {
|
||||
uint32_t mask = 0xFFFFFFFF;
|
||||
uint32_t topbit = 0x80000000;
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
uint32_t c = (i << 24);
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (c & topbit) {
|
||||
c = ((c << 1) ^ poly) & mask;
|
||||
} else {
|
||||
c = (c << 1) & mask;
|
||||
}
|
||||
}
|
||||
CRCTable[i] = c;
|
||||
}
|
||||
}
|
||||
static inline uint32_t crc32(uint8_t val, uint32_t crc, uint32_t poly) {
|
||||
const uint8_t idx = ((crc >> 24) ^ val) & 0xFF;
|
||||
crc = ((crc << 8) ^ CRCTable[idx]);
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
@@ -255,15 +272,27 @@ void second_cpu_thread() {
|
||||
pinMode(HSEL2, INPUT);
|
||||
pinMode(HSEL3, INPUT);
|
||||
|
||||
uint32_t cs = current_cyl;
|
||||
|
||||
while (1) {
|
||||
|
||||
if (!mounted_file) {
|
||||
phase = 0;
|
||||
load_sm = LOAD_IDLE;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t hp = format->header_poly;
|
||||
uint32_t dp = format->data_poly;
|
||||
uint32_t tcs = 0;
|
||||
|
||||
current_head = digitalRead(HSEL0) | (digitalRead(HSEL1) << 1) | (digitalRead(HSEL2) << 2) | (digitalRead(HSEL3) << 3);
|
||||
|
||||
switch (phase) {
|
||||
case PH_INDEX_START: // Start index pulse
|
||||
tcs = current_cyl;
|
||||
if (tcs != cs) {
|
||||
cs = tcs;
|
||||
}
|
||||
ts = micros();
|
||||
format->idx_period = micros() - format->idx_ts;
|
||||
format->idx_ts = micros();
|
||||
@@ -362,8 +391,8 @@ void second_cpu_thread() {
|
||||
load->header[0] = 0;
|
||||
load->header[1] = 0xA1;
|
||||
load->header[2] = 0xFE;
|
||||
load->header[3] = (current_cyl & 0xFF);
|
||||
load->header[4] = ((current_cyl & 0xF00) >> 4) | (current_head & 0x0F);
|
||||
load->header[3] = (cs & 0xFF);
|
||||
load->header[4] = ((cs & 0xF00) >> 4) | (current_head & 0x0F);
|
||||
load->header[5] = next_sector;
|
||||
load->header[6] = format->sector_size;
|
||||
load->header[7] = 0x00;
|
||||
@@ -376,10 +405,10 @@ void second_cpu_thread() {
|
||||
load->data[0] = 0;
|
||||
load->data[1] = 0xA1;
|
||||
load->data[2] = 0xFB;
|
||||
load->data[515] = ((cyl_data.track[current_cyl].sector[next_sector].data_crc >> 24) & 0xFF);
|
||||
load->data[516] = ((cyl_data.track[current_cyl].sector[next_sector].data_crc >> 16) & 0xFF);
|
||||
load->data[517] = ((cyl_data.track[current_cyl].sector[next_sector].data_crc >> 8) & 0xFF);
|
||||
load->data[518] = (cyl_data.track[current_cyl].sector[next_sector].data_crc & 0xFF);
|
||||
load->data[515] = ((cyl_data.track[cs].sector[next_sector].data_crc >> 24) & 0xFF);
|
||||
load->data[516] = ((cyl_data.track[cs].sector[next_sector].data_crc >> 16) & 0xFF);
|
||||
load->data[517] = ((cyl_data.track[cs].sector[next_sector].data_crc >> 8) & 0xFF);
|
||||
load->data[518] = (cyl_data.track[cs].sector[next_sector].data_crc & 0xFF);
|
||||
load->data[519] = 0;
|
||||
load_iter = 0;
|
||||
load_sm = LOAD_HEADER_CS;
|
||||
@@ -417,7 +446,7 @@ void second_cpu_thread() {
|
||||
case LOAD_DATA_MFM:
|
||||
|
||||
if ((load_iter >= 3) && (load_iter < 515)) {
|
||||
load->data[load_iter] = mfm_encode(cyl_data.track[current_cyl].sector[next_sector].data[load_iter - 3]);
|
||||
load->data[load_iter] = mfm_encode(cyl_data.track[cs].sector[next_sector].data[load_iter - 3]);
|
||||
} else {
|
||||
load->data[load_iter] = mfm_encode(load->data[load_iter]);
|
||||
}
|
||||
@@ -425,7 +454,7 @@ void second_cpu_thread() {
|
||||
load_iter++;
|
||||
|
||||
if ((load_iter >= 3) && (load_iter < 515)) {
|
||||
load->data[load_iter] = mfm_encode(cyl_data.track[current_cyl].sector[next_sector].data[load_iter - 3]);
|
||||
load->data[load_iter] = mfm_encode(cyl_data.track[cs].sector[next_sector].data[load_iter - 3]);
|
||||
} else {
|
||||
load->data[load_iter] = mfm_encode(load->data[load_iter]);
|
||||
}
|
||||
@@ -433,7 +462,7 @@ void second_cpu_thread() {
|
||||
load_iter++;
|
||||
|
||||
if ((load_iter >= 3) && (load_iter < 515)) {
|
||||
load->data[load_iter] = mfm_encode(cyl_data.track[current_cyl].sector[next_sector].data[load_iter - 3]);
|
||||
load->data[load_iter] = mfm_encode(cyl_data.track[cs].sector[next_sector].data[load_iter - 3]);
|
||||
} else {
|
||||
load->data[load_iter] = mfm_encode(load->data[load_iter]);
|
||||
}
|
||||
@@ -441,7 +470,7 @@ void second_cpu_thread() {
|
||||
load_iter++;
|
||||
|
||||
if ((load_iter >= 3) && (load_iter < 515)) {
|
||||
load->data[load_iter] = mfm_encode(cyl_data.track[current_cyl].sector[next_sector].data[load_iter - 3]);
|
||||
load->data[load_iter] = mfm_encode(cyl_data.track[cs].sector[next_sector].data[load_iter - 3]);
|
||||
} else {
|
||||
load->data[load_iter] = mfm_encode(load->data[load_iter]);
|
||||
}
|
||||
@@ -449,7 +478,7 @@ void second_cpu_thread() {
|
||||
load_iter++;
|
||||
|
||||
if ((load_iter >= 3) && (load_iter < 515)) {
|
||||
load->data[load_iter] = mfm_encode(cyl_data.track[current_cyl].sector[next_sector].data[load_iter - 3]);
|
||||
load->data[load_iter] = mfm_encode(cyl_data.track[cs].sector[next_sector].data[load_iter - 3]);
|
||||
} else {
|
||||
load->data[load_iter] = mfm_encode(load->data[load_iter]);
|
||||
}
|
||||
@@ -479,7 +508,7 @@ void create_track_store() {
|
||||
if (cyl_data.track[i].sector) {
|
||||
for (int j = 0; j < cyl_data.sectors; j++) {
|
||||
if (cyl_data.track[i].sector[j].data) {
|
||||
free(cyl_data.track[i].sector[j].data);
|
||||
digitalWrite(SEEK_DONE, HIGH); free(cyl_data.track[i].sector[j].data);
|
||||
}
|
||||
}
|
||||
free(cyl_data.track[i].sector);
|
||||
@@ -497,33 +526,104 @@ void create_track_store() {
|
||||
}
|
||||
}
|
||||
|
||||
void load_sector(FsFile file, uint32_t cyl, uint32_t head, uint32_t sector, uint8_t sectorsize) {
|
||||
uint32_t len = 0x80 << sectorsize;
|
||||
len *= sector;
|
||||
len *= head;
|
||||
|
||||
uint32_t offset = cyl * len;
|
||||
|
||||
file.seekSet(offset);
|
||||
file.read(cyl_data.track[head].sector[sector].data, 0x80 << sectorsize);
|
||||
|
||||
void calculate_sector_crc(int head, int sector, int sectorsize) {
|
||||
uint32_t crc = 0xFFFFFFFF;
|
||||
crc = crc32(0xA1, crc, format->data_poly);
|
||||
crc = crc32(0xFB, crc, format->data_poly);
|
||||
uint32_t poly = format->data_poly;
|
||||
|
||||
crc = crc32(0xA1, crc, poly);
|
||||
crc = crc32(0xFB, crc, poly);
|
||||
uint8_t *data = cyl_data.track[head].sector[sector].data;
|
||||
for (int i = 0; i < (0x80 << sectorsize); i++) {
|
||||
crc = crc32(cyl_data.track[head].sector[sector].data[i], crc, format->data_poly);
|
||||
crc = crc32(data[i], crc, poly);
|
||||
}
|
||||
|
||||
cyl_data.track[head].sector[sector].data_crc = crc;
|
||||
|
||||
}
|
||||
|
||||
void load_cyl(FsFile file, uint32_t cyl, uint32_t heads, uint32_t sectors, uint32_t sectorsize) {
|
||||
|
||||
uint32_t ts = micros();
|
||||
|
||||
uint32_t offset = cyl * heads * (0x80 << sectorsize);
|
||||
file.seekSet(offset);
|
||||
|
||||
file.read(track_buffer, heads * sectors * (0x80 << sectorsize));
|
||||
|
||||
uint32_t rts = micros() - ts;
|
||||
|
||||
for (int head = 0; head < format->heads; head++) {
|
||||
for (int sector = 0; sector < format->sectors; sector++) {
|
||||
load_sector(file, cyl, head, sector, sectorsize);
|
||||
calculate_sector_crc(head, sector, sectorsize);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t cts = micros() - ts;
|
||||
|
||||
Serial.printf("T: %d R: %u c: %u %f tps\r\n", cyl, rts, cts - rts, 1 / (cts / 1000000.0));
|
||||
|
||||
|
||||
}
|
||||
|
||||
char *trim(char *str)
|
||||
{
|
||||
char *end;
|
||||
|
||||
// Trim leading space
|
||||
while(isspace((unsigned char)*str)) str++;
|
||||
|
||||
if(*str == 0) // All spaces?
|
||||
return str;
|
||||
|
||||
// Trim trailing space
|
||||
end = str + strlen(str) - 1;
|
||||
while(end > str && isspace((unsigned char)*end)) end--;
|
||||
|
||||
// Write new null terminator character
|
||||
end[1] = '\0';
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
int execute_file(const char *filename, CLIClient *client) {
|
||||
FsFile file;
|
||||
|
||||
if (!open_sd_if_needed()) {
|
||||
errno = ENOENT;
|
||||
return 10;
|
||||
}
|
||||
|
||||
if (!sd.exists(filename)) {
|
||||
errno = ENOENT;
|
||||
return 10;
|
||||
}
|
||||
|
||||
file.open(filename);
|
||||
char line[1024];
|
||||
while (file.fgets(line, 1024)) {
|
||||
char *tline = trim(line);
|
||||
if (strlen(tline) == 0) continue;
|
||||
if (tline[0] == '#') continue;
|
||||
client->print(filename);
|
||||
client->print(": ");
|
||||
client->println(tline);
|
||||
client->parseCommand(tline);
|
||||
}
|
||||
file.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
CLI_COMMAND(cli_source) {
|
||||
if (argc != 2) {
|
||||
dev->println("Usage: source <filename>");
|
||||
return 10;
|
||||
}
|
||||
|
||||
if (execute_file(argv[1], dev) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->println("File not found");
|
||||
return 10;
|
||||
}
|
||||
|
||||
|
||||
@@ -548,6 +648,14 @@ CLI_COMMAND(cli_status) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->print("Mounted image: ");
|
||||
if (mounted_file) {
|
||||
mounted_file.printName(dev);
|
||||
dev->println();
|
||||
} else {
|
||||
dev->println("none");
|
||||
}
|
||||
|
||||
float rpm = (format->data_rate / total_clocks) * 60.0;
|
||||
|
||||
dev->print("Cylinders: ");
|
||||
@@ -626,6 +734,13 @@ CLI_COMMAND(cli_status) {
|
||||
dev->print(current_head);
|
||||
dev->print("/");
|
||||
dev->println(current_sector);
|
||||
dev->println();
|
||||
dev->print("Known formats: ");
|
||||
for (struct format_list *scan = formats; scan; scan = scan->next) {
|
||||
dev->print(scan->fmt->name);
|
||||
dev->print(" ");
|
||||
}
|
||||
dev->println();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -735,14 +850,28 @@ CLI_COMMAND(cli_set) {
|
||||
}
|
||||
|
||||
CLI_COMMAND(cli_ls) {
|
||||
if (!open_sd_if_needed()) {
|
||||
return 10;
|
||||
}
|
||||
sd.ls(LS_A | LS_DATE | LS_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CLI_COMMAND(cli_create) {
|
||||
if (argc != 2) {
|
||||
dev->println("Usage: create <filename>");
|
||||
dev->println("Create a new image file using the current disk format");
|
||||
if (argc != 3) {
|
||||
dev->println("Usage: create <filename> <format>");
|
||||
dev->println("Create a new image file using the specified disk format");
|
||||
return 10;
|
||||
}
|
||||
if (!open_sd_if_needed()) {
|
||||
return 10;
|
||||
}
|
||||
|
||||
|
||||
struct disk_format *fmt = find_format_by_name(argv[2]);
|
||||
|
||||
if (fmt == NULL) {
|
||||
dev->println("Unknown format");
|
||||
return 10;
|
||||
}
|
||||
|
||||
@@ -751,10 +880,10 @@ CLI_COMMAND(cli_create) {
|
||||
return 10;
|
||||
}
|
||||
|
||||
uint32_t disk_size = 0x80 << format->sector_size;
|
||||
disk_size *= format->sectors;
|
||||
disk_size *= format->heads;
|
||||
disk_size *= format->cyls;
|
||||
uint32_t disk_size = 0x80 << fmt->sector_size;
|
||||
disk_size *= fmt->sectors;
|
||||
disk_size *= fmt->heads;
|
||||
disk_size *= fmt->cyls;
|
||||
|
||||
dev->println("Creating new file, please wait...");
|
||||
FsFile newfile;
|
||||
@@ -765,27 +894,53 @@ CLI_COMMAND(cli_create) {
|
||||
}
|
||||
|
||||
CLI_COMMAND(cli_mount) {
|
||||
if (argc != 2) {
|
||||
dev->println("Usage: mount <filename>");
|
||||
if (argc != 3) {
|
||||
dev->println("Usage: mount <filename> <format>");
|
||||
dev->println("Mount an image file as the virtual disk");
|
||||
return 10;
|
||||
}
|
||||
if (!open_sd_if_needed()) {
|
||||
return 10;
|
||||
}
|
||||
|
||||
if (!sd.exists(argv[1])) {
|
||||
dev->println("File not found");
|
||||
return 10;
|
||||
}
|
||||
|
||||
format = find_format_by_name(argv[2]);
|
||||
if (format == NULL) {
|
||||
dev->println("Format not known");
|
||||
return 10;
|
||||
}
|
||||
|
||||
create_track_store();
|
||||
|
||||
mounted_file = sd.open(argv[1], O_RDWR);
|
||||
current_cyl = 0;
|
||||
current_head = 0;
|
||||
|
||||
uint32_t bps = 0x80 << format->sector_size;
|
||||
|
||||
track_buffer = (uint8_t *)malloc(format->heads * format->sectors * bps);
|
||||
|
||||
for (int head = 0; head < format->heads; head++) {
|
||||
int hoff = head * format->sectors;
|
||||
for (int sector = 0; sector < format->sectors; sector++) {
|
||||
cyl_data.track[head].sector[sector].data = track_buffer + ((hoff + sector) * bps);
|
||||
}
|
||||
}
|
||||
|
||||
CRC32_init(format->data_poly);
|
||||
|
||||
load_cyl(mounted_file, current_cyl, format->heads, format->sectors, format->sector_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void do_step() {
|
||||
if (format == NULL) return;
|
||||
|
||||
digitalWrite(SEEK_DONE, LOW);
|
||||
int dir = digitalRead(DIR);
|
||||
|
||||
@@ -796,29 +951,262 @@ void do_step() {
|
||||
}
|
||||
|
||||
if (dir == 1) {
|
||||
current_cyl --;
|
||||
target_cyl --;
|
||||
} else {
|
||||
current_cyl ++;
|
||||
target_cyl ++;
|
||||
}
|
||||
if (current_cyl >= format->cyls) {
|
||||
current_cyl = 0;
|
||||
if (target_cyl >= format->cyls) {
|
||||
target_cyl = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct disk_format *find_format_by_name(const char *filename) {
|
||||
for (struct format_list *scan = formats; scan; scan = scan->next) {
|
||||
if (strcasecmp(filename, scan->fmt->name) == 0) {
|
||||
return scan->fmt;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void append_format(struct disk_format *fmt) {
|
||||
if (formats == NULL) {
|
||||
formats = (struct format_list *)malloc(sizeof(struct format_list));
|
||||
formats->fmt = fmt;
|
||||
formats->next = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
load_cyl(mounted_file, current_cyl, format->heads, format->sectors, format->sector_size);
|
||||
struct format_list *nf = (struct format_list *)malloc(sizeof(struct format_list));
|
||||
nf->fmt = fmt;
|
||||
nf->next = NULL;
|
||||
|
||||
digitalWrite(TRACK0, current_cyl == 0);
|
||||
for (struct format_list *scan = formats; scan; scan = scan->next) {
|
||||
if (scan->next == NULL) {
|
||||
scan->next = nf;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
digitalWrite(SEEK_DONE, HIGH);
|
||||
struct disk_format *load_format(const char *filename) {
|
||||
FsFile file;
|
||||
|
||||
file.open(filename);
|
||||
if (!file) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct disk_format *fmt = (struct disk_format *)malloc(sizeof(struct disk_format));
|
||||
memset(fmt, 0, sizeof(struct disk_format));
|
||||
|
||||
char l[1024];
|
||||
while (file.fgets(l, 1024)) {
|
||||
char *tl = trim(l);
|
||||
|
||||
if (strlen(tl) == 0) continue;
|
||||
if (tl[0] == '#') continue;
|
||||
if (tl[0] == ';') continue;
|
||||
if (tl[0] == '!') continue;
|
||||
|
||||
char *key = strtok(tl, "=");
|
||||
char *val = strtok(NULL, "=");
|
||||
|
||||
key = trim(key);
|
||||
val = trim(val);
|
||||
|
||||
if (strcasecmp(key, "name") == 0) {
|
||||
fmt->name = strdup(val);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "comment") == 0) {
|
||||
fmt->comment = strdup(val);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "cyls") == 0) {
|
||||
fmt->cyls = strtoul(val, NULL, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "heads") == 0) {
|
||||
fmt->heads = strtoul(val, NULL, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "sectors") == 0) {
|
||||
fmt->sectors = strtoul(val, NULL, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "sector_size") == 0) {
|
||||
int ss = strtoul(val, NULL, 0);
|
||||
switch (ss) {
|
||||
case 128: fmt->sector_size = SECTOR_128; break;
|
||||
case 256: fmt->sector_size = SECTOR_256; break;
|
||||
case 512: fmt->sector_size = SECTOR_512; break;
|
||||
case 1024: fmt->sector_size = SECTOR_1024; break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "index_width") == 0) {
|
||||
fmt->index_width = strtoul(val, NULL, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "track_pregap") == 0) {
|
||||
fmt->track_pregap = strtoul(val, NULL, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "track_postgap") == 0) {
|
||||
fmt->track_postgap = strtoul(val, NULL, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "header_postgap") == 0) {
|
||||
fmt->header_postgap = strtoul(val, NULL, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "data_postgap") == 0) {
|
||||
fmt->data_postgap = strtoul(val, NULL, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "data_rate") == 0) {
|
||||
fmt->data_rate = strtoul(val, NULL, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "header_crc") == 0) {
|
||||
int ss = strtoul(val, NULL, 0);
|
||||
switch (ss) {
|
||||
case 16: fmt->flags |= OPT_HEADER_CRC16; break;
|
||||
case 32: fmt->flags |= OPT_HEADER_CRC32; break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "data_crc") == 0) {
|
||||
int ss = strtoul(val, NULL, 0);
|
||||
switch (ss) {
|
||||
case 16: fmt->flags |= OPT_DATA_CRC16; break;
|
||||
case 32: fmt->flags |= OPT_DATA_CRC32; break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "header_poly") == 0) {
|
||||
fmt->header_poly = strtoul(val, NULL, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcasecmp(key, "data_poly") == 0) {
|
||||
fmt->data_poly = strtoul(val, NULL, 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
return fmt;
|
||||
}
|
||||
|
||||
void load_formats(CLIClient *dev) {
|
||||
char name[1024];
|
||||
FsFile f;
|
||||
FsFile dir;
|
||||
if (open_sd_if_needed()) {
|
||||
dir.open("/", O_RDONLY);
|
||||
dir.rewind();
|
||||
while (f.openNext(&dir, O_RDONLY)) {
|
||||
f.getName(name, 1024);
|
||||
f.close();
|
||||
int s = strlen(name);
|
||||
if (s > 4) {
|
||||
if ((name[s - 4] == '.') &&
|
||||
(name[s - 3] == 'f') &&
|
||||
(name[s - 2] == 'm') &&
|
||||
(name[s - 1] == 't')) {
|
||||
dev->println(name);
|
||||
struct disk_format *fmt = load_format(name);
|
||||
if (fmt == NULL) {
|
||||
dev->println("Error loading format");
|
||||
} else {
|
||||
append_format(fmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dir.close();
|
||||
}
|
||||
}
|
||||
|
||||
void factory_formats() {
|
||||
struct disk_format *rd54 = (struct disk_format *)malloc(sizeof(struct disk_format));
|
||||
|
||||
|
||||
rd54->name = strdup("RD54");
|
||||
rd54->comment = strdup("DEC RD54 Hard Drive");
|
||||
rd54->cyls=1225;
|
||||
rd54->heads=15;
|
||||
rd54->sectors=17;
|
||||
rd54->sector_size=SECTOR_512;
|
||||
rd54->index_width=10;
|
||||
rd54->track_pregap=290;
|
||||
rd54->track_postgap=1100;
|
||||
rd54->header_postgap=41;
|
||||
rd54->data_postgap=911;
|
||||
rd54->data_rate=5000000;
|
||||
rd54->flags = OPT_HEADER_CRC16 | OPT_DATA_CRC32;
|
||||
rd54->header_poly=0x1021;
|
||||
rd54->data_poly=0xa00805;
|
||||
|
||||
append_format(rd54);
|
||||
}
|
||||
|
||||
CLI_COMMAND(cli_eject) {
|
||||
if (mounted_file) {
|
||||
mounted_file.close();
|
||||
if (track_buffer) {
|
||||
free(track_buffer);
|
||||
track_buffer = NULL;
|
||||
}
|
||||
}
|
||||
sd.end();
|
||||
_sd_is_open = false;
|
||||
dev->println("It is now safe to remove the SD card.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
CLI_COMMAND(cli_load_formats) {
|
||||
load_formats(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CLI_COMMAND(cli_seek) {
|
||||
if (argc != 2) {
|
||||
dev->println("Usage: seek <track>");
|
||||
return 10;
|
||||
}
|
||||
|
||||
int track = strtol(argv[1], NULL, 0);
|
||||
|
||||
if ((track < 0) || (track >= format->cyls)) {
|
||||
dev->println("Track out of range");
|
||||
return 10;
|
||||
}
|
||||
|
||||
current_cyl = track;
|
||||
|
||||
load_cyl(mounted_file, current_cyl, format->heads, format->sectors, format->sector_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
|
||||
if (!sd.begin(SdioConfig(SDIO_CLK, SDIO_CMD, SDIO_DAT0, 1.5))) {
|
||||
sd.initErrorPrint();
|
||||
}
|
||||
|
||||
datastreamPgm.prepare(&pio, &sm, &offset);
|
||||
datastream_program_init(pio, sm, offset, DOUT);
|
||||
pio_sm_set_enabled(pio, sm, true);
|
||||
@@ -829,27 +1217,34 @@ void setup() {
|
||||
digitalWrite(13, HIGH);
|
||||
Serial.begin(115200);
|
||||
|
||||
format = &RD54;
|
||||
//format = &RD54;
|
||||
factory_formats();
|
||||
format = formats->fmt;
|
||||
load_formats(console);
|
||||
create_track_store();
|
||||
|
||||
|
||||
|
||||
format->slen = 0x80 << format->sector_size;
|
||||
format->tlen = format->slen * format->sectors;
|
||||
|
||||
|
||||
format->clock_div = F_CPU / format->data_rate / 20.0;
|
||||
pio_sm_set_clkdiv(pio, sm, format->clock_div);
|
||||
|
||||
multicore_launch_core1(second_cpu_thread);
|
||||
|
||||
Serial.begin(115200);
|
||||
CLI.setDefaultPrompt("RTmFM> ");
|
||||
CLI.addClient(Serial);
|
||||
console = CLI.addClient(Serial);
|
||||
|
||||
CLI.addCommand("status", cli_status);
|
||||
CLI.addCommand("set", cli_set);
|
||||
CLI.addCommand("ls", cli_ls);
|
||||
CLI.addCommand("dir", cli_ls);
|
||||
CLI.addCommand("create", cli_create);
|
||||
CLI.addCommand("mount", cli_mount);
|
||||
CLI.addCommand("source", cli_source);
|
||||
CLI.addCommand("eject", cli_eject);
|
||||
CLI.addCommand("lf", cli_load_formats);
|
||||
CLI.addCommand("seek", cli_seek);
|
||||
|
||||
pinMode(STEP, INPUT);
|
||||
pinMode(DIR, INPUT);
|
||||
@@ -858,10 +1253,33 @@ void setup() {
|
||||
pinMode(TRACK0, OUTPUT);
|
||||
digitalWrite(TRACK0, current_cyl == 0);
|
||||
|
||||
attachInterrupt(STEP, do_step, RISING);
|
||||
attachInterrupt(STEP, do_step, FALLING);
|
||||
|
||||
if (open_sd_if_needed()) {
|
||||
if (sd.exists("autoexec.bat")) {
|
||||
execute_file("autoexec.bat", console);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
CLI.process();
|
||||
|
||||
|
||||
cli();
|
||||
uint32_t tmp_target = target_cyl;
|
||||
sei();
|
||||
|
||||
if (tmp_target != current_cyl) {
|
||||
while (tmp_target != current_cyl) {
|
||||
current_cyl = tmp_target;
|
||||
load_cyl(mounted_file, current_cyl, format->heads, format->sectors, format->sector_size);
|
||||
digitalWrite(TRACK0, current_cyl == 0);
|
||||
cli();
|
||||
uint32_t tmp_target = target_cyl;
|
||||
sei();
|
||||
}
|
||||
digitalWrite(SEEK_DONE, HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user