mirror of
https://github.com/LemonBoy/grape.git
synced 2024-12-01 19:50:26 +00:00
279 lines
6.7 KiB
C
279 lines
6.7 KiB
C
#include <nds.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include "emu.h"
|
|
|
|
// Working buffer
|
|
static u8 diskbuf[35*6656];
|
|
|
|
static int Q6, Q7;
|
|
static int motor_on;
|
|
static int phase;
|
|
static int last_stepper;
|
|
static int track_start, track_pos;
|
|
static int sel_disk;
|
|
|
|
void disk_save (FILE *f)
|
|
{
|
|
fwrite(&Q6, 1, 4, f);
|
|
fwrite(&Q7, 1, 4, f);
|
|
fwrite(&motor_on, 1, 4, f);
|
|
fwrite(&phase, 1, 4, f);
|
|
fwrite(&last_stepper, 1, 4, f);
|
|
fwrite(&track_start, 1, 4, f);
|
|
fwrite(&track_pos, 1, 4, f);
|
|
fwrite(&sel_disk, 1, 4, f);
|
|
}
|
|
|
|
void disk_load (FILE *f)
|
|
{
|
|
fread(&Q6, 1, 4, f);
|
|
fread(&Q7, 1, 4, f);
|
|
fread(&motor_on, 1, 4, f);
|
|
fread(&phase, 1, 4, f);
|
|
fread(&last_stepper, 1, 4, f);
|
|
fread(&track_start, 1, 4, f);
|
|
fread(&track_pos, 1, 4, f);
|
|
fread(&sel_disk, 1, 4, f);
|
|
}
|
|
|
|
u8 disk_io_read (u16 addr) ITCM_CODE;
|
|
u8 disk_io_read (u16 addr)
|
|
{
|
|
int set;
|
|
int stepper;
|
|
int delta;
|
|
|
|
set = addr&1;
|
|
stepper = (addr>>1)&3;
|
|
|
|
switch (addr&0xf) {
|
|
case 0x1:
|
|
case 0x3:
|
|
case 0x5:
|
|
case 0x7:
|
|
if (motor_on) {
|
|
delta = 0;
|
|
if (stepper == ((last_stepper + 1)&3))
|
|
delta += 1;
|
|
if (stepper == ((last_stepper + 3)&3))
|
|
delta -= 1;
|
|
last_stepper = stepper;
|
|
if (delta) {
|
|
phase += delta;
|
|
if (phase < 0)
|
|
phase = 0;
|
|
if (phase > 70)
|
|
phase = 70;
|
|
/*track_pos = 0;*/
|
|
track_start = (phase >> 1) * 6656;
|
|
}
|
|
}
|
|
return 0xff;
|
|
case 0x0:
|
|
case 0x2:
|
|
case 0x4:
|
|
case 0x6:
|
|
return 0xff;
|
|
// ENABLE
|
|
case 0x8:
|
|
case 0x9:
|
|
motor_on = set;
|
|
return 0xff;
|
|
// SELECT
|
|
case 0xa:
|
|
case 0xb:
|
|
sel_disk = set;
|
|
return 0xff;
|
|
// Q6L
|
|
case 0xc:
|
|
Q6 = 0;
|
|
if (!Q7) {
|
|
// The tracks are circular, so wrap around
|
|
if (track_pos >= 6656) track_pos = 0;
|
|
return diskbuf[track_start + (track_pos++)];
|
|
}
|
|
// Handshake register
|
|
return 0x80;
|
|
// Q6H
|
|
case 0xd:
|
|
Q6 = 1;
|
|
return 0;
|
|
// Q7
|
|
case 0xe:
|
|
case 0xf:
|
|
Q7 = set;
|
|
// The status register is read from Q7L
|
|
return 0x20|0x80; // Write protect and ready
|
|
}
|
|
return 0xff;
|
|
}
|
|
|
|
int load_nib_disk (const char *file)
|
|
{
|
|
FILE *f;
|
|
size_t size;
|
|
|
|
f = fopen(file, "rb");
|
|
|
|
if (!f)
|
|
return 0;
|
|
|
|
fseek(f, 0, SEEK_END);
|
|
size = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
|
|
if (size != 232960) {
|
|
iprintf("Size mismatch\n");
|
|
fclose(f);
|
|
return 0;
|
|
}
|
|
fread(diskbuf, 1, 232960, f);
|
|
fclose(f);
|
|
|
|
return 1;
|
|
}
|
|
|
|
// DOS 3.3 format 35 T 16 S (343 nybbles)
|
|
// http://www.umich.edu/~archive/apple2/misc/hardware/disk.encoding.txt
|
|
// http://mirrors.apple2.org.za/ground.icaen.uiowa.edu/MiscInfo/Programming/c600.disasm
|
|
// http://www.mac.linux-m68k.org/devel/iwm.php
|
|
// http://www.textfiles.com/apple/ANATOMY/t.dos.b800.bcff.txt
|
|
|
|
const u8 dos33table[] = {
|
|
0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6,
|
|
0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3,
|
|
0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC,
|
|
0xBD, 0xBE, 0xBF, 0xCB, 0xCD, 0xCE, 0xCF, 0xD3,
|
|
0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE,
|
|
0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC,
|
|
0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,
|
|
0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
|
|
};
|
|
const int dos_order[] = {
|
|
0x0, 0x7, 0xE, 0x6, 0xD, 0x5, 0xC, 0x4, 0xB, 0x3, 0xA, 0x2, 0x9, 0x1, 0x8, 0xF
|
|
};
|
|
const int prodos_order[] = {
|
|
0x0, 0x8, 0x1, 0x9, 0x2, 0xA, 0x3, 0xB, 0x4, 0xC, 0x5, 0xD, 0x6, 0xE, 0x7, 0xF
|
|
};
|
|
|
|
void write_address (u8 *b, u8 track, u8 sector, u8 volume)
|
|
{
|
|
// Handy macros for 4 and 4 encoding
|
|
#define X1(x) (((x)>>1)|0xAA)
|
|
#define X2(x) ((x)|0xAA)
|
|
b[0] = 0xD5;
|
|
b[1] = 0xAA;
|
|
b[2] = 0x96;
|
|
b[3] = X1(volume);
|
|
b[4] = X2(volume);
|
|
b[5] = X1(track);
|
|
b[6] = X2(track);
|
|
b[7] = X1(sector);
|
|
b[8] = X2(sector);
|
|
b[9] = X1(volume^track^sector);
|
|
b[10] = X2(volume^track^sector);
|
|
b[11] = 0xDE;
|
|
b[12] = 0xAA;
|
|
b[13] = 0xEB;
|
|
#undef X1
|
|
#undef X2
|
|
}
|
|
|
|
// GAP + (ADDRESS + GAP + DATA + GAP)
|
|
#define GAP1_LEN 48
|
|
#define GAP2_LEN 6
|
|
#define GAP3_LEN 27
|
|
#define ADDRESS_LEN 14 // 3 + 2 + 2 + 2 + 2 + 3
|
|
#define DATA_LEN 349 // 3 + 342 + 1 + 3
|
|
|
|
int load_dsk_disk (const char *file, const int *sec_order)
|
|
{
|
|
FILE *f;
|
|
size_t size;
|
|
u8 sec_buf[256];
|
|
u8 nib_buf[343];
|
|
u8 *p, chksum;
|
|
int i, j, k;
|
|
|
|
f = fopen(file, "rb");
|
|
|
|
if (!f)
|
|
return 0;
|
|
|
|
fseek(f, 0, SEEK_END);
|
|
size = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
|
|
if (size > 143360) {
|
|
iprintf("Size mismatch\n");
|
|
fclose(f);
|
|
return 0;
|
|
}
|
|
|
|
p = diskbuf;
|
|
|
|
memset(p, 0xff, sizeof(diskbuf));
|
|
|
|
// Crunch all the tracks
|
|
for (i = 0; i < 35; i++) {
|
|
p += 64;
|
|
// Crunch all the sectors
|
|
for (j = 0; j < 16; j++) {
|
|
fseek(f, 256 * sec_order[j] + (i * 16 * 256), SEEK_SET);
|
|
fread(sec_buf, 1, 256, f);
|
|
// 0xFE is the default volume
|
|
write_address(p, i, j, 0xFE);
|
|
p += 14;
|
|
// Second sync gap
|
|
p += 4;
|
|
// Data marker
|
|
p[0] = 0xD5; p[1] = 0xAA; p[2] = 0xAD;
|
|
p += 3;
|
|
// Convert to 6bit, the stashed bits start at 0
|
|
memset(nib_buf, 0, sizeof(nib_buf));
|
|
for (k = 0; k < 256; k++) {
|
|
u8 v = sec_buf[k];
|
|
nib_buf[k+86] = v >> 2;
|
|
nib_buf[k%86] |= ((v&1) << 1 | (v&2) >> 1) << (2 * (k/86));
|
|
}
|
|
chksum = 0;
|
|
for (k = 0; k < 342; k++) {
|
|
*p++ = dos33table[chksum^nib_buf[k]];
|
|
chksum = nib_buf[k];
|
|
}
|
|
// Write the checksum
|
|
*p++ = dos33table[chksum];
|
|
// Write the last marker
|
|
p[0] = 0xDE; p[1] = 0xAA; p[2] = 0xEB;
|
|
p += 3;
|
|
p += 45;
|
|
}
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int load_disk (const char *path)
|
|
{
|
|
char *ext;
|
|
|
|
ext = strrchr(path, '.');
|
|
if (!ext)
|
|
return 0;
|
|
|
|
if (!stricmp(ext + 1, "dsk") || !stricmp(ext + 1, "do"))
|
|
return load_dsk_disk(path, dos_order);
|
|
|
|
if (!stricmp(ext + 1, "po"))
|
|
return load_dsk_disk(path, prodos_order);
|
|
|
|
if (!stricmp(ext + 1, "nib"))
|
|
return load_nib_disk(path);
|
|
|
|
return 0;
|
|
}
|