📄 main.c
字号:
/*
Copyright 2005, 2006, 2007 Dennis van Weeren
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/>.
Minimig boot controller / floppy emulator / on screen display
27-11-2005 -started coding
29-01-2005 -done a lot of work
06-02-2006 -it start to look like something!
19-02-2006 -improved floppy dma offset code
02-01-2007 -added osd support
11-02-2007 -added insert floppy progress bar
01-07-2007 -added filetype filtering for directory routines
JB:
2008-02-09 -added error handling
number of blinks:
1: neither mmc nor sd card detected
2: fat16 filesystem not detected
3: FPGA configuration error (INIT low or DONE high before config)
4: no MINIMIG1.BIN file found
5: FPGA configuration error (DONE is low after config)
6: no kickstart file found
2008-07-18 -better read support (sector loaders are now less confused)
-write support added (strict sector format checking - may not work with non DOS games)
-removed bug in filename filtering (initial directory fill didn't filter)
-communication interface with new bootloader
-OSD control of reset, ram configuration, interpolation filters and kickstart
WriteTrack errors:
#20 : unexpected dma transfer end (sector header)
#21 : no second sync word found
#22 : first header byte not 0xFF
#23 : second header byte (track number) not within 0..159 range
#24 : third header byte (sector number) not within 0..10 range
#25 : fourth header byte (sectors to gap number) not within 1..11 range
#26 : header checksum error
#27 : track number in sector header not the same as drive head position
#28 : unexpected dma transfer end (sector data)
#29 : data checksum error
#30 : write attempt to protected disk
2008-07-25 -update of write sector header format checking
-disk led active during writes to disk
*/
#include <pic18.h>
#include <stdio.h>
#include <string.h>
#include "hardware.h"
#include "osd.h"
#include "ata18.h"
#include "fat1618_2.h"
#define DEBUG
void CheckTrack(struct adfTYPE *drive);
void ReadTrack(struct adfTYPE *drive);
void SendFile(struct file2TYPE *file);
void WriteTrack(struct adfTYPE *drive);
unsigned char FindSync(struct adfTYPE *drive);
unsigned char GetHeader(unsigned char *pTrack, unsigned char *pSector);
unsigned char GetData();
char BootPrint(const char* text);
char BootUpload(struct file2TYPE *file, unsigned char base, unsigned char size);
void BootExit(void);
void ErrorMessage(const char* message, unsigned char code);
unsigned short SectorToFpga(unsigned char sector,unsigned char track);
void SectorGapToFpga(void);
void SectorHeaderToFpga(unsigned char);
char UploadKickstart(const unsigned char *name);
unsigned char Open(const unsigned char *name);
unsigned char ConfigureFpga(void);
void HandleFpgaCmd(unsigned char c1, unsigned char c2);
void InsertFloppy(struct adfTYPE *drive);
void ScrollDir(const unsigned char *type, unsigned char mode);
void PrintDir(void);
void User(void);
/*FPGA commands <c1> argument*/
#define CMD_USERSELECT 0x80 /*user interface SELECT*/
#define CMD_USERUP 0x40 /*user interface UP*/
#define CMD_USERDOWN 0x20 /*user interface DOWN*/
#define CMD_GETDSKSTAT 0x04 /*FPGA requests status of disk drive*/
#define CMD_RDTRCK 0x02 /*FPGA requests reading of track <c2>*/
#define CMD_WRTRCK 0x01 /*FPGA requests writing of trck <c2>*/
#define ST_READREQ 0x02
/*floppy status*/
#define DSK_INSERTED 0x01 /*disk is inserted*/
#define DSK_WRITABLE 0x02 /*disk is writable*/
/*menu states*/
#define MENU_NONE1 0 /*no menu*/
#define MENU_NONE2 1 /*no menu*/
#define MENU_MAIN1 2 /*main menu*/
#define MENU_MAIN2 3 /*main menu*/
#define MENU_FILE1 4 /*file requester menu*/
#define MENU_FILE2 5 /*file requester menu*/
#define MENU_RESET1 6 /*reset menu*/
#define MENU_RESET2 7 /*reset menu*/
#define MENU_SETTINGS1 8 /*settings menu*/
#define MENU_SETTINGS2 9 /*settings menu*/
#define MENU_ROMSELECT1 10 /*rom select menu*/
#define MENU_ROMSELECT2 11 /*rom select menu*/
#define MENU_ROMFILE1 12 /*rom file select menu*/
#define MENU_ROMFILE2 13 /*rom file select menu*/
#define MENU_ERROR 127 /*error message menu*/
/*other constants*/
#define DIRSIZE 8 /*size of directory display window*/
#define REPEATTIME 50 /*repeat delay in 10ms units*/
#define REPEATRATE 5 /*repeat rate in 10ms units*/
#define EEPROM_LRFILTER 0x10
#define EEPROM_HRFILTER 0x11
#define EEPROM_MEMCFG 0x12
#define EEPROM_KICKNAME 0x18 //size 8
/*variables*/
struct adfTYPE
{
unsigned char status; /*status of floppy*/
unsigned short cache[160]; /*cluster cache*/
unsigned short clusteroffset; /*cluster offset to handle tricky loaders*/
unsigned char sectoroffset; /*sector offset to handle tricky loaders*/
unsigned char track; /*current track*/
unsigned char trackprev; /*previous track*/
unsigned char name[12]; /*floppy name*/
};
struct adfTYPE df0; /*drive 0 information structure*/
struct file2TYPE file; /*global file handle*/
struct file2TYPE directory[DIRSIZE]; /*directory array*/
unsigned char dirptr; /*pointer into directory array*/
unsigned char menustate = MENU_NONE1;
unsigned char menusub = 0;
unsigned char s[25]; /*used to build strings*/
bdata unsigned char kickname[12];
unsigned char lr_filter;
unsigned char hr_filter;
const char* filter_msg[] = {"none","HOR ","VER ","H+V "};
unsigned char memcfg;
const char* memcfg_msg[] = {"512K CHIP","1Meg CHIP","512K/512K","1Meg/512K"};
unsigned char Error;
void FatalError(unsigned char code)
{
// code = number of blinks
unsigned long t;
unsigned char i;
while (1)
{
i = code;
do
{
t = 38000;
while (--t) //wait 100ms
DISKLED = 1;
t = 2*38000;
while (--t) //wait 200ms
DISKLED = 0;
} while (--i);
t = 8*38000;
while (--t) //wait 900ms
DISKLED = 0;
}
}
/*This is where it all starts after reset*/
void main(void)
{
unsigned char c1,c2,c3,c4;
unsigned short t;
unsigned char c;
unsigned char i;
/*initialize hardware*/
HardwareInit();
lr_filter = eeprom_read(EEPROM_LRFILTER);
if (lr_filter&0xFC)
lr_filter = 0;
hr_filter = eeprom_read(EEPROM_HRFILTER);
if (hr_filter&0xFC)
hr_filter = 0;
memcfg = eeprom_read(EEPROM_MEMCFG);
if (memcfg&0xFC)
memcfg = 0;
//check correctness of kickstart file name
for (i=0;i<8;i++)
{
c = eeprom_read(EEPROM_KICKNAME+i);
if (c==' ' || (c>='0' && c<='9') || (c>='A' && c<='Z')) //only 0-9,A-Z and space allowed
kickname[i] = c;
else
{
strncpy(kickname,"KICK ",8); //if illegal character detected revert to default name
break;
}
}
strncpy(&kickname[8],"ROM",3); //add rom file extension
printf("\rMinimig Controller by Dennis van Weeren\r");
printf("Bug fixes, mods and extensions by Jakub Bednarski\r\r");
printf("Version PYQ080725\r\r");
/*intialize mmc card*/
if (SDCARD_Init()==0)
{
FatalError(1);
}
/*initalize FAT partition*/
if (FindDrive2())
{
printf("FAT16 filesystem found!\r");
}
else
{
printf("No FAT16 filesystem!\r");
FatalError(2);
}
/* if (DONE) //FPGA has not been configured yet
{
printf("FPGA already configured\r");
}
else
*/ {
/*configure FPGA*/
if (ConfigureFpga())
{
printf("FPGA configured\r");
}
else
{
printf("FPGA configuration failed\r");
FatalError(3);
}
}
BootPrint("** PIC firmware PYQ080725 **\n");
if (UploadKickstart(kickname))
{
strcpy(kickname,"KICK ROM");
if (UploadKickstart(kickname))
FatalError(6);
}
if (!CheckButton()) //if menu button pressed don't load Action Replay
if (Open("AR3 ROM"))
{
if (file.len == 0x40000)
{//256KB Action Replay 3 ROM
BootPrint("\nUploading Action Replay ROM...");
BootUpload(&file,0x40,0x04);
}
else
{
BootPrint("\nUnsupported AR3.ROM file size!!!");
FatalError(6);
}
}
OsdFilter(lr_filter,hr_filter); //set interpolation filters
OsdMemoryConfig(memcfg); //set memory config
printf("Bootloading complete.\r");
BootPrint("Exiting bootloader...");
BootExit();
df0.status=0;
/******************************************************************************/
/******************************************************************************/
/*System is up now*/
/******************************************************************************/
/******************************************************************************/
/*fill initial directory*/
ScrollDir("ADF",0);
/*get initial timer for checking user interface*/
t=GetTimer(5);
while(1)
{
/*read command from FPGA*/
EnableFpga();
c1=SPI(0);
c2=SPI(0);
DisableFpga();
/*handle command*/
HandleFpgaCmd(c1,c2);
/*handle user interface*/
if (CheckTimer(t))
{
t=GetTimer(2);
User();
}
}
}
char UploadKickstart(const unsigned char *name)
{
if (Open(name))
{
if (file.len == 0x80000)
{//512KB Kickstart ROM
BootPrint("Uploading 512KB Kickstart...");
BootUpload(&file,0xF8,0x08);
}
else if (file.len == 0x40000)
{//256KB Kickstart ROM
BootPrint("Uploading 256KB Kickstart...");
BootUpload(&file,0xF8,0x04);
}
else
{
BootPrint("Unsupported Kickstart ROM file size!");
return 41;
}
}
else
{
sprintf(s,"No \"%11s\" file!",name);
BootPrint(s);
return 40;
}
return 0;
}
char BootPrint(const char* text)
{
char c1,c2,c3,c4;
char cmd;
const char* p;
unsigned char n;
p = text;
n = 0;
while (*(p++) != 0)
n++; //calculating string length
cmd = 1;
while (1)
{
EnableFpga();
c1=SPI(0);
c2=SPI(0);
c3=SPI(0);
c4=SPI(1); //disk present
//printf("CMD%d:%02X,%02X,%02X,%02X\r",cmd,c1,c2,c3,c4);
if (c1 == CMD_RDTRCK)
{
if (cmd)
{//command phase
if (c3==0x80 && c4==0x06) //command packet size 12 bytes
{
cmd = 0;;
SPI(0xAA); //command header
SPI(0x55);
SPI(0x00); //cmd: 0001 = print
SPI(0x01);
//data packet size in bytes
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(n+2); //+2 because only even byte count is possible to send and we have to send termination zero byte
//don't care
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
}
else break;
}
else
{//data phase
if (c3==0x80 && c4==((n+2)>>1))
{
p = text;
n = c4<<1;
while (n--)
{
c4 = *p;
SPI(c4);
if (c4) //if current character is not zero go to next one
p++;
}
DisableFpga();
return 1;
}
else break;
}
}
DisableFpga();
}
DisableFpga();
return 0;
}
char BootUpload(struct file2TYPE *file, unsigned char base, unsigned char size)
// this function sends given file to minimig's memory
// base - memory base address (bits 23..16)
// size - memory size (bits 23..16)
{
char c1,c2,c3,c4;
char cmd;
cmd = 1;
while (1)
{
EnableFpga();
c1=SPI(0);
c2=SPI(0);
c3=SPI(0);
c4=SPI(1); //disk present
//printf("CMD%d:%02X,%02X,%02X,%02X\r",cmd,c1,c2,c3,c4);
if (c1 == CMD_RDTRCK)
{
if (cmd)
{//command phase
if (c3==0x80 && c4==0x06) //command packet size 12 bytes
{
cmd = 0;
SPI(0xAA);
SPI(0x55); //command header 0xAA55
SPI(0x00);
SPI(0x02); //cmd: 0x0002 = upload memory
//memory base address
SPI(0x00);
SPI(base);
SPI(0x00);
SPI(0x00);
//memory size
SPI(0x00);
SPI(size);
SPI(0x00);
SPI(0x00);
}
else break;
}
else
{//data phase
DisableFpga();
printf("uploading ROM file\r");
//send rom image to FPGA
SendFile(file);
printf("\rROM file uploaded\r");
return 0;
}
}
DisableFpga();
}
DisableFpga();
return -1;
}
void BootExit(void)
{
char c1,c2,c3,c4;
while (1)
{
EnableFpga();
c1 = SPI(0);
c2 = SPI(0);
c3 = SPI(0);
c4 = SPI(1); //disk present
if (c1 == CMD_RDTRCK)
{
if (c3==0x80 && c4==0x06) //command packet size 12 bytes
{
SPI(0xAA); //command header
SPI(0x55);
SPI(0x00); //cmd: 0003 = restart
SPI(0x03);
//don't care
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
//don't care
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
}
DisableFpga();
return;
}
DisableFpga();
}
}
/*user interface*/
void User(void)
{
unsigned char i,c,up,down,select,menu;
/*get user control codes*/
c=OsdGetCtrl();
/*decode and set events*/
up=0;
down=0;
select=0;
menu=0;
if (c&OSDCTRLUP)
up=1;
if (c&OSDCTRLDOWN)
down=1;
if (c&OSDCTRLSELECT)
select=1;
if (c&OSDCTRLMENU)
menu=1;
/*menu state machine*/
switch (menustate)
{
/******************************************************************/
/*no menu selected / menu exited / menu not displayed*/
/******************************************************************/
case MENU_NONE1:
OsdDisable();
menustate=MENU_NONE2;
break;
case MENU_NONE2:
if (menu)/*check if user wants to go to menu*/
{
menustate=MENU_MAIN1;
menusub=0;
OsdClear();
OsdEnable();
}
break;
/******************************************************************/
/*main menu: insert/eject floppy, reset and exit*/
/******************************************************************/
case MENU_MAIN1:
/*menu title*/
OsdWrite(0," ** Minimig Menu **",0);
/*df0 info*/
strcpy(s," df0: ");
if (df0.status&DSK_INSERTED)/*floppy currently in df0*/
strncpy(&s[10],df0.name,8);
else/*no floppy in df0*/
strncpy(&s[10],"--------",8);
s[18]=0x0d;
s[19]=0x00;
OsdWrite(2,s,0);
if (df0.status&DSK_INSERTED)/*floppy currently in df0*/
if (df0.status&DSK_WRITABLE)/*floppy is writable*/
strcpy(s," writable ");
else
strcpy(s," read only");
else /*no floppy in df0*/
strcpy(s," no disk ");
OsdWrite(3,s,0);
/*eject/insert df0 options*/
if (df0.status&DSK_INSERTED)/*floppy currently in df0*/
sprintf(s," eject df0 ");
else/*no floppy in df0*/
sprintf(s," insert df0");
OsdWrite(4,s,menusub==0);
OsdWrite(5," settings",menusub==1);
/*reset system*/
OsdWrite(6," reset",menusub==2);
/*exit menu*/
OsdWrite(7," exit",menusub==3);
/*goto to second state of main menu*/
menustate = MENU_MAIN2;
break;
case MENU_MAIN2:
if (menu)/*menu pressed*/
menustate=MENU_NONE1;
else if (up)/*up pressed*/
{
if (menusub>0)
menusub--;
menustate=MENU_MAIN1;
}
else if (down)/*down pressed*/
{
if (menusub<3)
menusub++;
menustate=MENU_MAIN1;
}
else if (select)/*select pressed*/
{
if (menusub==0 && (df0.status&DSK_INSERTED))/*eject floppy*/
{
df0.status = 0;
menustate = MENU_MAIN1;
}
else if (menusub==0)/*insert floppy*/
{
df0.status = 0;
menustate = MENU_FILE1;
OsdClear();
}
else if (menusub==1)/*settings*/
{
menusub = 4;
menustate = MENU_SETTINGS1;
OsdClear();
}
else if (menusub==2)/*reset*/
{
menusub = 1;
menustate = MENU_RESET1;
OsdClear();
}
else if (menusub==3)/*exit menu*/
menustate = MENU_NONE1;
}
break;
/******************************************************************/
/*adf file requester menu*/
/******************************************************************/
case MENU_FILE1:
PrintDir();
menustate=MENU_FILE2;
break;
case MENU_FILE2:
if (down)/*scroll down through file requester*/
{
ScrollDir("ADF",1);
menustate=MENU_FILE1;
}
if (up)/*scroll up through file requester*/
{
ScrollDir("ADF",2);
menustate=MENU_FILE1;
}
if (select)/*insert floppy*/
{
if (directory[dirptr].len)
{
file = directory[dirptr];
InsertFloppy(&df0);
}
menustate = MENU_MAIN1;
menusub = 3;
OsdClear();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -