⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 Verilog, c and asm source codes of the Minimig system, a fpga implementation of the Amiga computer.
💻 C
📖 第 1 页 / 共 3 页
字号:
 /*
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 + -