Created a support folder and move core ARM support code for minimig into it. Updated menu, osd, and user_io. Makefile also updated to account for new support folder
This commit is contained in:
476
support/minimig/minimig_boot.cpp
Normal file
476
support/minimig/minimig_boot.cpp
Normal file
@@ -0,0 +1,476 @@
|
||||
// boot.c
|
||||
// bootscreen functions
|
||||
// 2014, rok.krajnc@gmail.com
|
||||
|
||||
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
#include "minimig_boot.h"
|
||||
#include "../../hardware.h"
|
||||
#include "../../osd.h"
|
||||
#include "../../spi.h"
|
||||
#include "../../file_io.h"
|
||||
#include "minimig_config.h"
|
||||
#include "minimig_fdd.h"
|
||||
#include "../../cfg.h"
|
||||
|
||||
static uint8_t buffer[1024];
|
||||
|
||||
static void mem_upload_init(unsigned long addr)
|
||||
{
|
||||
spi_osd_cmd32le_cont(OSD_CMD_WR, addr);
|
||||
}
|
||||
|
||||
static void mem_upload_fini()
|
||||
{
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
static void mem_write16(unsigned short x)
|
||||
{
|
||||
spi8((((x) >> 8) & 0xff)); spi8(((x)& 0xff));
|
||||
}
|
||||
|
||||
//// boot cursor positions ////
|
||||
unsigned short bcurx = 0;
|
||||
unsigned short bcury = 96;
|
||||
|
||||
static int bootscreen_adr = 0x80000 + /*120*/112 * 640 / 8;
|
||||
|
||||
void BootHome()
|
||||
{
|
||||
bootscreen_adr = 0x80000 + /*120*/112 * 640 / 8;
|
||||
}
|
||||
|
||||
static const char boot_font[96][8] =
|
||||
{
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // SPACE
|
||||
{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00 }, // !
|
||||
{ 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // "
|
||||
{ 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00 }, // #
|
||||
{ 0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0x00 }, // $
|
||||
{ 0x00, 0x66, 0xAC, 0xD8, 0x36, 0x6A, 0xCC, 0x00 }, // %
|
||||
{ 0x38, 0x6C, 0x68, 0x76, 0xDC, 0xCE, 0x7B, 0x00 }, // &
|
||||
{ 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00 }, // '
|
||||
{ 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00 }, // (
|
||||
{ 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00 }, // )
|
||||
{ 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00 }, // *
|
||||
{ 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00 }, // +
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30 }, // ,
|
||||
{ 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00 }, // -
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00 }, // .
|
||||
{ 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00 }, // /
|
||||
{ 0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x3C, 0x00 }, // 0
|
||||
{ 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x00 }, // 1
|
||||
{ 0x3C, 0x66, 0x06, 0x0C, 0x18, 0x30, 0x7E, 0x00 }, // 2
|
||||
{ 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00 }, // 3
|
||||
{ 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x0C, 0x00 }, // 4
|
||||
{ 0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00 }, // 5
|
||||
{ 0x1C, 0x30, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00 }, // 6
|
||||
{ 0x7E, 0x06, 0x06, 0x0C, 0x18, 0x18, 0x18, 0x00 }, // 7
|
||||
{ 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00 }, // 8
|
||||
{ 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0x00 }, // 9
|
||||
{ 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00 }, // :
|
||||
{ 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30 }, // ;
|
||||
{ 0x00, 0x06, 0x18, 0x60, 0x18, 0x06, 0x00, 0x00 }, // <
|
||||
{ 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00 }, // =
|
||||
{ 0x00, 0x60, 0x18, 0x06, 0x18, 0x60, 0x00, 0x00 }, // >
|
||||
{ 0x3C, 0x66, 0x06, 0x0C, 0x18, 0x00, 0x18, 0x00 }, // ?
|
||||
{ 0x7C, 0xC6, 0xDE, 0xD6, 0xDE, 0xC0, 0x78, 0x00 }, // @
|
||||
{ 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00 }, // A
|
||||
{ 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00 }, // B
|
||||
{ 0x1E, 0x30, 0x60, 0x60, 0x60, 0x30, 0x1E, 0x00 }, // C
|
||||
{ 0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00 }, // D
|
||||
{ 0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x7E, 0x00 }, // E
|
||||
{ 0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00 }, // F
|
||||
{ 0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3E, 0x00 }, // G
|
||||
{ 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00 }, // H
|
||||
{ 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00 }, // I
|
||||
{ 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x3C, 0x00 }, // J
|
||||
{ 0xC6, 0xCC, 0xD8, 0xF0, 0xD8, 0xCC, 0xC6, 0x00 }, // K
|
||||
{ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00 }, // L
|
||||
{ 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0x00 }, // M
|
||||
{ 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00 }, // N
|
||||
{ 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00 }, // O
|
||||
{ 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00 }, // P
|
||||
{ 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xDC, 0x7E, 0x00 }, // Q
|
||||
{ 0x7C, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x00 }, // R
|
||||
{ 0x3C, 0x66, 0x70, 0x3C, 0x0E, 0x66, 0x3C, 0x00 }, // S
|
||||
{ 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00 }, // T
|
||||
{ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00 }, // U
|
||||
{ 0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x00 }, // V
|
||||
{ 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00 }, // W
|
||||
{ 0xC3, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0xC3, 0x00 }, // X
|
||||
{ 0xC3, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x00 }, // Y
|
||||
{ 0xFE, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xFE, 0x00 }, // Z
|
||||
{ 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00 }, // [
|
||||
{ 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x00 }, // Backslash
|
||||
{ 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00 }, // ]
|
||||
{ 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00 }, // ^
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE }, // _
|
||||
{ 0x18, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00 }, // `
|
||||
{ 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00 }, // a
|
||||
{ 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00 }, // b
|
||||
{ 0x00, 0x00, 0x3C, 0x60, 0x60, 0x60, 0x3C, 0x00 }, // c
|
||||
{ 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00 }, // d
|
||||
{ 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00 }, // e
|
||||
{ 0x1C, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x30, 0x00 }, // f
|
||||
{ 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x3C }, // g
|
||||
{ 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00 }, // h
|
||||
{ 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x0C, 0x00 }, // i
|
||||
{ 0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x78 }, // j
|
||||
{ 0x60, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00 }, // k
|
||||
{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0C, 0x00 }, // l
|
||||
{ 0x00, 0x00, 0xEC, 0xFE, 0xD6, 0xC6, 0xC6, 0x00 }, // m
|
||||
{ 0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00 }, // n
|
||||
{ 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00 }, // o
|
||||
{ 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60 }, // p
|
||||
{ 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06 }, // q
|
||||
{ 0x00, 0x00, 0x7C, 0x66, 0x60, 0x60, 0x60, 0x00 }, // r
|
||||
{ 0x00, 0x00, 0x3C, 0x60, 0x3C, 0x06, 0x7C, 0x00 }, // s
|
||||
{ 0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x1C, 0x00 }, // t
|
||||
{ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00 }, // u
|
||||
{ 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00 }, // v
|
||||
{ 0x00, 0x00, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00 }, // w
|
||||
{ 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00 }, // x
|
||||
{ 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x30 }, // y
|
||||
{ 0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00 }, // z
|
||||
{ 0x0E, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0E, 0x00 }, // {
|
||||
{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00 }, // |
|
||||
{ 0x70, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x70, 0x00 }, // }
|
||||
{ 0x72, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // ~
|
||||
{ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x00 } //
|
||||
};
|
||||
|
||||
static void BootEnableMem()
|
||||
{
|
||||
// TEMP enable 1MB memory
|
||||
spi_osd_cmd8(OSD_CMD_MEM, 0x5);
|
||||
//EnableOsd();
|
||||
//spi8(OSD_CMD_RST);
|
||||
//rstval = (SPI_CPU_HLT | SPI_RST_CPU);
|
||||
//spi8(rstval);
|
||||
//DisableOsd();
|
||||
//SPIN(); SPIN(); SPIN(); SPIN();
|
||||
//while ((read32(REG_SYS_STAT_ADR) & 0x2));
|
||||
}
|
||||
|
||||
static void BootClearScreen(int adr, int size)
|
||||
{
|
||||
int i;
|
||||
mem_upload_init(adr);
|
||||
for (i = 0; i<size; i++)
|
||||
{
|
||||
mem_write16(0x0000);
|
||||
//mem_write16(i);
|
||||
}
|
||||
mem_upload_fini();
|
||||
}
|
||||
|
||||
static void BootUploadLogo()
|
||||
{
|
||||
fileTYPE file = { 0 };
|
||||
int x, y;
|
||||
int i = 0;
|
||||
int adr;
|
||||
|
||||
if (FileOpen(&file, "Amiga/" LOGO_FILE) || FileOpen(&file, LOGO_FILE)) {
|
||||
FileReadSec(&file, buffer);
|
||||
mem_upload_init(SCREEN_BPL1 + LOGO_OFFSET);
|
||||
adr = SCREEN_BPL1 + LOGO_OFFSET;
|
||||
for (y = 0; y<LOGO_HEIGHT; y++)
|
||||
{
|
||||
for (x = 0; x<LOGO_WIDTH / 16; x++)
|
||||
{
|
||||
if (i == 512)
|
||||
{
|
||||
mem_upload_fini();
|
||||
FileReadSec(&file, buffer);
|
||||
mem_upload_init(adr);
|
||||
i = 0;
|
||||
}
|
||||
spi8(buffer[i++]);
|
||||
spi8(buffer[i++]);
|
||||
//for (tmp=0; tmp<0x80000; tmp++);
|
||||
//printf("i=%03d x=%03d y=%03d dat[0]=0x%08x dat[1]=0x%08x\n", i, x, y, buffer[i], buffer[i+1]);
|
||||
adr += 2;
|
||||
}
|
||||
mem_upload_fini();
|
||||
mem_upload_init(SCREEN_BPL1 + LOGO_OFFSET + (y + 1)*(SCREEN_WIDTH / 8));
|
||||
adr = SCREEN_BPL1 + LOGO_OFFSET + (y + 1)*(SCREEN_WIDTH / 8);
|
||||
}
|
||||
mem_upload_fini();
|
||||
mem_upload_init(SCREEN_BPL2 + LOGO_OFFSET);
|
||||
adr = SCREEN_BPL2 + LOGO_OFFSET;
|
||||
for (y = 0; y<LOGO_HEIGHT; y++)
|
||||
{
|
||||
for (x = 0; x<LOGO_WIDTH / 16; x++)
|
||||
{
|
||||
if (i == 512)
|
||||
{
|
||||
mem_upload_fini();
|
||||
FileReadSec(&file, buffer);
|
||||
mem_upload_init(adr);
|
||||
i = 0;
|
||||
}
|
||||
spi8(buffer[i++]);
|
||||
spi8(buffer[i++]);
|
||||
adr += 2;
|
||||
}
|
||||
mem_upload_fini();
|
||||
mem_upload_init(SCREEN_BPL2 + LOGO_OFFSET + (y + 1)*(SCREEN_WIDTH / 8));
|
||||
adr = SCREEN_BPL2 + LOGO_OFFSET + (y + 1)*(SCREEN_WIDTH / 8);
|
||||
}
|
||||
mem_upload_fini();
|
||||
FileClose(&file);
|
||||
}
|
||||
}
|
||||
|
||||
static void BootUploadBall()
|
||||
{
|
||||
fileTYPE file = { 0 };
|
||||
int x;
|
||||
int i = 0;
|
||||
int adr;
|
||||
|
||||
if (FileOpen(&file, "Amiga/" BALL_FILE) || FileOpen(&file, BALL_FILE))
|
||||
{
|
||||
FileReadSec(&file, buffer);
|
||||
mem_upload_init(BALL_ADDRESS);
|
||||
adr = BALL_ADDRESS;
|
||||
for (x = 0; x<BALL_SIZE / 2; x++)
|
||||
{
|
||||
if (i == 512)
|
||||
{
|
||||
mem_upload_fini();
|
||||
FileReadSec(&file, buffer);
|
||||
mem_upload_init(adr);
|
||||
i = 0;
|
||||
}
|
||||
spi8(buffer[i++]);
|
||||
spi8(buffer[i++]);
|
||||
adr += 2;
|
||||
}
|
||||
mem_upload_fini();
|
||||
FileClose(&file);
|
||||
}
|
||||
}
|
||||
|
||||
static void BootUploadCopper()
|
||||
{
|
||||
fileTYPE file = { 0 };
|
||||
int x;
|
||||
int i = 0;
|
||||
int adr;
|
||||
|
||||
if (FileOpen(&file, "Amiga/" COPPER_FILE) || FileOpen(&file, COPPER_FILE))
|
||||
{
|
||||
FileReadSec(&file, buffer);
|
||||
mem_upload_init(COPPER_ADDRESS);
|
||||
adr = COPPER_ADDRESS;
|
||||
for (x = 0; x<COPPER_SIZE / 2; x++)
|
||||
{
|
||||
if (i == 512)
|
||||
{
|
||||
mem_upload_fini();
|
||||
FileReadSec(&file, buffer);
|
||||
mem_upload_init(adr);
|
||||
i = 0;
|
||||
}
|
||||
spi8(buffer[i++]);
|
||||
spi8(buffer[i++]);
|
||||
adr += 2;
|
||||
}
|
||||
mem_upload_fini();
|
||||
FileClose(&file);
|
||||
}
|
||||
else {
|
||||
mem_upload_init(COPPER_ADDRESS);
|
||||
mem_write16(0x00e0); mem_write16(0x0008);
|
||||
mem_write16(0x00e2); mem_write16(0x0000);
|
||||
mem_write16(0x00e4); mem_write16(0x0008);
|
||||
mem_write16(0x00e6); mem_write16(0x5000);
|
||||
mem_write16(0x0100); mem_write16(0xa200);
|
||||
mem_write16(0xffff); mem_write16(0xfffe);
|
||||
mem_upload_fini();
|
||||
}
|
||||
}
|
||||
|
||||
static void BootCustomInit()
|
||||
{
|
||||
//move.w #$0000,$dff1fc ; FMODE, slow fetch mode for AGA compatibility
|
||||
mem_upload_init(0xdff1fc);
|
||||
mem_write16(0x0000);
|
||||
mem_upload_fini();
|
||||
|
||||
//move.w #$0002,$dff02e ; COPCON, enable danger mode
|
||||
mem_upload_init(0xdff02e);
|
||||
mem_write16(0x0002);
|
||||
mem_upload_fini();
|
||||
|
||||
//move.l #Copper1,$dff080 ; COP1LCH, copper 1 pointer
|
||||
//move.l #Copper2,$dff084 ; CPO2LCH, copper 2 pointer
|
||||
mem_upload_init(0xdff080);
|
||||
mem_write16(0x0008); mem_write16(0xe680);
|
||||
mem_write16(0x0008); mem_write16(0xe69c);
|
||||
mem_upload_fini();
|
||||
|
||||
//move.w #$2c81,$dff08e ; DIWSTRT, screen upper left corner
|
||||
//move.w #$f4c1,$dff090 ; DIWSTOP, screen lower right corner
|
||||
//move.w #$003c,$dff092 ; DDFSTRT, display data fetch start
|
||||
//move.w #$00d4,$dff094 ; DDFSTOP, display data fetch stop
|
||||
//move.w #$87c0,$dff096 ; DMACON, enable important bits
|
||||
//move.w #$0000,$dff098 ; CLXCON, TODO
|
||||
//move.w #$7fff,$dff09a ; INTENA, disable all interrupts
|
||||
//move.w #$7fff,$dff09c ; INTREQ, disable all interrupts
|
||||
//move.w #$0000,$dff09e ; ADKCON, TODO
|
||||
mem_upload_init(0xdff08e);
|
||||
//mem_write16(0x1d64);
|
||||
//mem_write16(0x38c7);
|
||||
//mem_write16(0x0028);
|
||||
//mem_write16(0x00d8);
|
||||
mem_write16(0x2c81);
|
||||
mem_write16(0xf4c1);
|
||||
mem_write16(0x003c);
|
||||
mem_write16(0x00d4);
|
||||
mem_write16(0x87c0);
|
||||
mem_write16(0x0000);
|
||||
mem_write16(0x7fff);
|
||||
mem_write16(0x7fff);
|
||||
mem_upload_fini();
|
||||
|
||||
//move.w #(bpl1>>16)&$ffff,$dff0e0 ; BPL1PTH
|
||||
//move.w #bpl1&$ffff,$dff0e2 ; BPL1PTL
|
||||
//move.w #(bpl2>>16)&$ffff,$dff0e4 ; BPL2PTH
|
||||
//move.w #bpl2&$ffff,$dff0e6 ; BPL2PTL
|
||||
mem_upload_init(0xdff0e0);
|
||||
mem_write16(0x0008); mem_write16(0x0000);
|
||||
mem_write16(0x0008); mem_write16(0x5000);
|
||||
mem_upload_fini();
|
||||
|
||||
//move.w #$a200,$dff100 ; BPLCON0, two bitplanes & colorburst enabled
|
||||
//move.w #$0000,$dff102 ; BPLCON1, bitplane control scroll value
|
||||
//move.w #$0000,$dff104 ; BPLCON2, misc bitplane bits
|
||||
//move.w #$0000,$dff106 ; BPLCON3, TODO
|
||||
//move.w #$0000,$dff108 ; BPL1MOD, bitplane modulo for odd planes
|
||||
//move.w #$0000,$dff10a ; BPL2MOD, bitplane modulo for even planes
|
||||
mem_upload_init(0xdff100);
|
||||
mem_write16(0xa200);
|
||||
mem_write16(0x0000);
|
||||
mem_write16(0x0000);
|
||||
mem_write16(0x0000);
|
||||
mem_write16(0x0000);
|
||||
mem_write16(0x0000);
|
||||
mem_upload_fini();
|
||||
|
||||
//move.w #$09f0,$dff040 ; BLTCON0
|
||||
//move.w #$0000,$dff042 ; BLTCON1
|
||||
//move.w #$ffff,$dff044 ; BLTAFWM, blitter first word mask for srcA
|
||||
//move.w #$ffff,$dff046 ; BLTALWM, blitter last word mask for srcA
|
||||
mem_upload_init(0xdff040);
|
||||
mem_write16(0x09f0);
|
||||
mem_write16(0x0000);
|
||||
mem_write16(0xffff);
|
||||
mem_write16(0xffff);
|
||||
mem_upload_fini();
|
||||
|
||||
//move.w #$0000,$dff064 ; BLTAMOD
|
||||
//move.w #BLITS,$dff066 ; BLTDMOD
|
||||
mem_upload_init(0xdff064);
|
||||
mem_write16(0x0000);
|
||||
mem_write16(BLITS);
|
||||
mem_upload_fini();
|
||||
|
||||
//move.w #$0000,$dff180 ; COLOR00
|
||||
//move.w #$0aaa,$dff182 ; COLOR01
|
||||
//move.w #$0a00,$dff184 ; COLOR02
|
||||
//move.w #$0000,$dff186 ; COLOR03
|
||||
mem_upload_init(0xdff180);
|
||||
mem_write16(0x0000);
|
||||
mem_write16(0x0aaa);
|
||||
mem_write16(0x0a00);
|
||||
mem_write16(0x000a);
|
||||
mem_upload_fini();
|
||||
|
||||
//move.w #$0000,$dff088 ; COPJMP1, restart copper at location 1
|
||||
mem_upload_init(0xdff088);
|
||||
mem_write16(0x0000);
|
||||
mem_upload_fini();
|
||||
}
|
||||
|
||||
void BootInit()
|
||||
{
|
||||
puts("Running minimig setup");
|
||||
|
||||
EnableOsd();
|
||||
spi8(OSD_CMD_VERSION);
|
||||
char ver_beta = spi_b(0xff);
|
||||
char ver_major = spi_b(0xff);
|
||||
char ver_minor = spi_b(0xff);
|
||||
char ver_minion = spi_b(0xff);
|
||||
DisableOsd();
|
||||
spi8(OSD_CMD_RST);
|
||||
rstval = (SPI_RST_USR | SPI_RST_CPU | SPI_CPU_HLT);
|
||||
spi8(rstval);
|
||||
DisableOsd();
|
||||
EnableOsd();
|
||||
spi8(OSD_CMD_RST);
|
||||
rstval = (SPI_RST_CPU | SPI_CPU_HLT);
|
||||
spi8(rstval);
|
||||
DisableOsd();
|
||||
|
||||
if (cfg.bootscreen)
|
||||
{
|
||||
//default video config till real config loaded.
|
||||
ConfigVideo(0, 0, 0x40);
|
||||
ConfigAudio(0);
|
||||
|
||||
WaitTimer(100);
|
||||
|
||||
BootEnableMem();
|
||||
BootClearScreen(SCREEN_ADDRESS, SCREEN_MEM_SIZE);
|
||||
BootUploadLogo();
|
||||
BootUploadBall();
|
||||
BootUploadCopper();
|
||||
BootCustomInit();
|
||||
|
||||
WaitTimer(500);
|
||||
char rtl_ver[128];
|
||||
sprintf(rtl_ver, "MINIMIG-AGA%s v%d.%d.%d by Rok Krajnc. MiSTer port by Sorgelig.", ver_beta ? " BETA" : "", ver_major, ver_minor, ver_minion);
|
||||
BootPrintEx(rtl_ver);
|
||||
BootPrintEx(" ");
|
||||
BootPrintEx("Original Minimig by Dennis van Weeren");
|
||||
BootPrintEx("Updates by Jakub Bednarski, Tobias Gubener, Sascha Boing, A.M. Robinson & others");
|
||||
BootPrintEx(" ");
|
||||
}
|
||||
|
||||
config.kickstart[0] = 0;
|
||||
LoadConfiguration(0);
|
||||
}
|
||||
|
||||
void BootPrintEx(const char * str)
|
||||
{
|
||||
unsigned char i, j;
|
||||
unsigned char len;
|
||||
|
||||
printf(str);
|
||||
printf("\n");
|
||||
|
||||
len = strlen(str);
|
||||
len = (len>80) ? 80 : len;
|
||||
|
||||
for (j = 0; j<8; j++)
|
||||
{
|
||||
mem_upload_init(bootscreen_adr);
|
||||
for (i = 0; i<len; i += 2)
|
||||
{
|
||||
spi8(boot_font[str[i] - 32][j]);
|
||||
if (i == (len - 1))
|
||||
spi8(boot_font[0][j]);
|
||||
else
|
||||
spi8(boot_font[str[i + 1] - 32][j]);
|
||||
}
|
||||
mem_upload_fini();
|
||||
bootscreen_adr += 640 / 8;
|
||||
}
|
||||
}
|
||||
45
support/minimig/minimig_boot.h
Normal file
45
support/minimig/minimig_boot.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// boot.h
|
||||
// bootscreen functions
|
||||
// 2014, rok.krajnc@gmail.com
|
||||
|
||||
|
||||
#ifndef __MINIMIG_BOOT_H__
|
||||
#define __MINIMIG_BOOT_H__
|
||||
|
||||
|
||||
//// defines ////
|
||||
#define SCREEN_WIDTH 640
|
||||
#define SCREEN_HEIGHT 256
|
||||
#define SCREEN_SIZE SCREEN_WIDTH * SCREEN_HEIGHT
|
||||
#define SCREEN_MEM_SIZE 2*SCREEN_SIZE/8
|
||||
#define SCREEN_ADDRESS 0x80000
|
||||
#define SCREEN_BPL1 0x80000
|
||||
#define SCREEN_BPL2 0x85000
|
||||
|
||||
|
||||
#define LOGO_WIDTH 208
|
||||
#define LOGO_HEIGHT 32
|
||||
#define LOGO_OFFSET (64*SCREEN_WIDTH/8+24)
|
||||
#define LOGO_LSKIP (SCREEN_WIDTH-LOGO_WIDTH)/8
|
||||
#define LOGO_SIZE 0x680
|
||||
#define LOGO_FILE "MINIMIG.ART"
|
||||
|
||||
#define BALL_SIZE 0x4000
|
||||
#define BALL_ADDRESS 0x8a000
|
||||
#define BALL_FILE "MINIMIG.BAL"
|
||||
|
||||
#define COPPER_SIZE 0x35c
|
||||
#define COPPER_ADDRESS 0x8e680
|
||||
#define COPPER_FILE "MINIMIG.COP"
|
||||
|
||||
#define BLITS 64
|
||||
|
||||
//// functions ////
|
||||
void BootInit();
|
||||
void BootPrintEx(const char * str);
|
||||
void BootHome();
|
||||
|
||||
#define BootPrint(text) printf("%s\n", text)
|
||||
|
||||
#endif // __BOOT_H__
|
||||
|
||||
510
support/minimig/minimig_config.cpp
Normal file
510
support/minimig/minimig_config.cpp
Normal file
@@ -0,0 +1,510 @@
|
||||
// config.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "../../hardware.h"
|
||||
#include "minimig_boot.h"
|
||||
#include "../../file_io.h"
|
||||
#include "../../osd.h"
|
||||
#include "minimig_fdd.h"
|
||||
#include "minimig_hdd.h"
|
||||
#include "../../menu.h"
|
||||
#include "minimig_config.h"
|
||||
#include "../../user_io.h"
|
||||
#include "../../input.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char id[8];
|
||||
unsigned long version;
|
||||
char kickstart[1024];
|
||||
filterTYPE filter;
|
||||
unsigned char memory;
|
||||
unsigned char chipset;
|
||||
floppyTYPE floppy;
|
||||
unsigned char disable_ar3;
|
||||
unsigned char enable_ide;
|
||||
unsigned char scanlines;
|
||||
unsigned char audio;
|
||||
hardfileTYPE hardfile[2];
|
||||
unsigned char cpu;
|
||||
unsigned char autofire;
|
||||
} configTYPE_old;
|
||||
|
||||
configTYPE config = { 0 };
|
||||
unsigned char romkey[3072];
|
||||
|
||||
static void SendFileV2(fileTYPE* file, unsigned char* key, int keysize, int address, int size)
|
||||
{
|
||||
static uint8_t buf[512];
|
||||
unsigned int keyidx = 0;
|
||||
printf("File size: %dkB\n", size >> 1);
|
||||
printf("[");
|
||||
if (keysize)
|
||||
{
|
||||
// read header
|
||||
FileReadAdv(file, buf, 0xb);
|
||||
}
|
||||
|
||||
for (int i = 0; i<size; i++)
|
||||
{
|
||||
if (!(i & 31)) printf("*");
|
||||
FileReadAdv(file, buf, 512);
|
||||
|
||||
if (keysize)
|
||||
{
|
||||
// decrypt ROM
|
||||
for (int j = 0; j<512; j++)
|
||||
{
|
||||
buf[j] ^= key[keyidx++];
|
||||
if (keyidx >= keysize) keyidx -= keysize;
|
||||
}
|
||||
}
|
||||
EnableOsd();
|
||||
unsigned int adr = address + i * 512;
|
||||
spi8(OSD_CMD_WR);
|
||||
spi8(adr & 0xff); adr = adr >> 8;
|
||||
spi8(adr & 0xff); adr = adr >> 8;
|
||||
spi8(adr & 0xff); adr = adr >> 8;
|
||||
spi8(adr & 0xff); adr = adr >> 8;
|
||||
for (int j = 0; j<512; j = j + 4)
|
||||
{
|
||||
spi8(buf[j + 0]);
|
||||
spi8(buf[j + 1]);
|
||||
spi8(buf[j + 2]);
|
||||
spi8(buf[j + 3]);
|
||||
}
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
printf("]\n");
|
||||
}
|
||||
|
||||
static char UploadKickstart(char *name)
|
||||
{
|
||||
fileTYPE file = { 0 };
|
||||
int keysize = 0;
|
||||
|
||||
BootPrint("Checking for Amiga Forever key file:");
|
||||
if (FileOpen(&file, "Amiga/ROM.KEY") || FileOpen(&file, "ROM.KEY")) {
|
||||
keysize = file.size;
|
||||
if (file.size<sizeof(romkey))
|
||||
{
|
||||
FileReadAdv(&file, romkey, keysize);
|
||||
BootPrint("Loaded Amiga Forever key file");
|
||||
}
|
||||
else
|
||||
{
|
||||
BootPrint("Amiga Forever keyfile is too large!");
|
||||
}
|
||||
FileClose(&file);
|
||||
}
|
||||
BootPrint("Loading file: ");
|
||||
BootPrint(name);
|
||||
|
||||
if (FileOpen(&file, name)) {
|
||||
if (file.size == 0x100000) {
|
||||
// 1MB Kickstart ROM
|
||||
BootPrint("Uploading 1MB Kickstart ...");
|
||||
SendFileV2(&file, NULL, 0, 0xe00000, file.size >> 10);
|
||||
SendFileV2(&file, NULL, 0, 0xf80000, file.size >> 10);
|
||||
FileClose(&file);
|
||||
return(1);
|
||||
}
|
||||
else if (file.size == 0x80000) {
|
||||
// 512KB Kickstart ROM
|
||||
BootPrint("Uploading 512KB Kickstart ...");
|
||||
SendFileV2(&file, NULL, 0, 0xf80000, file.size >> 9);
|
||||
FileClose(&file);
|
||||
FileOpen(&file, name);
|
||||
SendFileV2(&file, NULL, 0, 0xe00000, file.size >> 9);
|
||||
FileClose(&file);
|
||||
return(1);
|
||||
}
|
||||
else if ((file.size == 0x8000b) && keysize) {
|
||||
// 512KB Kickstart ROM
|
||||
BootPrint("Uploading 512 KB Kickstart (Probably Amiga Forever encrypted...)");
|
||||
SendFileV2(&file, romkey, keysize, 0xf80000, file.size >> 9);
|
||||
FileClose(&file);
|
||||
FileOpen(&file, name);
|
||||
SendFileV2(&file, romkey, keysize, 0xe00000, file.size >> 9);
|
||||
FileClose(&file);
|
||||
return(1);
|
||||
}
|
||||
else if (file.size == 0x40000) {
|
||||
// 256KB Kickstart ROM
|
||||
BootPrint("Uploading 256 KB Kickstart...");
|
||||
SendFileV2(&file, NULL, 0, 0xf80000, file.size >> 9);
|
||||
FileClose(&file);
|
||||
FileOpen(&file, name); // TODO will this work
|
||||
SendFileV2(&file, NULL, 0, 0xfc0000, file.size >> 9);
|
||||
FileClose(&file);
|
||||
return(1);
|
||||
}
|
||||
else if ((file.size == 0x4000b) && keysize) {
|
||||
// 256KB Kickstart ROM
|
||||
BootPrint("Uploading 256 KB Kickstart (Probably Amiga Forever encrypted...");
|
||||
SendFileV2(&file, romkey, keysize, 0xf80000, file.size >> 9);
|
||||
FileClose(&file);
|
||||
FileOpen(&file, name); // TODO will this work
|
||||
SendFileV2(&file, romkey, keysize, 0xfc0000, file.size >> 9);
|
||||
FileClose(&file);
|
||||
return(1);
|
||||
}
|
||||
else {
|
||||
BootPrint("Unsupported ROM file size!");
|
||||
}
|
||||
FileClose(&file);
|
||||
}
|
||||
else {
|
||||
printf("No \"%s\" file!\n", name);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static char UploadActionReplay()
|
||||
{
|
||||
fileTYPE file = { 0 };
|
||||
if(FileOpen(&file, "Amiga/HRTMON.ROM") || FileOpen(&file, "HRTMON.ROM"))
|
||||
{
|
||||
int adr, data;
|
||||
puts("Uploading HRTmon ROM... ");
|
||||
SendFileV2(&file, NULL, 0, 0xa10000, (file.size + 511) >> 9);
|
||||
// HRTmon config
|
||||
adr = 0xa10000 + 20;
|
||||
spi_osd_cmd32le_cont(OSD_CMD_WR, adr);
|
||||
data = 0x00800000; // mon_size, 4 bytes
|
||||
spi8((data >> 24) & 0xff); spi8((data >> 16) & 0xff);
|
||||
spi8((data >> 8) & 0xff); spi8((data >> 0) & 0xff);
|
||||
data = 0x00; // col0h, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = 0x5a; // col0l, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = 0x0f; // col1h, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = 0xff; // col1l, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = 0x01; // right, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = 0x00; // keyboard, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = 0x01; // key, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = config.enable_ide ? 1 : 0; // ide, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = 0x01; // a1200, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = config.chipset&CONFIG_AGA ? 1 : 0; // aga, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = 0x01; // insert, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = 0x0f; // delay, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = 0x01; // lview, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = 0x00; // cd32, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = config.chipset&CONFIG_NTSC ? 1 : 0; // screenmode, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = 1; // novbr, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = 0; // entered, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
data = 1; // hexmode, 1 byte
|
||||
spi8((data >> 0) & 0xff);
|
||||
DisableOsd();
|
||||
adr = 0xa10000 + 68;
|
||||
spi_osd_cmd32le_cont(OSD_CMD_WR, adr);
|
||||
data = ((config.memory & 0x3) + 1) * 512 * 1024; // maxchip, 4 bytes TODO is this correct?
|
||||
spi8((data >> 24) & 0xff); spi8((data >> 16) & 0xff);
|
||||
spi8((data >> 8) & 0xff); spi8((data >> 0) & 0xff);
|
||||
DisableOsd();
|
||||
|
||||
FileClose(&file);
|
||||
return(1);
|
||||
}
|
||||
else {
|
||||
puts("\nhrtmon.rom not found!\n");
|
||||
return(0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static char* GetConfigurationName(int num)
|
||||
{
|
||||
static char path[128];
|
||||
sprintf(path, "%s/%s", getRootDir(), CONFIG_DIR);
|
||||
|
||||
DIR *d;
|
||||
struct dirent *dir;
|
||||
d = opendir(path);
|
||||
if (d)
|
||||
{
|
||||
if(num) sprintf(path, "minimig%d", num);
|
||||
else sprintf(path, "minimig.cfg", num);
|
||||
|
||||
while ((dir = readdir(d)) != NULL)
|
||||
{
|
||||
int len = strlen(dir->d_name);
|
||||
if (len>10 && !strncasecmp(dir->d_name, path, strlen(path)) && !strcasecmp(dir->d_name+len-4, ".cfg"))
|
||||
{
|
||||
closedir(d);
|
||||
strcpy(path, dir->d_name);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned char SaveConfiguration(int num)
|
||||
{
|
||||
const char *filename = GetConfigurationName(num);
|
||||
if (!filename)
|
||||
{
|
||||
static char name[32];
|
||||
if (num) sprintf(name, "minimig%d.cfg", num);
|
||||
else sprintf(name, "minimig.cfg");
|
||||
|
||||
filename = name;
|
||||
}
|
||||
|
||||
return FileSaveConfig(filename, &config, sizeof(config));
|
||||
}
|
||||
|
||||
const char* GetConfigDisplayName(int num)
|
||||
{
|
||||
char *filename = GetConfigurationName(num);
|
||||
if (!filename) return NULL;
|
||||
|
||||
filename[strlen(filename) - 4] = 0;
|
||||
char *p = strchr(filename, '_');
|
||||
|
||||
if (p) return p+1;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static int force_reload_kickstart = 0;
|
||||
static void ApplyConfiguration(char reloadkickstart)
|
||||
{
|
||||
if (force_reload_kickstart) reloadkickstart = 1;
|
||||
force_reload_kickstart = 0;
|
||||
|
||||
ConfigCPU(config.cpu);
|
||||
|
||||
if (!reloadkickstart)
|
||||
{
|
||||
ConfigChipset(config.chipset);
|
||||
ConfigFloppy(config.floppy.drives, config.floppy.speed);
|
||||
}
|
||||
|
||||
printf("CPU clock : %s\n", config.chipset & 0x01 ? "turbo" : "normal");
|
||||
printf("Chip RAM size : %s\n", config_memory_chip_msg[config.memory & 0x03]);
|
||||
printf("Slow RAM size : %s\n", config_memory_slow_msg[config.memory >> 2 & 0x03]);
|
||||
printf("Fast RAM size : %s\n", config_memory_fast_msg[config.memory >> 4 & 0x03]);
|
||||
|
||||
printf("Floppy drives : %u\n", config.floppy.drives + 1);
|
||||
printf("Floppy speed : %s\n", config.floppy.speed ? "fast" : "normal");
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("\nIDE state: %s.\n", config.enable_ide ? "enabled" : "disabled");
|
||||
if (config.enable_ide)
|
||||
{
|
||||
printf("Primary Master HDD is %s.\n", config.hardfile[0].enabled ? "enabled" : "disabled");
|
||||
printf("Primary Slave HDD is %s.\n", config.hardfile[1].enabled ? "enabled" : "disabled");
|
||||
printf("Secondary Master HDD is %s.\n", config.hardfile[2].enabled ? "enabled" : "disabled");
|
||||
printf("Secondary Slave HDD is %s.\n", config.hardfile[3].enabled ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
rstval = SPI_CPU_HLT;
|
||||
spi_osd_cmd8(OSD_CMD_RST, rstval);
|
||||
spi_osd_cmd8(OSD_CMD_HDD, (config.enable_ide ? 1 : 0) | (OpenHardfile(0) ? 2 : 0) | (OpenHardfile(1) ? 4 : 0) | (OpenHardfile(2) ? 8 : 0) | (OpenHardfile(3) ? 16 : 0));
|
||||
|
||||
ConfigMemory(config.memory);
|
||||
ConfigCPU(config.cpu);
|
||||
|
||||
ConfigChipset(config.chipset);
|
||||
ConfigFloppy(config.floppy.drives, config.floppy.speed);
|
||||
|
||||
if (config.memory & 0x40) UploadActionReplay();
|
||||
|
||||
if (reloadkickstart)
|
||||
{
|
||||
printf("Reloading kickstart ...\n");
|
||||
rstval |= (SPI_RST_CPU | SPI_CPU_HLT);
|
||||
spi_osd_cmd8(OSD_CMD_RST, rstval);
|
||||
if (!UploadKickstart(config.kickstart))
|
||||
{
|
||||
strcpy(config.kickstart, "Amiga/KICK.ROM");
|
||||
if (!UploadKickstart(config.kickstart))
|
||||
{
|
||||
strcpy(config.kickstart, "KICK.ROM");
|
||||
if (!UploadKickstart(config.kickstart))
|
||||
{
|
||||
BootPrintEx("No Kickstart loaded. Press F12 for settings.");
|
||||
BootPrintEx("** Halted! **");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
rstval |= (SPI_RST_USR | SPI_RST_CPU);
|
||||
spi_osd_cmd8(OSD_CMD_RST, rstval);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Resetting ...\n");
|
||||
rstval |= (SPI_RST_USR | SPI_RST_CPU);
|
||||
spi_osd_cmd8(OSD_CMD_RST, rstval);
|
||||
}
|
||||
|
||||
rstval = 0;
|
||||
spi_osd_cmd8(OSD_CMD_RST, rstval);
|
||||
|
||||
ConfigVideo(config.filter.hires, config.filter.lores, config.scanlines);
|
||||
ConfigAudio(config.audio);
|
||||
ConfigAutofire(config.autofire, 0xC);
|
||||
}
|
||||
|
||||
unsigned char LoadConfiguration(int num)
|
||||
{
|
||||
static const char config_id[] = "MNMGCFG0";
|
||||
char updatekickstart = 0;
|
||||
char result = 0;
|
||||
unsigned char key, i;
|
||||
|
||||
const char *filename = GetConfigurationName(num);
|
||||
|
||||
// load configuration data
|
||||
int size;
|
||||
if(filename && (size = FileLoadConfig(filename, 0, 0))>0)
|
||||
{
|
||||
BootPrint("Opened configuration file\n");
|
||||
printf("Configuration file size: %s, %lu\n", filename, size);
|
||||
if (size == sizeof(config))
|
||||
{
|
||||
static configTYPE tmpconf;
|
||||
if (FileLoadConfig(filename, &tmpconf, sizeof(tmpconf)))
|
||||
{
|
||||
// check file id and version
|
||||
if (strncmp(tmpconf.id, config_id, sizeof(config.id)) == 0) {
|
||||
// A few more sanity checks...
|
||||
if (tmpconf.floppy.drives <= 4) {
|
||||
// If either the old config and new config have a different kickstart file,
|
||||
// or this is the first boot, we need to upload a kickstart image.
|
||||
if (strcmp(tmpconf.kickstart, config.kickstart) != 0) {
|
||||
updatekickstart = true;
|
||||
}
|
||||
memcpy((void*)&config, (void*)&tmpconf, sizeof(config));
|
||||
result = 1; // We successfully loaded the config.
|
||||
}
|
||||
else BootPrint("Config file sanity check failed!\n");
|
||||
}
|
||||
else BootPrint("Wrong configuration file format!\n");
|
||||
}
|
||||
else printf("Cannot load configuration file\n");
|
||||
}
|
||||
else if (size == sizeof(configTYPE_old))
|
||||
{
|
||||
static configTYPE_old tmpconf;
|
||||
printf("Old Configuration file.\n");
|
||||
if (FileLoadConfig(filename, &tmpconf, sizeof(tmpconf)))
|
||||
{
|
||||
// check file id and version
|
||||
if (strncmp(tmpconf.id, config_id, sizeof(config.id)) == 0) {
|
||||
// A few more sanity checks...
|
||||
if (tmpconf.floppy.drives <= 4) {
|
||||
// If either the old config and new config have a different kickstart file,
|
||||
// or this is the first boot, we need to upload a kickstart image.
|
||||
if (strcmp(tmpconf.kickstart, config.kickstart) != 0) {
|
||||
updatekickstart = true;
|
||||
}
|
||||
memcpy((void*)&config, (void*)&tmpconf, sizeof(config));
|
||||
config.cpu = tmpconf.cpu;
|
||||
config.autofire = tmpconf.autofire;
|
||||
memset(&config.hardfile[2], 0, sizeof(config.hardfile[2]));
|
||||
memset(&config.hardfile[3], 0, sizeof(config.hardfile[3]));
|
||||
result = 1; // We successfully loaded the config.
|
||||
}
|
||||
else BootPrint("Config file sanity check failed!\n");
|
||||
}
|
||||
else BootPrint("Wrong configuration file format!\n");
|
||||
}
|
||||
else printf("Cannot load configuration file\n");
|
||||
}
|
||||
else printf("Wrong configuration file size: %lu (expected: %lu)\n", size, sizeof(config));
|
||||
}
|
||||
if (!result) {
|
||||
BootPrint("Can not open configuration file!\n");
|
||||
BootPrint("Setting config defaults\n");
|
||||
// set default configuration
|
||||
memset((void*)&config, 0, sizeof(config)); // Finally found default config bug - params were reversed!
|
||||
strncpy(config.id, config_id, sizeof(config.id));
|
||||
strcpy(config.kickstart, "Amiga/KICK.ROM");
|
||||
config.memory = 0x11;
|
||||
config.cpu = 0;
|
||||
config.chipset = 0;
|
||||
config.floppy.speed = CONFIG_FLOPPY2X;
|
||||
config.floppy.drives = 1;
|
||||
config.enable_ide = 0;
|
||||
config.hardfile[0].enabled = 1;
|
||||
config.hardfile[0].filename[0] = 0;
|
||||
config.hardfile[1].enabled = 1;
|
||||
config.hardfile[1].filename[0] = 0;
|
||||
updatekickstart = true;
|
||||
BootPrintEx(">>> No config found. Using defaults. <<<");
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
df[i].status = 0;
|
||||
FileClose(&df[i].file);
|
||||
}
|
||||
|
||||
// print config to boot screen
|
||||
char cfg_str[256];
|
||||
sprintf(cfg_str, "CPU: %s, Chipset: %s, ChipRAM: %s, FastRAM: %s, SlowRAM: %s",
|
||||
config_cpu_msg[config.cpu & 0x03], config_chipset_msg[(config.chipset >> 2) & 7],
|
||||
config_memory_chip_msg[(config.memory >> 0) & 0x03], config_memory_fast_msg[(config.memory >> 4) & 0x03], config_memory_slow_msg[(config.memory >> 2) & 0x03]
|
||||
);
|
||||
BootPrintEx(cfg_str);
|
||||
|
||||
input_poll(0);
|
||||
if (is_key_pressed(59))
|
||||
{
|
||||
BootPrintEx("Forcing NTSC video ...");
|
||||
//force NTSC mode if F1 pressed
|
||||
config.chipset |= CONFIG_NTSC;
|
||||
}
|
||||
else if (is_key_pressed(60))
|
||||
{
|
||||
BootPrintEx("Forcing PAL video ...");
|
||||
// force PAL mode if F2 pressed
|
||||
config.chipset &= ~CONFIG_NTSC;
|
||||
}
|
||||
|
||||
ApplyConfiguration(updatekickstart);
|
||||
return(result);
|
||||
}
|
||||
|
||||
void MinimigReset()
|
||||
{
|
||||
ApplyConfiguration(0);
|
||||
user_io_rtc_reset();
|
||||
}
|
||||
|
||||
void SetKickstart(char *name)
|
||||
{
|
||||
int len = strlen(name);
|
||||
if (len > (sizeof(config.kickstart) - 1)) len = sizeof(config.kickstart) - 1;
|
||||
memcpy(config.kickstart, name, len);
|
||||
config.kickstart[len] = 0;
|
||||
force_reload_kickstart = 1;
|
||||
}
|
||||
53
support/minimig/minimig_config.h
Normal file
53
support/minimig/minimig_config.h
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
#ifndef __MINIMIG_CONFIG_H__
|
||||
#define __MINIMIG_CONFIG_H__
|
||||
|
||||
#include "../../file_io.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char lores;
|
||||
unsigned char hires;
|
||||
} filterTYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char speed;
|
||||
unsigned char drives;
|
||||
} floppyTYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char enabled;
|
||||
unsigned char reserved;
|
||||
char filename[1024];
|
||||
} hardfileTYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char id[8];
|
||||
unsigned long version;
|
||||
char kickstart[1024];
|
||||
filterTYPE filter;
|
||||
unsigned char memory;
|
||||
unsigned char chipset;
|
||||
floppyTYPE floppy;
|
||||
unsigned char disable_ar3;
|
||||
unsigned char enable_ide;
|
||||
unsigned char scanlines;
|
||||
unsigned char audio;
|
||||
hardfileTYPE hardfile[4];
|
||||
unsigned char cpu;
|
||||
unsigned char autofire;
|
||||
} configTYPE;
|
||||
|
||||
extern configTYPE config;
|
||||
|
||||
unsigned char LoadConfiguration(int num);
|
||||
unsigned char SaveConfiguration(int num);
|
||||
const char* GetConfigDisplayName(int num);
|
||||
|
||||
void MinimigReset();
|
||||
void SetKickstart(char *name);
|
||||
|
||||
#endif
|
||||
672
support/minimig/minimig_fdd.cpp
Normal file
672
support/minimig/minimig_fdd.cpp
Normal file
@@ -0,0 +1,672 @@
|
||||
/*
|
||||
Copyright 2005, 2006, 2007 Dennis van Weeren
|
||||
Copyright 2008, 2009 Jakub Bednarski
|
||||
|
||||
This file is part of Minimig
|
||||
|
||||
Minimig is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Minimig is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// 2009-11-14 - adapted gap size
|
||||
// 2009-12-24 - updated sync word list
|
||||
// - fixed sector header generation
|
||||
// 2010-01-09 - support for variable number of tracks
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../../hardware.h"
|
||||
#include "../../file_io.h"
|
||||
#include "minimig_fdd.h"
|
||||
#include "minimig_config.h"
|
||||
#include "../../debug.h"
|
||||
#include "../../fpga_io.h"
|
||||
#include "../../menu.h"
|
||||
|
||||
unsigned char drives = 0; // number of active drives reported by FPGA (may change only during reset)
|
||||
adfTYPE *pdfx; // drive select pointer
|
||||
adfTYPE df[4] = { 0 }; // drive information structure
|
||||
|
||||
static uint8_t sector_buffer[512];
|
||||
|
||||
unsigned char Error;
|
||||
|
||||
#define TRACK_SIZE 12668
|
||||
#define HEADER_SIZE 0x40
|
||||
#define DATA_SIZE 0x400
|
||||
#define SECTOR_SIZE (HEADER_SIZE + DATA_SIZE)
|
||||
#define SECTOR_COUNT 11
|
||||
#define LAST_SECTOR (SECTOR_COUNT - 1)
|
||||
#define GAP_SIZE (TRACK_SIZE - SECTOR_COUNT * SECTOR_SIZE)
|
||||
|
||||
#define B2W(a,b) (((((uint16_t)(a))<<8) & 0xFF00) | ((uint16_t)(b) & 0x00FF))
|
||||
|
||||
// sends the data in the sector buffer to the FPGA, translated into an Amiga floppy format sector
|
||||
// note that we do not insert clock bits because they will be stripped by the Amiga software anyway
|
||||
void SendSector(unsigned char *pData, unsigned char sector, unsigned char track, unsigned char dsksynch, unsigned char dsksyncl)
|
||||
{
|
||||
unsigned char checksum[4];
|
||||
unsigned short i;
|
||||
unsigned char x,y;
|
||||
unsigned char *p;
|
||||
|
||||
// preamble
|
||||
spi_w(0xAAAA);
|
||||
spi_w(0xAAAA);
|
||||
|
||||
// synchronization
|
||||
spi_w(B2W(dsksynch, dsksyncl));
|
||||
spi_w(B2W(dsksynch, dsksyncl));
|
||||
|
||||
// odd bits of header
|
||||
x = 0x55;
|
||||
checksum[0] = x;
|
||||
y = track >> 1 & 0x55;
|
||||
checksum[1] = y;
|
||||
spi_w(B2W(x,y));
|
||||
|
||||
x = sector >> 1 & 0x55;
|
||||
checksum[2] = x;
|
||||
y = 11 - sector >> 1 & 0x55;
|
||||
checksum[3] = y;
|
||||
spi_w(B2W(x, y));
|
||||
|
||||
// even bits of header
|
||||
x = 0x55;
|
||||
checksum[0] ^= x;
|
||||
y = track & 0x55;
|
||||
checksum[1] ^= y;
|
||||
spi_w(B2W(x, y));
|
||||
|
||||
x = sector & 0x55;
|
||||
checksum[2] ^= x;
|
||||
y = 11 - sector & 0x55;
|
||||
checksum[3] ^= y;
|
||||
spi_w(B2W(x, y));
|
||||
|
||||
// sector label and reserved area (changes nothing to checksum)
|
||||
i = 0x10;
|
||||
while (i--) spi_w(0xAAAA);
|
||||
|
||||
// send header checksum
|
||||
spi_w(0xAAAA);
|
||||
spi_w(0xAAAA);
|
||||
spi_w(B2W(checksum[0] | 0xAA, checksum[1] | 0xAA));
|
||||
spi_w(B2W(checksum[2] | 0xAA, checksum[3] | 0xAA));
|
||||
|
||||
// calculate data checksum
|
||||
checksum[0] = 0;
|
||||
checksum[1] = 0;
|
||||
checksum[2] = 0;
|
||||
checksum[3] = 0;
|
||||
|
||||
p = pData;
|
||||
i = DATA_SIZE / 2 / 4;
|
||||
while (i--)
|
||||
{
|
||||
x = *p++;
|
||||
checksum[0] ^= x ^ x >> 1;
|
||||
x = *p++;
|
||||
checksum[1] ^= x ^ x >> 1;
|
||||
x = *p++;
|
||||
checksum[2] ^= x ^ x >> 1;
|
||||
x = *p++;
|
||||
checksum[3] ^= x ^ x >> 1;
|
||||
}
|
||||
|
||||
// send data checksum
|
||||
spi_w(0xAAAA);
|
||||
spi_w(0xAAAA);
|
||||
spi_w(B2W(checksum[0] | 0xAA, checksum[1] | 0xAA));
|
||||
spi_w(B2W(checksum[2] | 0xAA, checksum[3] | 0xAA));
|
||||
|
||||
// odd bits of data field
|
||||
i = DATA_SIZE / 4;
|
||||
p = pData;
|
||||
while (i--)
|
||||
{
|
||||
x = *p++ >> 1 | 0xAA;
|
||||
y = *p++ >> 1 | 0xAA;
|
||||
spi_w(B2W(x, y));
|
||||
}
|
||||
|
||||
// even bits of data field
|
||||
i = DATA_SIZE / 4;
|
||||
p = pData;
|
||||
while (i--)
|
||||
{
|
||||
x = *p++ | 0xAA;
|
||||
y = *p++ | 0xAA;
|
||||
spi_w(B2W(x, y));
|
||||
}
|
||||
}
|
||||
|
||||
void SendGap(void)
|
||||
{
|
||||
unsigned short i = GAP_SIZE/2;
|
||||
while (i--) spi_w(0xAAAA);
|
||||
}
|
||||
|
||||
// read a track from disk
|
||||
void ReadTrack(adfTYPE *drive)
|
||||
{
|
||||
// track number is updated in drive struct before calling this function
|
||||
|
||||
unsigned char sector;
|
||||
unsigned char status;
|
||||
unsigned char track;
|
||||
unsigned short dsksync;
|
||||
unsigned short dsklen;
|
||||
uint16_t tmp;
|
||||
//unsigned short n;
|
||||
|
||||
if (drive->track >= drive->tracks)
|
||||
{
|
||||
fdd_debugf("Illegal track read: %d\n", drive->track);
|
||||
drive->track = drive->tracks - 1;
|
||||
}
|
||||
|
||||
unsigned long lba;
|
||||
|
||||
if (drive->track != drive->track_prev)
|
||||
{ // track step or track 0, start at beginning of track
|
||||
drive->track_prev = drive->track;
|
||||
sector = 0;
|
||||
drive->sector_offset = sector;
|
||||
lba = drive->track * SECTOR_COUNT;
|
||||
}
|
||||
else
|
||||
{ // same track, start at next sector in track
|
||||
sector = drive->sector_offset;
|
||||
lba = (drive->track * SECTOR_COUNT) + sector;
|
||||
}
|
||||
|
||||
if (!FileSeekLBA(&drive->file, lba))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnableFpga();
|
||||
tmp = spi_w(0);
|
||||
status = (uint8_t)(tmp>>8); // read request signal
|
||||
track = (uint8_t)tmp; // track number (cylinder & head)
|
||||
dsksync = spi_w(0); // disk sync
|
||||
dsklen = spi_w(0) & 0x3FFF; // mfm words to transfer
|
||||
DisableFpga();
|
||||
|
||||
if (track >= drive->tracks)
|
||||
track = drive->tracks - 1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
FileReadSec(&drive->file, sector_buffer);
|
||||
|
||||
EnableFpga();
|
||||
|
||||
// check if FPGA is still asking for data
|
||||
tmp = spi_w(0);
|
||||
status = (uint8_t)(tmp >> 8); // read request signal
|
||||
track = (uint8_t)tmp; // track number (cylinder & head)
|
||||
dsksync = spi_w(0); // disk sync
|
||||
dsklen = spi_w(0) & 0x3FFF; // mfm words to transfer
|
||||
|
||||
if (track >= drive->tracks)
|
||||
track = drive->tracks - 1;
|
||||
|
||||
// workaround for Copy Lock in Wiz'n'Liz and North&South (might brake other games)
|
||||
if (dsksync == 0x0000 || dsksync == 0x8914 || dsksync == 0xA144)
|
||||
dsksync = 0x4489;
|
||||
|
||||
// North&South: $A144
|
||||
// Wiz'n'Liz (Copy Lock): $8914
|
||||
// Prince of Persia: $4891
|
||||
// Commando: $A245
|
||||
|
||||
// some loaders stop dma if sector header isn't what they expect
|
||||
// because we don't check dma transfer count after sending a word
|
||||
// the track can be changed while we are sending the rest of the previous sector
|
||||
// in this case let's start transfer from the beginning
|
||||
if (track == drive->track)
|
||||
{
|
||||
// send sector if fpga is still asking for data
|
||||
if (status & CMD_RDTRK)
|
||||
{
|
||||
//GenerateHeader(sector_header, sector_buffer, sector, track, dsksync);
|
||||
//SendSector(sector_header, sector_buffer);
|
||||
SendSector(sector_buffer, sector, track, (unsigned char)(dsksync >> 8), (unsigned char)dsksync);
|
||||
|
||||
if (sector == LAST_SECTOR)
|
||||
SendGap();
|
||||
}
|
||||
}
|
||||
|
||||
// we are done accessing FPGA
|
||||
DisableFpga();
|
||||
|
||||
// track has changed
|
||||
if (track != drive->track)
|
||||
break;
|
||||
|
||||
// read dma request
|
||||
if (!(status & CMD_RDTRK))
|
||||
break;
|
||||
|
||||
sector++;
|
||||
if (sector >= SECTOR_COUNT)
|
||||
{
|
||||
// go to the start of current track
|
||||
sector = 0;
|
||||
lba = drive->track * SECTOR_COUNT;
|
||||
if (!FileSeekLBA(&drive->file, lba))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// remember current sector
|
||||
drive->sector_offset = sector;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char FindSync(adfTYPE *drive)
|
||||
// reads data from fifo till it finds sync word or fifo is empty and dma inactive (so no more data is expected)
|
||||
{
|
||||
unsigned char c1, c2, c3, c4;
|
||||
unsigned short n;
|
||||
uint16_t tmp;
|
||||
|
||||
while (1)
|
||||
{
|
||||
EnableFpga();
|
||||
tmp = spi_w(0);
|
||||
c1 = (uint8_t)(tmp >> 8); // write request signal
|
||||
c2 = (uint8_t)tmp; // track number (cylinder & head)
|
||||
if (!(c1 & CMD_WRTRK))
|
||||
break;
|
||||
if (c2 != drive->track)
|
||||
break;
|
||||
spi_w(0); //disk sync word
|
||||
|
||||
n = spi_w(0) & 0xBFFF; // mfm words to transfer
|
||||
|
||||
if (n == 0)
|
||||
break;
|
||||
|
||||
n &= 0x3FFF;
|
||||
|
||||
while (n--)
|
||||
{
|
||||
if (spi_w(0) == 0x4489)
|
||||
{
|
||||
DisableFpga();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
DisableFpga();
|
||||
}
|
||||
DisableFpga();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char GetHeader(unsigned char *pTrack, unsigned char *pSector)
|
||||
// this function reads data from fifo till it finds sync word or dma is inactive
|
||||
{
|
||||
unsigned char c, c1, c2, c3, c4;
|
||||
unsigned char i;
|
||||
unsigned char checksum[4];
|
||||
uint16_t tmp;
|
||||
|
||||
Error = 0;
|
||||
while (1)
|
||||
{
|
||||
EnableFpga();
|
||||
c1 = (uint8_t)(spi_w(0)>>8); // write request signal, track number (cylinder & head)
|
||||
if (!(c1 & CMD_WRTRK))
|
||||
break;
|
||||
spi_w(0); //disk sync word
|
||||
tmp = spi_w(0); // mfm words to transfer
|
||||
|
||||
if ((tmp & 0x3F00) != 0 || (tmp & 0xFF) > 24)// remaining header data is 25 mfm words
|
||||
{
|
||||
tmp = spi_w(0); // second sync
|
||||
if (tmp != 0x4489)
|
||||
{
|
||||
Error = 21;
|
||||
fdd_debugf("\nSecond sync word missing...\n");
|
||||
break;
|
||||
}
|
||||
|
||||
tmp = spi_w(0);
|
||||
c = (uint8_t)(tmp >> 8);
|
||||
checksum[0] = c;
|
||||
c1 = (c & 0x55) << 1;
|
||||
c = (uint8_t)tmp;
|
||||
checksum[1] = c;
|
||||
c2 = (c & 0x55) << 1;
|
||||
|
||||
tmp = spi_w(0);
|
||||
c = (uint8_t)(tmp >> 8);
|
||||
checksum[2] = c;
|
||||
c3 = (c & 0x55) << 1;
|
||||
c = (uint8_t)tmp;
|
||||
checksum[3] = c;
|
||||
c4 = (c & 0x55) << 1;
|
||||
|
||||
tmp = spi_w(0);
|
||||
c = (uint8_t)(tmp >> 8);
|
||||
checksum[0] ^= c;
|
||||
c1 |= c & 0x55;
|
||||
c = (uint8_t)tmp;
|
||||
checksum[1] ^= c;
|
||||
c2 |= c & 0x55;
|
||||
|
||||
tmp = spi_w(0);
|
||||
c = (uint8_t)(tmp >> 8);
|
||||
checksum[2] ^= c;
|
||||
c3 |= c & 0x55;
|
||||
c = (uint8_t)tmp;
|
||||
checksum[3] ^= c;
|
||||
c4 |= c & 0x55;
|
||||
|
||||
if (c1 != 0xFF) // always 0xFF
|
||||
Error = 22;
|
||||
else if (c2 > 159) // Track number (0-159)
|
||||
Error = 23;
|
||||
else if (c3 > 10) // Sector number (0-10)
|
||||
Error = 24;
|
||||
else if (c4 > 11 || c4 == 0) // Number of sectors to gap (1-11)
|
||||
Error = 25;
|
||||
|
||||
if (Error)
|
||||
{
|
||||
fdd_debugf("\nWrong header: %u.%u.%u.%u\n", c1, c2, c3, c4);
|
||||
break;
|
||||
}
|
||||
|
||||
*pTrack = c2;
|
||||
*pSector = c3;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
tmp = spi_w(0);
|
||||
checksum[0] ^= (uint8_t)(tmp >> 8);
|
||||
checksum[1] ^= (uint8_t)tmp;
|
||||
tmp = spi_w(0);
|
||||
checksum[2] ^= (uint8_t)(tmp >> 8);
|
||||
checksum[3] ^= (uint8_t)tmp;
|
||||
}
|
||||
|
||||
checksum[0] &= 0x55;
|
||||
checksum[1] &= 0x55;
|
||||
checksum[2] &= 0x55;
|
||||
checksum[3] &= 0x55;
|
||||
|
||||
tmp = (spi_w(0) & 0x5555) << 1;
|
||||
c1 = (uint8_t)(tmp >> 8);
|
||||
c2 = (uint8_t)tmp;
|
||||
tmp = (spi_w(0) & 0x5555) << 1;
|
||||
c3 = (uint8_t)(tmp >> 8);
|
||||
c4 = (uint8_t)tmp;
|
||||
|
||||
tmp = spi_w(0) & 0x5555;
|
||||
c1 |= (uint8_t)(tmp >> 8);
|
||||
c2 |= (uint8_t)tmp;
|
||||
tmp = spi_w(0) & 0x5555;
|
||||
c3 |= (uint8_t)(tmp >> 8);
|
||||
c4 |= (uint8_t)tmp;
|
||||
|
||||
if (c1 != checksum[0] || c2 != checksum[1] || c3 != checksum[2] || c4 != checksum[3])
|
||||
{
|
||||
Error = 26;
|
||||
break;
|
||||
}
|
||||
|
||||
DisableFpga();
|
||||
return 1;
|
||||
}
|
||||
else if ((tmp & 0x8000) == 0) // not enough data for header and write dma is not active
|
||||
{
|
||||
Error = 20;
|
||||
break;
|
||||
}
|
||||
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
DisableFpga();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char GetData(void)
|
||||
{
|
||||
unsigned char c, c1, c2, c3, c4;
|
||||
unsigned char i;
|
||||
unsigned char *p;
|
||||
unsigned short n;
|
||||
unsigned char checksum[4];
|
||||
uint16_t tmp;
|
||||
|
||||
Error = 0;
|
||||
while (1)
|
||||
{
|
||||
EnableFpga();
|
||||
c1 = (uint8_t)(spi_w(0) >> 8); // write request signal, track number (cylinder & head)
|
||||
if (!(c1 & CMD_WRTRK))
|
||||
break;
|
||||
spi_w(0);
|
||||
tmp = spi_w(0); // mfm words to transfer
|
||||
|
||||
n = tmp & 0x3FFF;
|
||||
|
||||
if (n >= 0x204)
|
||||
{
|
||||
tmp = (spi_w(0) & 0x5555) << 1;
|
||||
c1 = (uint8_t)(tmp >> 8);
|
||||
c2 = (uint8_t)tmp & 0x55;
|
||||
tmp = (spi_w(0) & 0x5555) << 1;
|
||||
c3 = (uint8_t)(tmp >> 8);
|
||||
c4 = (uint8_t)tmp;
|
||||
|
||||
tmp = spi_w(0) & 0x5555;
|
||||
c1 |= (uint8_t)(tmp >> 8);
|
||||
c2 |= (uint8_t)tmp;
|
||||
tmp = spi_w(0) & 0x5555;
|
||||
c3 |= (uint8_t)(tmp >> 8);
|
||||
c4 |= (uint8_t)tmp;
|
||||
|
||||
checksum[0] = 0;
|
||||
checksum[1] = 0;
|
||||
checksum[2] = 0;
|
||||
checksum[3] = 0;
|
||||
|
||||
// odd bits of data field
|
||||
i = 128;
|
||||
p = sector_buffer;
|
||||
do
|
||||
{
|
||||
tmp = spi_w(0);
|
||||
c = (uint8_t)(tmp >> 8);
|
||||
checksum[0] ^= c;
|
||||
*p++ = (c & 0x55) << 1;
|
||||
c = (uint8_t)tmp;
|
||||
checksum[1] ^= c;
|
||||
*p++ = (c & 0x55) << 1;
|
||||
tmp = spi_w(0);
|
||||
c = (uint8_t)(tmp >> 8);
|
||||
checksum[2] ^= c;
|
||||
*p++ = (c & 0x55) << 1;
|
||||
c = (uint8_t)tmp;
|
||||
checksum[3] ^= c;
|
||||
*p++ = (c & 0x55) << 1;
|
||||
} while (--i);
|
||||
|
||||
// even bits of data field
|
||||
i = 128;
|
||||
p = sector_buffer;
|
||||
do
|
||||
{
|
||||
tmp = spi_w(0);
|
||||
c = (uint8_t)(tmp >> 8);
|
||||
checksum[0] ^= c;
|
||||
*p++ |= c & 0x55;
|
||||
c = (uint8_t)tmp;
|
||||
checksum[1] ^= c;
|
||||
*p++ |= c & 0x55;
|
||||
tmp = spi_w(0);
|
||||
c = (uint8_t)(tmp >> 8);
|
||||
checksum[2] ^= c;
|
||||
*p++ |= c & 0x55;
|
||||
c = (uint8_t)tmp;
|
||||
checksum[3] ^= c;
|
||||
*p++ |= c & 0x55;
|
||||
} while (--i);
|
||||
|
||||
checksum[0] &= 0x55;
|
||||
checksum[1] &= 0x55;
|
||||
checksum[2] &= 0x55;
|
||||
checksum[3] &= 0x55;
|
||||
|
||||
if (c1 != checksum[0] || c2 != checksum[1] || c3 != checksum[2] || c4 != checksum[3])
|
||||
{
|
||||
Error = 29;
|
||||
break;
|
||||
}
|
||||
|
||||
DisableFpga();
|
||||
return 1;
|
||||
}
|
||||
else if ((tmp & 0x8000) == 0) // not enough data in fifo and write dma is not active
|
||||
{
|
||||
Error = 28;
|
||||
break;
|
||||
}
|
||||
|
||||
DisableFpga();
|
||||
}
|
||||
DisableFpga();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WriteTrack(adfTYPE *drive)
|
||||
{
|
||||
unsigned char Track;
|
||||
unsigned char Sector;
|
||||
|
||||
unsigned long lba = drive->track * SECTOR_COUNT;
|
||||
|
||||
drive->track_prev = drive->track + 1; // just to force next read from the start of current track
|
||||
|
||||
while (FindSync(drive))
|
||||
{
|
||||
if (GetHeader(&Track, &Sector))
|
||||
{
|
||||
if (Track == drive->track)
|
||||
{
|
||||
if (!FileSeekLBA(&drive->file, lba+Sector))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetData())
|
||||
{
|
||||
if (drive->status & DSK_WRITABLE)
|
||||
{
|
||||
FileWriteSec(&drive->file, sector_buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Error = 30;
|
||||
fdd_debugf("Write attempt to protected disk!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
Error = 27; //track number reported in sector header is not the same as current drive track
|
||||
}
|
||||
if (Error)
|
||||
{
|
||||
fdd_debugf("WriteTrack: error %u\n", Error);
|
||||
ErrorMessage(" WriteTrack", Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateDriveStatus(void)
|
||||
{
|
||||
EnableFpga();
|
||||
spi_w(0x1000 | df[0].status | (df[1].status << 1) | (df[2].status << 2) | (df[3].status << 3));
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
void HandleFDD(unsigned char c1, unsigned char c2)
|
||||
{
|
||||
unsigned char sel;
|
||||
drives = (c1 >> 4) & 0x03; // number of active floppy drives
|
||||
|
||||
if (c1 & CMD_RDTRK)
|
||||
{
|
||||
DISKLED_ON;
|
||||
sel = (c1 >> 6) & 0x03;
|
||||
df[sel].track = c2;
|
||||
ReadTrack(&df[sel]);
|
||||
DISKLED_OFF;
|
||||
}
|
||||
else if (c1 & CMD_WRTRK)
|
||||
{
|
||||
DISKLED_ON;
|
||||
sel = (c1 >> 6) & 0x03;
|
||||
df[sel].track = c2;
|
||||
WriteTrack(&df[sel]);
|
||||
DISKLED_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
// insert floppy image pointed to to by global <file> into <drive>
|
||||
void InsertFloppy(adfTYPE *drive, char* path)
|
||||
{
|
||||
int writable = FileCanWrite(path);
|
||||
|
||||
if (!FileOpenEx(&drive->file, path, writable ? O_RDWR | O_SYNC : O_RDONLY))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned char i, j;
|
||||
unsigned long tracks;
|
||||
|
||||
// calculate number of tracks in the ADF image file
|
||||
tracks = drive->file.size / (512 * 11);
|
||||
if (tracks > MAX_TRACKS)
|
||||
{
|
||||
menu_debugf("UNSUPPORTED ADF SIZE!!! Too many tracks: %lu\n", tracks);
|
||||
tracks = MAX_TRACKS;
|
||||
}
|
||||
drive->tracks = (unsigned char)tracks;
|
||||
|
||||
strcpy(drive->name, path);
|
||||
|
||||
// initialize the rest of drive struct
|
||||
drive->status = DSK_INSERTED;
|
||||
if (writable) // read-only attribute
|
||||
drive->status |= DSK_WRITABLE;
|
||||
|
||||
drive->sector_offset = 0;
|
||||
drive->track = 0;
|
||||
drive->track_prev = -1;
|
||||
|
||||
menu_debugf("Inserting floppy: \"%s\"\n", path);
|
||||
menu_debugf("file writable: %d\n", writable);
|
||||
menu_debugf("file size: %lu (%lu KB)\n", drive->file.size, drive->file.size >> 10);
|
||||
menu_debugf("drive tracks: %u\n", drive->tracks);
|
||||
menu_debugf("drive status: 0x%02X\n", drive->status);
|
||||
}
|
||||
35
support/minimig/minimig_fdd.h
Normal file
35
support/minimig/minimig_fdd.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef __MINIMIG_FDD_H__
|
||||
#define __MINIMIG_FDD_H__
|
||||
|
||||
#include "../../file_io.h"
|
||||
|
||||
// floppy disk interface defs
|
||||
#define CMD_RDTRK 0x01
|
||||
#define CMD_WRTRK 0x02
|
||||
|
||||
// floppy status
|
||||
#define DSK_INSERTED 0x01 /*disk is inserted*/
|
||||
#define DSK_WRITABLE 0x10 /*disk is writable*/
|
||||
|
||||
#define MAX_TRACKS (83*2)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
fileTYPE file;
|
||||
unsigned char status; /*status of floppy*/
|
||||
unsigned char tracks; /*number of tracks*/
|
||||
unsigned char sector_offset; /*sector offset to handle tricky loaders*/
|
||||
unsigned char track; /*current track*/
|
||||
unsigned char track_prev; /*previous track*/
|
||||
char name[1024]; /*floppy name*/
|
||||
} adfTYPE;
|
||||
|
||||
extern unsigned char drives;
|
||||
extern adfTYPE df[4];
|
||||
|
||||
void UpdateDriveStatus(void);
|
||||
void HandleFDD(unsigned char c1, unsigned char c2);
|
||||
void InsertFloppy(adfTYPE *drive, char* path);
|
||||
|
||||
#endif
|
||||
|
||||
768
support/minimig/minimig_hdd.cpp
Normal file
768
support/minimig/minimig_hdd.cpp
Normal file
@@ -0,0 +1,768 @@
|
||||
/*
|
||||
Copyright 2008, 2009 Jakub Bednarski
|
||||
Copyright 2017, 2018 Sorgelig
|
||||
|
||||
This file is part of Minimig
|
||||
|
||||
Minimig is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Minimig is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// 2009-11-22 - read/write multiple implemented
|
||||
// 2018-05-13 - 4xIDE implemented
|
||||
// 2018-05-xx - Use RDB CHS values if valid
|
||||
// 2018-05-29 - LBA mode implemented
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../../hardware.h"
|
||||
#include "../../file_io.h"
|
||||
#include "minimig_hdd.h"
|
||||
#include "../../menu.h"
|
||||
#include "minimig_config.h"
|
||||
#include "../../debug.h"
|
||||
#include "../../fpga_io.h"
|
||||
|
||||
#define CMD_IDECMD 0x04
|
||||
#define CMD_IDEDAT 0x08
|
||||
|
||||
#define CMD_IDE_REGS_RD 0x80
|
||||
#define CMD_IDE_REGS_WR 0x90
|
||||
#define CMD_IDE_DATA_WR 0xA0
|
||||
#define CMD_IDE_DATA_RD 0xB0
|
||||
#define CMD_IDE_STATUS_WR 0xF0
|
||||
|
||||
#define IDE_STATUS_END 0x80
|
||||
#define IDE_STATUS_IRQ 0x10
|
||||
#define IDE_STATUS_RDY 0x08
|
||||
#define IDE_STATUS_REQ 0x04
|
||||
#define IDE_STATUS_ERR 0x01
|
||||
|
||||
#define ACMD_RECALIBRATE 0x10
|
||||
#define ACMD_DIAGNOSTIC 0x90
|
||||
#define ACMD_IDENTIFY_DEVICE 0xEC
|
||||
#define ACMD_INITIALIZE_PARAMETERS 0x91
|
||||
#define ACMD_READ_SECTORS 0x20
|
||||
#define ACMD_WRITE_SECTORS 0x30
|
||||
#define ACMD_READ_MULTIPLE 0xC4
|
||||
#define ACMD_WRITE_MULTIPLE 0xC5
|
||||
#define ACMD_SET_MULTIPLE_MODE 0xC6
|
||||
|
||||
#define SWAP(a) ((((a)&0x000000ff)<<24)|(((a)&0x0000ff00)<<8)|(((a)&0x00ff0000)>>8)|(((a)&0xff000000)>>24))
|
||||
#define SWAPW(a) ((((a)<<8)&0xff00)|(((a)>>8)&0x00ff))
|
||||
|
||||
// hardfile structure
|
||||
typedef struct
|
||||
{
|
||||
int unit;
|
||||
int enabled;
|
||||
fileTYPE file;
|
||||
uint32_t cylinders;
|
||||
uint16_t heads;
|
||||
uint16_t sectors;
|
||||
uint16_t sectors_per_block;
|
||||
int32_t offset; // if a partition, the lba offset of the partition. Can be negative if we've synthesized an RDB.
|
||||
|
||||
uint8_t lu;
|
||||
int32_t lba, nextlba;
|
||||
uint16_t sector;
|
||||
uint16_t cylinder;
|
||||
uint16_t head;
|
||||
uint16_t sector_count;
|
||||
} hdfTYPE;
|
||||
|
||||
static hdfTYPE HDF[4] = { 0 };
|
||||
static uint8_t sector_buffer[512];
|
||||
|
||||
static void CalcGeometry(hdfTYPE *hdf)
|
||||
{
|
||||
uint32_t head, cyl, spt;
|
||||
uint32_t sptt[] = { 63, 127, 255, 0 };
|
||||
uint32_t total = hdf->file.size / 512;
|
||||
for (int i = 0; sptt[i] != 0; i++)
|
||||
{
|
||||
spt = sptt[i];
|
||||
for (head = 4; head <= 16; head++)
|
||||
{
|
||||
cyl = total / (head * spt);
|
||||
if (total <= 1024 * 1024)
|
||||
{
|
||||
if (cyl <= 1023) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cyl < 16383) break;
|
||||
if (cyl < 32767 && head >= 5) break;
|
||||
if (cyl <= 65536) break;
|
||||
}
|
||||
}
|
||||
if (head <= 16) break;
|
||||
}
|
||||
|
||||
hdf->cylinders = cyl;
|
||||
hdf->heads = (uint16_t)head;
|
||||
hdf->sectors = (uint16_t)spt;
|
||||
}
|
||||
|
||||
static void GetRDBGeometry(hdfTYPE *hdf)
|
||||
{
|
||||
struct RigidDiskBlock *rdb = (struct RigidDiskBlock *)sector_buffer;
|
||||
hdf->heads = SWAP(rdb->rdb_Heads);
|
||||
hdf->sectors = SWAP(rdb->rdb_Sectors);
|
||||
hdf->cylinders = SWAP(rdb->rdb_Cylinders);
|
||||
if (hdf->sectors > 255 || hdf->heads > 16)
|
||||
{
|
||||
printf("ATTN: Illegal CHS value(s).");
|
||||
if (!(hdf->sectors & 1) && (hdf->sectors < 512) && (hdf->heads <= 8))
|
||||
{
|
||||
printf(" Translate: sectors %d->%d, heads %d->%d.\n", hdf->sectors, hdf->sectors / 2, hdf->heads, hdf->heads * 2);
|
||||
hdf->sectors /= 2;
|
||||
hdf->heads *= 2;
|
||||
return;
|
||||
}
|
||||
|
||||
printf(" DANGEROUS: Cannot translate to legal CHS values. Re-calculate the CHS.\n");
|
||||
CalcGeometry(hdf);
|
||||
}
|
||||
}
|
||||
|
||||
static void SetHardfileGeometry(hdfTYPE *hdf, int isHDF)
|
||||
{
|
||||
struct RigidDiskBlock *rdb = (struct RigidDiskBlock *)sector_buffer;
|
||||
uint8_t flg = 0;
|
||||
|
||||
hdf->offset = 0;
|
||||
|
||||
for (int i = 0; i<16; ++i)
|
||||
{
|
||||
if (!FileReadSec(&hdf->file, sector_buffer)) break;
|
||||
for (int i = 0; i < 512; i++) flg |= sector_buffer[i];
|
||||
|
||||
if (rdb->rdb_ID == RDB_MAGIC)
|
||||
{
|
||||
printf("Found RDB header -> native Amiga image.\n");
|
||||
GetRDBGeometry(hdf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (isHDF && flg)
|
||||
{
|
||||
//use UAE settings.
|
||||
hdf->heads = 1;
|
||||
hdf->sectors = 32;
|
||||
|
||||
int spc = hdf->heads * hdf->sectors;
|
||||
hdf->cylinders = hdf->file.size / (512 * spc) + 1;
|
||||
hdf->offset = -spc;
|
||||
|
||||
printf("No RDB header found in HDF image. Assume it's image of single partition. Use Virtual RDB header.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
CalcGeometry(hdf);
|
||||
printf("No RDB header found. Possible non-Amiga or empty image.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t GetDiskStatus(void)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
EnableFpga();
|
||||
status = (uint8_t)(spi_w(0) >> 8);
|
||||
spi_w(0);
|
||||
spi_w(0);
|
||||
DisableFpga();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static uint32_t RDBChecksum(uint32_t *p, int set)
|
||||
{
|
||||
uint32_t count = SWAP(p[1]);
|
||||
uint32_t result = 0;
|
||||
if(set) p[2] = 0;
|
||||
|
||||
for (uint32_t i = 0; i<count; ++i) result += SWAP(p[i]);
|
||||
if (!set) return result;
|
||||
|
||||
result = 0 - result;
|
||||
p[2] = SWAP(result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if the HDF file doesn't have a RigidDiskBlock, we synthesize one
|
||||
static void FakeRDB(hdfTYPE *hdf)
|
||||
{
|
||||
int i;
|
||||
// start by clearing the sector buffer
|
||||
memset(sector_buffer, 0, 512);
|
||||
|
||||
// if we're asked for LBA 0 we create an RDSK block, and if LBA 1, a PART block
|
||||
switch (hdf->lba)
|
||||
{
|
||||
case 0: {
|
||||
// RDB
|
||||
struct RigidDiskBlock *rdb = (struct RigidDiskBlock *)sector_buffer;
|
||||
rdb->rdb_ID = 'R' << 24 | 'D' << 16 | 'S' << 8 | 'K';
|
||||
rdb->rdb_Summedlongs = 0x40;
|
||||
rdb->rdb_HostID = 0x07;
|
||||
rdb->rdb_BlockBytes = 0x200;
|
||||
rdb->rdb_Flags = 0x12; // (Disk ID valid, no LUNs after this one)
|
||||
rdb->rdb_BadBlockList = 0xffffffff; // We don't provide a bad block list
|
||||
rdb->rdb_PartitionList = 1;
|
||||
rdb->rdb_FileSysHeaderList = 0xffffffff;
|
||||
rdb->rdb_DriveInit = 0xffffffff;
|
||||
rdb->rdb_Reserved1[0] = 0xffffffff;
|
||||
rdb->rdb_Reserved1[1] = 0xffffffff;
|
||||
rdb->rdb_Reserved1[2] = 0xffffffff;
|
||||
rdb->rdb_Reserved1[3] = 0xffffffff;
|
||||
rdb->rdb_Reserved1[4] = 0xffffffff;
|
||||
rdb->rdb_Reserved1[5] = 0xffffffff;
|
||||
rdb->rdb_Cylinders = hdf->cylinders;
|
||||
rdb->rdb_Sectors = hdf->sectors;
|
||||
rdb->rdb_Heads = hdf->heads;
|
||||
rdb->rdb_Interleave = 1;
|
||||
rdb->rdb_Park = rdb->rdb_Cylinders;
|
||||
rdb->rdb_WritePreComp = rdb->rdb_Cylinders;
|
||||
rdb->rdb_ReducedWrite = rdb->rdb_Cylinders;
|
||||
rdb->rdb_StepRate = 3;
|
||||
rdb->rdb_RDBBlocksLo = 0;
|
||||
rdb->rdb_RDBBlocksHi = 1;
|
||||
rdb->rdb_LoCylinder = 1;
|
||||
rdb->rdb_HiCylinder = rdb->rdb_Cylinders - 1;
|
||||
rdb->rdb_CylBlocks = rdb->rdb_Heads * rdb->rdb_Sectors;
|
||||
rdb->rdb_AutoParkSeconds = 0;
|
||||
rdb->rdb_HighRDSKBlock = 1;
|
||||
strcpy(rdb->rdb_DiskVendor, "DON'T REPARTITION! 0.00");
|
||||
uint32_t *p = (uint32_t*)(sector_buffer);
|
||||
for (int i = 0; i < 40; i++) p[i] = SWAP(p[i]);
|
||||
RDBChecksum(p, 1);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
// Partition
|
||||
struct PartitionBlock *pb = (struct PartitionBlock *)sector_buffer;
|
||||
pb->pb_ID = 'P' << 24 | 'A' << 16 | 'R' << 8 | 'T';
|
||||
pb->pb_Summedlongs = 0x40;
|
||||
pb->pb_HostID = 0x07;
|
||||
pb->pb_Next = 0xffffffff;
|
||||
pb->pb_Flags = 0x1; // bootable
|
||||
pb->pb_DevFlags = 0;
|
||||
strcpy(pb->pb_DriveName, "0HD\003"); // "DHx" BCPL string
|
||||
pb->pb_DriveName[0] = hdf->unit + '0';
|
||||
pb->pb_Environment.de_TableSize = 0x10;
|
||||
pb->pb_Environment.de_SizeBlock = 0x80;
|
||||
pb->pb_Environment.de_Surfaces = hdf->heads;
|
||||
pb->pb_Environment.de_SectorPerBlock = 1;
|
||||
pb->pb_Environment.de_BlocksPerTrack = hdf->sectors;
|
||||
pb->pb_Environment.de_Reserved = 2;
|
||||
pb->pb_Environment.de_LowCyl = 1;
|
||||
pb->pb_Environment.de_HighCyl = hdf->cylinders - 1;
|
||||
pb->pb_Environment.de_NumBuffers = 30;
|
||||
pb->pb_Environment.de_MaxTransfer = 0xffffff;
|
||||
pb->pb_Environment.de_Mask = 0x7ffffffe;
|
||||
pb->pb_Environment.de_DosType = 0x444f5301;
|
||||
uint32_t *p = (uint32_t*)(sector_buffer);
|
||||
for (int i = 0; i < 64; i++) p[i] = SWAP(p[i]);
|
||||
RDBChecksum(p, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// builds Identify Device struct
|
||||
static void IdentifyDevice(uint16_t *pBuffer, hdfTYPE *hdf)
|
||||
{
|
||||
char *p, i, x;
|
||||
uint32_t total_sectors = hdf->cylinders * hdf->heads * hdf->sectors;
|
||||
memset(pBuffer, 0, 512);
|
||||
|
||||
if(hdf->enabled)
|
||||
{
|
||||
pBuffer[0] = 1 << 6; // hard disk
|
||||
pBuffer[1] = hdf->cylinders; // cyl count
|
||||
pBuffer[3] = hdf->heads; // head count
|
||||
pBuffer[6] = hdf->sectors; // sectors per track
|
||||
// FIXME - can get serial no from card itself.
|
||||
memcpy((char*)&pBuffer[10], "MiniMigHardfile0000 ", 20); // serial number - byte swapped
|
||||
p = (char*)&pBuffer[27];
|
||||
|
||||
if (hdf->offset < 0)
|
||||
{
|
||||
memcpy((char*)&pBuffer[23], ".000 ", 8); // firmware version - byte swapped
|
||||
memcpy(p, "DON'T REPARTITION! ", 40);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy((char*)&pBuffer[23], ".100 ", 8); // firmware version - byte swapped
|
||||
memcpy(p, "MiSTer ", 40); // model name - byte swapped
|
||||
p += 8;
|
||||
char *s = strrchr(config.hardfile[hdf->unit].filename, '/');
|
||||
if (s) s++;
|
||||
else s = config.hardfile[hdf->unit].filename;
|
||||
|
||||
i = strlen(s);
|
||||
if (i > 32) s += i - 32;
|
||||
for (i = 0; (x = s[i]) && i < 16; i++) p[i] = x; // copy file name as model name
|
||||
}
|
||||
|
||||
p = (char*)&pBuffer[27];
|
||||
for (i = 0; i < 40; i += 2)
|
||||
{
|
||||
char c = p[i];
|
||||
p[i] = p[i + 1];
|
||||
p[i + 1] = c;
|
||||
}
|
||||
}
|
||||
|
||||
pBuffer[47] = 0x8010; // maximum sectors per block in Read/Write Multiple command
|
||||
pBuffer[49] = 1<<9; // LBA support
|
||||
pBuffer[53] = 1;
|
||||
pBuffer[54] = hdf->cylinders;
|
||||
pBuffer[55] = hdf->heads;
|
||||
pBuffer[56] = hdf->sectors;
|
||||
pBuffer[57] = (uint16_t)total_sectors;
|
||||
pBuffer[58] = (uint16_t)(total_sectors >> 16);
|
||||
}
|
||||
|
||||
static void WriteTaskFile(uint8_t error, uint8_t sector_count, uint8_t sector_number, uint8_t cylinder_low, uint8_t cylinder_high, uint8_t drive_head)
|
||||
{
|
||||
EnableFpga();
|
||||
|
||||
spi_w(CMD_IDE_REGS_WR<<8); // write task file registers command
|
||||
spi_w(0); // dummy
|
||||
spi_w(0); // dummy
|
||||
|
||||
spi_w(0); // data (dummy)
|
||||
spi_w(error); // error
|
||||
spi_w(sector_count); // sector count
|
||||
spi_w(sector_number); // sector number
|
||||
spi_w(cylinder_low); // cylinder low
|
||||
spi_w(cylinder_high); // cylinder high
|
||||
spi_w(drive_head); // drive/head
|
||||
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
static void WriteStatus(uint8_t status)
|
||||
{
|
||||
EnableFpga();
|
||||
spi_w((CMD_IDE_STATUS_WR<<8) | status);
|
||||
spi_w(0);
|
||||
spi_w(0);
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
static void ATA_Recalibrate(uint8_t* tfr, hdfTYPE *hdf)
|
||||
{
|
||||
// Recalibrate 0x10-0x1F (class 3 command: no data)
|
||||
hdd_debugf("IDE%d: Recalibrate", hdf->unit);
|
||||
WriteTaskFile(0, 0, tfr[6] & 0x40 ? 0 : 1, 0, 0, tfr[6] & 0xF0);
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
|
||||
static void ATA_Diagnostic(uint8_t* tfr, hdfTYPE *hdf)
|
||||
{
|
||||
// Execute Drive Diagnostic (0x90)
|
||||
hdd_debugf("IDE: Drive Diagnostic");
|
||||
WriteTaskFile(1, 0, 0, 0, 0, 0);
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
|
||||
static void ATA_IdentifyDevice(uint8_t* tfr, hdfTYPE *hdf)
|
||||
{
|
||||
int i;
|
||||
// Identify Device (0xec)
|
||||
hdd_debugf("IDE%d: Identify Device", hdf->unit);
|
||||
IdentifyDevice((uint16_t*)sector_buffer, hdf);
|
||||
WriteTaskFile(0, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]);
|
||||
WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type
|
||||
EnableFpga();
|
||||
spi_w(CMD_IDE_DATA_WR<<8); // write data command
|
||||
spi_w(0);
|
||||
spi_w(0);
|
||||
spi_block_write_16be((uint16_t*)sector_buffer);
|
||||
DisableFpga();
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
|
||||
static void ATA_Initialize(uint8_t* tfr, hdfTYPE *hdf)
|
||||
{
|
||||
// Initialize Device Parameters (0x91)
|
||||
hdd_debugf("Initialize Device Parameters");
|
||||
hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", hdf->unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]);
|
||||
WriteTaskFile(0, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]);
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
|
||||
static void ATA_SetMultipleMode(uint8_t* tfr, hdfTYPE *hdf)
|
||||
{
|
||||
// Set Multiple Mode (0xc6)
|
||||
hdd_debugf("Set Multiple Mode");
|
||||
hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", hdf->unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]);
|
||||
hdf->sectors_per_block = tfr[2];
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
|
||||
static int Preface(uint8_t* tfr, hdfTYPE *hdf)
|
||||
{
|
||||
hdf->sector = tfr[3];
|
||||
hdf->cylinder = tfr[4] | (tfr[5] << 8);
|
||||
hdf->head = tfr[6] & 0x0F;
|
||||
hdf->lu = tfr[6] & 0xF0;
|
||||
hdf->sector_count = tfr[2];
|
||||
if (hdf->sector_count == 0) hdf->sector_count = 256;
|
||||
|
||||
uint8_t uselba = hdf->lu & 0x40;
|
||||
|
||||
if (uselba)
|
||||
{
|
||||
hdf->lba = (hdf->head << 24) | (hdf->cylinder << 8) | hdf->sector;
|
||||
}
|
||||
else
|
||||
{
|
||||
hdf->lba = hdf->cylinder;
|
||||
hdf->lba *= hdf->heads;
|
||||
hdf->lba += hdf->head;
|
||||
hdf->lba *= hdf->sectors;
|
||||
hdf->lba += hdf->sector - 1;
|
||||
}
|
||||
|
||||
//printf("setCHS: %s: %d,%d,%d -> %d\n", uselba ? "LBA" : "CHS", hdf->cylinder, hdf->head, hdf->sector, hdf->lba);
|
||||
hdf->nextlba = hdf->lba;
|
||||
|
||||
if (hdf->enabled && hdf->lba >= 0 && hdf->file.size)
|
||||
{
|
||||
FileSeekLBA(&hdf->file, (hdf->lba + hdf->offset) < 0 ? 0 : hdf->lba + hdf->offset);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nextCHS(hdfTYPE *hdf)
|
||||
{
|
||||
// do not increment after last sector
|
||||
if (hdf->sector_count)
|
||||
{
|
||||
hdf->nextlba++;
|
||||
if (hdf->lu & 0x40)
|
||||
{
|
||||
hdf->sector = (uint8_t)hdf->nextlba;
|
||||
hdf->cylinder = (uint16_t)(hdf->nextlba >> 8);
|
||||
hdf->head = 0xF & (uint8_t)(hdf->nextlba >> 24);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hdf->sector == hdf->sectors)
|
||||
{
|
||||
hdf->sector = 1;
|
||||
hdf->head++;
|
||||
if (hdf->head == hdf->heads)
|
||||
{
|
||||
hdf->head = 0;
|
||||
hdf->cylinder++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hdf->sector++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void updateTaskFile(hdfTYPE *hdf)
|
||||
{
|
||||
WriteTaskFile(0, hdf->sector_count, hdf->sector, (uint8_t)hdf->cylinder, (uint8_t)(hdf->cylinder >> 8), (uint8_t)(hdf->lu | hdf->head));
|
||||
}
|
||||
|
||||
static void ReadSector(hdfTYPE *hdf)
|
||||
{
|
||||
// sector outside limit (fake rdb header)
|
||||
if ((hdf->lba + hdf->offset) < 0)
|
||||
FakeRDB(hdf);
|
||||
else
|
||||
FileReadSec(&hdf->file, sector_buffer);
|
||||
}
|
||||
|
||||
static void SendSector()
|
||||
{
|
||||
EnableFpga();
|
||||
spi_w(CMD_IDE_DATA_WR << 8); // write data command
|
||||
spi_w(0);
|
||||
spi_w(0);
|
||||
spi_block_write_16be((uint16_t*)sector_buffer);
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
static void RecvSector()
|
||||
{
|
||||
EnableFpga();
|
||||
spi_w(CMD_IDE_DATA_RD << 8); // read data command
|
||||
spi_w(0);
|
||||
spi_w(0);
|
||||
spi_block_read_16be((uint16_t*)sector_buffer);
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
static void WriteSector(hdfTYPE *hdf)
|
||||
{
|
||||
//Do not write to fake RDB header
|
||||
if ((hdf->lba + hdf->offset) < 0) return;
|
||||
|
||||
//Write RDB header, grab the CHS!
|
||||
if (!hdf->offset && hdf->lba < 16 && (*(uint32_t*)sector_buffer) == RDB_MAGIC)
|
||||
{
|
||||
printf("Writing RDB header, LBA=%d: ", hdf->lba);
|
||||
uint32_t sum = RDBChecksum((uint32_t*)sector_buffer, 0);
|
||||
if (sum)
|
||||
{
|
||||
printf("Checksumm is incorrect(0x%08X)! Ignore the RDB parameters.\n", sum);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetRDBGeometry(hdf);
|
||||
printf("Using new CHS: %u/%u/%u (%lu MB)\n", hdf->cylinders, hdf->heads, hdf->sectors, ((((uint32_t)hdf->cylinders) * hdf->heads * hdf->sectors) >> 11));
|
||||
}
|
||||
}
|
||||
FileWriteSec(&hdf->file, sector_buffer);
|
||||
}
|
||||
|
||||
// Read Sectors (0x20)
|
||||
static void ATA_ReadSectors(uint8_t* tfr, hdfTYPE *hdf)
|
||||
{
|
||||
WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type
|
||||
|
||||
if(Preface(tfr, hdf))
|
||||
{
|
||||
while (hdf->sector_count)
|
||||
{
|
||||
while (!(GetDiskStatus() & CMD_IDECMD)); // wait for empty sector buffer
|
||||
WriteStatus(IDE_STATUS_IRQ);
|
||||
|
||||
ReadSector(hdf);
|
||||
|
||||
// to be modified sector of first partition
|
||||
if (!hdf->unit && !hdf->lba)
|
||||
{
|
||||
struct RigidDiskBlock *rdb = (struct RigidDiskBlock *)sector_buffer;
|
||||
if (rdb->rdb_ID == RDB_MAGIC)
|
||||
{
|
||||
// adjust checksum by the difference between old and new flag value
|
||||
rdb->rdb_ChkSum = SWAP(SWAP(rdb->rdb_ChkSum) + SWAP(rdb->rdb_Flags) - 0x12);
|
||||
rdb->rdb_Flags = SWAP(0x12);
|
||||
}
|
||||
}
|
||||
SendSector();
|
||||
|
||||
hdf->lba++;
|
||||
hdf->sector_count--;
|
||||
nextCHS(hdf);
|
||||
updateTaskFile(hdf);
|
||||
}
|
||||
}
|
||||
WriteStatus(IDE_STATUS_END);
|
||||
}
|
||||
|
||||
// multiple sector transfer per IRQ
|
||||
static void ATA_ReadMultiple(uint8_t* tfr, hdfTYPE *hdf)
|
||||
{
|
||||
WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type
|
||||
|
||||
if (Preface(tfr, hdf))
|
||||
{
|
||||
while (hdf->sector_count)
|
||||
{
|
||||
while (!(GetDiskStatus() & CMD_IDECMD)); // wait for empty sector buffer
|
||||
uint16_t block_count = hdf->sector_count;
|
||||
if (block_count > hdf->sectors_per_block) block_count = hdf->sectors_per_block;
|
||||
WriteStatus(IDE_STATUS_IRQ);
|
||||
while (block_count--)
|
||||
{
|
||||
ReadSector(hdf);
|
||||
SendSector();
|
||||
|
||||
hdf->lba++;
|
||||
hdf->sector_count--;
|
||||
nextCHS(hdf);
|
||||
}
|
||||
updateTaskFile(hdf);
|
||||
}
|
||||
}
|
||||
WriteStatus(IDE_STATUS_END);
|
||||
}
|
||||
|
||||
static void ATA_WriteSectors(uint8_t* tfr, hdfTYPE *hdf)
|
||||
{
|
||||
WriteStatus(IDE_STATUS_REQ); // pio out (class 2) command type
|
||||
|
||||
if (Preface(tfr, hdf))
|
||||
{
|
||||
hdf->lba += hdf->offset;
|
||||
while (hdf->sector_count)
|
||||
{
|
||||
while (!(GetDiskStatus() & CMD_IDEDAT)); // wait for full write buffer
|
||||
|
||||
RecvSector();
|
||||
hdf->sector_count--;
|
||||
|
||||
nextCHS(hdf);
|
||||
updateTaskFile(hdf);
|
||||
WriteStatus(hdf->sector_count ? IDE_STATUS_IRQ : IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
|
||||
WriteSector(hdf);
|
||||
hdf->lba++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ATA_WriteMultiple(uint8_t* tfr, hdfTYPE *hdf)
|
||||
{
|
||||
WriteStatus(IDE_STATUS_REQ); // pio out (class 2) command type
|
||||
|
||||
if (Preface(tfr, hdf))
|
||||
{
|
||||
hdf->lba += hdf->offset;
|
||||
while (hdf->sector_count)
|
||||
{
|
||||
uint16_t block_count = hdf->sector_count;
|
||||
if (block_count > hdf->sectors_per_block) block_count = hdf->sectors_per_block;
|
||||
while (block_count)
|
||||
{
|
||||
while (!(GetDiskStatus() & CMD_IDEDAT)); // wait for full write buffer
|
||||
|
||||
RecvSector();
|
||||
WriteSector(hdf);
|
||||
hdf->lba++;
|
||||
|
||||
block_count--;
|
||||
hdf->sector_count--;
|
||||
nextCHS(hdf);
|
||||
}
|
||||
updateTaskFile(hdf);
|
||||
WriteStatus(hdf->sector_count ? IDE_STATUS_IRQ : IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandleHDD(uint8_t c1, uint8_t c2)
|
||||
{
|
||||
if (c1 & CMD_IDECMD)
|
||||
{
|
||||
uint8_t unit = 0;
|
||||
uint8_t tfr[8];
|
||||
DISKLED_ON;
|
||||
|
||||
EnableFpga();
|
||||
spi_w(CMD_IDE_REGS_RD<<8); // read task file registers
|
||||
spi_w(0);
|
||||
spi_w(0);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uint16_t tmp = spi_w(0);
|
||||
tfr[i] = (uint8_t)tmp;
|
||||
if (i == 6) unit = ((tmp >> 7) & 2) | ((tmp >> 4) & 1);
|
||||
}
|
||||
DisableFpga();
|
||||
|
||||
//printf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X\n", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]);
|
||||
hdfTYPE *hdf = &HDF[unit];
|
||||
|
||||
if (hdf->enabled)
|
||||
{
|
||||
if ((tfr[7] & 0xF0) == ACMD_RECALIBRATE) ATA_Recalibrate (tfr, hdf);
|
||||
else if (tfr[7] == ACMD_DIAGNOSTIC) ATA_Diagnostic (tfr, hdf);
|
||||
else if (tfr[7] == ACMD_IDENTIFY_DEVICE) ATA_IdentifyDevice (tfr, hdf);
|
||||
else if (tfr[7] == ACMD_INITIALIZE_PARAMETERS) ATA_Initialize (tfr, hdf);
|
||||
else if (tfr[7] == ACMD_SET_MULTIPLE_MODE) ATA_SetMultipleMode (tfr, hdf);
|
||||
else if (tfr[7] == ACMD_READ_SECTORS) ATA_ReadSectors (tfr, hdf);
|
||||
else if (tfr[7] == ACMD_READ_MULTIPLE) ATA_ReadMultiple (tfr, hdf);
|
||||
else if (tfr[7] == ACMD_WRITE_SECTORS) ATA_WriteSectors (tfr, hdf);
|
||||
else if (tfr[7] == ACMD_WRITE_MULTIPLE) ATA_WriteMultiple (tfr, hdf);
|
||||
else
|
||||
{
|
||||
printf("Unknown ATA command: IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X\n", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]);
|
||||
WriteTaskFile(0x04, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]);
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ | IDE_STATUS_ERR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("IDE%d not enabled: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X\n", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]);
|
||||
WriteTaskFile(0x04, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]);
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ | IDE_STATUS_ERR);
|
||||
}
|
||||
DISKLED_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t OpenHardfile(uint8_t unit)
|
||||
{
|
||||
hdfTYPE *hdf = &HDF[unit];
|
||||
hdf->unit = unit;
|
||||
hdf->enabled = 0;
|
||||
if (config.enable_ide && config.hardfile[unit].enabled)
|
||||
{
|
||||
printf("\nChecking HDD %d\n", unit);
|
||||
if (config.hardfile[unit].filename[0])
|
||||
{
|
||||
if (FileOpenEx(&hdf->file, config.hardfile[unit].filename, FileCanWrite(config.hardfile[unit].filename) ? O_RDWR : O_RDONLY))
|
||||
{
|
||||
hdf->enabled = 1;
|
||||
printf("file: \"%s\": ", hdf->file.name);
|
||||
SetHardfileGeometry(hdf, !strcasecmp(".hdf", config.hardfile[unit].filename + strlen(config.hardfile[unit].filename) - 4));
|
||||
printf("size: %llu (%llu MB)\n", hdf->file.size, hdf->file.size >> 20);
|
||||
printf("CHS: %u/%u/%u", hdf->cylinders, hdf->heads, hdf->sectors);
|
||||
printf(" (%lu MB), ", ((((uint32_t)hdf->cylinders) * hdf->heads * hdf->sectors) >> 11));
|
||||
printf("Offset: %d\n", hdf->offset);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
printf("HDD %d: not present\n", unit);
|
||||
}
|
||||
|
||||
// close if opened earlier.
|
||||
FileClose(&hdf->file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int checkHDF(const char* name, struct RigidDiskBlock **rdb)
|
||||
{
|
||||
fileTYPE file = { 0 };
|
||||
|
||||
*rdb = NULL;
|
||||
if (FileOpenEx(&file, name, O_RDONLY))
|
||||
{
|
||||
*rdb = (struct RigidDiskBlock *)sector_buffer;
|
||||
for (int i = 0; i<16; ++i)
|
||||
{
|
||||
if (!FileReadSec(&file, sector_buffer)) break;
|
||||
if ((*rdb)->rdb_ID == RDB_MAGIC)
|
||||
{
|
||||
FileClose(&file);
|
||||
(*rdb)->rdb_Heads = SWAP((*rdb)->rdb_Heads);
|
||||
(*rdb)->rdb_Sectors = SWAP((*rdb)->rdb_Sectors);
|
||||
(*rdb)->rdb_Cylinders = SWAP((*rdb)->rdb_Cylinders);
|
||||
return ((*rdb)->rdb_Heads <= 16 && (*rdb)->rdb_Sectors <= 255 && (*rdb)->rdb_Cylinders <= 65536);
|
||||
}
|
||||
}
|
||||
|
||||
FileClose(&file);
|
||||
return 1; // non-HDF file
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
13
support/minimig/minimig_hdd.h
Normal file
13
support/minimig/minimig_hdd.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// hdd.h
|
||||
|
||||
#ifndef __MINIMIG_HDD_H__
|
||||
#define __MINIMIG_HDD_H__
|
||||
|
||||
#include "minimig_hdd_internal.h"
|
||||
|
||||
// functions
|
||||
void HandleHDD(uint8_t c1, uint8_t c2);
|
||||
uint8_t OpenHardfile(uint8_t unit);
|
||||
int checkHDF(const char* name, struct RigidDiskBlock **rdb);
|
||||
|
||||
#endif // __HDD_H__
|
||||
90
support/minimig/minimig_hdd_internal.h
Normal file
90
support/minimig/minimig_hdd_internal.h
Normal file
@@ -0,0 +1,90 @@
|
||||
#ifndef __MINIMIG_HDD_INTERNAL_H__
|
||||
#define __MINIMIG_HDD_INTERNAL_H__
|
||||
|
||||
// Structure definitions for RDB emulation.
|
||||
// For hardfiles that have no RDB information, we'll just create a single-partition RDB and Part block
|
||||
// on blocks 0 and 1. All other blocks within the first cylinder will be translated into the hardfile
|
||||
|
||||
#define RDB_MAGIC 0x4B534452 // "RDSK"
|
||||
|
||||
struct RigidDiskBlock {
|
||||
unsigned long rdb_ID; // "RDSK"
|
||||
unsigned long rdb_Summedlongs; // 0x40
|
||||
long rdb_ChkSum; // Sum to zero
|
||||
unsigned long rdb_HostID; // 0x07
|
||||
unsigned long rdb_BlockBytes; // 0x200
|
||||
unsigned long rdb_Flags; // 0x12 (Disk ID valid, no LUNs after this one)
|
||||
unsigned long rdb_BadBlockList; // -1 since we don't provide one
|
||||
unsigned long rdb_PartitionList; // 1
|
||||
unsigned long rdb_FileSysHeaderList; // -1
|
||||
unsigned long rdb_DriveInit; // -1
|
||||
unsigned long rdb_Reserved1[6]; // 0xffffffff
|
||||
unsigned long rdb_Cylinders;
|
||||
unsigned long rdb_Sectors;
|
||||
unsigned long rdb_Heads;
|
||||
unsigned long rdb_Interleave; // 1
|
||||
unsigned long rdb_Park; // =Cylinder count
|
||||
unsigned long rdb_Reserved2[3];
|
||||
unsigned long rdb_WritePreComp; // High cylinder ?
|
||||
unsigned long rdb_ReducedWrite; // High cylinder ?
|
||||
unsigned long rdb_StepRate; // 3 ?
|
||||
unsigned long rdb_Reserved3[5];
|
||||
unsigned long rdb_RDBBlocksLo; // block zero
|
||||
unsigned long rdb_RDBBlocksHi; // block one
|
||||
unsigned long rdb_LoCylinder; // 1
|
||||
unsigned long rdb_HiCylinder; // From the hardfile: cylinder count -1
|
||||
unsigned long rdb_CylBlocks; // From the hardfile: heads * sectors
|
||||
unsigned long rdb_AutoParkSeconds; // zero
|
||||
unsigned long rdb_HighRDSKBlock; // 1
|
||||
unsigned long rdb_Reserved4;
|
||||
char rdb_DiskVendor[8]; // "Don't"
|
||||
char rdb_DiskProduct[16]; // " repartition!"
|
||||
char rdb_DiskRevision[4];
|
||||
char rdb_ControllerVendor[8];
|
||||
char rdb_ControllerProduct[16];
|
||||
char rdb_ControllerRevision[4];
|
||||
unsigned long rdb_Reserved5[10];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct DosEnvec {
|
||||
unsigned long de_TableSize; // Size of Environment vector - 0x10
|
||||
unsigned long de_SizeBlock; // in longwords - 0x80
|
||||
unsigned long de_SecOrg; // 0
|
||||
unsigned long de_Surfaces; // Heads?
|
||||
unsigned long de_SectorPerBlock; // 1
|
||||
unsigned long de_BlocksPerTrack;
|
||||
unsigned long de_Reserved; // 2 ?
|
||||
unsigned long de_PreAlloc; // 0
|
||||
unsigned long de_Interleave; // 0
|
||||
unsigned long de_LowCyl;
|
||||
unsigned long de_HighCyl;
|
||||
unsigned long de_NumBuffers; // 30
|
||||
unsigned long de_BufMemType; // 0 - any available
|
||||
unsigned long de_MaxTransfer; // 0x00ffffff
|
||||
unsigned long de_Mask; // 0x7ffffffe
|
||||
long de_BootPri; // 0
|
||||
unsigned long de_DosType; // 0x444f5301 or 3
|
||||
// Extra fields
|
||||
unsigned long de_Baud;
|
||||
unsigned long de_Control;
|
||||
unsigned long de_BootBlocks;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
struct PartitionBlock {
|
||||
unsigned long pb_ID; // "PART"
|
||||
unsigned long pb_Summedlongs; // 0x40
|
||||
long pb_ChkSum; // Sum to zero
|
||||
unsigned long pb_HostID; // 0x07
|
||||
unsigned long pb_Next; // -1
|
||||
unsigned long pb_Flags; // 1 - Bootable
|
||||
unsigned long pb_Reserved1[2]; // 0
|
||||
unsigned long pb_DevFlags; // 0
|
||||
char pb_DriveName[32]; // 0x03"DH0"
|
||||
unsigned long pb_Reserved2[15];
|
||||
struct DosEnvec pb_Environment;
|
||||
unsigned long pb_EReserved[12]; /* reserved for future environment vector */
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif /* HDD_INTERNAL_H */
|
||||
|
||||
Reference in New Issue
Block a user