Initial Commit.
This commit is contained in:
28
.gitignore
vendored
Normal file
28
.gitignore
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# ignore backup files
|
||||
*~
|
||||
|
||||
# ignore vi swapfiles
|
||||
.*.swp
|
||||
|
||||
# ignore compiled python
|
||||
*pyc
|
||||
|
||||
# ignore some backup files
|
||||
*bak
|
||||
|
||||
# ignore some c files
|
||||
*\.o
|
||||
*\.d
|
||||
|
||||
# ignore dropbox files
|
||||
.dropbox.attr
|
||||
|
||||
# ignore directories
|
||||
Debug
|
||||
|
||||
*.lst
|
||||
*.elf
|
||||
*.map
|
||||
*.user
|
||||
.vs
|
||||
MiSTer
|
||||
39
Makefile
Normal file
39
Makefile
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
# makefile to fail if any command in pipe is failed.
|
||||
SHELL = /bin/bash -o pipefail
|
||||
|
||||
# using gcc version 5.4.1 20161213 (Linaro GCC 5.4-2017.01-rc2)
|
||||
BASE = arm-linux-gnueabihf
|
||||
|
||||
CC = $(BASE)-gcc
|
||||
LD = $(CC)
|
||||
STRIP = $(BASE)-strip
|
||||
|
||||
PRJ = MiSTer
|
||||
SRC = $(wildcard *.c)
|
||||
|
||||
OBJ = $(SRC:.c=.o)
|
||||
DEP = $(SRC:.c=.d)
|
||||
|
||||
CFLAGS = $(DFLAGS) -c -O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DVDATE=\"`date +"%y%m%d"`\"
|
||||
LFLAGS = -lc
|
||||
|
||||
$(PRJ): $(OBJ)
|
||||
@$(info $@)
|
||||
@$(LD) $(LFLAGS) -o $@ $+
|
||||
@$(STRIP) $@
|
||||
|
||||
clean:
|
||||
rm -f *.d *.o *.elf *.map *.lst *.bak *.rej *.org *.user *~ $(PRJ)
|
||||
rm -rf obj .vs DTAR* x64
|
||||
|
||||
%.o: %.c
|
||||
@$(info $<)
|
||||
@$(CC) $(CFLAGS) -o $@ -c $< 2>&1 | sed -e 's/\(.[a-zA-Z]\+\):\([0-9]\+\):\([0-9]\+\):/\1(\2,\ \3):/g'
|
||||
|
||||
-include $(DEP)
|
||||
%.d: %.c
|
||||
@$(CC) $(DFLAGS) -MM $< -MT $@ -MT $*.o -MF $@ 2>&1 | sed -e 's/\(.[a-zA-Z]\+\):\([0-9]\+\):\([0-9]\+\):/\1(\2,\ \3):/g'
|
||||
|
||||
# Ensure correct time stamp
|
||||
main.o: $(filter-out main.o, $(OBJ))
|
||||
6
MiSTer.ini
Normal file
6
MiSTer.ini
Normal file
@@ -0,0 +1,6 @@
|
||||
[MiSTer]
|
||||
key_menu_as_rgui=0 ; set to 1 to make the MENU key map to RGUI in Minimig (e.g. for Right Amiga)
|
||||
forced_scandoubler=0 ; set to 1 to run scandoubler on VGA output always (depends on core).
|
||||
ypbpr=0 ; set to 1 for YPbPr on VGA output.
|
||||
composite_sync=0 ; set to 1 for composite sync on HSync signal of VGA output.
|
||||
vga_scaler=1 ; set to 1 to connect VGA to scaler output.
|
||||
19
MiSTer.sln
Normal file
19
MiSTer.sln
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.23107.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MiSTer", "MiSTer.vcxproj", "{C1D6BEA2-1469-4FBC-8A27-A82BDE9041AC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x86 = Debug|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C1D6BEA2-1469-4FBC-8A27-A82BDE9041AC}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{C1D6BEA2-1469-4FBC-8A27-A82BDE9041AC}.Debug|x86.Build.0 = Debug|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
101
MiSTer.vcxproj
Normal file
101
MiSTer.vcxproj
Normal file
@@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{C1D6BEA2-1469-4FBC-8A27-A82BDE9041AC}</ProjectGuid>
|
||||
<Keyword>MakeFileProj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Makefile</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<NMakeBuildCommandLine>git.lnk ./build.sh</NMakeBuildCommandLine>
|
||||
<NMakeOutput>MiSTer</NMakeOutput>
|
||||
<NMakeCleanCommandLine>git.lnk ./clean.sh</NMakeCleanCommandLine>
|
||||
<NMakePreprocessorDefinitions>WIN32;VDATE="000000";_FILE_OFFSET_BITS=64;_LARGEFILE64_SOURCE;$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>
|
||||
<NMakeIncludeSearchPath>c:\Work\Git\opt\gcc54\arm-linux-gnueabihf\libc\usr\include;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
|
||||
<OutDir>$(TEMP)</OutDir>
|
||||
<IntDir>$(TEMP)</IntDir>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="archie.c" />
|
||||
<ClCompile Include="boot.c" />
|
||||
<ClCompile Include="config.c" />
|
||||
<ClCompile Include="file_io.c" />
|
||||
<ClCompile Include="fdd.c" />
|
||||
<ClCompile Include="fpga_io.c" />
|
||||
<ClCompile Include="hardware.c" />
|
||||
<ClCompile Include="hdd.c" />
|
||||
<ClCompile Include="ikbd.c" />
|
||||
<ClCompile Include="ini_parser.c" />
|
||||
<ClCompile Include="input.c" />
|
||||
<ClCompile Include="main.c" />
|
||||
<ClCompile Include="menu.c" />
|
||||
<ClCompile Include="mist_cfg.c" />
|
||||
<ClCompile Include="osd.c" />
|
||||
<ClCompile Include="spi.c" />
|
||||
<ClCompile Include="state.c" />
|
||||
<ClCompile Include="tos.c" />
|
||||
<ClCompile Include="user_io.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="archie.h" />
|
||||
<ClInclude Include="boot.h" />
|
||||
<ClInclude Include="charrom.h" />
|
||||
<ClInclude Include="config.h" />
|
||||
<ClInclude Include="debug.h" />
|
||||
<ClInclude Include="errors.h" />
|
||||
<ClInclude Include="file_io.h" />
|
||||
<ClInclude Include="fdd.h" />
|
||||
<ClInclude Include="fpga_base_addr_ac5.h" />
|
||||
<ClInclude Include="fpga_io.h" />
|
||||
<ClInclude Include="fpga_manager.h" />
|
||||
<ClInclude Include="fpga_nic301.h" />
|
||||
<ClInclude Include="fpga_reset_manager.h" />
|
||||
<ClInclude Include="fpga_system_manager.h" />
|
||||
<ClInclude Include="hardware.h" />
|
||||
<ClInclude Include="hdd.h" />
|
||||
<ClInclude Include="hdd_internal.h" />
|
||||
<ClInclude Include="ikbd.h" />
|
||||
<ClInclude Include="ini_parser.h" />
|
||||
<ClInclude Include="input.h" />
|
||||
<ClInclude Include="keycodes.h" />
|
||||
<ClInclude Include="logo.h" />
|
||||
<ClInclude Include="menu.h" />
|
||||
<ClInclude Include="mist_cfg.h" />
|
||||
<ClInclude Include="osd.h" />
|
||||
<ClInclude Include="spi.h" />
|
||||
<ClInclude Include="state.h" />
|
||||
<ClInclude Include="tos.h" />
|
||||
<ClInclude Include="user_io.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="build.sh" />
|
||||
<None Include="clean.sh" />
|
||||
<None Include="Makefile" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
166
MiSTer.vcxproj.filters
Normal file
166
MiSTer.vcxproj.filters
Normal file
@@ -0,0 +1,166 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="archie.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="boot.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="config.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="fdd.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="fpga_io.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hardware.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hdd.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ikbd.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ini_parser.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="input.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="menu.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mist_cfg.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="osd.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="spi.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="state.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tos.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="user_io.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="file_io.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="archie.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="boot.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="charrom.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="config.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="debug.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="errors.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="fdd.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="fpga_base_addr_ac5.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="fpga_io.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="fpga_manager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="fpga_nic301.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="fpga_reset_manager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="fpga_system_manager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hardware.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hdd.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hdd_internal.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ikbd.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ini_parser.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="input.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="keycodes.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="logo.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="menu.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="mist_cfg.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="osd.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="spi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="state.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tos.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="user_io.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="file_io.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="build.sh" />
|
||||
<None Include="Makefile" />
|
||||
<None Include="clean.sh" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
603
archie.c
Normal file
603
archie.c
Normal file
@@ -0,0 +1,603 @@
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#include "hardware.h"
|
||||
#include "fpga_io.h"
|
||||
#include "menu.h"
|
||||
#include "archie.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define MAX_FLOPPY 4
|
||||
|
||||
#define CONFIG_FILENAME "ARCHIE.CFG"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned long system_ctrl; // system control word
|
||||
char rom_img[1024]; // rom image file name
|
||||
} archie_config_t;
|
||||
|
||||
static archie_config_t config;
|
||||
|
||||
fileTYPE floppy[MAX_FLOPPY];
|
||||
|
||||
#define ARCHIE_FILE_TX 0x53
|
||||
#define ARCHIE_FILE_TX_DAT 0x54
|
||||
#define ARCHIE_FDC_GET_STATUS 0x55
|
||||
#define ARCHIE_FDC_TX_DATA 0x56
|
||||
#define ARCHIE_FDC_SET_STATUS 0x57
|
||||
|
||||
#define archie_debugf(a, ...) iprintf("\033[1;31mARCHIE: " a "\033[0m\n", ##__VA_ARGS__)
|
||||
// #define archie_debugf(a, ...)
|
||||
#define archie_x_debugf(a, ...) iprintf("\033[1;32mARCHIE: " a "\033[0m\n", ##__VA_ARGS__)
|
||||
|
||||
enum state {
|
||||
STATE_HRST, STATE_RAK1, STATE_RAK2, STATE_IDLE,
|
||||
STATE_WAIT4ACK1, STATE_WAIT4ACK2, STATE_HOLD_OFF
|
||||
} kbd_state;
|
||||
|
||||
// archie keyboard controller commands
|
||||
#define HRST 0xff
|
||||
#define RAK1 0xfe
|
||||
#define RAK2 0xfd
|
||||
#define RQPD 0x40 // mask 0xf0
|
||||
#define PDAT 0xe0 // mask 0xf0
|
||||
#define RQID 0x20
|
||||
#define KBID 0x80 // mask 0xc0
|
||||
#define KDDA 0xc0 // new key down data, mask 0xf0
|
||||
#define KUDA 0xd0 // new key up data, mask 0xf0
|
||||
#define RQMP 0x22 // request mouse data
|
||||
#define MDAT 0x00 // mouse data, mask 0x80
|
||||
#define BACK 0x3f
|
||||
#define NACK 0x30 // disable kbd scan, disable mouse
|
||||
#define SACK 0x31 // enable kbd scan, disable mouse
|
||||
#define MACK 0x32 // disable kbd scan, enable mouse
|
||||
#define SMAK 0x33 // enable kbd scan, enable mouse
|
||||
#define LEDS 0x00 // mask 0xf8
|
||||
#define PRST 0x21 // nop
|
||||
|
||||
#define QUEUE_LEN 8
|
||||
static unsigned char tx_queue[QUEUE_LEN][2];
|
||||
static unsigned char tx_queue_rptr, tx_queue_wptr;
|
||||
#define QUEUE_NEXT(a) ((a+1)&(QUEUE_LEN-1))
|
||||
|
||||
static unsigned long ack_timeout;
|
||||
static short mouse_x, mouse_y;
|
||||
|
||||
#define FLAG_SCAN_ENABLED 0x01
|
||||
#define FLAG_MOUSE_ENABLED 0x02
|
||||
static unsigned char flags;
|
||||
|
||||
// #define HOLD_OFF_TIME 2
|
||||
#ifdef HOLD_OFF_TIME
|
||||
static unsigned long hold_off_timer;
|
||||
#endif
|
||||
|
||||
static char sector_buffer[1024];
|
||||
|
||||
static void nice_name(char *dest, char *src)
|
||||
{
|
||||
char *c;
|
||||
|
||||
// copy and append nul
|
||||
strncpy(dest, src, 8);
|
||||
for (c = dest + 7; *c == ' '; c--); c++;
|
||||
*c++ = '.';
|
||||
strncpy(c, src + 8, 3);
|
||||
for (c += 2; *c == ' '; c--); c++;
|
||||
*c++ = '\0';
|
||||
}
|
||||
|
||||
static char buffer[17]; // local buffer to assemble file name (8+.+3+\0)
|
||||
|
||||
char *archie_get_rom_name(void)
|
||||
{
|
||||
nice_name(buffer, config.rom_img);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char *archie_get_floppy_name(char i)
|
||||
{
|
||||
if (!floppy[i].size)
|
||||
strcpy(buffer, "* no disk *");
|
||||
else
|
||||
nice_name(buffer, floppy[i].name);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void archie_save_config(void)
|
||||
{
|
||||
FileSave(CONFIG_FILENAME, &config, sizeof(config));
|
||||
}
|
||||
|
||||
void archie_send_file(unsigned char id, char *name)
|
||||
{
|
||||
archie_debugf("Sending file with id %d", id);
|
||||
|
||||
fileTYPE file;
|
||||
if (!FileOpen(&file, name)) return;
|
||||
|
||||
// prepare transmission of new file
|
||||
EnableFpga();
|
||||
spi8(ARCHIE_FILE_TX);
|
||||
spi8(id);
|
||||
DisableFpga();
|
||||
|
||||
unsigned long time = GetTimer(0);
|
||||
|
||||
iprintf("[");
|
||||
|
||||
unsigned short i, blocks = file.size / 512;
|
||||
for (i = 0; i<blocks; i++) {
|
||||
if (!(i & 127)) iprintf("*");
|
||||
|
||||
DISKLED_ON;
|
||||
FileRead(&file, sector_buffer);
|
||||
DISKLED_OFF;
|
||||
|
||||
EnableFpga();
|
||||
spi8(ARCHIE_FILE_TX_DAT);
|
||||
spi_block_write(sector_buffer, 0);
|
||||
DisableFpga();
|
||||
|
||||
// still bytes to send? read next sector
|
||||
if (i != blocks - 1)
|
||||
FileNextSector(&file);
|
||||
}
|
||||
|
||||
FileClose(&file);
|
||||
iprintf("]\n");
|
||||
|
||||
time = GetTimer(0) - time;
|
||||
archie_debugf("Uploaded in %lu ms", time >> 20);
|
||||
|
||||
// signal end of transmission
|
||||
EnableFpga();
|
||||
spi8(ARCHIE_FILE_TX);
|
||||
spi8(0x00);
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
void archie_fdc_set_status(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
// send status bytes for all four possible floppies
|
||||
EnableFpga();
|
||||
spi8(ARCHIE_FDC_SET_STATUS);
|
||||
for (i = 0; i<MAX_FLOPPY; i++)
|
||||
{
|
||||
unsigned char floppy_status = 0x00;
|
||||
if (floppy[i].size) floppy_status |= 1;
|
||||
spi8(floppy_status);
|
||||
}
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
void archie_set_floppy(char i, char *name)
|
||||
{
|
||||
if (!name)
|
||||
{
|
||||
archie_debugf("Floppy %d eject", i);
|
||||
FileClose(&floppy[i]);
|
||||
floppy[i].size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
archie_debugf("Floppy %d insert %s", i, name);
|
||||
FileOpen(&floppy[i], name);
|
||||
}
|
||||
|
||||
// update floppy status in fpga
|
||||
archie_fdc_set_status();
|
||||
}
|
||||
|
||||
char archie_floppy_is_inserted(char i)
|
||||
{
|
||||
return(floppy[i].size != 0);
|
||||
}
|
||||
|
||||
void archie_set_rom(char *name)
|
||||
{
|
||||
if (!name) return;
|
||||
|
||||
// save file name
|
||||
strcpy(config.rom_img, name);
|
||||
|
||||
archie_send_file(0x01, name);
|
||||
}
|
||||
|
||||
static void archie_kbd_enqueue(unsigned char state, unsigned char byte)
|
||||
{
|
||||
if (QUEUE_NEXT(tx_queue_wptr) == tx_queue_rptr)
|
||||
{
|
||||
archie_debugf("KBD tx queue overflow");
|
||||
return;
|
||||
}
|
||||
|
||||
archie_debugf("KBD ENQUEUE %x (%x)", byte, state);
|
||||
tx_queue[tx_queue_wptr][0] = state;
|
||||
tx_queue[tx_queue_wptr][1] = byte;
|
||||
tx_queue_wptr = QUEUE_NEXT(tx_queue_wptr);
|
||||
}
|
||||
|
||||
static void archie_kbd_tx(unsigned char state, unsigned char byte)
|
||||
{
|
||||
archie_debugf("KBD TX %x (%x)", byte, state);
|
||||
spi_uio_cmd_cont(0x05);
|
||||
spi8(byte);
|
||||
DisableIO();
|
||||
|
||||
kbd_state = state;
|
||||
ack_timeout = GetTimer(10); // 10ms timeout
|
||||
}
|
||||
|
||||
static void archie_kbd_send(unsigned char state, unsigned char byte)
|
||||
{
|
||||
// don't send if we are waiting for an ack
|
||||
if ((kbd_state != STATE_WAIT4ACK1) && (kbd_state != STATE_WAIT4ACK2))
|
||||
archie_kbd_tx(state, byte);
|
||||
else
|
||||
archie_kbd_enqueue(state, byte);
|
||||
}
|
||||
|
||||
static void archie_kbd_reset(void)
|
||||
{
|
||||
archie_debugf("KBD reset");
|
||||
tx_queue_rptr = tx_queue_wptr = 0;
|
||||
kbd_state = STATE_HRST;
|
||||
mouse_x = mouse_y = 0;
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
void archie_init(void)
|
||||
{
|
||||
fileTYPE file;
|
||||
char i;
|
||||
|
||||
archie_debugf("init");
|
||||
|
||||
// set config defaults
|
||||
config.system_ctrl = 0;
|
||||
strcpy(config.rom_img, "RISCOS.ROM");
|
||||
|
||||
// try to load config from card
|
||||
if (FileOpen(&file, CONFIG_FILENAME))
|
||||
{
|
||||
if (file.size == sizeof(archie_config_t))
|
||||
{
|
||||
FileReadAdv(&file, &config, sizeof(archie_config_t));
|
||||
}
|
||||
else
|
||||
archie_debugf("Unexpected config size %d != %d", file.size, sizeof(archie_config_t));
|
||||
FileClose(&file);
|
||||
}
|
||||
else
|
||||
archie_debugf("No %s config found", CONFIG_FILENAME);
|
||||
|
||||
// upload rom file
|
||||
archie_set_rom(config.rom_img);
|
||||
|
||||
// upload ext file
|
||||
archie_send_file(0x02, "RISCOS.EXT");
|
||||
|
||||
// try to open default floppies
|
||||
for (i = 0; i<MAX_FLOPPY; i++)
|
||||
{
|
||||
char fdc_name[] = "FLOPPY0.ADF";
|
||||
fdc_name[6] = '0' + i;
|
||||
if (FileOpen(&floppy[i], fdc_name))
|
||||
archie_debugf("Inserted floppy %d with %d bytes", i, floppy[i].size);
|
||||
else
|
||||
floppy[i].size = 0;
|
||||
}
|
||||
// update floppy status in fpga
|
||||
archie_fdc_set_status();
|
||||
|
||||
archie_kbd_send(STATE_RAK1, HRST);
|
||||
ack_timeout = GetTimer(20); // give archie 20ms to reply
|
||||
}
|
||||
|
||||
void archie_kbd(unsigned short code)
|
||||
{
|
||||
archie_debugf("KBD key code %x", code);
|
||||
|
||||
// don't send anything yet if we are still in reset state
|
||||
if (kbd_state <= STATE_RAK2)
|
||||
{
|
||||
archie_debugf("KBD still in reset");
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore any key event if key scanning is disabled
|
||||
if (!(flags & FLAG_SCAN_ENABLED))
|
||||
{
|
||||
archie_debugf("KBD keyboard scan is disabled!");
|
||||
return;
|
||||
}
|
||||
|
||||
// select prefix for up or down event
|
||||
unsigned char prefix = (code & 0x8000) ? KUDA : KDDA;
|
||||
|
||||
archie_kbd_send(STATE_WAIT4ACK1, prefix | (code >> 4));
|
||||
archie_kbd_send(STATE_WAIT4ACK2, prefix | (code & 0x0f));
|
||||
}
|
||||
|
||||
void archie_mouse(unsigned char b, char x, char y)
|
||||
{
|
||||
archie_debugf("KBD MOUSE X:%d Y:%d B:%d", x, y, b);
|
||||
|
||||
// max values -64 .. 63
|
||||
mouse_x += x;
|
||||
if (mouse_x > 63) mouse_x = 63;
|
||||
if (mouse_x < -64) mouse_x = -64;
|
||||
|
||||
mouse_y -= y;
|
||||
if (mouse_y > 63) mouse_y = 63;
|
||||
if (mouse_y < -64) mouse_y = -64;
|
||||
|
||||
// don't send anything yet if we are still in reset state
|
||||
if (kbd_state <= STATE_RAK2)
|
||||
{
|
||||
archie_debugf("KBD still in reset");
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore any mouse movement if mouse is disabled or if nothing to report
|
||||
if ((flags & FLAG_MOUSE_ENABLED) && (mouse_x || mouse_y))
|
||||
{
|
||||
// send asap if no pending byte
|
||||
if (kbd_state == STATE_IDLE) {
|
||||
archie_kbd_send(STATE_WAIT4ACK1, mouse_x & 0x7f);
|
||||
archie_kbd_send(STATE_WAIT4ACK2, mouse_y & 0x7f);
|
||||
mouse_x = mouse_y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ignore mouse buttons if key scanning is disabled
|
||||
if (flags & FLAG_SCAN_ENABLED)
|
||||
{
|
||||
static const uint8_t remap[] = { 0, 2, 1 };
|
||||
static unsigned char buts = 0;
|
||||
uint8_t s;
|
||||
|
||||
// map all three buttons
|
||||
for (s = 0; s<3; s++)
|
||||
{
|
||||
uint8_t mask = (1 << s);
|
||||
if ((b&mask) != (buts&mask))
|
||||
{
|
||||
unsigned char prefix = (b&mask) ? KDDA : KUDA;
|
||||
archie_kbd_send(STATE_WAIT4ACK1, prefix | 0x07);
|
||||
archie_kbd_send(STATE_WAIT4ACK2, prefix | remap[s]);
|
||||
}
|
||||
}
|
||||
buts = b;
|
||||
}
|
||||
}
|
||||
|
||||
static void archie_check_queue(void)
|
||||
{
|
||||
if (tx_queue_rptr == tx_queue_wptr)
|
||||
return;
|
||||
|
||||
archie_kbd_tx(tx_queue[tx_queue_rptr][0], tx_queue[tx_queue_rptr][1]);
|
||||
tx_queue_rptr = QUEUE_NEXT(tx_queue_rptr);
|
||||
}
|
||||
|
||||
void archie_handle_kbd(void)
|
||||
{
|
||||
|
||||
#ifdef HOLD_OFF_TIME
|
||||
if ((kbd_state == STATE_HOLD_OFF) && CheckTimer(hold_off_timer)) {
|
||||
archie_debugf("KBD resume after hold off");
|
||||
kbd_state = STATE_IDLE;
|
||||
archie_check_queue();
|
||||
}
|
||||
#endif
|
||||
|
||||
// timeout waiting for ack?
|
||||
if ((kbd_state == STATE_WAIT4ACK1) || (kbd_state == STATE_WAIT4ACK2)) {
|
||||
if (CheckTimer(ack_timeout)) {
|
||||
if (kbd_state == STATE_WAIT4ACK1)
|
||||
archie_debugf(">>>> KBD ACK TIMEOUT 1ST BYTE <<<<");
|
||||
if (kbd_state == STATE_WAIT4ACK2)
|
||||
archie_debugf(">>>> KBD ACK TIMEOUT 2ND BYTE <<<<");
|
||||
|
||||
kbd_state = STATE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
// timeout in reset sequence?
|
||||
if (kbd_state <= STATE_RAK2)
|
||||
{
|
||||
if (CheckTimer(ack_timeout))
|
||||
{
|
||||
archie_debugf("KBD timeout in reset state");
|
||||
|
||||
archie_kbd_send(STATE_RAK1, HRST);
|
||||
ack_timeout = GetTimer(20); // 20ms timeout
|
||||
}
|
||||
}
|
||||
|
||||
spi_uio_cmd_cont(0x04);
|
||||
if (spi_in() == 0xa1)
|
||||
{
|
||||
unsigned char data = spi_in();
|
||||
DisableIO();
|
||||
|
||||
archie_debugf("KBD RX %x", data);
|
||||
|
||||
switch (data) {
|
||||
// arm requests reset
|
||||
case HRST:
|
||||
archie_kbd_reset();
|
||||
archie_kbd_send(STATE_RAK1, HRST);
|
||||
ack_timeout = GetTimer(20); // 20ms timeout
|
||||
break;
|
||||
|
||||
// arm sends reset ack 1
|
||||
case RAK1:
|
||||
if (kbd_state == STATE_RAK1) {
|
||||
archie_kbd_send(STATE_RAK2, RAK1);
|
||||
ack_timeout = GetTimer(20); // 20ms timeout
|
||||
}
|
||||
else
|
||||
kbd_state = STATE_HRST;
|
||||
break;
|
||||
|
||||
// arm sends reset ack 2
|
||||
case RAK2:
|
||||
if (kbd_state == STATE_RAK2) {
|
||||
archie_kbd_send(STATE_IDLE, RAK2);
|
||||
ack_timeout = GetTimer(20); // 20ms timeout
|
||||
}
|
||||
else
|
||||
kbd_state = STATE_HRST;
|
||||
break;
|
||||
|
||||
// arm request keyboard id
|
||||
case RQID:
|
||||
archie_kbd_send(STATE_IDLE, KBID | 1);
|
||||
break;
|
||||
|
||||
// arm acks first byte
|
||||
case BACK:
|
||||
if (kbd_state != STATE_WAIT4ACK1)
|
||||
archie_debugf("KBD unexpected BACK");
|
||||
|
||||
#ifdef HOLD_OFF_TIME
|
||||
// wait some time before sending next byte
|
||||
archie_debugf("KBD starting hold off");
|
||||
kbd_state = STATE_HOLD_OFF;
|
||||
hold_off_timer = GetTimer(10);
|
||||
#else
|
||||
kbd_state = STATE_IDLE;
|
||||
archie_check_queue();
|
||||
#endif
|
||||
break;
|
||||
|
||||
// arm acks second byte
|
||||
case NACK:
|
||||
case SACK:
|
||||
case MACK:
|
||||
case SMAK:
|
||||
|
||||
if (((data == SACK) || (data == SMAK)) && !(flags & FLAG_SCAN_ENABLED)) {
|
||||
archie_debugf("KBD Enabling key scanning");
|
||||
flags |= FLAG_SCAN_ENABLED;
|
||||
}
|
||||
|
||||
if (((data == NACK) || (data == MACK)) && (flags & FLAG_SCAN_ENABLED)) {
|
||||
archie_debugf("KBD Disabling key scanning");
|
||||
flags &= ~FLAG_SCAN_ENABLED;
|
||||
}
|
||||
|
||||
if (((data == MACK) || (data == SMAK)) && !(flags & FLAG_MOUSE_ENABLED)) {
|
||||
archie_debugf("KBD Enabling mouse");
|
||||
flags |= FLAG_MOUSE_ENABLED;
|
||||
}
|
||||
|
||||
if (((data == NACK) || (data == SACK)) && (flags & FLAG_MOUSE_ENABLED)) {
|
||||
archie_debugf("KBD Disabling mouse");
|
||||
flags &= ~FLAG_MOUSE_ENABLED;
|
||||
}
|
||||
|
||||
// wait another 10ms before sending next byte
|
||||
#ifdef HOLD_OFF_TIME
|
||||
archie_debugf("KBD starting hold off");
|
||||
kbd_state = STATE_HOLD_OFF;
|
||||
hold_off_timer = GetTimer(10);
|
||||
#else
|
||||
kbd_state = STATE_IDLE;
|
||||
archie_check_queue();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
DisableIO();
|
||||
}
|
||||
|
||||
static unsigned char fdc_buffer[1024];
|
||||
|
||||
void archie_handle_fdc(void)
|
||||
{
|
||||
static unsigned char old_status[4] = { 0,0,0,0 };
|
||||
unsigned char status[4];
|
||||
|
||||
// read status
|
||||
EnableFpga();
|
||||
spi8(ARCHIE_FDC_GET_STATUS);
|
||||
status[0] = spi_in();
|
||||
status[1] = spi_in();
|
||||
status[2] = spi_in();
|
||||
status[3] = spi_in();
|
||||
DisableFpga();
|
||||
|
||||
if (memcmp(status, old_status, 4) != 0)
|
||||
{
|
||||
archie_x_debugf("status changed to %x %x %x %x",
|
||||
status[0], status[1], status[2], status[3]);
|
||||
memcpy(old_status, status, 4);
|
||||
|
||||
// top four bits must be magic marker 1010
|
||||
if (((status[0] & 0xf0) == 0xa0) && (status[0] & 1))
|
||||
{
|
||||
archie_x_debugf("DIO: BUSY with commmand %lx", status[1]);
|
||||
|
||||
// check for read sector command
|
||||
if ((status[1] & 0xe0) == 0x80)
|
||||
{
|
||||
if (status[0] & 2)
|
||||
{
|
||||
int floppy_map = status[3] >> 4;
|
||||
int side = (status[2] & 0x80) ? 0 : 1;
|
||||
int track = status[2] & 0x7f;
|
||||
int sector = status[3] & 0x0f;
|
||||
unsigned long lba = 2 * (10 * track + 5 * side + sector);
|
||||
int floppy_index = -1;
|
||||
|
||||
// allow only single floppy drives to be selected
|
||||
int i;
|
||||
for (i = 0; i<MAX_FLOPPY; i++)
|
||||
if (floppy_map == (0x0f ^ (1 << i)))
|
||||
floppy_index = i;
|
||||
|
||||
if (floppy_index < 0)
|
||||
archie_x_debugf("DIO: unexpected floppy_map %x", floppy_map);
|
||||
else
|
||||
{
|
||||
fileTYPE *f = &floppy[floppy_index];
|
||||
|
||||
archie_x_debugf("DIO: floppy %d sector read SD%d T%d S%d -> %ld",
|
||||
floppy_index, side, track, sector, lba);
|
||||
|
||||
if (!f->size)
|
||||
archie_x_debugf("DIO: floppy not inserted. Core should not do this!!");
|
||||
else {
|
||||
DISKLED_ON;
|
||||
// read two consecutive sectors
|
||||
FileSeek(f, lba, SEEK_SET);
|
||||
FileRead(f, fdc_buffer);
|
||||
FileNextSector(f);
|
||||
FileRead(f, fdc_buffer + 512);
|
||||
DISKLED_OFF;
|
||||
|
||||
EnableFpga();
|
||||
spi8(ARCHIE_FDC_TX_DATA);
|
||||
spi_write(fdc_buffer, 1024, 0);
|
||||
DisableFpga();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void archie_poll(void)
|
||||
{
|
||||
archie_handle_kbd();
|
||||
archie_handle_fdc();
|
||||
}
|
||||
17
archie.h
Normal file
17
archie.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef ARCHIE_H
|
||||
#define ARCHIE_H
|
||||
|
||||
#include "file_io.h"
|
||||
|
||||
void archie_init(void);
|
||||
void archie_poll(void);
|
||||
void archie_kbd(unsigned short code);
|
||||
void archie_mouse(unsigned char b, char x, char y);
|
||||
char *archie_get_rom_name(void);
|
||||
char *archie_get_floppy_name(char b);
|
||||
void archie_set_rom(char *);
|
||||
void archie_set_floppy(char i, char *);
|
||||
char archie_floppy_is_inserted(char i);
|
||||
void archie_save_config(void);
|
||||
|
||||
#endif // ARCHIE_H
|
||||
501
boot.c
Normal file
501
boot.c
Normal file
@@ -0,0 +1,501 @@
|
||||
// boot.c
|
||||
// bootscreen functions
|
||||
// 2014, rok.krajnc@gmail.com
|
||||
|
||||
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
#include "boot.h"
|
||||
#include "hardware.h"
|
||||
#include "osd.h"
|
||||
#include "spi.h"
|
||||
#include "file_io.h"
|
||||
#include "config.h"
|
||||
#include "fdd.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;
|
||||
}
|
||||
|
||||
//// boot font ////
|
||||
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 } //
|
||||
};
|
||||
|
||||
|
||||
//// BootEnableMem() ////
|
||||
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));
|
||||
}
|
||||
|
||||
//// BootClearScreen() ////
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
//// BootUploadLogo() ////
|
||||
void BootUploadLogo()
|
||||
{
|
||||
fileTYPE file;
|
||||
int x, y;
|
||||
int i = 0;
|
||||
int adr;
|
||||
|
||||
if (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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// BootUploadBall() ////
|
||||
void BootUploadBall()
|
||||
{
|
||||
fileTYPE file;
|
||||
int x;
|
||||
int i = 0;
|
||||
int adr;
|
||||
|
||||
if (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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// BootUploadCopper() ////
|
||||
void BootUploadCopper()
|
||||
{
|
||||
fileTYPE file;
|
||||
int x;
|
||||
int i = 0;
|
||||
int adr;
|
||||
|
||||
if (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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// BootCustomInit() ////
|
||||
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();
|
||||
}
|
||||
|
||||
extern adfTYPE df[4];
|
||||
|
||||
//// BootInit() ////
|
||||
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();
|
||||
|
||||
//default video config till real config loaded.
|
||||
ConfigVideo(0,0, 0x40);
|
||||
|
||||
WaitTimer(100);
|
||||
|
||||
BootEnableMem();
|
||||
BootClearScreen(SCREEN_ADDRESS, SCREEN_MEM_SIZE);
|
||||
BootUploadLogo();
|
||||
BootUploadBall();
|
||||
BootUploadCopper();
|
||||
BootCustomInit();
|
||||
|
||||
WaitTimer(500);
|
||||
char rtl_ver[45];
|
||||
siprintf(rtl_ver, "**** MINIMIG-AGA%s v%d.%d.%d for MiST ****", ver_beta ? " BETA" : "", ver_major, ver_minor, ver_minion);
|
||||
BootPrintEx(rtl_ver);
|
||||
BootPrintEx(" ");
|
||||
BootPrintEx("MINIMIG-AGA for MiST by Rok Krajnc (rok.krajnc@gmail.com)");
|
||||
BootPrintEx("Original Minimig by Dennis van Weeren");
|
||||
BootPrintEx("Updates by Jakub Bednarski, Tobias Gubener, Sascha Boing, A.M. Robinson & others");
|
||||
BootPrintEx("MiST by Till Harbaum (till@harbaum.org)");
|
||||
BootPrintEx("For updates & code see https://github.com/rkrajnc/minimig-mist");
|
||||
BootPrintEx(" ");
|
||||
WaitTimer(1000);
|
||||
|
||||
//eject all disk
|
||||
df[0].status = 0;
|
||||
df[1].status = 0;
|
||||
df[2].status = 0;
|
||||
df[3].status = 0;
|
||||
|
||||
config.kickstart[0] = 0;
|
||||
SetConfigurationFilename(0); // Use default config
|
||||
LoadConfiguration(0); // Use slot-based config filename
|
||||
}
|
||||
|
||||
|
||||
//// BootPrint() ////
|
||||
void BootPrintEx(char * str)
|
||||
{
|
||||
char buf[2];
|
||||
unsigned char i, j;
|
||||
unsigned char len;
|
||||
|
||||
iprintf(str);
|
||||
iprintf("\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;
|
||||
}
|
||||
}
|
||||
|
||||
43
boot.h
Normal file
43
boot.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// boot.h
|
||||
// bootscreen functions
|
||||
// 2014, rok.krajnc@gmail.com
|
||||
|
||||
|
||||
#ifndef __BOOT_H__
|
||||
#define __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(char * str);
|
||||
void BootHome();
|
||||
|
||||
#endif // __BOOT_H__
|
||||
|
||||
20
build.sh
Normal file
20
build.sh
Normal file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
# make script fail if any command failed,
|
||||
# so we don't need to check the exit status of every command.
|
||||
set -e
|
||||
set -o pipefail
|
||||
make
|
||||
|
||||
set +e
|
||||
plink root@192.168.1.75 -pw 1 'killall MiSTer'
|
||||
|
||||
set -e
|
||||
ftp -n <<EOF
|
||||
open 192.168.1.75
|
||||
user root 1
|
||||
binary
|
||||
put MiSTer /media/fat/MiSTer
|
||||
EOF
|
||||
|
||||
plink root@192.168.1.75 -pw 1 'PATH=/media/fat:$PATH;MiSTer >/dev/ttyS0 2>/dev/ttyS0 </dev/null &'
|
||||
173
charrom.h
Normal file
173
charrom.h
Normal file
@@ -0,0 +1,173 @@
|
||||
#ifndef CHARROM_H
|
||||
#define CHARROM_H
|
||||
|
||||
/*
|
||||
Write protect. Characters are defined in columns, not rows, LSB first
|
||||
. . . . . . . .
|
||||
. . * * * . . .
|
||||
. * . . . * . .
|
||||
. * . . . * . .
|
||||
* * * * * * * .
|
||||
* * * * * * * .
|
||||
* * * * * * * .
|
||||
. . . . . . . .
|
||||
0x70,0x7c,0x72,0x72,0x72,0x7c,0x70,0x00,0x00
|
||||
|
||||
Write enable
|
||||
. . . . . . . .
|
||||
. . . . . * * .
|
||||
. . . . * . . *
|
||||
. . . . * . . *
|
||||
* * * * * * . .
|
||||
* * * * * * . .
|
||||
* * * * * * . .
|
||||
. . . . . . . .
|
||||
0x70,0x70,0x70,0x70,0x7c,0x72,0x02,0x0c
|
||||
|
||||
Middle Dot
|
||||
. . . . . . . .
|
||||
. . . . . . . .
|
||||
. . . * * . . .
|
||||
. . . * * . . .
|
||||
. . . . . . . .
|
||||
. . . . . . . .
|
||||
. . . . . . . .
|
||||
. . . . . . . .
|
||||
0x00,0x00,0x00,0x0c,0x0c,0x00,0x00,0x00
|
||||
|
||||
*/
|
||||
|
||||
// *character font
|
||||
unsigned char charfont[128][8] =
|
||||
{
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 0 [0x0]
|
||||
{ 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55 }, // 1 [0x1]
|
||||
{ 0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A }, // 2 [0x2]
|
||||
{ 0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14 }, // 3 [0x3]
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 4 [0x4]
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 5 [0x5]
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 6 [0x6]
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 7 [0x7]
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 8 [0x8]
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 9 [0x9]
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 10 [0xa]
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 11 [0xb]
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 12 [0xc]
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 13 [0xd]
|
||||
{ 0x00,0xc0,0xc0,0xe0,0x78,0x1f,0x00,0xff }, // 14 [0xe] atari logo left
|
||||
{ 0xff,0x00,0x1f,0x78,0xe0,0xc0,0xc0,0x00 }, // 15 [0xf] atari logo right
|
||||
{ 0x08,0x08,0x1C,0x1C,0x3E,0x3E,0x7F,0x7F }, // 16 [0x10] arrow left
|
||||
{ 0x7F,0x7F,0x3E,0x3E,0x1C,0x1C,0x08,0x08 }, // 17 [0x11] arrow right
|
||||
{ 0x00,0x10,0x18,0x7c,0x7c,0x18,0x10,0x00 }, // 18 [0x12] arrow up
|
||||
{ 0x00,0x10,0x30,0x7c,0x7c,0x30,0x10,0x00 }, // 19 [0x13] arrow down
|
||||
{ 0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x00,0x00 }, // 20 [0x14]
|
||||
{ 0x00,0x00,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C }, // 21 [0x15]
|
||||
{ 0x00,0x7C,0x7C,0x38,0x38,0x10,0x10,0x00 }, // 22 [0x16] mini arrow right
|
||||
{ 0x70,0x7c,0x72,0x72,0x72,0x7c,0x70,0x00 }, // 23 [0x17] write protect
|
||||
{ 0x70,0x70,0x70,0x70,0x7c,0x72,0x02,0x0c }, // 24 [0x18] write enable
|
||||
{ 0x3e,0x3e,0x22,0x22,0x22,0x3e,0x3e,0x00 }, // 25 [0x19] unchecked checkbox
|
||||
{ 0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x3e,0x00 }, // 26 [0x1a] checked checkbox
|
||||
{ 0x00,0x00,0x00,0x0c,0x0c,0x00,0x00,0x00 }, // 27 [0x1b] middle dot
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 28 [0x1c]
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 29 [0x1d]
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 30 [0x1e]
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 31 [0x1f]
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // 32 [0x20]
|
||||
{ 0x00,0x00,0x00,0x5F,0x5F,0x00,0x00,0x00 }, // 33 [0x21]
|
||||
{ 0x00,0x03,0x03,0x00,0x03,0x03,0x00,0x00 }, // 34 [0x22]
|
||||
{ 0x14,0x7F,0x7F,0x14,0x7F,0x7F,0x14,0x00 }, // 35 [0x23]
|
||||
{ 0x00,0x24,0x2E,0x6B,0x6B,0x3A,0x12,0x00 }, // 36 [0x24]
|
||||
{ 0x4C,0x6A,0x36,0x18,0x6C,0x56,0x32,0x00 }, // 37 [0x25]
|
||||
{ 0x30,0x7E,0x4F,0x59,0x77,0x3A,0x68,0x40 }, // 38 [0x26]
|
||||
{ 0x00,0x00,0x04,0x07,0x03,0x00,0x00,0x00 }, // 39 [0x27]
|
||||
{ 0x00,0x00,0x1C,0x3E,0x63,0x41,0x00,0x00 }, // 40 [0x28]
|
||||
{ 0x00,0x00,0x41,0x63,0x3E,0x1C,0x00,0x00 }, // 41 [0x29]
|
||||
{ 0x08,0x2A,0x3E,0x1C,0x1C,0x3E,0x2A,0x08 }, // 42 [0x2a]
|
||||
{ 0x00,0x08,0x08,0x3E,0x3E,0x08,0x08,0x00 }, // 43 [0x2b]
|
||||
{ 0x00,0x00,0x80,0xE0,0x60,0x00,0x00,0x00 }, // 44 [0x2c]
|
||||
{ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00 }, // 45 [0x2d]
|
||||
{ 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00 }, // 46 [0x2e]
|
||||
{ 0x40,0x60,0x30,0x18,0x0C,0x06,0x03,0x01 }, // 47 [0x2f]
|
||||
{ 0x00,0x3E,0x7F,0x59,0x4D,0x7F,0x3E,0x00 }, // 48 [0x30]
|
||||
{ 0x00,0x04,0x06,0x7F,0x7F,0x00,0x00,0x00 }, // 49 [0x31]
|
||||
{ 0x00,0x42,0x63,0x71,0x59,0x4F,0x46,0x00 }, // 50 [0x32]
|
||||
{ 0x00,0x22,0x63,0x49,0x49,0x7F,0x36,0x00 }, // 51 [0x33]
|
||||
{ 0x18,0x1C,0x16,0x13,0x7F,0x7F,0x10,0x00 }, // 52 [0x34]
|
||||
{ 0x00,0x27,0x67,0x45,0x45,0x7D,0x39,0x00 }, // 53 [0x35]
|
||||
{ 0x00,0x3C,0x7E,0x4B,0x49,0x79,0x30,0x00 }, // 54 [0x36]
|
||||
{ 0x00,0x01,0x01,0x71,0x79,0x0F,0x07,0x00 }, // 55 [0x37]
|
||||
{ 0x00,0x36,0x7F,0x49,0x49,0x7F,0x36,0x00 }, // 56 [0x38]
|
||||
{ 0x00,0x06,0x4F,0x49,0x69,0x3F,0x1E,0x00 }, // 57 [0x39]
|
||||
{ 0x00,0x00,0x00,0x66,0x66,0x00,0x00,0x00 }, // 58 [0x3a]
|
||||
{ 0x00,0x00,0x80,0xE6,0x66,0x00,0x00,0x00 }, // 59 [0x3b]
|
||||
{ 0x00,0x08,0x08,0x14,0x14,0x22,0x22,0x00 }, // 60 [0x3c]
|
||||
{ 0x00,0x14,0x14,0x14,0x14,0x14,0x14,0x00 }, // 61 [0x3d]
|
||||
{ 0x00,0x22,0x22,0x14,0x14,0x08,0x08,0x00 }, // 62 [0x3e]
|
||||
{ 0x00,0x02,0x03,0x51,0x59,0x0F,0x06,0x00 }, // 63 [0x3f]
|
||||
{ 0x3E,0x7F,0x41,0x5D,0x55,0x1F,0x1E,0x00 }, // 64 [0x40]
|
||||
{ 0x00,0x7E,0x7F,0x09,0x09,0x7F,0x7E,0x00 }, // 65 [0x41]
|
||||
{ 0x00,0x7F,0x7F,0x49,0x49,0x7F,0x36,0x00 }, // 66 [0x42]
|
||||
{ 0x00,0x1C,0x3E,0x63,0x41,0x41,0x41,0x00 }, // 67 [0x43]
|
||||
{ 0x00,0x7F,0x7F,0x41,0x63,0x3E,0x1C,0x00 }, // 68 [0x44]
|
||||
{ 0x00,0x7F,0x7F,0x49,0x49,0x41,0x41,0x00 }, // 69 [0x45]
|
||||
{ 0x00,0x7F,0x7F,0x09,0x09,0x01,0x01,0x00 }, // 70 [0x46]
|
||||
{ 0x00,0x3E,0x7F,0x41,0x49,0x7B,0x7A,0x00 }, // 71 [0x47]
|
||||
{ 0x00,0x7F,0x7F,0x08,0x08,0x7F,0x7F,0x00 }, // 72 [0x48]
|
||||
{ 0x00,0x00,0x41,0x7F,0x7F,0x41,0x00,0x00 }, // 73 [0x49]
|
||||
{ 0x00,0x20,0x60,0x40,0x40,0x7F,0x3F,0x00 }, // 74 [0x4a]
|
||||
{ 0x7F,0x7F,0x08,0x1C,0x36,0x63,0x41,0x00 }, // 75 [0x4b]
|
||||
{ 0x00,0x7F,0x7F,0x40,0x40,0x40,0x40,0x00 }, // 76 [0x4c]
|
||||
{ 0x7F,0x7F,0x06,0x0C,0x06,0x7F,0x7F,0x00 }, // 77 [0x4d]
|
||||
{ 0x7F,0x7F,0x06,0x0C,0x18,0x7F,0x7F,0x00 }, // 78 [0x4e]
|
||||
{ 0x00,0x3E,0x7F,0x41,0x41,0x7F,0x3E,0x00 }, // 79 [0x4f]
|
||||
{ 0x00,0x7F,0x7F,0x09,0x09,0x0F,0x06,0x00 }, // 80 [0x50]
|
||||
{ 0x3E,0x7F,0x41,0x61,0x7F,0x7E,0x40,0x00 }, // 81 [0x51]
|
||||
{ 0x00,0x7F,0x7F,0x09,0x19,0x7F,0x66,0x00 }, // 82 [0x52]
|
||||
{ 0x00,0x26,0x6F,0x4D,0x59,0x7B,0x32,0x00 }, // 83 [0x53]
|
||||
{ 0x00,0x01,0x01,0x7F,0x7F,0x01,0x01,0x00 }, // 84 [0x54]
|
||||
{ 0x00,0x3F,0x7F,0x40,0x40,0x7F,0x3F,0x00 }, // 85 [0x55]
|
||||
{ 0x00,0x0F,0x3F,0x70,0x70,0x3F,0x0F,0x00 }, // 86 [0x56]
|
||||
{ 0x7F,0x7F,0x30,0x18,0x30,0x7F,0x7F,0x00 }, // 87 [0x57]
|
||||
{ 0x41,0x63,0x36,0x1C,0x1C,0x36,0x63,0x41 }, // 88 [0x58]
|
||||
{ 0x01,0x03,0x06,0x7C,0x7C,0x06,0x03,0x01 }, // 89 [0x59]
|
||||
{ 0x61,0x71,0x59,0x4D,0x47,0x43,0x41,0x00 }, // 90 [0x5a]
|
||||
{ 0x00,0x00,0x7F,0x7F,0x41,0x41,0x00,0x00 }, // 91 [0x5b]
|
||||
{ 0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0x40 }, // 92 [0x5c]
|
||||
{ 0x00,0x00,0x41,0x41,0x7F,0x7F,0x00,0x00 }, // 93 [0x5d]
|
||||
{ 0x08,0x0C,0x06,0x03,0x06,0x0C,0x08,0x00 }, // 94 [0x5e]
|
||||
{ 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00 }, // 95 [0x5f]
|
||||
{ 0x00,0x00,0x00,0x03,0x07,0x04,0x00,0x00 }, // 96 [0x60]
|
||||
{ 0x00,0x20,0x74,0x54,0x54,0x7C,0x78,0x00 }, // 97 [0x61]
|
||||
{ 0x00,0x7F,0x7F,0x44,0x44,0x7C,0x38,0x00 }, // 98 [0x62]
|
||||
{ 0x00,0x38,0x7C,0x44,0x44,0x44,0x00,0x00 }, // 99 [0x63]
|
||||
{ 0x00,0x38,0x7C,0x44,0x44,0x7F,0x7F,0x00 }, // 100 [0x64]
|
||||
{ 0x00,0x38,0x7C,0x54,0x54,0x5C,0x18,0x00 }, // 101 [0x65]
|
||||
{ 0x00,0x04,0x7E,0x7F,0x05,0x05,0x00,0x00 }, // 102 [0x66]
|
||||
{ 0x00,0x18,0xBC,0xA4,0xA4,0xFC,0x7C,0x00 }, // 103 [0x67]
|
||||
{ 0x00,0x7F,0x7F,0x04,0x04,0x7C,0x78,0x00 }, // 104 [0x68]
|
||||
{ 0x00,0x00,0x00,0x3D,0x7D,0x40,0x00,0x00 }, // 105 [0x69]
|
||||
{ 0x00,0x80,0x80,0x80,0xFD,0x7D,0x00,0x00 }, // 106 [0x6a]
|
||||
{ 0x00,0x7F,0x7F,0x10,0x38,0x6C,0x44,0x00 }, // 107 [0x6b]
|
||||
{ 0x00,0x00,0x00,0x3F,0x7F,0x40,0x00,0x00 }, // 108 [0x6c]
|
||||
{ 0x7C,0x7C,0x0C,0x18,0x0C,0x7C,0x78,0x00 }, // 109 [0x6d]
|
||||
{ 0x00,0x7C,0x7C,0x04,0x04,0x7C,0x78,0x00 }, // 110 [0x6e]
|
||||
{ 0x00,0x38,0x7C,0x44,0x44,0x7C,0x38,0x00 }, // 111 [0x6f]
|
||||
{ 0x00,0xFC,0xFC,0x24,0x24,0x3C,0x18,0x00 }, // 112 [0x70]
|
||||
{ 0x00,0x18,0x3C,0x24,0x24,0xFC,0xFC,0x00 }, // 113 [0x71]
|
||||
{ 0x00,0x7C,0x7C,0x04,0x04,0x0C,0x08,0x00 }, // 114 [0x72]
|
||||
{ 0x00,0x48,0x5C,0x54,0x54,0x74,0x20,0x00 }, // 115 [0x73]
|
||||
{ 0x00,0x04,0x3F,0x7F,0x44,0x44,0x00,0x00 }, // 116 [0x74]
|
||||
{ 0x00,0x3C,0x7C,0x40,0x40,0x7C,0x7C,0x00 }, // 117 [0x75]
|
||||
{ 0x00,0x1C,0x3C,0x60,0x60,0x3C,0x1C,0x00 }, // 118 [0x76]
|
||||
{ 0x3C,0x7C,0x60,0x30,0x60,0x7C,0x3C,0x00 }, // 119 [0x77]
|
||||
{ 0x44,0x6C,0x38,0x10,0x38,0x6C,0x44,0x00 }, // 120 [0x78]
|
||||
{ 0x00,0x1C,0xBC,0xE0,0x60,0x3C,0x1C,0x00 }, // 121 [0x79]
|
||||
{ 0x00,0x44,0x64,0x74,0x5C,0x4C,0x44,0x00 }, // 122 [0x7a]
|
||||
{ 0x00,0x08,0x08,0x3E,0x77,0x41,0x41,0x00 }, // 123 [0x7b]
|
||||
{ 0x00,0x00,0x00,0x7F,0x7F,0x00,0x00,0x00 }, // 124 [0x7c]
|
||||
{ 0x00,0x41,0x41,0x77,0x3E,0x08,0x08,0x00 }, // 125 [0x7d]
|
||||
{ 0x02,0x01,0x01,0x03,0x02,0x02,0x01,0x00 }, // 126 [0x7e]
|
||||
{ 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x00 } // 127 [0x7f]
|
||||
};
|
||||
|
||||
#endif
|
||||
492
config.c
Normal file
492
config.c
Normal file
@@ -0,0 +1,492 @@
|
||||
// config.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "errors.h"
|
||||
#include "hardware.h"
|
||||
#include "boot.h"
|
||||
#include "file_io.h"
|
||||
#include "osd.h"
|
||||
#include "fdd.h"
|
||||
#include "hdd.h"
|
||||
#include "menu.h"
|
||||
#include "config.h"
|
||||
#include "user_io.h"
|
||||
|
||||
configTYPE config;
|
||||
char configfilename[32];
|
||||
char DebugMode = 0;
|
||||
unsigned char romkey[3072];
|
||||
|
||||
void SendFileV2(fileTYPE* file, unsigned char* key, int keysize, int address, int size)
|
||||
{
|
||||
static uint8_t buf[512];
|
||||
int i, j;
|
||||
unsigned int keyidx = 0;
|
||||
iprintf("File size: %dkB\n", size >> 1);
|
||||
iprintf("[");
|
||||
if (keysize)
|
||||
{
|
||||
// read header
|
||||
FileReadAdv(file, buf, 0xb);
|
||||
}
|
||||
for (i = 0; i<size; i++)
|
||||
{
|
||||
if (!(i & 31)) iprintf("*");
|
||||
FileReadAdv(file, buf, 512);
|
||||
if (keysize)
|
||||
{
|
||||
// decrypt ROM
|
||||
for (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 (j = 0; j<512; j = j + 4)
|
||||
{
|
||||
spi8(buf[j + 0]);
|
||||
spi8(buf[j + 1]);
|
||||
spi8(buf[j + 2]);
|
||||
spi8(buf[j + 3]);
|
||||
}
|
||||
DisableOsd();
|
||||
}
|
||||
iprintf("]\n");
|
||||
}
|
||||
|
||||
//// UploadKickstart() ////
|
||||
char UploadKickstart(char *name)
|
||||
{
|
||||
fileTYPE file;
|
||||
int keysize = 0;
|
||||
|
||||
BootPrint("Checking for Amiga Forever key file:");
|
||||
if (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);
|
||||
}
|
||||
|
||||
|
||||
//// UploadActionReplay() ////
|
||||
char UploadActionReplay()
|
||||
{
|
||||
fileTYPE file;
|
||||
if (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);
|
||||
}
|
||||
|
||||
|
||||
//// SetConfigurationFilename() ////
|
||||
void SetConfigurationFilename(int config)
|
||||
{
|
||||
if (config)
|
||||
siprintf(configfilename, "MINIMIG%d.CFG", config);
|
||||
else
|
||||
strcpy(configfilename, "MINIMIG.CFG");
|
||||
}
|
||||
|
||||
|
||||
//// ConfigurationExists() ////
|
||||
unsigned char ConfigurationExists(char *filename)
|
||||
{
|
||||
if (!filename) {
|
||||
// use slot-based filename if none provided
|
||||
filename = configfilename;
|
||||
}
|
||||
fileTYPE f;
|
||||
if(FileOpen(&f, filename))
|
||||
{
|
||||
FileClose(&f);
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
//// LoadConfiguration() ////
|
||||
unsigned char LoadConfiguration(char *filename)
|
||||
{
|
||||
static const char config_id[] = "MNMGCFG0";
|
||||
char updatekickstart = 0;
|
||||
char result = 0;
|
||||
unsigned char key, i;
|
||||
static configTYPE tmpconf;
|
||||
|
||||
if (!filename)
|
||||
{
|
||||
// use slot-based filename if none provided
|
||||
filename = configfilename;
|
||||
}
|
||||
|
||||
fileTYPE file;
|
||||
// load configuration data
|
||||
if (FileOpen(&file, filename)) {
|
||||
FileClose(&file);
|
||||
BootPrint("Opened configuration file\n");
|
||||
printf("Configuration file size: %s, %lu\n", file.name, file.size);
|
||||
if (file.size == sizeof(config))
|
||||
{
|
||||
if (FileLoad(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 printf("Wrong configuration file size: %lu (expected: %lu)\n", file.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, "KICK.ROM");
|
||||
config.memory = 0x15;
|
||||
config.cpu = 0;
|
||||
config.chipset = 0;
|
||||
config.floppy.speed = CONFIG_FLOPPY2X;
|
||||
config.floppy.drives = 1;
|
||||
config.enable_ide = 0;
|
||||
config.hardfile[0].enabled = 1;
|
||||
strcpy(config.hardfile[0].long_name, "HARDFILE1.HDF");
|
||||
config.hardfile[0].long_name[0] = 0;
|
||||
strcpy(config.hardfile[1].long_name, "HARDFILE2.HDF");
|
||||
config.hardfile[1].long_name[0] = 0;
|
||||
config.hardfile[1].enabled = 1; // Default is access to entire SD card
|
||||
updatekickstart = true;
|
||||
BootPrint("Defaults set\n");
|
||||
}
|
||||
|
||||
// print config to boot screen
|
||||
char cfg_str[41];
|
||||
siprintf(cfg_str, "CPU: %s", config_cpu_msg[config.cpu & 0x03]); BootPrintEx(cfg_str);
|
||||
siprintf(cfg_str, "Chipset: %s", config_chipset_msg[(config.chipset >> 2) & 7]); BootPrintEx(cfg_str);
|
||||
siprintf(cfg_str, "Memory: CHIP: %s FAST: %s SLOW: %s", 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);
|
||||
|
||||
// wait up to 3 seconds for keyboard to appear. If it appears wait another
|
||||
// two seconds for the user to press a key
|
||||
/*
|
||||
int8_t keyboard_present = 0;
|
||||
for(i=0;i<3;i++) {
|
||||
unsigned long to = GetTimer(1000);
|
||||
//while(!CheckTimer(to)) usb_poll();
|
||||
|
||||
// check if keyboard just appeared
|
||||
if(!keyboard_present && hid_keyboard_present()) {
|
||||
// BootPrintEx("Press F1 for NTSC, F2 for PAL");
|
||||
keyboard_present = 1;
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
key = OsdGetCtrl();
|
||||
if (key == KEY_F1) {
|
||||
// BootPrintEx("Forcing NTSC video ...");
|
||||
// force NTSC mode if F1 pressed
|
||||
config.chipset |= CONFIG_NTSC;
|
||||
}
|
||||
|
||||
if (key == KEY_F2) {
|
||||
// BootPrintEx("Forcing PAL video ...");
|
||||
// force PAL mode if F2 pressed
|
||||
config.chipset &= ~CONFIG_NTSC;
|
||||
}
|
||||
|
||||
ApplyConfiguration(updatekickstart);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
//// ApplyConfiguration() ////
|
||||
void ApplyConfiguration(char reloadkickstart)
|
||||
{
|
||||
ConfigCPU(config.cpu);
|
||||
|
||||
if (reloadkickstart)
|
||||
{
|
||||
|
||||
}
|
||||
else {
|
||||
ConfigChipset(config.chipset);
|
||||
ConfigFloppy(config.floppy.drives, config.floppy.speed);
|
||||
}
|
||||
|
||||
// Whether or not we uploaded a kickstart image we now need to set various parameters from the config.
|
||||
if (OpenHardfile(0)) {
|
||||
switch (hdf[0].type) {
|
||||
// Customise message for SD card acces
|
||||
case (HDF_FILE | HDF_SYNTHRDB) :
|
||||
printf("\nHardfile 0 (with fake RDB): %s\n", hdf[0].file.name);
|
||||
break;
|
||||
case HDF_FILE:
|
||||
printf("\nHardfile 0: %s\n", hdf[0].file.name);
|
||||
break;
|
||||
}
|
||||
printf("CHS: %u.%u.%u\n", hdf[0].cylinders, hdf[0].heads, hdf[0].sectors);
|
||||
printf("Size: %lu MB\n", ((((unsigned long)hdf[0].cylinders) * hdf[0].heads * hdf[0].sectors) >> 11));
|
||||
printf("Offset: %ld\n", hdf[0].offset);
|
||||
}
|
||||
|
||||
if (OpenHardfile(1)) {
|
||||
switch (hdf[1].type) {
|
||||
case (HDF_FILE | HDF_SYNTHRDB) :
|
||||
printf("\nHardfile 1 (with fake RDB): %s\n", hdf[1].file.name);
|
||||
break;
|
||||
case HDF_FILE:
|
||||
printf("\nHardfile 1: %s\n", hdf[1].file.name);
|
||||
break;
|
||||
}
|
||||
printf("CHS: %u.%u.%u\n", hdf[1].cylinders, hdf[1].heads, hdf[1].sectors);
|
||||
printf("Size: %lu MB\n", ((((unsigned long)hdf[1].cylinders) * hdf[1].heads * hdf[1].sectors) >> 11));
|
||||
printf("Offset: %ld\n", hdf[1].offset);
|
||||
}
|
||||
|
||||
ConfigIDE(config.enable_ide, config.hardfile[0].present && config.hardfile[0].enabled, config.hardfile[1].present && config.hardfile[1].enabled);
|
||||
|
||||
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("\nA600/A1200 IDE HDC is %s.\n", config.enable_ide ? "enabled" : "disabled");
|
||||
printf("Master HDD is %s.\n", config.hardfile[0].present ? config.hardfile[0].enabled ? "enabled" : "disabled" : "not present");
|
||||
printf("Slave HDD is %s.\n", config.hardfile[1].present ? config.hardfile[1].enabled ? "enabled" : "disabled" : "not present");
|
||||
|
||||
#if 0
|
||||
if (cluster_size < 64) {
|
||||
BootPrint("\n***************************************************");
|
||||
BootPrint("* It's recommended to reformat your memory card *");
|
||||
BootPrint("* using 32 KB clusters to improve performance *");
|
||||
BootPrint("* when using large hardfiles. *"); // AMR
|
||||
BootPrint("***************************************************");
|
||||
}
|
||||
iprintf("Bootloading is complete.\n");
|
||||
#endif
|
||||
|
||||
printf("\nExiting bootloader...\n");
|
||||
|
||||
ConfigMemory(config.memory);
|
||||
ConfigCPU(config.cpu);
|
||||
|
||||
ConfigChipset(config.chipset);
|
||||
ConfigFloppy(config.floppy.drives, config.floppy.speed);
|
||||
|
||||
if (reloadkickstart)
|
||||
{
|
||||
UploadActionReplay();
|
||||
|
||||
printf("Reloading kickstart ...\n");
|
||||
WaitTimer(1000);
|
||||
EnableOsd();
|
||||
spi8(OSD_CMD_RST);
|
||||
rstval |= (SPI_RST_CPU | SPI_CPU_HLT);
|
||||
spi8(rstval);
|
||||
DisableOsd();
|
||||
if (!UploadKickstart(config.kickstart))
|
||||
{
|
||||
strcpy(config.kickstart, "KICK.ROM");
|
||||
if (!UploadKickstart(config.kickstart))
|
||||
{
|
||||
FatalError(6);
|
||||
}
|
||||
}
|
||||
EnableOsd();
|
||||
spi8(OSD_CMD_RST);
|
||||
rstval |= (SPI_RST_USR | SPI_RST_CPU);
|
||||
spi8(rstval);
|
||||
DisableOsd();
|
||||
EnableOsd();
|
||||
spi8(OSD_CMD_RST);
|
||||
rstval = 0;
|
||||
spi8(rstval);
|
||||
DisableOsd();
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Resetting ...\n");
|
||||
EnableOsd();
|
||||
spi8(OSD_CMD_RST);
|
||||
rstval |= (SPI_RST_USR | SPI_RST_CPU);
|
||||
spi8(rstval);
|
||||
DisableOsd();
|
||||
EnableOsd();
|
||||
spi8(OSD_CMD_RST);
|
||||
rstval = 0;
|
||||
spi8(rstval);
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
ConfigVideo(config.filter.hires, config.filter.lores, config.scanlines);
|
||||
}
|
||||
|
||||
//// SaveConfiguration() ////
|
||||
unsigned char SaveConfiguration(char *filename)
|
||||
{
|
||||
if (!filename) {
|
||||
// use slot-based filename if none provided
|
||||
filename = configfilename;
|
||||
}
|
||||
return FileSave(filename, &config, sizeof(config));
|
||||
}
|
||||
50
config.h
Normal file
50
config.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#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; // 0: Disabled, 1: Hard file, 2: MMC (entire card), 3-6: Partition 1-4 of MMC card
|
||||
unsigned char present;
|
||||
char long_name[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 pad1;
|
||||
hardfileTYPE hardfile[2];
|
||||
unsigned char cpu;
|
||||
unsigned char autofire;
|
||||
} configTYPE;
|
||||
|
||||
extern configTYPE config;
|
||||
extern char DebugMode;
|
||||
|
||||
char UploadKickstart(char *name);
|
||||
char UploadActionReplay();
|
||||
void SetConfigurationFilename(int config); // Set configuration filename by slot number
|
||||
unsigned char LoadConfiguration(char *filename); // Can supply NULL to use filename previously set by slot number
|
||||
unsigned char SaveConfiguration(char *filename); // Can supply NULL to use filename previously set by slot number
|
||||
unsigned char ConfigurationExists(char *filename);
|
||||
void ApplyConfiguration(char reloadkickstart);
|
||||
|
||||
102
debug.h
Normal file
102
debug.h
Normal file
@@ -0,0 +1,102 @@
|
||||
// this file allows to enabled and disable rs232 debugging on a detailed basis
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include "hardware.h"
|
||||
|
||||
// ------------ generic debugging -----------
|
||||
|
||||
#if 0
|
||||
#define menu_debugf(...) iprintf(__VA_ARGS__)
|
||||
#else
|
||||
#define menu_debugf(...)
|
||||
#endif
|
||||
|
||||
|
||||
// ----------- minimig debugging -------------
|
||||
#if 0
|
||||
#define hdd_debugf(a, ...) iprintf("\033[1;32mHDD: " a "\033[0m\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define hdd_debugf(...)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define fdd_debugf(...) iprintf(__VA_ARGS__)
|
||||
#else
|
||||
#define fdd_debugf(...)
|
||||
#endif
|
||||
|
||||
// -------------- TOS debugging --------------
|
||||
|
||||
#if 1
|
||||
#define tos_debugf(a, ...) iprintf("\033[1;32mTOS: " a "\033[0m\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define tos_debugf(...)
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
// ikbd debug output in red
|
||||
#define IKBD_DEBUG
|
||||
#define ikbd_debugf(a, ...) iprintf("\033[1;31mIKBD: " a "\033[0m\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define ikbd_debugf(...)
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
// 8bit debug output in blue
|
||||
#define bit8_debugf(a, ...) iprintf("\033[1;34m8BIT: " a "\033[0m\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define bit8_debugf(...)
|
||||
#endif
|
||||
|
||||
// ------------ usb debugging -----------
|
||||
|
||||
#if 0
|
||||
#define hidp_debugf(a, ...) iprintf("\033[1;34mHIDP: " a "\033[0m\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define hidp_debugf(...)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// usb asix debug output in blue
|
||||
#define asix_debugf(a, ...) iprintf("\033[1;34mASIX: " a "\033[0m\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define asix_debugf(...)
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
// usb hid debug output in green
|
||||
#define hid_debugf(a, ...) iprintf("\033[1;32mHID: " a "\033[0m\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define hid_debugf(...)
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
// usb mass storage debug output in purple
|
||||
#define storage_debugf(a, ...) iprintf("\033[1;35mSTORAGE: " a "\033[0m\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define storage_debugf(...)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// usb rts debug output in blue
|
||||
#define usbrtc_debugf(a, ...) iprintf("\033[1;34mUSBRTC: " a "\033[0m\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define usbrtc_debugf(...)
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
// usb rts debug output in blue
|
||||
#define pl2303_debugf(a, ...) iprintf("\033[1;34mPL2303: " a "\033[0m\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define pl2303_debugf(...)
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
// ini_parser debug output
|
||||
#define ini_parser_debugf(a, ...) iprintf("\033[1;34mINI_PARSER : " a "\033[0m\n",## __VA_ARGS__)
|
||||
#else
|
||||
#define ini_parser_debugf(...)
|
||||
#endif
|
||||
|
||||
#endif // DEBUG_H
|
||||
9
errors.h
Normal file
9
errors.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#define ERROR_NONE 0
|
||||
#define ERROR_FILE_NOT_FOUND 1
|
||||
#define ERROR_INVALID_DATA 2
|
||||
#define ERROR_UPDATE_FAILED 3
|
||||
|
||||
extern unsigned char Error;
|
||||
|
||||
void ErrorMessage(const char *message, unsigned char code);
|
||||
void FatalError(unsigned long error);
|
||||
630
fdd.c
Normal file
630
fdd.c
Normal file
@@ -0,0 +1,630 @@
|
||||
/*
|
||||
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 "errors.h"
|
||||
#include "hardware.h"
|
||||
#include "file_io.h"
|
||||
#include "fdd.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "fpga_io.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]; // drive 0 information structure
|
||||
|
||||
static uint8_t sector_buffer[512];
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
31
fdd.h
Normal file
31
fdd.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef FDD_H
|
||||
#define 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;
|
||||
|
||||
void UpdateDriveStatus(void);
|
||||
void HandleFDD(unsigned char c1, unsigned char c2);
|
||||
|
||||
#endif
|
||||
|
||||
682
file_io.c
Normal file
682
file_io.c
Normal file
@@ -0,0 +1,682 @@
|
||||
#include "file_io.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <linux/magic.h>
|
||||
#include "osd.h"
|
||||
#include "fpga_io.h"
|
||||
|
||||
int nDirEntries = 0;
|
||||
struct dirent DirItem[1000];
|
||||
int iSelectedEntry = 0; // selected entry index
|
||||
int iFirstEntry = 0;
|
||||
|
||||
void FileClose(fileTYPE *file)
|
||||
{
|
||||
if (file->fd > 0) close(file->fd);
|
||||
file->fd = -1;
|
||||
}
|
||||
|
||||
static char full_path[1200];
|
||||
|
||||
unsigned char FileOpenEx(fileTYPE *file, const char *name, int mode)
|
||||
{
|
||||
sprintf(full_path, "%s/%s", getRootDir(), name);
|
||||
|
||||
FileClose(file);
|
||||
file->mode = 0;
|
||||
|
||||
char *p = strrchr(full_path, '/');
|
||||
strcpy(file->name, p+1);
|
||||
|
||||
file->fd = open(full_path, mode);
|
||||
if (file->fd < 0)
|
||||
{
|
||||
printf("FileOpenEx(open) File:%s, error: %d.\n", full_path, file->fd);
|
||||
file->fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct stat64 st;
|
||||
int ret = fstat64(file->fd, &st);
|
||||
if ( ret < 0)
|
||||
{
|
||||
printf("FileOpenEx(fstat) File:%s, error: %d.\n", full_path, ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
file->size = st.st_size;
|
||||
file->offset = 0;
|
||||
file->mode = mode;
|
||||
|
||||
// printf("opened %s, size %lu\n", full_path, file->size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned char FileOpen(fileTYPE *file, const char *name)
|
||||
{
|
||||
return FileOpenEx(file, name, O_RDONLY);
|
||||
}
|
||||
|
||||
unsigned char FileNextSector(fileTYPE *file)
|
||||
{
|
||||
__off64_t newoff = lseek64(file->fd, file->offset + 512, SEEK_SET);
|
||||
if (newoff != file->offset + 512)
|
||||
{
|
||||
//printf("Fail to seek to next sector. File: %s.\n", file->name);
|
||||
lseek64(file->fd, file->offset, SEEK_SET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
file->offset = newoff;
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned char FileSeek(fileTYPE *file, __off64_t offset, unsigned long origin)
|
||||
{
|
||||
__off64_t newoff = lseek64(file->fd, offset, origin);
|
||||
if(newoff<0)
|
||||
{
|
||||
printf("Fail to seek the file.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
file->offset = newoff;
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned char FileSeekLBA(fileTYPE *file, uint32_t offset)
|
||||
{
|
||||
__off64_t off64 = offset;
|
||||
off64 <<= 9;
|
||||
return FileSeek(file, off64, SEEK_SET);
|
||||
}
|
||||
|
||||
// Read. MiST compatible. Avoid to use it.
|
||||
unsigned char FileRead(fileTYPE *file, void *pBuffer)
|
||||
{
|
||||
return FileReadEx(file, pBuffer, 1);
|
||||
}
|
||||
|
||||
unsigned char FileReadEx(fileTYPE *file, void *pBuffer, unsigned long nSize)
|
||||
{
|
||||
static uint8_t tmpbuff[512];
|
||||
|
||||
if (!FileSeek(file, file->offset, SEEK_SET))
|
||||
{
|
||||
printf("FileRead error(seek).\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pBuffer)
|
||||
{
|
||||
for (int i = 0; i < nSize; i++)
|
||||
{
|
||||
int ret = read(file->fd, tmpbuff, 512);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("FileRead error(%d).\n", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EnableDMode();
|
||||
spi_block_write(tmpbuff, 0);
|
||||
DisableDMode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int ret = read(file->fd, pBuffer, nSize * 512);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("FileRead error(%d).\n", ret);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Write. MiST compatible. Avoid to use it.
|
||||
unsigned char FileWrite(fileTYPE *file, void *pBuffer)
|
||||
{
|
||||
if (!FileSeek(file, file->offset, SEEK_SET))
|
||||
{
|
||||
printf("FileWrite error(seek).\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = write(file->fd, pBuffer, 512);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("FileWrite error(%d).\n", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Read with offset advancing
|
||||
unsigned long FileReadAdv(fileTYPE *file, void *pBuffer, unsigned long length)
|
||||
{
|
||||
ssize_t ret = read(file->fd, pBuffer, length);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("FileReadAdv error(%d).\n", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
file->offset += ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned long FileReadSec(fileTYPE *file, void *pBuffer)
|
||||
{
|
||||
return FileReadAdv(file, pBuffer, 512);
|
||||
}
|
||||
|
||||
// Write with offset advancing
|
||||
unsigned long FileWriteAdv(fileTYPE *file, void *pBuffer, unsigned long length)
|
||||
{
|
||||
int ret = write(file->fd, pBuffer, length);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("FileWriteAdv error(%d).\n", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
file->offset += ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned long FileWriteSec(fileTYPE *file, void *pBuffer)
|
||||
{
|
||||
return FileWriteAdv(file, pBuffer, 512);
|
||||
}
|
||||
|
||||
|
||||
unsigned char FileSave(char *name, void *pBuffer, int size)
|
||||
{
|
||||
sprintf(full_path, "%s/%s", getRootDir(), name);
|
||||
int fd = open(full_path, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
if (fd < 0)
|
||||
{
|
||||
printf("FileSave(open) File:%s, error: %d.\n", full_path, fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = write(fd, pBuffer, size);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("FileSave(write) File:%s, error: %d.\n", full_path, ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FileLoad(char *name, void *pBuffer, int size)
|
||||
{
|
||||
sprintf(full_path, "%s/%s", getRootDir(), name);
|
||||
int fd = open(full_path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
printf("FileLoad(open) File:%s, error: %d.\n", full_path, fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct stat64 st;
|
||||
int ret = fstat64(fd, &st);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("FileLoad(fstat) File:%s, error: %d.\n", full_path, ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = read(fd, pBuffer, size ? size : st.st_size);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("FileLoad(write) File:%s, error: %d.\n", full_path, ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int FileCanWrite(char *name)
|
||||
{
|
||||
sprintf(full_path, "%s/%s", getRootDir(), name);
|
||||
|
||||
struct stat64 st;
|
||||
int ret = stat64(full_path, &st);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("FileCanWrite(stat) File:%s, error: %d.\n", full_path, ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//printf("FileCanWrite: mode=%04o.\n", st.st_mode);
|
||||
return ((st.st_mode & S_IWUSR) != 0);
|
||||
}
|
||||
|
||||
char *make_name(char *short_name)
|
||||
{
|
||||
static char name[16];
|
||||
memset(name, 0, sizeof(name));
|
||||
memcpy(name, short_name, 8);
|
||||
memcpy(name + 10, short_name + 8, 3);
|
||||
|
||||
for (int i = 7; i >= 0; i--)
|
||||
{
|
||||
if (name[i] <= 0x20) name[i] = 0;
|
||||
else break;
|
||||
}
|
||||
|
||||
for (int i = 12; i >= 10; i--)
|
||||
{
|
||||
if (name[i] <= 0x20) name[i] = 0;
|
||||
else break;
|
||||
}
|
||||
|
||||
if (strlen(name + 10))
|
||||
{
|
||||
strcat(name, ".");
|
||||
strcat(name, name + 10);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static int device = 0;
|
||||
static int usbnum = 0;
|
||||
char *getRootDir()
|
||||
{
|
||||
static char dev[16];
|
||||
if(!device) return "/media/fat";
|
||||
sprintf(dev, "/media/usb%d", usbnum);
|
||||
return dev;
|
||||
}
|
||||
|
||||
void setStorage(int dev)
|
||||
{
|
||||
device = 0;
|
||||
FileSave("device.bin", &dev, sizeof(int));
|
||||
app_restart();
|
||||
}
|
||||
|
||||
static int orig_device = 0;
|
||||
int getStorage(int from_setting)
|
||||
{
|
||||
return from_setting ? orig_device : device;
|
||||
}
|
||||
|
||||
int isPathMounted(int n)
|
||||
{
|
||||
char path[32];
|
||||
sprintf(path, "/media/usb%d", n);
|
||||
|
||||
struct stat file_stat;
|
||||
struct stat parent_stat;
|
||||
|
||||
if (-1 == stat(path, &file_stat))
|
||||
{
|
||||
printf("failed to stat %s\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(file_stat.st_mode & S_IFDIR))
|
||||
{
|
||||
printf("%s is not a directory.\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (-1 == stat("/media", &parent_stat))
|
||||
{
|
||||
printf("failed to stat /media\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (file_stat.st_dev != parent_stat.st_dev ||
|
||||
(file_stat.st_dev == parent_stat.st_dev &&
|
||||
file_stat.st_ino == parent_stat.st_ino))
|
||||
{
|
||||
printf("%s IS a mountpoint.\n", path);
|
||||
struct statfs fs_stat;
|
||||
if (!statfs(path, &fs_stat))
|
||||
{
|
||||
printf("%s is FS: 0x%08X\n", path, fs_stat.f_type);
|
||||
if (fs_stat.f_type != EXT4_SUPER_MAGIC)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s is NOT a VFAT mountpoint.\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isUSBMounted()
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (isPathMounted(i))
|
||||
{
|
||||
usbnum = i;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FindStorage(void)
|
||||
{
|
||||
printf("Looking for root device...\n");
|
||||
device = 0;
|
||||
FileLoad("device.bin", &device, sizeof(int));
|
||||
orig_device = device;
|
||||
|
||||
if (device)
|
||||
{
|
||||
printf("Waiting for USB...\n");
|
||||
int btn = 0;
|
||||
int done = 0;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
if (isUSBMounted()) done = 1;
|
||||
if (done) break;
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
btn = fpga_get_buttons();
|
||||
if (btn)
|
||||
{
|
||||
printf("Button has been pressed %d\n", btn);
|
||||
device = 0;
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
usleep(100000);
|
||||
}
|
||||
}
|
||||
|
||||
if (!done) device = 0;
|
||||
}
|
||||
|
||||
if (device)
|
||||
{
|
||||
printf("Using USB as a root device\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Using SD card as a root device\n");
|
||||
}
|
||||
}
|
||||
|
||||
int de_cmp(const void *e1, const void *e2)
|
||||
{
|
||||
const struct dirent *de1 = e1;
|
||||
const struct dirent *de2 = e2;
|
||||
|
||||
if ((de1->d_type == DT_DIR) && !strcmp(de1->d_name, "..")) return -1;
|
||||
if ((de2->d_type == DT_DIR) && !strcmp(de1->d_name, "..")) return 1;
|
||||
|
||||
if ((de1->d_type == DT_DIR) && (de2->d_type == DT_REG)) return -1;
|
||||
if ((de1->d_type == DT_REG) && (de2->d_type == DT_DIR)) return 1;
|
||||
|
||||
if ((de1->d_type == DT_REG) && (de2->d_type == DT_REG))
|
||||
{
|
||||
int len1 = strlen(de1->d_name);
|
||||
int len2 = strlen(de2->d_name);
|
||||
if ((len1 > 4) && (de1->d_name[len1 - 4] == '.')) len1 -= 4;
|
||||
if ((len2 > 4) && (de2->d_name[len2 - 4] == '.')) len2 -= 4;
|
||||
|
||||
int len = (len1 < len2) ? len1 : len2;
|
||||
int ret = strncasecmp(de1->d_name, de2->d_name, len);
|
||||
if (!ret)
|
||||
{
|
||||
return len1 - len2;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return strcasecmp(de1->d_name, de2->d_name);
|
||||
}
|
||||
|
||||
void AdjustDirectory(char *path)
|
||||
{
|
||||
sprintf(full_path, "%s/%s", getRootDir(), path);
|
||||
|
||||
struct stat64 st;
|
||||
int ret = stat64(full_path, &st);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("AdjustDirectory(stat) path:%s, error: %d.\n", full_path, ret);
|
||||
path[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (st.st_mode & S_IFDIR) return;
|
||||
|
||||
char *p = strrchr(path, '/');
|
||||
if (p)
|
||||
{
|
||||
*p = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
path[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ScanDirectory(char* path, unsigned long mode, char *extension, unsigned char options)
|
||||
{
|
||||
int extlen = strlen(extension);
|
||||
//printf("scan dir\n");
|
||||
|
||||
if (mode == SCAN_INIT)
|
||||
{
|
||||
sprintf(full_path, "%s/%s", getRootDir(), path);
|
||||
printf("Start to scan dir: %s\n", full_path);
|
||||
|
||||
iFirstEntry = 0;
|
||||
iSelectedEntry = 0;
|
||||
nDirEntries = 0;
|
||||
|
||||
DIR *d = opendir(full_path);
|
||||
if (!d)
|
||||
{
|
||||
printf("Couldn't open dir: %s\n", full_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dirent *de;
|
||||
while(nDirEntries < 1000)
|
||||
{
|
||||
de = readdir(d);
|
||||
if (de == NULL) break;
|
||||
|
||||
if (de->d_type == DT_DIR)
|
||||
{
|
||||
if (!strcmp(de->d_name, ".")) continue;
|
||||
if (!strcmp(de->d_name, ".."))
|
||||
{
|
||||
if(!strlen(path)) continue;
|
||||
}
|
||||
if (!(options & SCAN_DIR)) continue;
|
||||
}
|
||||
else if (de->d_type == DT_REG)
|
||||
{
|
||||
if (!strcasecmp(de->d_name, "menu.rbf")) continue;
|
||||
if (extlen > 0)
|
||||
{
|
||||
int len = strlen(de->d_name);
|
||||
char *ext = extension;
|
||||
int found = 0;
|
||||
while(*ext)
|
||||
{
|
||||
char e[5];
|
||||
memcpy(e+1, ext, 3);
|
||||
if (e[3] == 0x20)
|
||||
{
|
||||
e[3] = 0;
|
||||
if (e[2] == 0x20)
|
||||
{
|
||||
e[2] = 0;
|
||||
}
|
||||
}
|
||||
e[0] = '.';
|
||||
e[4] = 0;
|
||||
int l = strlen(e);
|
||||
if((len>l) && !strncasecmp(de->d_name + len - l, e, l))
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strlen(ext) < 3) break;
|
||||
ext += 3;
|
||||
}
|
||||
if (!found) continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
memcpy(&DirItem[nDirEntries], de, sizeof(struct dirent));
|
||||
nDirEntries++;
|
||||
}
|
||||
closedir(d);
|
||||
|
||||
printf("Got %d dir entries\n", nDirEntries);
|
||||
if (!nDirEntries) return 0;
|
||||
|
||||
qsort(DirItem, nDirEntries, sizeof(struct dirent), de_cmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nDirEntries == 0) // directory is empty so there is no point in searching for any entry
|
||||
return 0;
|
||||
|
||||
if (mode == SCAN_NEXT)
|
||||
{
|
||||
if(iSelectedEntry + 1 < nDirEntries) // scroll within visible items
|
||||
{
|
||||
iSelectedEntry++;
|
||||
if (iSelectedEntry > iFirstEntry + OsdGetSize() - 1) iFirstEntry = iSelectedEntry - OsdGetSize() + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (mode == SCAN_PREV)
|
||||
{
|
||||
if (iSelectedEntry > 0) // scroll within visible items
|
||||
{
|
||||
iSelectedEntry--;
|
||||
if (iSelectedEntry < iFirstEntry) iFirstEntry = iSelectedEntry;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (mode == SCAN_NEXT_PAGE)
|
||||
{
|
||||
if (iSelectedEntry < iFirstEntry + OsdGetSize() - 1)
|
||||
{
|
||||
iSelectedEntry = iFirstEntry + OsdGetSize() - 1;
|
||||
if (iSelectedEntry >= nDirEntries) iSelectedEntry = nDirEntries - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
iSelectedEntry += OsdGetSize();
|
||||
iFirstEntry += OsdGetSize();
|
||||
if (iSelectedEntry >= nDirEntries)
|
||||
{
|
||||
iSelectedEntry = nDirEntries - 1;
|
||||
iFirstEntry = iSelectedEntry - OsdGetSize() + 1;
|
||||
if (iFirstEntry < 0) iFirstEntry = 0;
|
||||
}
|
||||
else if (iFirstEntry + OsdGetSize() > nDirEntries)
|
||||
{
|
||||
iFirstEntry = nDirEntries - OsdGetSize();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (mode == SCAN_PREV_PAGE)
|
||||
{
|
||||
if(iSelectedEntry != iFirstEntry)
|
||||
{
|
||||
iSelectedEntry = iFirstEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
iFirstEntry -= OsdGetSize();
|
||||
if (iFirstEntry < 0) iFirstEntry = 0;
|
||||
iSelectedEntry = iFirstEntry;
|
||||
}
|
||||
}
|
||||
else if (mode == SCAN_SET_ITEM)
|
||||
{
|
||||
for (int i = 0; i < nDirEntries; i++)
|
||||
{
|
||||
if((DirItem[i].d_type == DT_DIR) && !strcmp(DirItem[i].d_name, extension))
|
||||
{
|
||||
iSelectedEntry = i;
|
||||
if (iSelectedEntry + (OsdGetSize() / 2) - 1 >= nDirEntries) iFirstEntry = nDirEntries - OsdGetSize();
|
||||
else iFirstEntry = iSelectedEntry - (OsdGetSize() / 2) + 1;
|
||||
if (iFirstEntry < 0) iFirstEntry = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("dir scan for key: %x/%c\n", mode, mode);
|
||||
mode = toupper(mode);
|
||||
if ((mode >= '0' && mode <= '9') || (mode >= 'A' && mode <= 'Z'))
|
||||
{
|
||||
int found = -1;
|
||||
for (int i = iSelectedEntry+1; i < nDirEntries; i++)
|
||||
{
|
||||
if (toupper(DirItem[i].d_name[0]) == mode)
|
||||
{
|
||||
found = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found < 0)
|
||||
{
|
||||
for (int i = 0; i < nDirEntries; i++)
|
||||
{
|
||||
if (toupper(DirItem[i].d_name[0]) == mode)
|
||||
{
|
||||
found = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found >= 0)
|
||||
{
|
||||
iSelectedEntry = found;
|
||||
if (iSelectedEntry + (OsdGetSize() / 2) - 1 >= nDirEntries) iFirstEntry = nDirEntries - OsdGetSize();
|
||||
else iFirstEntry = iSelectedEntry - (OsdGetSize()/2) + 1;
|
||||
if (iFirstEntry < 0) iFirstEntry = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
70
file_io.h
Normal file
70
file_io.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef _FAT16_H_INCLUDED
|
||||
#define _FAT16_H_INCLUDED
|
||||
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include "spi.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int fd;
|
||||
int mode;
|
||||
__off64_t size;
|
||||
__off64_t offset;
|
||||
char name[261];
|
||||
} fileTYPE;
|
||||
|
||||
extern int nDirEntries;
|
||||
extern struct dirent DirItem[1000];
|
||||
extern int iSelectedEntry;
|
||||
extern int iFirstEntry;
|
||||
|
||||
// scanning flags
|
||||
#define SCAN_INIT 0 // start search from beginning of directory
|
||||
#define SCAN_NEXT 1 // find next file in directory
|
||||
#define SCAN_PREV -1 // find previous file in directory
|
||||
#define SCAN_NEXT_PAGE 2 // find next 8 files in directory
|
||||
#define SCAN_PREV_PAGE -2 // find previous 8 files in directory
|
||||
#define SCAN_SET_ITEM 3 // find exact item
|
||||
|
||||
// options flags
|
||||
#define SCAN_DIR 1 // include subdirectories
|
||||
|
||||
void FindStorage();
|
||||
int getStorage(int from_setting);
|
||||
void setStorage(int dev);
|
||||
int isUSBMounted();
|
||||
|
||||
unsigned char FileOpenEx(fileTYPE *file, const char *name, int mode);
|
||||
unsigned char FileOpen(fileTYPE *file, const char *name);
|
||||
void FileClose(fileTYPE *file);
|
||||
|
||||
unsigned char FileSeek(fileTYPE *file, __off64_t offset, unsigned long origin);
|
||||
unsigned char FileSeekLBA(fileTYPE *file, uint32_t offset);
|
||||
|
||||
//MiST compatible functions. Avoid to use them.
|
||||
unsigned char FileRead(fileTYPE *file, void *pBuffer);
|
||||
unsigned char FileReadEx(fileTYPE *file, void *pBuffer, unsigned long nSize);
|
||||
unsigned char FileWrite(fileTYPE *file, void *pBuffer);
|
||||
unsigned char FileNextSector(fileTYPE *file);
|
||||
|
||||
//New functions.
|
||||
unsigned long FileReadAdv(fileTYPE *file, void *pBuffer, unsigned long length);
|
||||
unsigned long FileReadSec(fileTYPE *file, void *pBuffer);
|
||||
unsigned long FileWriteAdv(fileTYPE *file, void *pBuffer, unsigned long length);
|
||||
unsigned long FileWriteSec(fileTYPE *file, void *pBuffer);
|
||||
|
||||
|
||||
int FileCanWrite(char *name);
|
||||
|
||||
unsigned char FileSave(char *name, void *pBuffer, int size);
|
||||
int FileLoad(char *name, void *pBuffer, int size);
|
||||
|
||||
void AdjustDirectory(char *path);
|
||||
int ScanDirectory(char* path, unsigned long mode, char *extension, unsigned char options);
|
||||
|
||||
char *make_name(char *short_name);
|
||||
char *getRootDir();
|
||||
|
||||
#endif
|
||||
62
fpga_base_addr_ac5.h
Normal file
62
fpga_base_addr_ac5.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Altera Corporation <www.altera.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef _SOCFPGA_BASE_ADDRS_H_
|
||||
#define _SOCFPGA_BASE_ADDRS_H_
|
||||
|
||||
#define SOCFPGA_DAP_ADDRESS 0xff000000
|
||||
#define SOCFPGA_EMAC0_ADDRESS 0xff700000
|
||||
#define SOCFPGA_EMAC1_ADDRESS 0xff702000
|
||||
#define SOCFPGA_SDMMC_ADDRESS 0xff704000
|
||||
#define SOCFPGA_QSPI_ADDRESS 0xff705000
|
||||
#define SOCFPGA_MGR_ADDRESS 0xff706000
|
||||
#define SOCFPGA_GPIO0_ADDRESS 0xff708000
|
||||
#define SOCFPGA_GPIO1_ADDRESS 0xff709000
|
||||
#define SOCFPGA_GPIO2_ADDRESS 0xff70a000
|
||||
#define SOCFPGA_L3REGS_ADDRESS 0xff800000
|
||||
#define SOCFPGA_USB0_ADDRESS 0xffb00000
|
||||
#define SOCFPGA_USB1_ADDRESS 0xffb40000
|
||||
#define SOCFPGA_CAN0_ADDRESS 0xffc00000
|
||||
#define SOCFPGA_CAN1_ADDRESS 0xffc01000
|
||||
#define SOCFPGA_UART0_ADDRESS 0xffc02000
|
||||
#define SOCFPGA_UART1_ADDRESS 0xffc03000
|
||||
#define SOCFPGA_I2C0_ADDRESS 0xffc04000
|
||||
#define SOCFPGA_I2C1_ADDRESS 0xffc05000
|
||||
#define SOCFPGA_I2C2_ADDRESS 0xffc06000
|
||||
#define SOCFPGA_I2C3_ADDRESS 0xffc07000
|
||||
#define SOCFPGA_SDR_ADDRESS 0xffc20000
|
||||
#define SOCFPGA_L4WD0_ADDRESS 0xffd02000
|
||||
#define SOCFPGA_L4WD1_ADDRESS 0xffd03000
|
||||
#define SOCFPGA_CLKMGR_ADDRESS 0xffd04000
|
||||
#define SOCFPGA_RSTMGR_ADDRESS 0xffd05000
|
||||
#define SOCFPGA_SYSMGR_ADDRESS 0xffd08000
|
||||
#define SOCFPGA_SPIS0_ADDRESS 0xffe02000
|
||||
#define SOCFPGA_SPIS1_ADDRESS 0xffe03000
|
||||
#define SOCFPGA_SPIM0_ADDRESS 0xfff00000
|
||||
#define SOCFPGA_SPIM1_ADDRESS 0xfff01000
|
||||
#define SOCFPGA_SCANMGR_ADDRESS 0xfff02000
|
||||
#define SOCFPGA_ROM_ADDRESS 0xfffd0000
|
||||
#define SOCFPGA_MPUSCU_ADDRESS 0xfffec000
|
||||
#define SOCFPGA_MPUL2_ADDRESS 0xfffef000
|
||||
#define SOCFPGA_OCRAM_ADDRESS 0xffff0000
|
||||
#define SOCFPGA_LWFPGASLAVES_ADDRESS 0xff200000
|
||||
#define SOCFPGA_LWHPS2FPGAREGS_ADDRESS 0xff400000
|
||||
#define SOCFPGA_HPS2FPGAREGS_ADDRESS 0xff500000
|
||||
#define SOCFPGA_FPGA2HPSREGS_ADDRESS 0xff600000
|
||||
#define SOCFPGA_FPGAMGRREGS_ADDRESS 0xff706000
|
||||
#define SOCFPGA_ACPIDMAP_ADDRESS 0xff707000
|
||||
#define SOCFPGA_NANDDATA_ADDRESS 0xff900000
|
||||
#define SOCFPGA_QSPIDATA_ADDRESS 0xffa00000
|
||||
#define SOCFPGA_NANDREGS_ADDRESS 0xffb80000
|
||||
#define SOCFPGA_FPGAMGRDATA_ADDRESS 0xffb90000
|
||||
#define SOCFPGA_SPTIMER0_ADDRESS 0xffc08000
|
||||
#define SOCFPGA_SPTIMER1_ADDRESS 0xffc09000
|
||||
#define SOCFPGA_OSC1TIMER0_ADDRESS 0xffd00000
|
||||
#define SOCFPGA_OSC1TIMER1_ADDRESS 0xffd01000
|
||||
#define SOCFPGA_DMANONSECURE_ADDRESS 0xffe00000
|
||||
#define SOCFPGA_DMASECURE_ADDRESS 0xffe01000
|
||||
|
||||
#endif /* _SOCFPGA_BASE_ADDRS_H_ */
|
||||
635
fpga_io.c
Normal file
635
fpga_io.c
Normal file
@@ -0,0 +1,635 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <termios.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include "fpga_io.h"
|
||||
#include "file_io.h"
|
||||
|
||||
#include "fpga_base_addr_ac5.h"
|
||||
#include "fpga_manager.h"
|
||||
#include "fpga_system_manager.h"
|
||||
#include "fpga_reset_manager.h"
|
||||
#include "fpga_nic301.h"
|
||||
|
||||
#define FPGA_REG_BASE 0xFF000000
|
||||
#define FPGA_REG_SIZE 0x01000000
|
||||
|
||||
#define MAP_ADDR(x) (volatile uint32_t*)(&map_base[(((uint32_t)(x)) & 0xFFFFFF)>>2])
|
||||
#define IS_REG(x) (((((uint32_t)(x))-1)>=(FPGA_REG_BASE - 1)) && ((((uint32_t)(x))-1)<(FPGA_REG_BASE + FPGA_REG_SIZE - 1)))
|
||||
|
||||
#define fatal(x) munmap((void*)map_base, FPGA_REG_SIZE); close(fd); exit(x)
|
||||
|
||||
static struct socfpga_reset_manager *reset_regs = (void *)SOCFPGA_RSTMGR_ADDRESS;
|
||||
static struct socfpga_fpga_manager *fpgamgr_regs = (void *)SOCFPGA_FPGAMGRREGS_ADDRESS;
|
||||
static struct socfpga_system_manager *sysmgr_regs = (void *)SOCFPGA_SYSMGR_ADDRESS;
|
||||
static struct nic301_registers *nic301_regs = (void *)SOCFPGA_L3REGS_ADDRESS;
|
||||
|
||||
static uint32_t *map_base;
|
||||
static int fd;
|
||||
|
||||
static __inline void writel(uint32_t val, const void* reg)
|
||||
{
|
||||
/*
|
||||
if(!IS_REG(reg))
|
||||
{
|
||||
printf("ERROR: Trying to write undefined address: %p\n.", reg);
|
||||
fatal(-1);
|
||||
}
|
||||
*/
|
||||
*MAP_ADDR(reg) = val;
|
||||
}
|
||||
|
||||
static __inline uint32_t readl(const void* reg)
|
||||
{
|
||||
/*
|
||||
if (!IS_REG(reg))
|
||||
{
|
||||
printf("ERROR: Trying to read undefined address: %p\n.", reg);
|
||||
fatal(-1);
|
||||
}
|
||||
*/
|
||||
return *MAP_ADDR(reg);
|
||||
}
|
||||
|
||||
#define clrsetbits_le32(addr, clear, set) writel((readl(addr) & ~(clear)) | (set), addr)
|
||||
#define setbits_le32(addr, set) writel( readl(addr) | (set), addr)
|
||||
#define clrbits_le32(addr, clear) writel( readl(addr) & ~(clear), addr)
|
||||
|
||||
/* Timeout count */
|
||||
#define FPGA_TIMEOUT_CNT 0x1000000
|
||||
|
||||
/* Set CD ratio */
|
||||
static void fpgamgr_set_cd_ratio(unsigned long ratio)
|
||||
{
|
||||
clrsetbits_le32(&fpgamgr_regs->ctrl,
|
||||
0x3 << FPGAMGRREGS_CTRL_CDRATIO_LSB,
|
||||
(ratio & 0x3) << FPGAMGRREGS_CTRL_CDRATIO_LSB);
|
||||
}
|
||||
|
||||
static int fpgamgr_dclkcnt_set(unsigned long cnt)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
/* Clear any existing done status */
|
||||
if (readl(&fpgamgr_regs->dclkstat))
|
||||
writel(0x1, &fpgamgr_regs->dclkstat);
|
||||
|
||||
/* Write the dclkcnt */
|
||||
writel(cnt, &fpgamgr_regs->dclkcnt);
|
||||
|
||||
/* Wait till the dclkcnt done */
|
||||
for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
|
||||
if (!readl(&fpgamgr_regs->dclkstat))
|
||||
continue;
|
||||
|
||||
writel(0x1, &fpgamgr_regs->dclkstat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Check whether FPGA Init_Done signal is high */
|
||||
static int is_fpgamgr_initdone_high(void)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
val = readl(&fpgamgr_regs->gpio_ext_porta);
|
||||
return val & FPGAMGRREGS_MON_GPIO_EXT_PORTA_ID_MASK;
|
||||
}
|
||||
|
||||
/* Get the FPGA mode */
|
||||
static int fpgamgr_get_mode(void)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
val = readl(&fpgamgr_regs->stat);
|
||||
return val & FPGAMGRREGS_STAT_MODE_MASK;
|
||||
}
|
||||
|
||||
/* Check whether FPGA is ready to be accessed */
|
||||
static int fpgamgr_test_fpga_ready(void)
|
||||
{
|
||||
/* Check for init done signal */
|
||||
if (!is_fpgamgr_initdone_high())
|
||||
return 0;
|
||||
|
||||
/* Check again to avoid false glitches */
|
||||
if (!is_fpgamgr_initdone_high())
|
||||
return 0;
|
||||
|
||||
if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_USERMODE)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Poll until FPGA is ready to be accessed or timeout occurred */
|
||||
static int fpgamgr_poll_fpga_ready(void)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
/* If FPGA is blank, wait till WD invoke warm reset */
|
||||
for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
|
||||
/* check for init done signal */
|
||||
if (!is_fpgamgr_initdone_high())
|
||||
continue;
|
||||
/* check again to avoid false glitches */
|
||||
if (!is_fpgamgr_initdone_high())
|
||||
continue;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Start the FPGA programming by initialize the FPGA Manager */
|
||||
static int fpgamgr_program_init(void)
|
||||
{
|
||||
unsigned long msel, i;
|
||||
|
||||
/* Get the MSEL value */
|
||||
msel = readl(&fpgamgr_regs->stat);
|
||||
msel &= FPGAMGRREGS_STAT_MSEL_MASK;
|
||||
msel >>= FPGAMGRREGS_STAT_MSEL_LSB;
|
||||
|
||||
/*
|
||||
* Set the cfg width
|
||||
* If MSEL[3] = 1, cfg width = 32 bit
|
||||
*/
|
||||
if (msel & 0x8) {
|
||||
setbits_le32(&fpgamgr_regs->ctrl,
|
||||
FPGAMGRREGS_CTRL_CFGWDTH_MASK);
|
||||
|
||||
/* To determine the CD ratio */
|
||||
/* MSEL[1:0] = 0, CD Ratio = 1 */
|
||||
if ((msel & 0x3) == 0x0)
|
||||
fpgamgr_set_cd_ratio(CDRATIO_x1);
|
||||
/* MSEL[1:0] = 1, CD Ratio = 4 */
|
||||
else if ((msel & 0x3) == 0x1)
|
||||
fpgamgr_set_cd_ratio(CDRATIO_x4);
|
||||
/* MSEL[1:0] = 2, CD Ratio = 8 */
|
||||
else if ((msel & 0x3) == 0x2)
|
||||
fpgamgr_set_cd_ratio(CDRATIO_x8);
|
||||
|
||||
}
|
||||
else { /* MSEL[3] = 0 */
|
||||
clrbits_le32(&fpgamgr_regs->ctrl,
|
||||
FPGAMGRREGS_CTRL_CFGWDTH_MASK);
|
||||
|
||||
/* To determine the CD ratio */
|
||||
/* MSEL[1:0] = 0, CD Ratio = 1 */
|
||||
if ((msel & 0x3) == 0x0)
|
||||
fpgamgr_set_cd_ratio(CDRATIO_x1);
|
||||
/* MSEL[1:0] = 1, CD Ratio = 2 */
|
||||
else if ((msel & 0x3) == 0x1)
|
||||
fpgamgr_set_cd_ratio(CDRATIO_x2);
|
||||
/* MSEL[1:0] = 2, CD Ratio = 4 */
|
||||
else if ((msel & 0x3) == 0x2)
|
||||
fpgamgr_set_cd_ratio(CDRATIO_x4);
|
||||
}
|
||||
|
||||
/* To enable FPGA Manager configuration */
|
||||
clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCE_MASK);
|
||||
|
||||
/* To enable FPGA Manager drive over configuration line */
|
||||
setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_EN_MASK);
|
||||
|
||||
/* Put FPGA into reset phase */
|
||||
setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCONFIGPULL_MASK);
|
||||
|
||||
/* (1) wait until FPGA enter reset phase */
|
||||
for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
|
||||
if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_RESETPHASE)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If not in reset state, return error */
|
||||
if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_RESETPHASE) {
|
||||
puts("FPGA: Could not reset\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Release FPGA from reset phase */
|
||||
clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCONFIGPULL_MASK);
|
||||
|
||||
/* (2) wait until FPGA enter configuration phase */
|
||||
for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
|
||||
if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_CFGPHASE)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If not in configuration state, return error */
|
||||
if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_CFGPHASE) {
|
||||
puts("FPGA: Could not configure\n");
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Clear all interrupts in CB Monitor */
|
||||
writel(0xFFF, &fpgamgr_regs->gpio_porta_eoi);
|
||||
|
||||
/* Enable AXI configuration */
|
||||
setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_AXICFGEN_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
|
||||
|
||||
/* Write the RBF data to FPGA Manager */
|
||||
static void fpgamgr_program_write(const void *rbf_data, unsigned long rbf_size)
|
||||
{
|
||||
uint32_t src = (uint32_t)rbf_data;
|
||||
uint32_t dst = (uint32_t)MAP_ADDR(SOCFPGA_FPGAMGRDATA_ADDRESS);
|
||||
|
||||
/* Number of loops for 32-byte long copying. */
|
||||
uint32_t loops32 = rbf_size / 32;
|
||||
/* Number of loops for 4-byte long copying + trailing bytes */
|
||||
uint32_t loops4 = DIV_ROUND_UP(rbf_size % 32, 4);
|
||||
|
||||
__asm volatile(
|
||||
"1: ldmia %0!,{r0-r7} \n"
|
||||
" stmia %1!,{r0-r7} \n"
|
||||
" sub %1, #32 \n"
|
||||
" subs %2, #1 \n"
|
||||
" bne 1b \n"
|
||||
" cmp %3, #0 \n"
|
||||
" beq 3f \n"
|
||||
"2: ldr %2, [%0], #4 \n"
|
||||
" str %2, [%1] \n"
|
||||
" subs %3, #1 \n"
|
||||
" bne 2b \n"
|
||||
"3: nop \n"
|
||||
: "+r"(src), "+r"(dst), "+r"(loops32), "+r"(loops4) :
|
||||
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "cc");
|
||||
}
|
||||
|
||||
/* Ensure the FPGA entering config done */
|
||||
static int fpgamgr_program_poll_cd(void)
|
||||
{
|
||||
const uint32_t mask = FPGAMGRREGS_MON_GPIO_EXT_PORTA_NS_MASK |
|
||||
FPGAMGRREGS_MON_GPIO_EXT_PORTA_CD_MASK;
|
||||
unsigned long reg, i;
|
||||
|
||||
/* (3) wait until full config done */
|
||||
for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
|
||||
reg = readl(&fpgamgr_regs->gpio_ext_porta);
|
||||
|
||||
/* Config error */
|
||||
if (!(reg & mask)) {
|
||||
printf("FPGA: Configuration error.\n");
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* Config done without error */
|
||||
if (reg & mask)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Timeout happened, return error */
|
||||
if (i == FPGA_TIMEOUT_CNT) {
|
||||
printf("FPGA: Timeout waiting for program.\n");
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* Disable AXI configuration */
|
||||
clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_AXICFGEN_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ensure the FPGA entering init phase */
|
||||
static int fpgamgr_program_poll_initphase(void)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
/* Additional clocks for the CB to enter initialization phase */
|
||||
if (fpgamgr_dclkcnt_set(0x4))
|
||||
return -5;
|
||||
|
||||
/* (4) wait until FPGA enter init phase or user mode */
|
||||
for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
|
||||
if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_INITPHASE)
|
||||
break;
|
||||
if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_USERMODE)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If not in configuration state, return error */
|
||||
if (i == FPGA_TIMEOUT_CNT)
|
||||
return -6;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ensure the FPGA entering user mode */
|
||||
static int fpgamgr_program_poll_usermode(void)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
/* Additional clocks for the CB to exit initialization phase */
|
||||
if (fpgamgr_dclkcnt_set(0x5000))
|
||||
return -7;
|
||||
|
||||
/* (5) wait until FPGA enter user mode */
|
||||
for (i = 0; i < FPGA_TIMEOUT_CNT; i++) {
|
||||
if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_USERMODE)
|
||||
break;
|
||||
}
|
||||
/* If not in configuration state, return error */
|
||||
if (i == FPGA_TIMEOUT_CNT)
|
||||
return -8;
|
||||
|
||||
/* To release FPGA Manager drive over configuration line */
|
||||
clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_EN_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* FPGA Manager to program the FPGA. This is the interface used by FPGA driver.
|
||||
* Return 0 for sucess, non-zero for error.
|
||||
*/
|
||||
static int socfpga_load(const void *rbf_data, size_t rbf_size)
|
||||
{
|
||||
unsigned long status;
|
||||
|
||||
if ((uint32_t)rbf_data & 0x3) {
|
||||
printf("FPGA: Unaligned data, realign to 32bit boundary.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Initialize the FPGA Manager */
|
||||
status = fpgamgr_program_init();
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Write the RBF data to FPGA Manager */
|
||||
fpgamgr_program_write(rbf_data, rbf_size);
|
||||
|
||||
/* Ensure the FPGA entering config done */
|
||||
status = fpgamgr_program_poll_cd();
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Ensure the FPGA entering init phase */
|
||||
status = fpgamgr_program_poll_initphase();
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Ensure the FPGA entering user mode */
|
||||
return fpgamgr_program_poll_usermode();
|
||||
}
|
||||
|
||||
static void do_bridge(uint32_t enable)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
writel(0x00003FFF, (void*)(SOCFPGA_SDR_ADDRESS + 0x5080));
|
||||
writel(0x00000000, &reset_regs->brg_mod_reset);
|
||||
writel(0x00000019, &nic301_regs->remap);
|
||||
}
|
||||
else
|
||||
{
|
||||
writel(0, &sysmgr_regs->fpgaintfgrp_module);
|
||||
writel(0, (void*)(SOCFPGA_SDR_ADDRESS + 0x5080));
|
||||
writel(7, &reset_regs->brg_mod_reset);
|
||||
writel(1, &nic301_regs->remap);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef REBOOT_ON_RBF_LOAD
|
||||
static int save_core_name(char *name)
|
||||
{
|
||||
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) return -1;
|
||||
|
||||
void* buf = mmap(0, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x1FFFF000);
|
||||
if (buf == (void *)-1)
|
||||
{
|
||||
printf("Unable to mmap(/dev/mem)\n");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
volatile char* str = (volatile char*)buf;
|
||||
|
||||
*str++ = 0x21;
|
||||
*str++ = 0x43;
|
||||
*str++ = 0x65;
|
||||
*str++ = 0x87;
|
||||
*str++ = 'c';
|
||||
*str++ = 'o';
|
||||
*str++ = 'r';
|
||||
*str++ = 'e';
|
||||
*str++ = '=';
|
||||
*str++ = '"';
|
||||
|
||||
for (int i = 0; i < strlen(name); i++)
|
||||
{
|
||||
*str++ = name[i];
|
||||
}
|
||||
|
||||
*str++ = '"';
|
||||
*str++ = 0;
|
||||
*str++ = 0;
|
||||
*str++ = 0;
|
||||
*str++ = 0;
|
||||
munmap(buf, 0x1000);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int fpga_load_rbf(char *name)
|
||||
{
|
||||
char path[512];
|
||||
int ret = 0;
|
||||
|
||||
printf("Loading RBF: %s\n", name);
|
||||
sprintf(path, "%s/%s", getRootDir(), name);
|
||||
|
||||
#ifdef REBOOT_ON_RBF_LOAD
|
||||
do_bridge(0);
|
||||
ret = save_core_name(name);
|
||||
#else
|
||||
|
||||
int rbf = open(path, O_RDONLY);
|
||||
if (rbf < 0)
|
||||
{
|
||||
printf("Couldn't open file %s\n", path);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct stat64 st;
|
||||
if (fstat64(rbf, &st)<0)
|
||||
{
|
||||
printf("Couldn't get info of file %s\n", path);
|
||||
ret = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Bitstream size: %lld bytes\n", st.st_size);
|
||||
|
||||
void *buf = malloc(st.st_size);
|
||||
if (!buf)
|
||||
{
|
||||
printf("Couldn't allocate %d bytes.\n", st.st_size);
|
||||
ret = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (read(rbf, buf, st.st_size)<st.st_size)
|
||||
{
|
||||
printf("Couldn't read file \n", st.st_size);
|
||||
ret = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
do_bridge(0);
|
||||
ret = socfpga_load(buf, st.st_size);
|
||||
if (ret)
|
||||
{
|
||||
printf("Error %d while loading %s\n", ret, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
do_bridge(1);
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
close(rbf);
|
||||
app_restart();
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fpga_io_init()
|
||||
{
|
||||
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) return -1;
|
||||
|
||||
map_base = mmap(0, FPGA_REG_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, FPGA_REG_BASE);
|
||||
if (map_base == (void *)-1)
|
||||
{
|
||||
printf("Unable to mmap(/dev/mem)\n");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t gpo_copy = 0;
|
||||
void fpga_gpo_write(uint32_t value)
|
||||
{
|
||||
gpo_copy = value;
|
||||
writel(value, (void*)(SOCFPGA_MGR_ADDRESS + 0x10));
|
||||
}
|
||||
|
||||
uint32_t fpga_gpo_read()
|
||||
{
|
||||
return gpo_copy; //readl((void*)(SOCFPGA_MGR_ADDRESS + 0x10));
|
||||
}
|
||||
|
||||
uint32_t fpga_gpi_read()
|
||||
{
|
||||
return readl((void*)(SOCFPGA_MGR_ADDRESS + 0x14));
|
||||
}
|
||||
|
||||
void fpga_core_write(uint32_t offset, uint32_t value)
|
||||
{
|
||||
if (offset <= 0x1FFFFF) writel(value, (void*)(SOCFPGA_LWFPGASLAVES_ADDRESS + (offset & ~3)));
|
||||
}
|
||||
|
||||
uint32_t fpga_core_read(uint32_t offset)
|
||||
{
|
||||
if (offset <= 0x1FFFFF) return readl((void*)(SOCFPGA_LWFPGASLAVES_ADDRESS + (offset & ~3)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpga_core_id()
|
||||
{
|
||||
uint32_t gpo = (fpga_gpo_read() & 0x7FFFFFFF);
|
||||
fpga_gpo_write(gpo);
|
||||
uint32_t coretype = fpga_gpi_read();
|
||||
gpo |= 0x80000000;
|
||||
fpga_gpo_write(gpo);
|
||||
|
||||
if ((coretype >> 8) != 0x5CA623) return -1;
|
||||
return coretype & 0xFF;
|
||||
}
|
||||
|
||||
int fpga_get_fio_size()
|
||||
{
|
||||
return (fpga_gpi_read()>>16) & 1;
|
||||
}
|
||||
|
||||
int fpga_get_io_version()
|
||||
{
|
||||
return (fpga_gpi_read() >> 18) & 3;
|
||||
}
|
||||
|
||||
void fpga_set_led(uint32_t on)
|
||||
{
|
||||
uint32_t gpo = fpga_gpo_read();
|
||||
fpga_gpo_write(on ? gpo | 0x20000000 : gpo & ~0x20000000);
|
||||
}
|
||||
|
||||
int fpga_get_buttons()
|
||||
{
|
||||
fpga_gpo_write(fpga_gpo_read() | 0x80000000);
|
||||
int gpi = fpga_gpi_read();
|
||||
if (gpi < 0) gpi = 0; // FPGA is not in user mode. Ignore the data;
|
||||
return (gpi >> 29) & 3;
|
||||
}
|
||||
|
||||
void reboot(int cold)
|
||||
{
|
||||
sync();
|
||||
if(cold) writel(0, &reset_regs->tstscratch);
|
||||
writel(2, &reset_regs->ctrl);
|
||||
while (1);
|
||||
}
|
||||
|
||||
char *getappname()
|
||||
{
|
||||
static char dest[PATH_MAX];
|
||||
memset(dest, 0, sizeof(dest));
|
||||
|
||||
char path[64];
|
||||
sprintf(path, "/proc/%d/exe", getpid());
|
||||
readlink(path, dest, PATH_MAX);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void app_restart()
|
||||
{
|
||||
sync();
|
||||
char *appname = getappname();
|
||||
printf("restarting the %s\n", appname);
|
||||
execve(appname, NULL, NULL);
|
||||
|
||||
printf("Something went wrong. Rebooting...\n");
|
||||
reboot(0);
|
||||
}
|
||||
|
||||
|
||||
void fpga_core_reset(int run)
|
||||
{
|
||||
fpga_gpo_write(run ? fpga_gpo_read() | 0x40000000 : fpga_gpo_read() & ~0x40000000);
|
||||
}
|
||||
|
||||
int fpga_ready()
|
||||
{
|
||||
return fpgamgr_test_fpga_ready();
|
||||
}
|
||||
37
fpga_io.h
Normal file
37
fpga_io.h
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef FPGAIO_H
|
||||
#define FPGAIO_H
|
||||
|
||||
#define DISKLED_ON fpga_set_led(1)
|
||||
#define DISKLED_OFF fpga_set_led(0)
|
||||
|
||||
#define BUTTON_OSD 1
|
||||
#define BUTTON_USR 2
|
||||
|
||||
int fpga_io_init();
|
||||
|
||||
void fpga_gpo_write(uint32_t value);
|
||||
uint32_t fpga_gpo_read();
|
||||
uint32_t fpga_gpi_read();
|
||||
|
||||
void fpga_set_led(uint32_t on);
|
||||
int fpga_get_buttons();
|
||||
|
||||
void fpga_core_reset(int run);
|
||||
void fpga_core_write(uint32_t offset, uint32_t value);
|
||||
uint32_t fpga_core_read(uint32_t offset);
|
||||
int fpga_core_id();
|
||||
int fpga_ready();
|
||||
|
||||
int fpga_get_fio_size();
|
||||
int fpga_get_io_version();
|
||||
|
||||
int fpga_load_rbf(char *name);
|
||||
|
||||
void reboot(int cold);
|
||||
void app_restart();
|
||||
char *getappname();
|
||||
|
||||
#endif
|
||||
70
fpga_manager.h
Normal file
70
fpga_manager.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Altera Corporation <www.altera.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _FPGA_MANAGER_H_
|
||||
#define _FPGA_MANAGER_H_
|
||||
|
||||
struct socfpga_fpga_manager {
|
||||
/* FPGA Manager Module */
|
||||
uint32_t stat; /* 0x00 */
|
||||
uint32_t ctrl;
|
||||
uint32_t dclkcnt;
|
||||
uint32_t dclkstat;
|
||||
uint32_t gpo; /* 0x10 */
|
||||
uint32_t gpi;
|
||||
uint32_t misci; /* 0x18 */
|
||||
uint32_t _pad_0x1c_0x82c[517];
|
||||
|
||||
/* Configuration Monitor (MON) Registers */
|
||||
uint32_t gpio_inten; /* 0x830 */
|
||||
uint32_t gpio_intmask;
|
||||
uint32_t gpio_inttype_level;
|
||||
uint32_t gpio_int_polarity;
|
||||
uint32_t gpio_intstatus; /* 0x840 */
|
||||
uint32_t gpio_raw_intstatus;
|
||||
uint32_t _pad_0x848;
|
||||
uint32_t gpio_porta_eoi;
|
||||
uint32_t gpio_ext_porta; /* 0x850 */
|
||||
uint32_t _pad_0x854_0x85c[3];
|
||||
uint32_t gpio_1s_sync; /* 0x860 */
|
||||
uint32_t _pad_0x864_0x868[2];
|
||||
uint32_t gpio_ver_id_code;
|
||||
uint32_t gpio_config_reg2; /* 0x870 */
|
||||
uint32_t gpio_config_reg1;
|
||||
};
|
||||
|
||||
#define FPGAMGRREGS_STAT_MODE_MASK 0x7
|
||||
#define FPGAMGRREGS_STAT_MSEL_MASK 0xf8
|
||||
#define FPGAMGRREGS_STAT_MSEL_LSB 3
|
||||
|
||||
#define FPGAMGRREGS_CTRL_CFGWDTH_MASK 0x200
|
||||
#define FPGAMGRREGS_CTRL_AXICFGEN_MASK 0x100
|
||||
#define FPGAMGRREGS_CTRL_NCONFIGPULL_MASK 0x4
|
||||
#define FPGAMGRREGS_CTRL_NCE_MASK 0x2
|
||||
#define FPGAMGRREGS_CTRL_EN_MASK 0x1
|
||||
#define FPGAMGRREGS_CTRL_CDRATIO_LSB 6
|
||||
|
||||
#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_CRC_MASK 0x8
|
||||
#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_ID_MASK 0x4
|
||||
#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_CD_MASK 0x2
|
||||
#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_NS_MASK 0x1
|
||||
|
||||
/* FPGA Mode */
|
||||
#define FPGAMGRREGS_MODE_FPGAOFF 0x0
|
||||
#define FPGAMGRREGS_MODE_RESETPHASE 0x1
|
||||
#define FPGAMGRREGS_MODE_CFGPHASE 0x2
|
||||
#define FPGAMGRREGS_MODE_INITPHASE 0x3
|
||||
#define FPGAMGRREGS_MODE_USERMODE 0x4
|
||||
#define FPGAMGRREGS_MODE_UNKNOWN 0x5
|
||||
|
||||
/* FPGA CD Ratio Value */
|
||||
#define CDRATIO_x1 0x0
|
||||
#define CDRATIO_x2 0x1
|
||||
#define CDRATIO_x4 0x2
|
||||
#define CDRATIO_x8 0x3
|
||||
|
||||
#endif /* _FPGA_MANAGER_H_ */
|
||||
195
fpga_nic301.h
Normal file
195
fpga_nic301.h
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Marek Vasut <marex@denx.de>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef _NIC301_REGISTERS_H_
|
||||
#define _NIC301_REGISTERS_H_
|
||||
|
||||
struct nic301_registers {
|
||||
uint32_t remap; /* 0x0 */
|
||||
/* Security Register Group */
|
||||
uint32_t _pad_0x4_0x8[1];
|
||||
uint32_t l4main;
|
||||
uint32_t l4sp;
|
||||
uint32_t l4mp; /* 0x10 */
|
||||
uint32_t l4osc1;
|
||||
uint32_t l4spim;
|
||||
uint32_t stm;
|
||||
uint32_t lwhps2fpgaregs; /* 0x20 */
|
||||
uint32_t _pad_0x24_0x28[1];
|
||||
uint32_t usb1;
|
||||
uint32_t nanddata;
|
||||
uint32_t _pad_0x30_0x80[20];
|
||||
uint32_t usb0; /* 0x80 */
|
||||
uint32_t nandregs;
|
||||
uint32_t qspidata;
|
||||
uint32_t fpgamgrdata;
|
||||
uint32_t hps2fpgaregs; /* 0x90 */
|
||||
uint32_t acp;
|
||||
uint32_t rom;
|
||||
uint32_t ocram;
|
||||
uint32_t sdrdata; /* 0xA0 */
|
||||
uint32_t _pad_0xa4_0x1fd0[1995];
|
||||
/* ID Register Group */
|
||||
uint32_t periph_id_4; /* 0x1FD0 */
|
||||
uint32_t _pad_0x1fd4_0x1fe0[3];
|
||||
uint32_t periph_id_0; /* 0x1FE0 */
|
||||
uint32_t periph_id_1;
|
||||
uint32_t periph_id_2;
|
||||
uint32_t periph_id_3;
|
||||
uint32_t comp_id_0; /* 0x1FF0 */
|
||||
uint32_t comp_id_1;
|
||||
uint32_t comp_id_2;
|
||||
uint32_t comp_id_3;
|
||||
uint32_t _pad_0x2000_0x2008[2];
|
||||
/* L4 MAIN */
|
||||
uint32_t l4main_fn_mod_bm_iss;
|
||||
uint32_t _pad_0x200c_0x3008[1023];
|
||||
/* L4 SP */
|
||||
uint32_t l4sp_fn_mod_bm_iss;
|
||||
uint32_t _pad_0x300c_0x4008[1023];
|
||||
/* L4 MP */
|
||||
uint32_t l4mp_fn_mod_bm_iss;
|
||||
uint32_t _pad_0x400c_0x5008[1023];
|
||||
/* L4 OSC1 */
|
||||
uint32_t l4osc_fn_mod_bm_iss;
|
||||
uint32_t _pad_0x500c_0x6008[1023];
|
||||
/* L4 SPIM */
|
||||
uint32_t l4spim_fn_mod_bm_iss;
|
||||
uint32_t _pad_0x600c_0x7008[1023];
|
||||
/* STM */
|
||||
uint32_t stm_fn_mod_bm_iss;
|
||||
uint32_t _pad_0x700c_0x7108[63];
|
||||
uint32_t stm_fn_mod;
|
||||
uint32_t _pad_0x710c_0x8008[959];
|
||||
/* LWHPS2FPGA */
|
||||
uint32_t lwhps2fpga_fn_mod_bm_iss;
|
||||
uint32_t _pad_0x800c_0x8108[63];
|
||||
uint32_t lwhps2fpga_fn_mod;
|
||||
uint32_t _pad_0x810c_0xa008[1983];
|
||||
/* USB1 */
|
||||
uint32_t usb1_fn_mod_bm_iss;
|
||||
uint32_t _pad_0xa00c_0xa044[14];
|
||||
uint32_t usb1_ahb_cntl;
|
||||
uint32_t _pad_0xa048_0xb008[1008];
|
||||
/* NANDDATA */
|
||||
uint32_t nanddata_fn_mod_bm_iss;
|
||||
uint32_t _pad_0xb00c_0xb108[63];
|
||||
uint32_t nanddata_fn_mod;
|
||||
uint32_t _pad_0xb10c_0x20008[21439];
|
||||
/* USB0 */
|
||||
uint32_t usb0_fn_mod_bm_iss;
|
||||
uint32_t _pad_0x2000c_0x20044[14];
|
||||
uint32_t usb0_ahb_cntl;
|
||||
uint32_t _pad_0x20048_0x21008[1008];
|
||||
/* NANDREGS */
|
||||
uint32_t nandregs_fn_mod_bm_iss;
|
||||
uint32_t _pad_0x2100c_0x21108[63];
|
||||
uint32_t nandregs_fn_mod;
|
||||
uint32_t _pad_0x2110c_0x22008[959];
|
||||
/* QSPIDATA */
|
||||
uint32_t qspidata_fn_mod_bm_iss;
|
||||
uint32_t _pad_0x2200c_0x22044[14];
|
||||
uint32_t qspidata_ahb_cntl;
|
||||
uint32_t _pad_0x22048_0x23008[1008];
|
||||
/* FPGAMGRDATA */
|
||||
uint32_t fpgamgrdata_fn_mod_bm_iss;
|
||||
uint32_t _pad_0x2300c_0x23040[13];
|
||||
uint32_t fpgamgrdata_wr_tidemark; /* 0x23040 */
|
||||
uint32_t _pad_0x23044_0x23108[49];
|
||||
uint32_t fn_mod;
|
||||
uint32_t _pad_0x2310c_0x24008[959];
|
||||
/* HPS2FPGA */
|
||||
uint32_t hps2fpga_fn_mod_bm_iss;
|
||||
uint32_t _pad_0x2400c_0x24040[13];
|
||||
uint32_t hps2fpga_wr_tidemark; /* 0x24040 */
|
||||
uint32_t _pad_0x24044_0x24108[49];
|
||||
uint32_t hps2fpga_fn_mod;
|
||||
uint32_t _pad_0x2410c_0x25008[959];
|
||||
/* ACP */
|
||||
uint32_t acp_fn_mod_bm_iss;
|
||||
uint32_t _pad_0x2500c_0x25108[63];
|
||||
uint32_t acp_fn_mod;
|
||||
uint32_t _pad_0x2510c_0x26008[959];
|
||||
/* Boot ROM */
|
||||
uint32_t bootrom_fn_mod_bm_iss;
|
||||
uint32_t _pad_0x2600c_0x26108[63];
|
||||
uint32_t bootrom_fn_mod;
|
||||
uint32_t _pad_0x2610c_0x27008[959];
|
||||
/* On-chip RAM */
|
||||
uint32_t ocram_fn_mod_bm_iss;
|
||||
uint32_t _pad_0x2700c_0x27040[13];
|
||||
uint32_t ocram_wr_tidemark; /* 0x27040 */
|
||||
uint32_t _pad_0x27044_0x27108[49];
|
||||
uint32_t ocram_fn_mod;
|
||||
uint32_t _pad_0x2710c_0x42024[27590];
|
||||
/* DAP */
|
||||
uint32_t dap_fn_mod2;
|
||||
uint32_t dap_fn_mod_ahb;
|
||||
uint32_t _pad_0x4202c_0x42100[53];
|
||||
uint32_t dap_read_qos; /* 0x42100 */
|
||||
uint32_t dap_write_qos;
|
||||
uint32_t dap_fn_mod;
|
||||
uint32_t _pad_0x4210c_0x43100[1021];
|
||||
/* MPU */
|
||||
uint32_t mpu_read_qos; /* 0x43100 */
|
||||
uint32_t mpu_write_qos;
|
||||
uint32_t mpu_fn_mod;
|
||||
uint32_t _pad_0x4310c_0x44028[967];
|
||||
/* SDMMC */
|
||||
uint32_t sdmmc_fn_mod_ahb;
|
||||
uint32_t _pad_0x4402c_0x44100[53];
|
||||
uint32_t sdmmc_read_qos; /* 0x44100 */
|
||||
uint32_t sdmmc_write_qos;
|
||||
uint32_t sdmmc_fn_mod;
|
||||
uint32_t _pad_0x4410c_0x45100[1021];
|
||||
/* DMA */
|
||||
uint32_t dma_read_qos; /* 0x45100 */
|
||||
uint32_t dma_write_qos;
|
||||
uint32_t dma_fn_mod;
|
||||
uint32_t _pad_0x4510c_0x46040[973];
|
||||
/* FPGA2HPS */
|
||||
uint32_t fpga2hps_wr_tidemark; /* 0x46040 */
|
||||
uint32_t _pad_0x46044_0x46100[47];
|
||||
uint32_t fpga2hps_read_qos; /* 0x46100 */
|
||||
uint32_t fpga2hps_write_qos;
|
||||
uint32_t fpga2hps_fn_mod;
|
||||
uint32_t _pad_0x4610c_0x47100[1021];
|
||||
/* ETR */
|
||||
uint32_t etr_read_qos; /* 0x47100 */
|
||||
uint32_t etr_write_qos;
|
||||
uint32_t etr_fn_mod;
|
||||
uint32_t _pad_0x4710c_0x48100[1021];
|
||||
/* EMAC0 */
|
||||
uint32_t emac0_read_qos; /* 0x48100 */
|
||||
uint32_t emac0_write_qos;
|
||||
uint32_t emac0_fn_mod;
|
||||
uint32_t _pad_0x4810c_0x49100[1021];
|
||||
/* EMAC1 */
|
||||
uint32_t emac1_read_qos; /* 0x49100 */
|
||||
uint32_t emac1_write_qos;
|
||||
uint32_t emac1_fn_mod;
|
||||
uint32_t _pad_0x4910c_0x4a028[967];
|
||||
/* USB0 */
|
||||
uint32_t usb0_fn_mod_ahb;
|
||||
uint32_t _pad_0x4a02c_0x4a100[53];
|
||||
uint32_t usb0_read_qos; /* 0x4A100 */
|
||||
uint32_t usb0_write_qos;
|
||||
uint32_t usb0_fn_mod;
|
||||
uint32_t _pad_0x4a10c_0x4b100[1021];
|
||||
/* NAND */
|
||||
uint32_t nand_read_qos; /* 0x4B100 */
|
||||
uint32_t nand_write_qos;
|
||||
uint32_t nand_fn_mod;
|
||||
uint32_t _pad_0x4b10c_0x4c028[967];
|
||||
/* USB1 */
|
||||
uint32_t usb1_fn_mod_ahb;
|
||||
uint32_t _pad_0x4c02c_0x4c100[53];
|
||||
uint32_t usb1_read_qos; /* 0x4C100 */
|
||||
uint32_t usb1_write_qos;
|
||||
uint32_t usb1_fn_mod;
|
||||
};
|
||||
|
||||
#endif /* _NIC301_REGISTERS_H_ */
|
||||
74
fpga_reset_manager.h
Normal file
74
fpga_reset_manager.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Altera Corporation <www.altera.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef _RESET_MANAGER_H_
|
||||
#define _RESET_MANAGER_H_
|
||||
|
||||
struct socfpga_reset_manager {
|
||||
uint32_t status;
|
||||
uint32_t ctrl;
|
||||
uint32_t counts;
|
||||
uint32_t padding1;
|
||||
uint32_t mpu_mod_reset;
|
||||
uint32_t per_mod_reset;
|
||||
uint32_t per2_mod_reset;
|
||||
uint32_t brg_mod_reset;
|
||||
uint32_t misc_mod_reset;
|
||||
uint32_t padding2[12];
|
||||
uint32_t tstscratch;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SOCFPGA_VIRTUAL_TARGET)
|
||||
#define RSTMGR_CTRL_SWWARMRSTREQ_LSB 2
|
||||
#else
|
||||
#define RSTMGR_CTRL_SWWARMRSTREQ_LSB 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define a reset identifier, from which a permodrst bank ID
|
||||
* and reset ID can be extracted using the subsequent macros
|
||||
* RSTMGR_RESET() and RSTMGR_BANK().
|
||||
*/
|
||||
#define RSTMGR_BANK_OFFSET 8
|
||||
#define RSTMGR_BANK_MASK 0x7
|
||||
#define RSTMGR_RESET_OFFSET 0
|
||||
#define RSTMGR_RESET_MASK 0x1f
|
||||
#define RSTMGR_DEFINE(_bank, _offset) \
|
||||
((_bank) << RSTMGR_BANK_OFFSET) | ((_offset) << RSTMGR_RESET_OFFSET)
|
||||
|
||||
/* Extract reset ID from the reset identifier. */
|
||||
#define RSTMGR_RESET(_reset) \
|
||||
(((_reset) >> RSTMGR_RESET_OFFSET) & RSTMGR_RESET_MASK)
|
||||
|
||||
/* Extract bank ID from the reset identifier. */
|
||||
#define RSTMGR_BANK(_reset) \
|
||||
(((_reset) >> RSTMGR_BANK_OFFSET) & RSTMGR_BANK_MASK)
|
||||
|
||||
/*
|
||||
* SocFPGA Cyclone V/Arria V reset IDs, bank mapping is as follows:
|
||||
* 0 ... mpumodrst
|
||||
* 1 ... permodrst
|
||||
* 2 ... per2modrst
|
||||
* 3 ... brgmodrst
|
||||
* 4 ... miscmodrst
|
||||
*/
|
||||
#define RSTMGR_EMAC0 RSTMGR_DEFINE(1, 0)
|
||||
#define RSTMGR_EMAC1 RSTMGR_DEFINE(1, 1)
|
||||
#define RSTMGR_NAND RSTMGR_DEFINE(1, 4)
|
||||
#define RSTMGR_QSPI RSTMGR_DEFINE(1, 5)
|
||||
#define RSTMGR_L4WD0 RSTMGR_DEFINE(1, 6)
|
||||
#define RSTMGR_OSC1TIMER0 RSTMGR_DEFINE(1, 8)
|
||||
#define RSTMGR_UART0 RSTMGR_DEFINE(1, 16)
|
||||
#define RSTMGR_SPIM0 RSTMGR_DEFINE(1, 18)
|
||||
#define RSTMGR_SPIM1 RSTMGR_DEFINE(1, 19)
|
||||
#define RSTMGR_SDMMC RSTMGR_DEFINE(1, 22)
|
||||
#define RSTMGR_DMA RSTMGR_DEFINE(1, 28)
|
||||
#define RSTMGR_SDR RSTMGR_DEFINE(1, 29)
|
||||
|
||||
/* Create a human-readable reference to SoCFPGA reset. */
|
||||
#define SOCFPGA_RESET(_name) RSTMGR_##_name
|
||||
|
||||
#endif /* _RESET_MANAGER_H_ */
|
||||
141
fpga_system_manager.h
Normal file
141
fpga_system_manager.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Altera Corporation <www.altera.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef _SYSTEM_MANAGER_H_
|
||||
#define _SYSTEM_MANAGER_H_
|
||||
|
||||
struct socfpga_system_manager {
|
||||
/* System Manager Module */
|
||||
uint32_t siliconid1; /* 0x00 */
|
||||
uint32_t siliconid2;
|
||||
uint32_t _pad_0x8_0xf[2];
|
||||
uint32_t wddbg; /* 0x10 */
|
||||
uint32_t bootinfo;
|
||||
uint32_t hpsinfo;
|
||||
uint32_t parityinj;
|
||||
/* FPGA Interface Group */
|
||||
uint32_t fpgaintfgrp_gbl; /* 0x20 */
|
||||
uint32_t fpgaintfgrp_indiv;
|
||||
uint32_t fpgaintfgrp_module;
|
||||
uint32_t _pad_0x2c_0x2f;
|
||||
/* Scan Manager Group */
|
||||
uint32_t scanmgrgrp_ctrl; /* 0x30 */
|
||||
uint32_t _pad_0x34_0x3f[3];
|
||||
/* Freeze Control Group */
|
||||
uint32_t frzctrl_vioctrl; /* 0x40 */
|
||||
uint32_t _pad_0x44_0x4f[3];
|
||||
uint32_t frzctrl_hioctrl; /* 0x50 */
|
||||
uint32_t frzctrl_src;
|
||||
uint32_t frzctrl_hwctrl;
|
||||
uint32_t _pad_0x5c_0x5f;
|
||||
/* EMAC Group */
|
||||
uint32_t emacgrp_ctrl; /* 0x60 */
|
||||
uint32_t emacgrp_l3master;
|
||||
uint32_t _pad_0x68_0x6f[2];
|
||||
/* DMA Controller Group */
|
||||
uint32_t dmagrp_ctrl; /* 0x70 */
|
||||
uint32_t dmagrp_persecurity;
|
||||
uint32_t _pad_0x78_0x7f[2];
|
||||
/* Preloader (initial software) Group */
|
||||
uint32_t iswgrp_handoff[8]; /* 0x80 */
|
||||
uint32_t _pad_0xa0_0xbf[8]; /* 0xa0 */
|
||||
/* Boot ROM Code Register Group */
|
||||
uint32_t romcodegrp_ctrl; /* 0xc0 */
|
||||
uint32_t romcodegrp_cpu1startaddr;
|
||||
uint32_t romcodegrp_initswstate;
|
||||
uint32_t romcodegrp_initswlastld;
|
||||
uint32_t romcodegrp_bootromswstate; /* 0xd0 */
|
||||
uint32_t __pad_0xd4_0xdf[3];
|
||||
/* Warm Boot from On-Chip RAM Group */
|
||||
uint32_t romcodegrp_warmramgrp_enable; /* 0xe0 */
|
||||
uint32_t romcodegrp_warmramgrp_datastart;
|
||||
uint32_t romcodegrp_warmramgrp_length;
|
||||
uint32_t romcodegrp_warmramgrp_execution;
|
||||
uint32_t romcodegrp_warmramgrp_crc; /* 0xf0 */
|
||||
uint32_t __pad_0xf4_0xff[3];
|
||||
/* Boot ROM Hardware Register Group */
|
||||
uint32_t romhwgrp_ctrl; /* 0x100 */
|
||||
uint32_t _pad_0x104_0x107;
|
||||
/* SDMMC Controller Group */
|
||||
uint32_t sdmmcgrp_ctrl;
|
||||
uint32_t sdmmcgrp_l3master;
|
||||
/* NAND Flash Controller Register Group */
|
||||
uint32_t nandgrp_bootstrap; /* 0x110 */
|
||||
uint32_t nandgrp_l3master;
|
||||
/* USB Controller Group */
|
||||
uint32_t usbgrp_l3master;
|
||||
uint32_t _pad_0x11c_0x13f[9];
|
||||
/* ECC Management Register Group */
|
||||
uint32_t eccgrp_l2; /* 0x140 */
|
||||
uint32_t eccgrp_ocram;
|
||||
uint32_t eccgrp_usb0;
|
||||
uint32_t eccgrp_usb1;
|
||||
uint32_t eccgrp_emac0; /* 0x150 */
|
||||
uint32_t eccgrp_emac1;
|
||||
uint32_t eccgrp_dma;
|
||||
uint32_t eccgrp_can0;
|
||||
uint32_t eccgrp_can1; /* 0x160 */
|
||||
uint32_t eccgrp_nand;
|
||||
uint32_t eccgrp_qspi;
|
||||
uint32_t eccgrp_sdmmc;
|
||||
uint32_t _pad_0x170_0x3ff[164];
|
||||
/* Pin Mux Control Group */
|
||||
uint32_t emacio[20]; /* 0x400 */
|
||||
uint32_t flashio[12]; /* 0x450 */
|
||||
uint32_t generalio[28]; /* 0x480 */
|
||||
uint32_t _pad_0x4f0_0x4ff[4];
|
||||
uint32_t mixed1io[22]; /* 0x500 */
|
||||
uint32_t mixed2io[8]; /* 0x558 */
|
||||
uint32_t gplinmux[23]; /* 0x578 */
|
||||
uint32_t gplmux[71]; /* 0x5d4 */
|
||||
uint32_t nandusefpga; /* 0x6f0 */
|
||||
uint32_t _pad_0x6f4;
|
||||
uint32_t rgmii1usefpga; /* 0x6f8 */
|
||||
uint32_t _pad_0x6fc_0x700[2];
|
||||
uint32_t i2c0usefpga; /* 0x704 */
|
||||
uint32_t sdmmcusefpga; /* 0x708 */
|
||||
uint32_t _pad_0x70c_0x710[2];
|
||||
uint32_t rgmii0usefpga; /* 0x714 */
|
||||
uint32_t _pad_0x718_0x720[3];
|
||||
uint32_t i2c3usefpga; /* 0x724 */
|
||||
uint32_t i2c2usefpga; /* 0x728 */
|
||||
uint32_t i2c1usefpga; /* 0x72c */
|
||||
uint32_t spim1usefpga; /* 0x730 */
|
||||
uint32_t _pad_0x734;
|
||||
uint32_t spim0usefpga; /* 0x738 */
|
||||
};
|
||||
|
||||
#define SYSMGR_ROMCODEGRP_CTRL_WARMRSTCFGPINMUX (1 << 0)
|
||||
#define SYSMGR_ROMCODEGRP_CTRL_WARMRSTCFGIO (1 << 1)
|
||||
#define SYSMGR_ECC_OCRAM_EN (1 << 0)
|
||||
#define SYSMGR_ECC_OCRAM_SERR (1 << 3)
|
||||
#define SYSMGR_ECC_OCRAM_DERR (1 << 4)
|
||||
#define SYSMGR_FPGAINTF_USEFPGA 0x1
|
||||
#define SYSMGR_FPGAINTF_SPIM0 (1 << 0)
|
||||
#define SYSMGR_FPGAINTF_SPIM1 (1 << 1)
|
||||
#define SYSMGR_FPGAINTF_EMAC0 (1 << 2)
|
||||
#define SYSMGR_FPGAINTF_EMAC1 (1 << 3)
|
||||
#define SYSMGR_FPGAINTF_NAND (1 << 4)
|
||||
#define SYSMGR_FPGAINTF_SDMMC (1 << 5)
|
||||
|
||||
#if defined(CONFIG_TARGET_SOCFPGA_GEN5)
|
||||
#define SYSMGR_SDMMC_SMPLSEL_SHIFT 3
|
||||
#else
|
||||
#define SYSMGR_SDMMC_SMPLSEL_SHIFT 4
|
||||
#endif
|
||||
|
||||
#define SYSMGR_SDMMC_DRVSEL_SHIFT 0
|
||||
|
||||
/* EMAC Group Bit definitions */
|
||||
#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0
|
||||
#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1
|
||||
#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2
|
||||
|
||||
#define SYSMGR_EMACGRP_CTRL_PHYSEL0_LSB 0
|
||||
#define SYSMGR_EMACGRP_CTRL_PHYSEL1_LSB 2
|
||||
#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x3
|
||||
|
||||
#endif /* _SYSTEM_MANAGER_H_ */
|
||||
75
hardware.c
Normal file
75
hardware.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "hardware.h"
|
||||
#include "user_io.h"
|
||||
|
||||
uint8_t rstval = 0;
|
||||
|
||||
void hexdump(void *data, uint16_t size, uint16_t offset)
|
||||
{
|
||||
uint8_t i, b2c;
|
||||
uint16_t n = 0;
|
||||
char *ptr = data;
|
||||
|
||||
if (!size) return;
|
||||
|
||||
while (size>0) {
|
||||
iprintf("%04x: ", n + offset);
|
||||
|
||||
b2c = (size>16) ? 16 : size;
|
||||
for (i = 0; i<b2c; i++) iprintf("%02x ", 0xff & ptr[i]);
|
||||
iprintf(" ");
|
||||
for (i = 0; i<(16 - b2c); i++) iprintf(" ");
|
||||
for (i = 0; i<b2c; i++) iprintf("%c", isprint(ptr[i]) ? ptr[i] : '.');
|
||||
iprintf("\n");
|
||||
ptr += b2c;
|
||||
size -= b2c;
|
||||
n += b2c;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long GetTimer(unsigned long offset)
|
||||
{
|
||||
struct timespec tp;
|
||||
clock_gettime(CLOCK_BOOTTIME, &tp);
|
||||
|
||||
unsigned long long res;
|
||||
|
||||
res = tp.tv_sec;
|
||||
res *= 1000;
|
||||
res += (tp.tv_nsec / 1000000);
|
||||
|
||||
return (unsigned long)(res + offset);
|
||||
}
|
||||
|
||||
unsigned long CheckTimer(unsigned long time)
|
||||
{
|
||||
return GetTimer(0) >= time;
|
||||
}
|
||||
|
||||
void WaitTimer(unsigned long time)
|
||||
{
|
||||
time = GetTimer(time);
|
||||
while (!CheckTimer(time));
|
||||
}
|
||||
23
hardware.h
Normal file
23
hardware.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef HARDWARE_H
|
||||
#define HARDWARE_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define iprintf(...) printf(__VA_ARGS__)
|
||||
#define siprintf(...) sprintf(__VA_ARGS__)
|
||||
#define BootPrint(text) iprintf("%s\n", text)
|
||||
|
||||
unsigned long GetTimer(unsigned long offset);
|
||||
unsigned long CheckTimer(unsigned long t);
|
||||
void WaitTimer(unsigned long time);
|
||||
|
||||
void hexdump(void *data, uint16_t size, uint16_t offset);
|
||||
|
||||
// minimig reset stuff
|
||||
#define SPI_RST_USR 0x1
|
||||
#define SPI_RST_CPU 0x2
|
||||
#define SPI_CPU_HLT 0x4
|
||||
extern uint8_t rstval;
|
||||
|
||||
#endif // HARDWARE_H
|
||||
766
hdd.c
Normal file
766
hdd.c
Normal file
@@ -0,0 +1,766 @@
|
||||
/*
|
||||
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-22 - read/write multiple implemented
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "errors.h"
|
||||
#include "hardware.h"
|
||||
#include "file_io.h"
|
||||
#include "hdd.h"
|
||||
#include "hdd_internal.h"
|
||||
#include "menu.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "fpga_io.h"
|
||||
|
||||
|
||||
#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
|
||||
hdfTYPE hdf[2];
|
||||
|
||||
static uint8_t sector_buffer[512];
|
||||
|
||||
unsigned char GetDiskStatus(void)
|
||||
{
|
||||
unsigned char status;
|
||||
|
||||
EnableFpga();
|
||||
status = (uint8_t)(spi_w(0) >> 8);
|
||||
spi_w(0);
|
||||
spi_w(0);
|
||||
DisableFpga();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// RDBChecksum()
|
||||
static void RDBChecksum(unsigned long *p)
|
||||
{
|
||||
unsigned long count = p[1];
|
||||
unsigned long c2;
|
||||
long result = 0;
|
||||
p[2] = 0;
|
||||
for (c2 = 0; c2<count; ++c2) result += p[c2];
|
||||
p[2] = (unsigned long)-result;
|
||||
}
|
||||
|
||||
|
||||
// FakeRDB()
|
||||
// if the hardfile doesn't have a RigidDiskBlock, we synthesize one
|
||||
static void FakeRDB(int unit, int block)
|
||||
{
|
||||
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 (block) {
|
||||
case 0: {
|
||||
// RDB
|
||||
hdd_debugf("FAKE: 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[unit].cylinders;
|
||||
rdb->rdb_Sectors = hdf[unit].sectors;
|
||||
rdb->rdb_Heads = hdf[unit].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, "Do not ");
|
||||
strcpy(rdb->rdb_DiskProduct, "repartition!");
|
||||
// swap byte order of strings to be able to "unswap" them after checksum
|
||||
unsigned long *p = (unsigned long*)rdb;
|
||||
for (i = 0; i<(8 + 16) / 4; i++) p[40 + i] = SWAP(p[40 + i]);
|
||||
RDBChecksum((unsigned long *)rdb);
|
||||
// swap byte order of first 0x40 long values
|
||||
for (i = 0; i<0x40; i++) p[i] = SWAP(p[i]);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
// Partition
|
||||
hdd_debugf("FAKE: 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, unit ? "1HD\003" : "0HD\003"); // "DH0"/"DH1" BCPL string
|
||||
pb->pb_Environment.de_TableSize = 0x10;
|
||||
pb->pb_Environment.de_SizeBlock = 0x80;
|
||||
pb->pb_Environment.de_Surfaces = hdf[unit].heads;
|
||||
pb->pb_Environment.de_SectorPerBlock = 1;
|
||||
pb->pb_Environment.de_BlocksPerTrack = hdf[unit].sectors;
|
||||
pb->pb_Environment.de_Reserved = 2;
|
||||
pb->pb_Environment.de_LowCyl = 1;
|
||||
pb->pb_Environment.de_HighCyl = hdf[unit].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;
|
||||
RDBChecksum((unsigned long *)pb);
|
||||
// swap byte order of first 0x40 entries
|
||||
unsigned long *p = (unsigned long*)pb;
|
||||
for (i = 0; i<0x40; i++) p[i] = SWAP(p[i]);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// IdentifiyDevice()
|
||||
// builds Identify Device struct
|
||||
void IdentifyDevice(unsigned short *pBuffer, unsigned char unit)
|
||||
{
|
||||
char *p, i, x;
|
||||
unsigned long total_sectors = hdf[unit].cylinders * hdf[unit].heads * hdf[unit].sectors;
|
||||
memset(pBuffer, 0, 512);
|
||||
|
||||
switch (hdf[unit].type) {
|
||||
case HDF_FILE | HDF_SYNTHRDB:
|
||||
case HDF_FILE:
|
||||
pBuffer[0] = 1 << 6; // hard disk
|
||||
pBuffer[1] = hdf[unit].cylinders; // cyl count
|
||||
pBuffer[3] = hdf[unit].heads; // head count
|
||||
pBuffer[6] = hdf[unit].sectors; // sectors per track
|
||||
// FIXME - can get serial no from card itself.
|
||||
memcpy((char*)&pBuffer[10], "MiSTMiniMigHardfile ", 20); // serial number - byte swapped
|
||||
memcpy((char*)&pBuffer[23], ".100 ", 8); // firmware version - byte swapped
|
||||
p = (char*)&pBuffer[27];
|
||||
// FIXME - likewise the model name can be fetched from the card.
|
||||
if (hdf[unit].type & HDF_SYNTHRDB) {
|
||||
memcpy(p, "DON'T ", 40);
|
||||
p += 8;
|
||||
memcpy(p, "REPARTITION! ", 16);
|
||||
}
|
||||
else {
|
||||
memcpy(p, "YAQUBE ", 40); // model name - byte swapped
|
||||
p += 8;
|
||||
for (i = 0; (x = config.hardfile[unit].long_name[i]) && i < 16; i++) // copy file name as model name
|
||||
p[i] = x;
|
||||
}
|
||||
// SwapBytes((char*)&pBuffer[27], 40); //not for 68000
|
||||
break;
|
||||
}
|
||||
|
||||
pBuffer[47] = 0x8010; // maximum sectors per block in Read/Write Multiple command
|
||||
pBuffer[53] = 1;
|
||||
pBuffer[54] = hdf[unit].cylinders;
|
||||
pBuffer[55] = hdf[unit].heads;
|
||||
pBuffer[56] = hdf[unit].sectors;
|
||||
pBuffer[57] = (unsigned short)total_sectors;
|
||||
pBuffer[58] = (unsigned short)(total_sectors >> 16);
|
||||
}
|
||||
|
||||
|
||||
// chs2lba()
|
||||
unsigned long chs2lba(unsigned short cylinder, unsigned char head, unsigned short sector, unsigned char unit)
|
||||
{
|
||||
return(cylinder * hdf[unit].heads + head) * hdf[unit].sectors + sector - 1;
|
||||
}
|
||||
|
||||
|
||||
// WriteTaskFile()
|
||||
void WriteTaskFile(unsigned char error, unsigned char sector_count, unsigned char sector_number, unsigned char cylinder_low, unsigned char cylinder_high, unsigned char 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); // 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();
|
||||
}
|
||||
|
||||
|
||||
// WriteStatus()
|
||||
void WriteStatus(unsigned char status)
|
||||
{
|
||||
EnableFpga();
|
||||
spi_w((CMD_IDE_STATUS_WR<<8) | status);
|
||||
spi_w(0);
|
||||
spi_w(0);
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
|
||||
// ATA_Recalibrate()
|
||||
static void ATA_Recalibrate(unsigned char* tfr, unsigned char unit)
|
||||
{
|
||||
// Recalibrate 0x10-0x1F (class 3 command: no data)
|
||||
hdd_debugf("IDE%d: Recalibrate", unit);
|
||||
WriteTaskFile(0, 0, 1, 0, 0, tfr[6] & 0xF0);
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
|
||||
|
||||
// ATA_Diagnostic()
|
||||
static void ATA_Diagnostic(unsigned char* tfr)
|
||||
{
|
||||
// Execute Drive Diagnostic (0x90)
|
||||
hdd_debugf("IDE: Drive Diagnostic");
|
||||
WriteTaskFile(1, 0, 0, 0, 0, 0);
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
|
||||
|
||||
// ATA_IdentifyDevice()
|
||||
static void ATA_IdentifyDevice(unsigned char* tfr, unsigned char unit)
|
||||
{
|
||||
int i;
|
||||
// Identify Device (0xec)
|
||||
hdd_debugf("IDE%d: Identify Device", unit);
|
||||
IdentifyDevice((uint16_t*)sector_buffer, unit);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
// ATA_Initialize()
|
||||
static void ATA_Initialize(unsigned char* tfr, unsigned char unit)
|
||||
{
|
||||
// Initialize Device Parameters (0x91)
|
||||
hdd_debugf("Initialize Device Parameters");
|
||||
hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", 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);
|
||||
}
|
||||
|
||||
|
||||
// ATA_SetMultipleMode()
|
||||
static void ATA_SetMultipleMode(unsigned char* tfr, unsigned char unit)
|
||||
{
|
||||
// Set Multiple Mode (0xc6)
|
||||
hdd_debugf("Set Multiple Mode");
|
||||
hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]);
|
||||
hdf[unit].sectors_per_block = tfr[2];
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
|
||||
|
||||
// ATA_ReadSectors()
|
||||
static void ATA_ReadSectors(unsigned char* tfr, unsigned short sector, unsigned short cylinder, unsigned char head, unsigned char unit, unsigned short sector_count)
|
||||
{
|
||||
// Read Sectors (0x20)
|
||||
long lba;
|
||||
sector = tfr[3];
|
||||
cylinder = tfr[4] | (tfr[5] << 8);
|
||||
head = tfr[6] & 0x0F;
|
||||
sector_count = tfr[2];
|
||||
if (sector_count == 0) sector_count = 0x100;
|
||||
hdd_debugf("IDE%d: read %d.%d.%d, %d", unit, cylinder, head, sector, sector_count);
|
||||
switch (hdf[unit].type) {
|
||||
case HDF_FILE | HDF_SYNTHRDB:
|
||||
case HDF_FILE:
|
||||
lba = chs2lba(cylinder, head, sector, unit);
|
||||
if (hdf[unit].file.size) HardFileSeek(&hdf[unit], (lba + hdf[unit].offset) < 0 ? 0 : lba + hdf[unit].offset);
|
||||
while (sector_count) {
|
||||
// decrease sector count
|
||||
if (sector_count != 1) {
|
||||
if (sector == hdf[unit].sectors) {
|
||||
sector = 1;
|
||||
head++;
|
||||
if (head == hdf[unit].heads) {
|
||||
head = 0;
|
||||
cylinder++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sector++;
|
||||
}
|
||||
}
|
||||
|
||||
WriteTaskFile(0, tfr[2], sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type
|
||||
|
||||
// sector outside limit (fake rdb header) or to be modified sector of first partition
|
||||
if (((lba + hdf[unit].offset)<0) || ((unit == 0) && (hdf[unit].type == HDF_FILE | HDF_SYNTHRDB) && (lba == 0)))
|
||||
{
|
||||
if ((lba + hdf[unit].offset)<0)
|
||||
{
|
||||
FakeRDB(unit, lba);
|
||||
}
|
||||
else
|
||||
{
|
||||
// read sector into buffer
|
||||
FileReadSec(&hdf[unit].file, sector_buffer);
|
||||
// adjust checksum by the difference between old and new flag value
|
||||
struct RigidDiskBlock *rdb = (struct RigidDiskBlock *)sector_buffer;
|
||||
rdb->rdb_ChkSum = SWAP(SWAP(rdb->rdb_ChkSum) + SWAP(rdb->rdb_Flags) - 0x12);
|
||||
|
||||
// adjust flags
|
||||
rdb->rdb_Flags = SWAP(0x12);
|
||||
}
|
||||
|
||||
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(sector_count == 1 ? IDE_STATUS_IRQ | IDE_STATUS_END : IDE_STATUS_IRQ);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!(GetDiskStatus() & CMD_IDECMD)); // wait for empty sector buffer
|
||||
WriteStatus(IDE_STATUS_IRQ);
|
||||
if (hdf[unit].file.size)
|
||||
{
|
||||
FileReadSec(&hdf[unit].file, sector_buffer);
|
||||
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();
|
||||
}
|
||||
}
|
||||
lba++;
|
||||
sector_count--; // decrease sector count
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// HandleHDD()
|
||||
void HandleHDD(unsigned char c1, unsigned char c2)
|
||||
{
|
||||
unsigned char tfr[8];
|
||||
unsigned short i;
|
||||
unsigned short sector;
|
||||
unsigned short cylinder;
|
||||
unsigned char head;
|
||||
unsigned char unit;
|
||||
unsigned short sector_count;
|
||||
unsigned short block_count;
|
||||
|
||||
if (c1 & CMD_IDECMD)
|
||||
{
|
||||
DISKLED_ON;
|
||||
EnableFpga();
|
||||
spi_w(CMD_IDE_REGS_RD<<8); // read task file registers
|
||||
spi_w(0);
|
||||
spi_w(0);
|
||||
for (i = 0; i < 8; i++) tfr[i] = (uint8_t)spi_w(0);
|
||||
DisableFpga();
|
||||
unit = tfr[6] & 0x10 ? 1 : 0; // master/slave selection
|
||||
if (0) hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]);
|
||||
|
||||
if ((tfr[7] & 0xF0) == ACMD_RECALIBRATE) {
|
||||
ATA_Recalibrate(tfr, unit);
|
||||
}
|
||||
else if (tfr[7] == ACMD_DIAGNOSTIC) {
|
||||
ATA_Diagnostic(tfr);
|
||||
}
|
||||
else if (tfr[7] == ACMD_IDENTIFY_DEVICE) {
|
||||
ATA_IdentifyDevice(tfr, unit);
|
||||
}
|
||||
else if (tfr[7] == ACMD_INITIALIZE_DEVICE_PARAMETERS) {
|
||||
ATA_Initialize(tfr, unit);
|
||||
}
|
||||
else if (tfr[7] == ACMD_SET_MULTIPLE_MODE) {
|
||||
ATA_SetMultipleMode(tfr, unit);
|
||||
}
|
||||
else if (tfr[7] == ACMD_READ_SECTORS) {
|
||||
ATA_ReadSectors(tfr, sector, cylinder, head, unit, sector_count);
|
||||
}
|
||||
else if (tfr[7] == ACMD_READ_MULTIPLE) {
|
||||
// Read Multiple Sectors (multiple sector transfer per IRQ)
|
||||
long lba;
|
||||
WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type
|
||||
sector = tfr[3];
|
||||
cylinder = tfr[4] | (tfr[5] << 8);
|
||||
head = tfr[6] & 0x0F;
|
||||
sector_count = tfr[2];
|
||||
if (sector_count == 0) sector_count = 0x100;
|
||||
hdd_debugf("IDE%d: read_multi %d.%d.%d, %d", unit, cylinder, head, sector, sector_count);
|
||||
|
||||
switch (hdf[unit].type) {
|
||||
case HDF_FILE | HDF_SYNTHRDB:
|
||||
case HDF_FILE:
|
||||
lba = chs2lba(cylinder, head, sector, unit);
|
||||
if (hdf[unit].file.size) HardFileSeek(&hdf[unit], (lba + hdf[unit].offset) < 0 ? 0 : lba + hdf[unit].offset);
|
||||
// FIXME - READM could cross the fake RDB -> real disk boundary.
|
||||
// FIXME - but first we should make some attempt to generate fake RGB in multiple mode.
|
||||
|
||||
while (sector_count) {
|
||||
while (!(GetDiskStatus() & CMD_IDECMD)); // wait for empty sector buffer
|
||||
block_count = sector_count;
|
||||
if (block_count > hdf[unit].sectors_per_block) block_count = hdf[unit].sectors_per_block;
|
||||
WriteStatus(IDE_STATUS_IRQ);
|
||||
while (block_count--)
|
||||
{
|
||||
if (hdf[unit].file.size)
|
||||
{
|
||||
FileReadSec(&hdf[unit].file, sector_buffer);
|
||||
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();
|
||||
}
|
||||
if (sector_count != 1)
|
||||
{
|
||||
if (sector == hdf[unit].sectors)
|
||||
{
|
||||
sector = 1;
|
||||
head++;
|
||||
if (head == hdf[unit].heads)
|
||||
{
|
||||
head = 0;
|
||||
cylinder++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sector++;
|
||||
}
|
||||
}
|
||||
sector_count--;
|
||||
}
|
||||
WriteTaskFile(0, tfr[2], sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
//WriteTaskFile(0, 0, sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
}
|
||||
//WriteTaskFile(0, 0, sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
break;
|
||||
}
|
||||
WriteStatus(IDE_STATUS_END);
|
||||
}
|
||||
else if (tfr[7] == ACMD_WRITE_SECTORS) {
|
||||
// write sectors
|
||||
WriteStatus(IDE_STATUS_REQ); // pio out (class 2) command type
|
||||
sector = tfr[3];
|
||||
cylinder = tfr[4] | (tfr[5] << 8);
|
||||
head = tfr[6] & 0x0F;
|
||||
sector_count = tfr[2];
|
||||
if (sector_count == 0) sector_count = 0x100;
|
||||
long lba = chs2lba(cylinder, head, sector, unit);
|
||||
//if (hdf[unit].type>=HDF_CARDPART0)
|
||||
lba += hdf[unit].offset;
|
||||
if (hdf[unit].file.size) {
|
||||
// File size will be 0 in direct card modes
|
||||
HardFileSeek(&hdf[unit], (lba>-1) ? lba : 0);
|
||||
}
|
||||
|
||||
while (sector_count)
|
||||
{
|
||||
while (!(GetDiskStatus() & CMD_IDEDAT)); // wait for full write buffer
|
||||
// decrease sector count
|
||||
if (sector_count != 1)
|
||||
{
|
||||
if (sector == hdf[unit].sectors)
|
||||
{
|
||||
sector = 1;
|
||||
head++;
|
||||
if (head == hdf[unit].heads)
|
||||
{
|
||||
head = 0;
|
||||
cylinder++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sector++;
|
||||
}
|
||||
}
|
||||
WriteTaskFile(0, tfr[2], sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
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();
|
||||
sector_count--; // decrease sector count
|
||||
if (sector_count)
|
||||
{
|
||||
WriteStatus(IDE_STATUS_IRQ);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
|
||||
switch (hdf[unit].type)
|
||||
{
|
||||
case HDF_FILE | HDF_SYNTHRDB:
|
||||
case HDF_FILE:
|
||||
// Don't attempt to write to fake RDB
|
||||
if (hdf[unit].file.size && (lba>-1))
|
||||
{
|
||||
FileWriteSec(&hdf[unit].file, sector_buffer);
|
||||
}
|
||||
lba++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tfr[7] == ACMD_WRITE_MULTIPLE) {
|
||||
// write sectors
|
||||
WriteStatus(IDE_STATUS_REQ); // pio out (class 2) command type
|
||||
sector = tfr[3];
|
||||
cylinder = tfr[4] | (tfr[5] << 8);
|
||||
head = tfr[6] & 0x0F;
|
||||
sector_count = tfr[2];
|
||||
if (sector_count == 0) sector_count = 0x100;
|
||||
long lba = chs2lba(cylinder, head, sector, unit);
|
||||
//if (hdf[unit].type>=HDF_CARDPART0)
|
||||
lba += hdf[unit].offset;
|
||||
if (hdf[unit].file.size) {
|
||||
// File size will be 0 in direct card modes
|
||||
HardFileSeek(&hdf[unit], (lba>-1) ? lba : 0);
|
||||
}
|
||||
while (sector_count) {
|
||||
block_count = sector_count;
|
||||
if (block_count > hdf[unit].sectors_per_block) block_count = hdf[unit].sectors_per_block;
|
||||
while (block_count) {
|
||||
while (!(GetDiskStatus() & CMD_IDEDAT)); // wait for full write buffer
|
||||
// decrease sector count
|
||||
if (sector_count != 1) {
|
||||
if (sector == hdf[unit].sectors) {
|
||||
sector = 1;
|
||||
head++;
|
||||
if (head == hdf[unit].heads) {
|
||||
head = 0;
|
||||
cylinder++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sector++;
|
||||
}
|
||||
}
|
||||
//WriteTaskFile(0, tfr[2], sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
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();
|
||||
switch (hdf[unit].type)
|
||||
{
|
||||
case HDF_FILE | HDF_SYNTHRDB:
|
||||
case HDF_FILE:
|
||||
if (hdf[unit].file.size && (lba>-1))
|
||||
{
|
||||
FileWriteSec(&hdf[unit].file, sector_buffer);
|
||||
}
|
||||
lba++;
|
||||
break;
|
||||
}
|
||||
block_count--; // decrease block count
|
||||
sector_count--; // decrease sector count
|
||||
}
|
||||
WriteTaskFile(0, tfr[2], sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
if (sector_count) {
|
||||
WriteStatus(IDE_STATUS_IRQ);
|
||||
}
|
||||
else {
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
hdd_debugf("Unknown ATA command");
|
||||
hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// GetHardfileGeometry()
|
||||
// this function comes from WinUAE, should return the same CHS as WinUAE
|
||||
void GetHardfileGeometry(hdfTYPE *pHDF)
|
||||
{
|
||||
unsigned long total = 0;
|
||||
unsigned long i, head, cyl, spt;
|
||||
unsigned long sptt[] = { 63, 127, 255, 0 };
|
||||
|
||||
switch (pHDF->type) {
|
||||
case (HDF_FILE | HDF_SYNTHRDB) :
|
||||
if (pHDF->file.size == 0) return;
|
||||
total = pHDF->file.size / 512;
|
||||
pHDF->heads = 1;
|
||||
pHDF->sectors = 32;
|
||||
pHDF->cylinders = total / 32 + 1; // Add a cylinder for the fake RDB.
|
||||
return;
|
||||
case HDF_FILE:
|
||||
if (pHDF->file.size == 0) return;
|
||||
total = pHDF->file.size / 512;
|
||||
break;
|
||||
}
|
||||
|
||||
for (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 <= 65535) // Should there some head constraint here?
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (head <= 16) break;
|
||||
}
|
||||
pHDF->cylinders = (unsigned short)cyl;
|
||||
pHDF->heads = (unsigned short)head;
|
||||
pHDF->sectors = (unsigned short)spt;
|
||||
}
|
||||
|
||||
|
||||
// HardFileSeek()
|
||||
unsigned char HardFileSeek(hdfTYPE *pHDF, unsigned long lba)
|
||||
{
|
||||
return FileSeekLBA(&pHDF->file, lba);
|
||||
}
|
||||
|
||||
|
||||
// OpenHardfile()
|
||||
unsigned char OpenHardfile(unsigned char unit)
|
||||
{
|
||||
unsigned long time;
|
||||
|
||||
switch (config.hardfile[unit].enabled)
|
||||
{
|
||||
case HDF_FILE | HDF_SYNTHRDB:
|
||||
case HDF_FILE:
|
||||
hdf[unit].type = config.hardfile[unit].enabled;
|
||||
if (config.hardfile[unit].long_name[0])
|
||||
{
|
||||
if(FileOpenEx(&hdf[unit].file, config.hardfile[unit].long_name, FileCanWrite(config.hardfile[unit].long_name) ? O_RDWR : O_RDONLY))
|
||||
{
|
||||
GetHardfileGeometry(&hdf[unit]);
|
||||
hdd_debugf("HARDFILE %d:", unit);
|
||||
hdd_debugf("file: \"%.8s.%.3s\"", hdf[unit].file.name, &hdf[unit].file.name[8]);
|
||||
hdd_debugf("size: %lu (%lu MB)", hdf[unit].file.size, hdf[unit].file.size >> 20);
|
||||
hdd_debugf("CHS: %u.%u.%u", hdf[unit].cylinders, hdf[unit].heads, hdf[unit].sectors);
|
||||
hdd_debugf(" (%lu MB)", ((((unsigned long)hdf[unit].cylinders) * hdf[unit].heads * hdf[unit].sectors) >> 11));
|
||||
time = GetTimer(0);
|
||||
time = GetTimer(0) - time;
|
||||
hdd_debugf("Hardfile indexed in %lu ms", time >> 16);
|
||||
if (config.hardfile[unit].enabled & HDF_SYNTHRDB) {
|
||||
hdf[unit].offset = -(hdf[unit].heads*hdf[unit].sectors);
|
||||
}
|
||||
else {
|
||||
hdf[unit].offset = 0;
|
||||
}
|
||||
config.hardfile[unit].present = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
config.hardfile[unit].present = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetHDFFileType()
|
||||
unsigned char GetHDFFileType(char *filename)
|
||||
{
|
||||
uint8_t type = HDF_FILETYPE_NOTFOUND;
|
||||
fileTYPE rdbfile;
|
||||
|
||||
if(FileOpen(&rdbfile, filename))
|
||||
{
|
||||
type = HDF_FILETYPE_UNKNOWN;
|
||||
for (int i = 0; i<16; ++i)
|
||||
{
|
||||
FileReadSec(&rdbfile, sector_buffer);
|
||||
if (sector_buffer[0] == 'R' && sector_buffer[1] == 'D' && sector_buffer[2] == 'S' && sector_buffer[3] == 'K')
|
||||
{
|
||||
type = HDF_FILETYPE_RDB;
|
||||
break;
|
||||
}
|
||||
if (sector_buffer[0] == 'D' && sector_buffer[1] == 'O' && sector_buffer[2] == 'S')
|
||||
{
|
||||
type = HDF_FILETYPE_DOS;
|
||||
break;
|
||||
}
|
||||
if (sector_buffer[0] == 'P' && sector_buffer[1] == 'F' && sector_buffer[2] == 'S')
|
||||
{
|
||||
type = HDF_FILETYPE_DOS;
|
||||
break;
|
||||
}
|
||||
if (sector_buffer[0] == 'S' && sector_buffer[1] == 'F' && sector_buffer[2] == 'S')
|
||||
{
|
||||
type = HDF_FILETYPE_DOS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FileClose(&rdbfile);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
77
hdd.h
Normal file
77
hdd.h
Normal file
@@ -0,0 +1,77 @@
|
||||
// hdd.h
|
||||
|
||||
|
||||
#ifndef __HDD_H__
|
||||
#define __HDD_H__
|
||||
|
||||
|
||||
// defines
|
||||
#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_DEVICE_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 HDF_DISABLED 0
|
||||
#define HDF_FILE 1
|
||||
#define HDF_TYPEMASK 15
|
||||
#define HDF_SYNTHRDB 128 // flag to indicate whether we should auto-synthesize a RigidDiskBlock
|
||||
|
||||
#define HDF_FILETYPE_UNKNOWN 0
|
||||
#define HDF_FILETYPE_NOTFOUND 1
|
||||
#define HDF_FILETYPE_RDB 2
|
||||
#define HDF_FILETYPE_DOS 3
|
||||
|
||||
|
||||
// types
|
||||
typedef struct
|
||||
{
|
||||
int type; // are we using a file, the entire SD card or a partition on the SD card?
|
||||
fileTYPE file;
|
||||
unsigned short cylinders;
|
||||
unsigned short heads;
|
||||
unsigned short sectors;
|
||||
unsigned short sectors_per_block;
|
||||
unsigned short partition; // partition no.
|
||||
long offset; // if a partition, the lba offset of the partition. Can be negative if we've synthesized an RDB.
|
||||
} hdfTYPE;
|
||||
|
||||
// variables
|
||||
extern char debugmsg[40];
|
||||
extern char debugmsg2[40];
|
||||
extern hdfTYPE hdf[2];
|
||||
|
||||
|
||||
// functions
|
||||
void IdentifyDevice(unsigned short *pBuffer, unsigned char unit);
|
||||
unsigned long chs2lba(unsigned short cylinder, unsigned char head, unsigned short sector, unsigned char unit);
|
||||
void WriteTaskFile(unsigned char error, unsigned char sector_count, unsigned char sector_number, unsigned char cylinder_low, unsigned char cylinder_high, unsigned char drive_head);
|
||||
void WriteStatus(unsigned char status);
|
||||
void HandleHDD(unsigned char c1, unsigned char c2);
|
||||
void GetHardfileGeometry(hdfTYPE *hdf);
|
||||
unsigned char HardFileSeek(hdfTYPE *hdf, unsigned long lba);
|
||||
unsigned char OpenHardfile(unsigned char unit);
|
||||
unsigned char GetHDFFileType(char *filename);
|
||||
|
||||
|
||||
#endif // __HDD_H__
|
||||
|
||||
88
hdd_internal.h
Normal file
88
hdd_internal.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#ifndef HDD_INTERNAL_H
|
||||
#define 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
|
||||
|
||||
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 */
|
||||
|
||||
652
ikbd.c
Normal file
652
ikbd.c
Normal file
@@ -0,0 +1,652 @@
|
||||
/*
|
||||
|
||||
http://removers.free.fr/wikipendium/wakka.php?wiki=IntelligentKeyboardBible
|
||||
https://www.kernel.org/doc/Documentation/input/atarikbd.txt
|
||||
|
||||
ikbd ToDo:
|
||||
|
||||
Feature Example using/needing it impl. tested
|
||||
---------------------------------------------------------------------
|
||||
mouse y at bottom Bolo X X
|
||||
mouse button key events Goldrunner/A_008 X X
|
||||
joystick interrogation mode Xevious/A_004 X X
|
||||
Absolute mouse mode Addicataball/A_050 X X
|
||||
disable mouse ? X
|
||||
disable joystick ? X
|
||||
Joysticks also generate Goldrunner X -X
|
||||
mouse button events!
|
||||
Pause/Resume PACMANIA_STE/Gembench X
|
||||
mouse keycode mode Goldrunner X X
|
||||
|
||||
Games that have ikbd problems:
|
||||
PowerMonger/PP_106 fixed
|
||||
Stardust fixed
|
||||
M1 tank platoon/A_385 fixed
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "user_io.h"
|
||||
#include "spi.h"
|
||||
#include "ikbd.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define IKBD_AUTO_MS 20
|
||||
|
||||
// atari ikbd stuff
|
||||
#define IKBD_STATE_JOYSTICK_EVENT_REPORTING 0x01
|
||||
#define IKBD_STATE_MOUSE_Y_BOTTOM 0x02
|
||||
#define IKBD_STATE_MOUSE_BUTTON_AS_KEY 0x04 // mouse buttons act like keys
|
||||
#define IKBD_STATE_MOUSE_DISABLED 0x08
|
||||
#define IKBD_STATE_MOUSE_ABSOLUTE 0x10
|
||||
#define IKBD_STATE_MOUSE_ABSOLUTE_IN_PROGRESS 0x20
|
||||
#define IKBD_STATE_WAIT4RESET 0x40
|
||||
#define IKBD_STATE_PAUSED 0x80
|
||||
|
||||
#define IKBD_DEFAULT IKBD_STATE_JOYSTICK_EVENT_REPORTING
|
||||
|
||||
/* ------------------- transmit queue ------------------- */
|
||||
#define QUEUE_LEN 16 // power of 2!
|
||||
static unsigned short tx_queue[QUEUE_LEN];
|
||||
static unsigned char wptr = 0, rptr = 0;
|
||||
static unsigned long ikbd_timer = 0;
|
||||
|
||||
/* -------- main structure to keep track of ikbd state -------- */
|
||||
static struct {
|
||||
unsigned char state;
|
||||
unsigned long auto_timer; // auto report timer (50hz/20ms)
|
||||
unsigned long rtc_timer;
|
||||
// ----- joystick state -------
|
||||
struct {
|
||||
unsigned char state; // current state
|
||||
unsigned char prev; // last reported state
|
||||
} joy[2];
|
||||
|
||||
// ----- mouse state -------
|
||||
struct {
|
||||
// current state
|
||||
unsigned char but, but_prev;
|
||||
short x, y;
|
||||
|
||||
struct {
|
||||
// absolute mouse state
|
||||
unsigned char buttons;
|
||||
struct { unsigned short x, y; } max;
|
||||
struct { unsigned char x, y; } scale;
|
||||
struct { unsigned short x, y; } pos;
|
||||
} abs;
|
||||
} mouse;
|
||||
|
||||
// ----- clock state ------
|
||||
unsigned char date[6];
|
||||
|
||||
unsigned int tx_cnt; // tx byte counter for debugging
|
||||
|
||||
// ----- buffer tp hold incoming commands ------
|
||||
struct {
|
||||
char size;
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned char code; // cmd code
|
||||
|
||||
// command specific structures
|
||||
union {
|
||||
unsigned char mouse_button_action;
|
||||
unsigned char reset;
|
||||
struct { unsigned short max_x, max_y; } __attribute__((packed)) abs_mouse_pos;
|
||||
struct { unsigned char dist_x, dist_y; } __attribute__((packed)) mouse_keycode;
|
||||
struct { unsigned char x, y; } __attribute__((packed)) mouse_threshold;
|
||||
struct { unsigned char x, y; } __attribute__((packed)) mouse_scale;
|
||||
struct { unsigned char f; unsigned short x, y; } __attribute__((packed)) load_mouse_pos;
|
||||
unsigned char date[6];
|
||||
};
|
||||
} __attribute__((packed)) command;
|
||||
|
||||
unsigned char byte[0];
|
||||
};
|
||||
} buffer;
|
||||
|
||||
} ikbd;
|
||||
|
||||
// read a 16 bit word in big endian
|
||||
unsigned short be16(unsigned short in) {
|
||||
return ((in & 0xff) << 8) + ((in & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
static void enqueue(unsigned short b) {
|
||||
if (((wptr + 1)&(QUEUE_LEN - 1)) == rptr)
|
||||
return;
|
||||
|
||||
tx_queue[wptr] = b;
|
||||
wptr = (wptr + 1)&(QUEUE_LEN - 1);
|
||||
}
|
||||
|
||||
unsigned char bcd2bin(unsigned char in) {
|
||||
return 10 * (in >> 4) + (in & 0x0f);
|
||||
}
|
||||
|
||||
unsigned char bin2bcd(unsigned char in) {
|
||||
return 16 * (in / 10) + (in % 10);
|
||||
}
|
||||
|
||||
// convert internal joystick format into atari ikbd format
|
||||
static unsigned char joystick_map2ikbd(unsigned char in) {
|
||||
unsigned char out = 0;
|
||||
|
||||
if (in & JOY_UP) out |= 0x01;
|
||||
if (in & JOY_DOWN) out |= 0x02;
|
||||
if (in & JOY_LEFT) out |= 0x04;
|
||||
if (in & JOY_RIGHT) out |= 0x08;
|
||||
if (in & JOY_BTN1) out |= 0x80;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void ikbd_handler_mouse_button_action(void) {
|
||||
unsigned char action = ikbd.buffer.command.mouse_button_action;
|
||||
ikbd_debugf("mouse button action = %d", action);
|
||||
|
||||
// bit 2: Mouse buttons act like keys (LEFT=0x74 & RIGHT=0x75)
|
||||
if (action & 0x04) ikbd.state |= IKBD_STATE_MOUSE_BUTTON_AS_KEY;
|
||||
else ikbd.state &= ~IKBD_STATE_MOUSE_BUTTON_AS_KEY;
|
||||
}
|
||||
|
||||
void ikbd_handler_set_relative_mouse_pos(void) {
|
||||
ikbd_debugf("Set relative mouse positioning");
|
||||
ikbd.state &= ~IKBD_STATE_MOUSE_DISABLED;
|
||||
ikbd.state &= ~IKBD_STATE_MOUSE_ABSOLUTE;
|
||||
}
|
||||
|
||||
void ikbd_handler_set_abs_mouse_pos(void) {
|
||||
ikbd.mouse.abs.max.x = be16(ikbd.buffer.command.abs_mouse_pos.max_x);
|
||||
ikbd.mouse.abs.max.y = be16(ikbd.buffer.command.abs_mouse_pos.max_y);
|
||||
|
||||
ikbd_debugf("Set absolute mouse positioning, max = %u/%u",
|
||||
ikbd.mouse.abs.max.x, ikbd.mouse.abs.max.y);
|
||||
|
||||
ikbd.state &= ~IKBD_STATE_MOUSE_DISABLED;
|
||||
ikbd.state |= IKBD_STATE_MOUSE_ABSOLUTE;
|
||||
ikbd.mouse.abs.buttons = 2 | 8;
|
||||
}
|
||||
|
||||
void ikbd_handler_set_mouse_keycode_mode(void) {
|
||||
ikbd_debugf("Set mouse keycode mode dist %u/%u",
|
||||
ikbd.buffer.command.mouse_keycode.dist_x,
|
||||
ikbd.buffer.command.mouse_keycode.dist_y);
|
||||
}
|
||||
|
||||
void ikbd_handler_set_mouse_threshold(void) {
|
||||
ikbd_debugf("Set mouse threshold %u/%u",
|
||||
ikbd.buffer.command.mouse_threshold.x,
|
||||
ikbd.buffer.command.mouse_threshold.y);
|
||||
}
|
||||
|
||||
void ikbd_handler_set_mouse_scale(void) {
|
||||
ikbd_debugf("Set mouse scale %u/%u",
|
||||
ikbd.buffer.command.mouse_scale.x,
|
||||
ikbd.buffer.command.mouse_scale.y);
|
||||
|
||||
ikbd.mouse.abs.scale.x = ikbd.buffer.command.mouse_scale.x;
|
||||
ikbd.mouse.abs.scale.y = ikbd.buffer.command.mouse_scale.y;
|
||||
}
|
||||
|
||||
void ikbd_handler_interrogate_mouse_pos(void) {
|
||||
// ikbd_debugf("Interrogate Mouse Position");
|
||||
if (ikbd.state & IKBD_STATE_MOUSE_ABSOLUTE) {
|
||||
|
||||
enqueue(0x8000 + 3); // 3ms delay, hatari uses 18000 cycles (~2.25ms)
|
||||
enqueue(0xf7);
|
||||
enqueue(ikbd.mouse.abs.buttons);
|
||||
enqueue(ikbd.mouse.abs.pos.x >> 8);
|
||||
enqueue(ikbd.mouse.abs.pos.x & 0xff);
|
||||
enqueue(ikbd.mouse.abs.pos.y >> 8);
|
||||
enqueue(ikbd.mouse.abs.pos.y & 0xff);
|
||||
|
||||
ikbd.mouse.abs.buttons = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ikbd_handler_load_mouse_pos(void) {
|
||||
ikbd.mouse.abs.pos.x = be16(ikbd.buffer.command.load_mouse_pos.x);
|
||||
ikbd.mouse.abs.pos.y = be16(ikbd.buffer.command.load_mouse_pos.y);
|
||||
|
||||
ikbd_debugf("Load mouse position %u/%u", ikbd.mouse.abs.pos.x, ikbd.mouse.abs.pos.y);
|
||||
}
|
||||
|
||||
void ikbd_handler_set_y_bottom(void) {
|
||||
ikbd_debugf("Set Y at bottom");
|
||||
ikbd.state |= IKBD_STATE_MOUSE_Y_BOTTOM;
|
||||
}
|
||||
|
||||
void ikbd_handler_set_y_top(void) {
|
||||
ikbd_debugf("Set Y at top");
|
||||
ikbd.state &= ~IKBD_STATE_MOUSE_Y_BOTTOM;
|
||||
}
|
||||
|
||||
void ikbd_handler_resume(void) {
|
||||
ikbd.state &= ~IKBD_STATE_PAUSED;
|
||||
}
|
||||
|
||||
void ikbd_handler_disable_mouse(void) {
|
||||
ikbd_debugf("Disable mouse");
|
||||
ikbd.state |= IKBD_STATE_MOUSE_DISABLED;
|
||||
}
|
||||
|
||||
void ikbd_handler_pause(void) {
|
||||
ikbd.state |= IKBD_STATE_PAUSED;
|
||||
}
|
||||
|
||||
void ikbd_handler_set_joystick_event_reporting(void) {
|
||||
ikbd_debugf("Set Joystick event reporting");
|
||||
ikbd.state |= IKBD_STATE_JOYSTICK_EVENT_REPORTING;
|
||||
ikbd.state &= ~IKBD_STATE_PAUSED;
|
||||
}
|
||||
|
||||
void ikbd_handler_set_joystick_interrogation_mode(void) {
|
||||
ikbd_debugf("Set Joystick interrogation mode");
|
||||
ikbd.state &= ~IKBD_STATE_JOYSTICK_EVENT_REPORTING;
|
||||
ikbd.state &= ~IKBD_STATE_PAUSED;
|
||||
}
|
||||
|
||||
void ikbd_handler_interrogate_joystick(void) {
|
||||
// send reply
|
||||
enqueue(0xfd);
|
||||
enqueue(ikbd.joy[0].state | ((ikbd.mouse.but & (1 << 0)) ? 0x80 : 0x00));
|
||||
enqueue(ikbd.joy[1].state | ((ikbd.mouse.but & (1 << 1)) ? 0x80 : 0x00));
|
||||
}
|
||||
|
||||
void ikbd_handler_disable_joysticks(void) {
|
||||
ikbd_debugf("Disable joysticks");
|
||||
ikbd.state &= ~IKBD_STATE_JOYSTICK_EVENT_REPORTING;
|
||||
}
|
||||
|
||||
void ikbd_handler_time_set(void) {
|
||||
unsigned char c;
|
||||
for (c = 0; c<6; c++)
|
||||
ikbd.date[c] = bcd2bin(ikbd.buffer.command.date[c]);
|
||||
|
||||
// release SPI since it will be used by usb when
|
||||
// reading the time from the rtc
|
||||
DisableIO();
|
||||
|
||||
// try to set time on rtc if present
|
||||
//usb_rtc_set_time(ikbd.date);
|
||||
|
||||
spi_uio_cmd_cont(UIO_IKBD_IN);
|
||||
|
||||
ikbd_debugf("Time of day clock set: %u:%02u:%02u %u.%u.%u",
|
||||
ikbd.date[3], ikbd.date[4], ikbd.date[5],
|
||||
ikbd.date[2], ikbd.date[1], 1900 + ikbd.date[0]);
|
||||
}
|
||||
|
||||
void ikbd_handler_interrogate_time(void) {
|
||||
unsigned char i;
|
||||
|
||||
// release SPI since it will be used by usb when
|
||||
// reading the time from the rtc
|
||||
DisableIO();
|
||||
|
||||
// try to fetch time from rtc if present
|
||||
//usb_rtc_get_time(ikbd.date);
|
||||
|
||||
spi_uio_cmd_cont(UIO_IKBD_IN);
|
||||
|
||||
ikbd_debugf("Interrogate time of day %u:%02u:%02u %u.%u.%u",
|
||||
ikbd.date[3], ikbd.date[4], ikbd.date[5],
|
||||
ikbd.date[2], ikbd.date[1], 1900 + ikbd.date[0]);
|
||||
|
||||
enqueue(0x8000 + 64); // wait 64ms
|
||||
enqueue(0xfc);
|
||||
for (i = 0; i<6; i++) enqueue(bin2bcd(ikbd.date[i]));
|
||||
}
|
||||
|
||||
void ikbd_handler_reset(void) {
|
||||
ikbd_debugf("Reset %x", ikbd.buffer.command.reset);
|
||||
|
||||
if (ikbd.buffer.command.reset == 1) {
|
||||
ikbd.state = IKBD_DEFAULT;
|
||||
|
||||
enqueue(0x8000 + 300); // wait 300ms
|
||||
enqueue(0xf0);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- list of supported ikbd commands ----
|
||||
struct {
|
||||
unsigned char code;
|
||||
unsigned char length;
|
||||
void(*handler)(void);
|
||||
} ikbd_command_handler[] = {
|
||||
{ 0x07, 2, ikbd_handler_mouse_button_action },
|
||||
{ 0x08, 1, ikbd_handler_set_relative_mouse_pos },
|
||||
{ 0x09, 5, ikbd_handler_set_abs_mouse_pos },
|
||||
{ 0x0a, 3, ikbd_handler_set_mouse_keycode_mode },
|
||||
{ 0x0b, 3, ikbd_handler_set_mouse_threshold },
|
||||
{ 0x0c, 3, ikbd_handler_set_mouse_scale },
|
||||
{ 0x0d, 1, ikbd_handler_interrogate_mouse_pos },
|
||||
{ 0x0e, 6, ikbd_handler_load_mouse_pos },
|
||||
{ 0x0f, 1, ikbd_handler_set_y_bottom },
|
||||
{ 0x10, 1, ikbd_handler_set_y_top },
|
||||
{ 0x11, 1, ikbd_handler_resume },
|
||||
{ 0x12, 1, ikbd_handler_disable_mouse },
|
||||
{ 0x13, 1, ikbd_handler_pause },
|
||||
{ 0x14, 1, ikbd_handler_set_joystick_event_reporting },
|
||||
{ 0x15, 1, ikbd_handler_set_joystick_interrogation_mode },
|
||||
{ 0x16, 1, ikbd_handler_interrogate_joystick },
|
||||
{ 0x1a, 1, ikbd_handler_disable_joysticks },
|
||||
{ 0x1c, 1, ikbd_handler_interrogate_time },
|
||||
{ 0x1b, 7, ikbd_handler_time_set },
|
||||
{ 0x80, 2, ikbd_handler_reset },
|
||||
{ 0, 0, NULL } // end of list
|
||||
};
|
||||
|
||||
void ikbd_init() {
|
||||
// reset ikbd state
|
||||
memset(&ikbd, 0, sizeof(ikbd));
|
||||
ikbd.state = IKBD_DEFAULT | IKBD_STATE_WAIT4RESET;
|
||||
|
||||
ikbd.mouse.abs.max.x = ikbd.mouse.abs.max.y = 65535;
|
||||
ikbd.mouse.abs.scale.x = ikbd.mouse.abs.scale.y = 1;
|
||||
|
||||
ikbd_debugf("Init");
|
||||
|
||||
// init ikbd date to some default
|
||||
ikbd.date[0] = 113;
|
||||
ikbd.date[1] = 7;
|
||||
ikbd.date[2] = 20;
|
||||
ikbd.date[3] = 20;
|
||||
ikbd.date[4] = 58;
|
||||
|
||||
// handle auto events
|
||||
ikbd.auto_timer = GetTimer(0);
|
||||
ikbd.rtc_timer = GetTimer(1000);
|
||||
}
|
||||
|
||||
void ikbd_reset(void) {
|
||||
ikbd.tx_cnt = 0;
|
||||
ikbd.state |= IKBD_STATE_WAIT4RESET;
|
||||
}
|
||||
|
||||
// process inout from atari core into ikbd
|
||||
void ikbd_handle_input(unsigned char cmd) {
|
||||
// store byte in buffer
|
||||
ikbd.buffer.byte[ikbd.buffer.size++] = cmd;
|
||||
|
||||
// check if there's a known command in the buffer
|
||||
char c;
|
||||
for (c = 0; ikbd_command_handler[c].length &&
|
||||
(ikbd_command_handler[c].code != ikbd.buffer.command.code); c++);
|
||||
|
||||
// not a valid command? -> flush buffer
|
||||
if (!ikbd_command_handler[c].length)
|
||||
ikbd.buffer.size = 0;
|
||||
else {
|
||||
// valid command and enough bytes?
|
||||
if (ikbd_command_handler[c].length == ikbd.buffer.size) {
|
||||
ikbd_command_handler[c].handler();
|
||||
ikbd.buffer.size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// advance the ikbd time by one second
|
||||
static void ikbd_update_time()
|
||||
{
|
||||
static const char mdays[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
short year = 1900 + ikbd.date[0];
|
||||
char is_leap = (!(year % 4) && (year % 100)) || !(year % 400);
|
||||
|
||||
// advance seconds
|
||||
ikbd.date[5]++;
|
||||
if (ikbd.date[5] == 60)
|
||||
{
|
||||
ikbd.date[5] = 0;
|
||||
|
||||
// advance minutes
|
||||
ikbd.date[4]++;
|
||||
if (ikbd.date[4] == 60)
|
||||
{
|
||||
ikbd.date[4] = 0;
|
||||
|
||||
// advance hours
|
||||
ikbd.date[3]++;
|
||||
if (ikbd.date[3] == 24)
|
||||
{
|
||||
ikbd.date[3] = 0;
|
||||
|
||||
// advance days
|
||||
ikbd.date[2]++;
|
||||
if ((ikbd.date[2] == mdays[ikbd.date[1] - 1] + 1) ||
|
||||
(is_leap && (ikbd.date[1] == 2) && (ikbd.date[2] == 29)))
|
||||
{
|
||||
ikbd.date[2] = 1;
|
||||
|
||||
// advance month
|
||||
ikbd.date[1]++;
|
||||
if (ikbd.date[1] == 13)
|
||||
{
|
||||
ikbd.date[1] = 0;
|
||||
|
||||
// advance year
|
||||
ikbd.date[0]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ikbd_poll(void) {
|
||||
#ifdef IKBD_DEBUG
|
||||
static unsigned long xtimer = 0;
|
||||
static int last_cnt = 0;
|
||||
if (CheckTimer(xtimer)) {
|
||||
xtimer = GetTimer(2000);
|
||||
if (ikbd.tx_cnt != last_cnt) {
|
||||
ikbd_debugf("sent bytes: %d", ikbd.tx_cnt);
|
||||
last_cnt = ikbd.tx_cnt;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (CheckTimer(ikbd.rtc_timer))
|
||||
{
|
||||
ikbd.rtc_timer = GetTimer(1000);
|
||||
ikbd_update_time();
|
||||
}
|
||||
|
||||
// do auto events every 20ms
|
||||
if (CheckTimer(ikbd.auto_timer)) {
|
||||
ikbd.auto_timer = GetTimer(IKBD_AUTO_MS);
|
||||
|
||||
if (!(ikbd.state & IKBD_STATE_WAIT4RESET) &&
|
||||
!(ikbd.state & IKBD_STATE_PAUSED)) {
|
||||
|
||||
/* --------- joystick ---------- */
|
||||
if (ikbd.state & IKBD_STATE_JOYSTICK_EVENT_REPORTING) {
|
||||
char i;
|
||||
for (i = 0; i<2; i++) {
|
||||
unsigned char state = ikbd.joy[i].state;
|
||||
|
||||
// left mouse button 1 is also joystick 0 fire button
|
||||
// right mouse button 0 is also joystick 1 fire button
|
||||
if (ikbd.mouse.but & (2 >> i)) state |= 0x80;
|
||||
|
||||
if (state != ikbd.joy[i].prev) {
|
||||
// iprintf("JOY%d: %x\n", i, state);
|
||||
enqueue(0xfe + i);
|
||||
enqueue(state);
|
||||
ikbd.joy[i].prev = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------- relative mouse ---------- */
|
||||
if (!(ikbd.state & IKBD_STATE_MOUSE_DISABLED) &&
|
||||
!(ikbd.state & IKBD_STATE_MOUSE_ABSOLUTE)) {
|
||||
unsigned char b = ikbd.mouse.but;
|
||||
|
||||
// include joystick buttons into mouse state
|
||||
if (ikbd.joy[0].state & 0x80) b |= 2;
|
||||
if (ikbd.joy[1].state & 0x80) b |= 1;
|
||||
|
||||
if (ikbd.mouse.x || ikbd.mouse.y || (b != ikbd.mouse.but_prev)) {
|
||||
do {
|
||||
char x, y;
|
||||
if (ikbd.mouse.x < -128) x = -128;
|
||||
else if (ikbd.mouse.x > 127) x = 127;
|
||||
else x = ikbd.mouse.x;
|
||||
|
||||
if (ikbd.mouse.y < -128) y = -128;
|
||||
else if (ikbd.mouse.y > 127) y = 127;
|
||||
else y = ikbd.mouse.y;
|
||||
|
||||
// iprintf("RMOUSE: %x %x %x\n", b, x&0xff, y&0xff);
|
||||
enqueue(0xf8 | b);
|
||||
enqueue(x & 0xff);
|
||||
enqueue(y & 0xff);
|
||||
|
||||
ikbd.mouse.x -= x;
|
||||
ikbd.mouse.y -= y;
|
||||
|
||||
} while (ikbd.mouse.x || ikbd.mouse.y);
|
||||
|
||||
// check if mouse buttons are supposed to be treated like keys
|
||||
if (ikbd.state & IKBD_STATE_MOUSE_BUTTON_AS_KEY) {
|
||||
|
||||
// check if mouse button state has changed
|
||||
if (b != ikbd.mouse.but_prev) {
|
||||
// Mouse buttons act like keys (LEFT=0x74 & RIGHT=0x75)
|
||||
|
||||
// handle left mouse button
|
||||
if ((b ^ ikbd.mouse.but_prev) & 2) ikbd_keyboard(0x74 | ((b & 2) ? 0x00 : 0x80));
|
||||
// handle right mouse button
|
||||
if ((b ^ ikbd.mouse.but_prev) & 1) ikbd_keyboard(0x75 | ((b & 1) ? 0x00 : 0x80));
|
||||
}
|
||||
}
|
||||
|
||||
ikbd.mouse.but_prev = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long mtimer = 0;
|
||||
if (CheckTimer(mtimer)) {
|
||||
mtimer = GetTimer(10);
|
||||
|
||||
// check for incoming ikbd data
|
||||
spi_uio_cmd_cont(UIO_IKBD_IN);
|
||||
|
||||
while (spi_in())
|
||||
ikbd_handle_input(spi_in());
|
||||
|
||||
DisableIO();
|
||||
}
|
||||
|
||||
// everything below must not happen faster than 1khz
|
||||
static unsigned long rtimer = 0;
|
||||
if (!CheckTimer(rtimer))
|
||||
return;
|
||||
|
||||
// next event 1 ms later
|
||||
rtimer = GetTimer(1);
|
||||
|
||||
// timer active?
|
||||
if (ikbd_timer) {
|
||||
if (!CheckTimer(ikbd_timer))
|
||||
return;
|
||||
|
||||
ikbd_timer = 0;
|
||||
}
|
||||
|
||||
if (rptr == wptr) return;
|
||||
|
||||
if (tx_queue[rptr] & 0x8000) {
|
||||
|
||||
// request to start timer?
|
||||
if (tx_queue[rptr] & 0x8000)
|
||||
ikbd_timer = GetTimer(tx_queue[rptr] & 0x3fff);
|
||||
|
||||
rptr = (rptr + 1)&(QUEUE_LEN - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// transmit data from queue
|
||||
spi_uio_cmd_cont(UIO_IKBD_OUT);
|
||||
spi8(tx_queue[rptr]);
|
||||
DisableIO();
|
||||
|
||||
ikbd.tx_cnt++;
|
||||
|
||||
rptr = (rptr + 1)&(QUEUE_LEN - 1);
|
||||
}
|
||||
|
||||
// called from external parts to report joystick states
|
||||
void ikbd_joystick(unsigned char joystick, unsigned char map) {
|
||||
ikbd.joy[joystick].state = joystick_map2ikbd(map);
|
||||
}
|
||||
|
||||
void ikbd_keyboard(unsigned char code) {
|
||||
#ifdef IKBD_DEBUG
|
||||
ikbd_debugf("send keycode %x%s", code & 0x7f, (code & 0x80) ? " BREAK" : "");
|
||||
#endif
|
||||
enqueue(code);
|
||||
}
|
||||
|
||||
void ikbd_mouse(unsigned char b, char x, char y) {
|
||||
|
||||
// honour reversal of y axis
|
||||
if (ikbd.state & IKBD_STATE_MOUSE_Y_BOTTOM)
|
||||
y = -y;
|
||||
|
||||
// update relative mouse state
|
||||
ikbd.mouse.but = ((b & 1) ? 2 : 0) | ((b & 2) ? 1 : 0);
|
||||
ikbd.mouse.x += x;
|
||||
ikbd.mouse.y += y;
|
||||
|
||||
// save button state for absolute mouse reports
|
||||
|
||||
if (ikbd.state & IKBD_STATE_MOUSE_ABSOLUTE) {
|
||||
// include joystick buttons into mouse state
|
||||
if (ikbd.joy[0].state & 0x80) b |= 2;
|
||||
if (ikbd.joy[1].state & 0x80) b |= 1;
|
||||
|
||||
if (b & 2) ikbd.mouse.abs.buttons |= 1;
|
||||
else ikbd.mouse.abs.buttons |= 2;
|
||||
if (b & 1) ikbd.mouse.abs.buttons |= 4;
|
||||
else ikbd.mouse.abs.buttons |= 8;
|
||||
|
||||
if (ikbd.mouse.abs.scale.x > 1) x *= ikbd.mouse.abs.scale.x;
|
||||
if (ikbd.mouse.abs.scale.y > 1) y *= ikbd.mouse.abs.scale.y;
|
||||
|
||||
// ikbd_debugf("abs inc %d %d -> ", x, y);
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
|
||||
if (ikbd.mouse.abs.pos.x > x) ikbd.mouse.abs.pos.x -= x;
|
||||
else ikbd.mouse.abs.pos.x = 0;
|
||||
}
|
||||
else if (x > 0) {
|
||||
if (ikbd.mouse.abs.pos.x < ikbd.mouse.abs.max.x - x)
|
||||
ikbd.mouse.abs.pos.x += x;
|
||||
else
|
||||
ikbd.mouse.abs.pos.x = ikbd.mouse.abs.max.x;
|
||||
}
|
||||
|
||||
if (y < 0) {
|
||||
y = -y;
|
||||
if (ikbd.mouse.abs.pos.y > y) ikbd.mouse.abs.pos.y -= y;
|
||||
else ikbd.mouse.abs.pos.y = 0;
|
||||
}
|
||||
else if (y > 0) {
|
||||
if (ikbd.mouse.abs.pos.y < ikbd.mouse.abs.max.y - y)
|
||||
ikbd.mouse.abs.pos.y += y;
|
||||
else
|
||||
ikbd.mouse.abs.pos.y = ikbd.mouse.abs.max.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
ikbd.h
Normal file
11
ikbd.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef IKBD_H
|
||||
#define IKBD_H
|
||||
|
||||
void ikbd_init(void);
|
||||
void ikbd_poll(void);
|
||||
void ikbd_reset(void);
|
||||
void ikbd_joystick(unsigned char joy, unsigned char map);
|
||||
void ikbd_mouse(unsigned char buttons, char x, char y);
|
||||
void ikbd_keyboard(unsigned char code);
|
||||
|
||||
#endif // IKBD_H
|
||||
368
ini_parser.c
Normal file
368
ini_parser.c
Normal file
@@ -0,0 +1,368 @@
|
||||
// ini_parser.c
|
||||
// 2015, rok.krajnc@gmail.com
|
||||
|
||||
|
||||
//// includes ////
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <ctype.h>
|
||||
#include "ini_parser.h"
|
||||
#include "debug.h"
|
||||
#include "file_io.h"
|
||||
#include "user_io.h"
|
||||
|
||||
//// defines ////
|
||||
#define INI_EOT 4 // End-Of-Transmission
|
||||
|
||||
#define INI_BUF_SIZE 512
|
||||
#define INI_LINE_SIZE 65
|
||||
|
||||
#define INI_SECTION_START '['
|
||||
#define INI_SECTION_END ']'
|
||||
#define INI_SECTION_INVALID_ID 0
|
||||
|
||||
|
||||
//// macros ////
|
||||
#define CHAR_IS_NUM(c) (((c) >= '0') && ((c) <= '9'))
|
||||
#define CHAR_IS_ALPHA_LOWER(c) (((c) >= 'a') && ((c) <= 'z'))
|
||||
#define CHAR_IS_ALPHA_UPPER(c) (((c) >= 'A') && ((c) <= 'Z'))
|
||||
#define CHAR_IS_ALPHA(c) (CHAR_IS_ALPHA_LOWER(c) || CHAR_IS_ALPHA_UPPER(c))
|
||||
#define CHAR_IS_ALPHANUM(c) (CHAR_IS_ALPHA_LOWER(c) || CHAR_IS_ALPHA_UPPER(c) || CHAR_IS_NUM(c))
|
||||
#define CHAR_IS_SPECIAL(c) (((c) == '[') || ((c) == ']') || ((c) == '-') || ((c) == '_') || ((c) == ',') || ((c) == '='))
|
||||
#define CHAR_IS_VALID(c) (CHAR_IS_ALPHANUM(c) || CHAR_IS_SPECIAL(c))
|
||||
#define CHAR_IS_WHITESPACE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\r') || ((c) == '\n'))
|
||||
#define CHAR_IS_SPACE(c) (((c) == ' ') || ((c) == '\t'))
|
||||
#define CHAR_IS_LINEEND(c) (((c) == '\n'))
|
||||
#define CHAR_IS_COMMENT(c) (((c) == ';'))
|
||||
#define CHAR_IS_QUOTE(c) (((c) == '"'))
|
||||
|
||||
|
||||
fileTYPE ini_file;
|
||||
static uint8_t buf[512];
|
||||
|
||||
int ini_pt = 0;
|
||||
|
||||
//// ini_getch() ////
|
||||
char ini_getch()
|
||||
{
|
||||
if ((ini_pt & 0x3ff) == 0x200)
|
||||
{
|
||||
// reload buffer
|
||||
FileReadSec(&ini_file, buf);
|
||||
}
|
||||
|
||||
if (ini_pt >= ini_file.size) return 0;
|
||||
else return buf[(ini_pt++) & 0x1ff];
|
||||
}
|
||||
|
||||
//// ini_putch() ////
|
||||
int ini_putch(char c)
|
||||
{
|
||||
static int ini_pt = 0;
|
||||
|
||||
buf[ini_pt++] = c;
|
||||
|
||||
if ((ini_pt % 0x3ff) == 0x200)
|
||||
{
|
||||
// write buffer
|
||||
ini_pt = 0;
|
||||
}
|
||||
return ini_pt;
|
||||
}
|
||||
|
||||
|
||||
//// ini_findch() ////
|
||||
char ini_findch(char c)
|
||||
{
|
||||
char t;
|
||||
do {
|
||||
t = ini_getch();
|
||||
} while ((t != 0) && (t != c));
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
//// ini_getline() ////
|
||||
int ini_getline(char* line)
|
||||
{
|
||||
char c;
|
||||
char ignore = 0;
|
||||
char literal = 0;
|
||||
int i = 0;
|
||||
|
||||
while (i<(INI_LINE_SIZE - 1)) {
|
||||
c = ini_getch();
|
||||
if ((!c) || CHAR_IS_LINEEND(c)) break;
|
||||
else if (CHAR_IS_QUOTE(c)) literal ^= 1;
|
||||
else if (CHAR_IS_COMMENT(c) && !ignore && !literal) ignore++;
|
||||
else if (literal) line[i++] = c;
|
||||
else if (CHAR_IS_VALID(c) && !ignore) line[i++] = c;
|
||||
}
|
||||
line[i] = '\0';
|
||||
return c == 0 ? INI_EOT : literal ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
//// ini_putline() ////
|
||||
int ini_putline(char* line)
|
||||
{
|
||||
int ini_pt, i = 0;
|
||||
|
||||
while (i<(INI_LINE_SIZE - 1)) {
|
||||
if (!line[i]) break;
|
||||
ini_pt = ini_putch(line[i++]);
|
||||
}
|
||||
return ini_pt;
|
||||
}
|
||||
|
||||
char *get_core_name()
|
||||
{
|
||||
switch (user_io_core_type())
|
||||
{
|
||||
case CORE_TYPE_MINIMIG2:
|
||||
return "MINIMIG";
|
||||
|
||||
case CORE_TYPE_PACE:
|
||||
return "PACE";
|
||||
|
||||
case CORE_TYPE_MIST:
|
||||
return "ST";
|
||||
|
||||
case CORE_TYPE_ARCHIE:
|
||||
return "ARCHIE";
|
||||
|
||||
case CORE_TYPE_8BIT:
|
||||
return user_io_get_core_name();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
//// ini_get_section() ////
|
||||
int ini_get_section(const ini_cfg_t* cfg, char* buf)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// get section start marker
|
||||
if (buf[0] != INI_SECTION_START) {
|
||||
return INI_SECTION_INVALID_ID;
|
||||
}
|
||||
else buf++;
|
||||
|
||||
// get section stop marker
|
||||
while (1) {
|
||||
if (buf[i] == INI_SECTION_END) {
|
||||
buf[i] = '\0';
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
if (i >= INI_LINE_SIZE) {
|
||||
return INI_SECTION_INVALID_ID;
|
||||
}
|
||||
}
|
||||
|
||||
// convert to uppercase
|
||||
for (i = 0; i<INI_LINE_SIZE; i++) {
|
||||
if (!buf[i]) break;
|
||||
else buf[i] = toupper(buf[i]);
|
||||
}
|
||||
|
||||
// parse section
|
||||
for (i = 0; i<cfg->nsections; i++) {
|
||||
if (!strcasecmp(buf, cfg->sections[i].name)) {
|
||||
ini_parser_debugf("Got SECTION '%s' with ID %d", buf, cfg->sections[i].id);
|
||||
return cfg->sections[i].id;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcasecmp(buf, get_core_name())) return cfg->sections[0].id;
|
||||
|
||||
return INI_SECTION_INVALID_ID;
|
||||
}
|
||||
|
||||
|
||||
//// ini_get_var() ////
|
||||
void* ini_get_var(const ini_cfg_t* cfg, int cur_section, char* buf)
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
int var_id = -1;
|
||||
|
||||
// find var
|
||||
while (1) {
|
||||
if (buf[i] == '=') {
|
||||
buf[i] = '\0';
|
||||
break;
|
||||
}
|
||||
else if (buf[i] == '\0') return (void*)0;
|
||||
i++;
|
||||
}
|
||||
|
||||
// convert to uppercase
|
||||
for (j = 0; j <= i; j++) {
|
||||
if (!buf[j]) break;
|
||||
else buf[j] = toupper(buf[j]);
|
||||
}
|
||||
|
||||
// parse var
|
||||
for (j = 0; j<cfg->nvars; j++) {
|
||||
if ((!strcasecmp(buf, cfg->vars[j].name)) && (cfg->vars[j].section_id == cur_section)) var_id = j;
|
||||
}
|
||||
|
||||
// get data
|
||||
if (var_id != -1) {
|
||||
ini_parser_debugf("Got VAR '%s' with VALUE %s", buf, &(buf[i + 1]));
|
||||
i++;
|
||||
switch (cfg->vars[var_id].type) {
|
||||
case UINT8:
|
||||
*(uint8_t*)(cfg->vars[var_id].var) = strtoul(&(buf[i]), NULL, 0);
|
||||
if (*(uint8_t*)(cfg->vars[var_id].var) > cfg->vars[var_id].max) *(uint8_t*)(cfg->vars[var_id].var) = cfg->vars[var_id].max;
|
||||
if (*(uint8_t*)(cfg->vars[var_id].var) < cfg->vars[var_id].min) *(uint8_t*)(cfg->vars[var_id].var) = cfg->vars[var_id].min;
|
||||
break;
|
||||
case INT8:
|
||||
*(int8_t*)(cfg->vars[var_id].var) = strtol(&(buf[i]), NULL, 0);
|
||||
if (*(int8_t*)(cfg->vars[var_id].var) > cfg->vars[var_id].max) *(int8_t*)(cfg->vars[var_id].var) = cfg->vars[var_id].max;
|
||||
if (*(int8_t*)(cfg->vars[var_id].var) < cfg->vars[var_id].min) *(int8_t*)(cfg->vars[var_id].var) = cfg->vars[var_id].min;
|
||||
break;
|
||||
case UINT16:
|
||||
*(uint16_t*)(cfg->vars[var_id].var) = strtoul(&(buf[i]), NULL, 0);
|
||||
if (*(uint16_t*)(cfg->vars[var_id].var) > cfg->vars[var_id].max) *(uint16_t*)(cfg->vars[var_id].var) = cfg->vars[var_id].max;
|
||||
if (*(uint16_t*)(cfg->vars[var_id].var) < cfg->vars[var_id].min) *(uint16_t*)(cfg->vars[var_id].var) = cfg->vars[var_id].min;
|
||||
break;
|
||||
case INT16:
|
||||
*(int16_t*)(cfg->vars[var_id].var) = strtol(&(buf[i]), NULL, 0);
|
||||
if (*(int16_t*)(cfg->vars[var_id].var) > cfg->vars[var_id].max) *(int16_t*)(cfg->vars[var_id].var) = cfg->vars[var_id].max;
|
||||
if (*(int16_t*)(cfg->vars[var_id].var) < cfg->vars[var_id].min) *(int16_t*)(cfg->vars[var_id].var) = cfg->vars[var_id].min;
|
||||
break;
|
||||
case UINT32:
|
||||
*(uint32_t*)(cfg->vars[var_id].var) = strtoul(&(buf[i]), NULL, 0);
|
||||
if (*(uint32_t*)(cfg->vars[var_id].var) > (uint32_t)cfg->vars[var_id].max) *(uint32_t*)(cfg->vars[var_id].var) = cfg->vars[var_id].max;
|
||||
if (*(uint32_t*)(cfg->vars[var_id].var) < (uint32_t)cfg->vars[var_id].min) *(uint32_t*)(cfg->vars[var_id].var) = cfg->vars[var_id].min;
|
||||
break;
|
||||
case INT32:
|
||||
*(int32_t*)(cfg->vars[var_id].var) = strtol(&(buf[i]), NULL, 0);
|
||||
if (*(int32_t*)(cfg->vars[var_id].var) > cfg->vars[var_id].max) *(int32_t*)(cfg->vars[var_id].var) = cfg->vars[var_id].max;
|
||||
if (*(int32_t*)(cfg->vars[var_id].var) < cfg->vars[var_id].min) *(int32_t*)(cfg->vars[var_id].var) = cfg->vars[var_id].min;
|
||||
break;
|
||||
case FLOAT:
|
||||
*(float*)(cfg->vars[var_id].var) = strtof(&(buf[i]), NULL);
|
||||
if (*(float*)(cfg->vars[var_id].var) > cfg->vars[var_id].max) *(float*)(cfg->vars[var_id].var) = cfg->vars[var_id].max;
|
||||
if (*(float*)(cfg->vars[var_id].var) < cfg->vars[var_id].min) *(float*)(cfg->vars[var_id].var) = cfg->vars[var_id].min;
|
||||
break;
|
||||
case STRING:
|
||||
strncpy((char*)(cfg->vars[var_id].var), &(buf[i]), cfg->vars[var_id].max);
|
||||
break;
|
||||
case CUSTOM_HANDLER:
|
||||
((custom_handler_t*)(cfg->vars[var_id].var))(&(buf[i]));
|
||||
break;
|
||||
}
|
||||
return (void*)(&(cfg->vars[var_id].var));
|
||||
}
|
||||
|
||||
return (void*)0;
|
||||
}
|
||||
|
||||
|
||||
//// ini_parse() ////
|
||||
void ini_parse(const ini_cfg_t* cfg)
|
||||
{
|
||||
char line[INI_LINE_SIZE] = { 0 };
|
||||
int section = INI_SECTION_INVALID_ID;
|
||||
int line_status;
|
||||
|
||||
ini_parser_debugf("Start INI parser for core \"%s\".", get_core_name());
|
||||
|
||||
memset(&ini_file, 0, sizeof(ini_file));
|
||||
if (!FileOpen(&ini_file, cfg->filename))
|
||||
{
|
||||
ini_parser_debugf("Can't open file %s !", cfg->filename);
|
||||
return;
|
||||
}
|
||||
|
||||
ini_parser_debugf("Opened file %s with size %d bytes.", cfg->filename, ini_file.size);
|
||||
|
||||
ini_pt = 0;
|
||||
|
||||
// preload buffer
|
||||
FileReadSec(&ini_file, buf);
|
||||
|
||||
// parse ini
|
||||
while (1)
|
||||
{
|
||||
// get line
|
||||
line_status = ini_getline(line);
|
||||
ini_parser_debugf("line(%d): \"%s\".", line_status, line);
|
||||
// if valid line
|
||||
if (line_status != 1)
|
||||
{
|
||||
if (line[0] == INI_SECTION_START)
|
||||
{
|
||||
// if first char in line is INI_SECTION_START, get section
|
||||
section = ini_get_section(cfg, line);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise this is a variable, get it
|
||||
ini_get_var(cfg, section, line);
|
||||
}
|
||||
}
|
||||
// if end of file, stop
|
||||
if (line_status == INI_EOT) break;
|
||||
}
|
||||
|
||||
FileClose(&ini_file);
|
||||
}
|
||||
|
||||
//// ini_save() ////
|
||||
void ini_save(const ini_cfg_t* cfg)
|
||||
{
|
||||
// Not fully implemented yet.
|
||||
|
||||
/*
|
||||
int section, var, ini_pt;
|
||||
char line[INI_LINE_SIZE] = { 0 };
|
||||
|
||||
// open ini file
|
||||
ini_parser_debugf("Can't open file %s !", cfg->filename);
|
||||
return;
|
||||
|
||||
// loop over sections
|
||||
for (section = 0; section<cfg->nsections; section++) {
|
||||
ini_parser_debugf("writing section %s ...", cfg->sections[section].name);
|
||||
siprintf(line, "[%s]\n", cfg->sections[section].name);
|
||||
ini_pt = ini_putline(line);
|
||||
// loop over vars
|
||||
for (var = 0; var<cfg->nvars; var++) {
|
||||
if (cfg->vars[var].section_id == cfg->sections[section].id) {
|
||||
ini_parser_debugf("writing var %s", cfg->vars[var].name);
|
||||
switch (cfg->vars[var].type) {
|
||||
case UINT8:
|
||||
case UINT16:
|
||||
case UINT32:
|
||||
siprintf(line, "%s=%u\n", cfg->vars[var].name, *(uint32_t*)(cfg->vars[var].var));
|
||||
break;
|
||||
case INT8:
|
||||
case INT16:
|
||||
case INT32:
|
||||
siprintf(line, "%s=%d\n", cfg->vars[var].name, *(int32_t*)(cfg->vars[var].var));
|
||||
break;
|
||||
case FLOAT:
|
||||
siprintf(line, "%s=%f\n", cfg->vars[var].name, *(float*)(cfg->vars[var].var));
|
||||
break;
|
||||
case STRING:
|
||||
siprintf(line, "%s=\"%s\"\n", cfg->vars[var].name, (char*)(cfg->vars[var].var));
|
||||
break;
|
||||
}
|
||||
ini_pt = ini_putline(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// in case the buffer is not written yet, write it now
|
||||
if (ini_pt)
|
||||
{
|
||||
//fwrite(buf, sizeof(char), ini_pt, ini_fp);
|
||||
}
|
||||
*/
|
||||
}
|
||||
47
ini_parser.h
Normal file
47
ini_parser.h
Normal file
@@ -0,0 +1,47 @@
|
||||
// ini_parser.h
|
||||
// 2015, rok.krajnc@gmail.com
|
||||
|
||||
#ifndef __INI_PARSER_H__
|
||||
#define __INI_PARSER_H__
|
||||
|
||||
//// includes ////
|
||||
#include <inttypes.h>
|
||||
|
||||
|
||||
//// type definitions ////
|
||||
typedef struct {
|
||||
int id;
|
||||
char* name;
|
||||
} ini_section_t;
|
||||
|
||||
typedef enum {
|
||||
UINT8 = 0, INT8, UINT16, INT16, UINT32, INT32, FLOAT,
|
||||
STRING, CUSTOM_HANDLER
|
||||
} ini_vartypes_t;
|
||||
|
||||
typedef void custom_handler_t(char*);
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
void* var;
|
||||
ini_vartypes_t type;
|
||||
int min;
|
||||
int max;
|
||||
int section_id;
|
||||
} ini_var_t;
|
||||
|
||||
typedef struct {
|
||||
const char* filename;
|
||||
const ini_section_t* sections;
|
||||
const ini_var_t* vars;
|
||||
int nsections;
|
||||
int nvars;
|
||||
} ini_cfg_t;
|
||||
|
||||
|
||||
//// functions ////
|
||||
void ini_parse(const ini_cfg_t* cfg);
|
||||
void ini_save(const ini_cfg_t* cfg);
|
||||
|
||||
#endif // __INI_PARSER_H__
|
||||
|
||||
955
input.c
Normal file
955
input.c
Normal file
@@ -0,0 +1,955 @@
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/input.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include "input.h"
|
||||
#include "user_io.h"
|
||||
|
||||
#define NUMDEV 10
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t vid, pid;
|
||||
char led;
|
||||
char has_map;
|
||||
char last_l, last_r, last_u, last_d;
|
||||
uint32_t map[32];
|
||||
} devInput;
|
||||
|
||||
static devInput input[NUMDEV] = {0};
|
||||
static int first_joystick = -1;
|
||||
|
||||
#define LCTRL 0x0100
|
||||
#define LSHIFT 0x0200
|
||||
#define LALT 0x0400
|
||||
#define LGUI 0x0800
|
||||
#define RCTRL 0x1000
|
||||
#define RSHIFT 0x2000
|
||||
#define RALT 0x4000
|
||||
#define RGUI 0x8000
|
||||
#define MODMASK 0xFF00
|
||||
#define NONE 0
|
||||
|
||||
static int ev2usb[] =
|
||||
{
|
||||
NONE, //0 KEY_RESERVED
|
||||
0x29, //1 KEY_ESC
|
||||
0x1e, //2 KEY_1
|
||||
0x1f, //3 KEY_2
|
||||
0x20, //4 KEY_3
|
||||
0x21, //5 KEY_4
|
||||
0x22, //6 KEY_5
|
||||
0x23, //7 KEY_6
|
||||
0x24, //8 KEY_7
|
||||
0x25, //9 KEY_8
|
||||
0x26, //10 KEY_9
|
||||
0x27, //11 KEY_0
|
||||
0x2D, //12 KEY_MINUS
|
||||
0x2E, //13 KEY_EQUAL
|
||||
0x2A, //14 KEY_BACKSPACE
|
||||
0x2B, //15 KEY_TAB
|
||||
0x14, //16 KEY_Q
|
||||
0x1a, //17 KEY_W
|
||||
0x08, //18 KEY_E
|
||||
0x15, //19 KEY_R
|
||||
0x17, //20 KEY_T
|
||||
0x1c, //21 KEY_Y
|
||||
0x18, //22 KEY_U
|
||||
0x0c, //23 KEY_I
|
||||
0x12, //24 KEY_O
|
||||
0x13, //25 KEY_P
|
||||
0x2F, //26 KEY_LEFTBRACE
|
||||
0x30, //27 KEY_RIGHTBRACE
|
||||
0x28, //28 KEY_ENTER
|
||||
LCTRL, //29 KEY_LEFTCTRL
|
||||
0x04, //30 KEY_A
|
||||
0x16, //31 KEY_S
|
||||
0x07, //32 KEY_D
|
||||
0x09, //33 KEY_F
|
||||
0x0a, //34 KEY_G
|
||||
0x0b, //35 KEY_H
|
||||
0x0d, //36 KEY_J
|
||||
0x0e, //37 KEY_K
|
||||
0x0f, //38 KEY_L
|
||||
0x33, //39 KEY_SEMICOLON
|
||||
0x34, //40 KEY_APOSTROPHE
|
||||
0x35, //41 KEY_GRAVE
|
||||
LSHIFT, //42 KEY_LEFTSHIFT
|
||||
0x31, //43 KEY_BACKSLASH
|
||||
0x1d, //44 KEY_Z
|
||||
0x1b, //45 KEY_X
|
||||
0x06, //46 KEY_C
|
||||
0x19, //47 KEY_V
|
||||
0x05, //48 KEY_B
|
||||
0x11, //49 KEY_N
|
||||
0x10, //50 KEY_M
|
||||
0x36, //51 KEY_COMMA
|
||||
0x37, //52 KEY_DOT
|
||||
0x38, //53 KEY_SLASH
|
||||
RSHIFT, //54 KEY_RIGHTSHIFT
|
||||
0x55, //55 KEY_KPASTERISK
|
||||
LALT, //56 KEY_LEFTALT
|
||||
0x2C, //57 KEY_SPACE
|
||||
0x39, //58 KEY_CAPSLOCK
|
||||
0x3a, //59 KEY_F1
|
||||
0x3b, //60 KEY_F2
|
||||
0x3c, //61 KEY_F3
|
||||
0x3d, //62 KEY_F4
|
||||
0x3e, //63 KEY_F5
|
||||
0x3f, //64 KEY_F6
|
||||
0x40, //65 KEY_F7
|
||||
0x41, //66 KEY_F8
|
||||
0x42, //67 KEY_F9
|
||||
0x43, //68 KEY_F10
|
||||
0x53, //69 KEY_NUMLOCK
|
||||
0x47, //70 KEY_SCROLLLOCK
|
||||
0x5F, //71 KEY_KP7
|
||||
0x60, //72 KEY_KP8
|
||||
0x61, //73 KEY_KP9
|
||||
0x56, //74 KEY_KPMINUS
|
||||
0x5C, //75 KEY_KP4
|
||||
0x5D, //76 KEY_KP5
|
||||
0x5E, //77 KEY_KP6
|
||||
0x57, //78 KEY_KPPLUS
|
||||
0x59, //79 KEY_KP1
|
||||
0x5A, //80 KEY_KP2
|
||||
0x5B, //81 KEY_KP3
|
||||
0x62, //82 KEY_KP0
|
||||
0x63, //83 KEY_KPDOT
|
||||
NONE, //84 ???
|
||||
NONE, //85 KEY_ZENKAKU
|
||||
NONE, //86 KEY_102ND
|
||||
0x44, //87 KEY_F11
|
||||
0x45, //88 KEY_F12
|
||||
NONE, //89 KEY_RO
|
||||
NONE, //90 KEY_KATAKANA
|
||||
NONE, //91 KEY_HIRAGANA
|
||||
NONE, //92 KEY_HENKAN
|
||||
NONE, //93 KEY_KATAKANA
|
||||
NONE, //94 KEY_MUHENKAN
|
||||
NONE, //95 KEY_KPJPCOMMA
|
||||
0x28, //96 KEY_KPENTER
|
||||
RCTRL, //97 KEY_RIGHTCTRL
|
||||
0x54, //98 KEY_KPSLASH
|
||||
NONE, //99 KEY_SYSRQ
|
||||
RALT, //100 KEY_RIGHTALT
|
||||
NONE, //101 KEY_LINEFEED
|
||||
0x4A, //102 KEY_HOME
|
||||
0x52, //103 KEY_UP
|
||||
0x4B, //104 KEY_PAGEUP
|
||||
0x50, //105 KEY_LEFT
|
||||
0x4F, //106 KEY_RIGHT
|
||||
0x4D, //107 KEY_END
|
||||
0x51, //108 KEY_DOWN
|
||||
0x4E, //109 KEY_PAGEDOWN
|
||||
0x49, //110 KEY_INSERT
|
||||
0x4C, //111 KEY_DELETE
|
||||
NONE, //112 KEY_MACRO
|
||||
NONE, //113 KEY_MUTE
|
||||
NONE, //114 KEY_VOLUMEDOWN
|
||||
NONE, //115 KEY_VOLUMEUP
|
||||
NONE, //116 KEY_POWER
|
||||
0x67, //117 KEY_KPEQUAL
|
||||
NONE, //118 KEY_KPPLUSMINUS
|
||||
0x48, //119 KEY_PAUSE
|
||||
NONE, //120 KEY_SCALE
|
||||
NONE, //121 KEY_KPCOMMA
|
||||
NONE, //122 KEY_HANGEUL
|
||||
NONE, //123 KEY_HANJA
|
||||
NONE, //124 KEY_YEN
|
||||
LGUI, //125 KEY_LEFTMETA
|
||||
RGUI, //126 KEY_RIGHTMETA
|
||||
0x65, //127 KEY_COMPOSE
|
||||
NONE, //128 KEY_STOP
|
||||
NONE, //129 KEY_AGAIN
|
||||
NONE, //130 KEY_PROPS
|
||||
NONE, //131 KEY_UNDO
|
||||
NONE, //132 KEY_FRONT
|
||||
NONE, //133 KEY_COPY
|
||||
NONE, //134 KEY_OPEN
|
||||
NONE, //135 KEY_PASTE
|
||||
NONE, //136 KEY_FIND
|
||||
NONE, //137 KEY_CUT
|
||||
NONE, //138 KEY_HELP
|
||||
NONE, //139 KEY_MENU
|
||||
NONE, //140 KEY_CALC
|
||||
NONE, //141 KEY_SETUP
|
||||
NONE, //142 KEY_SLEEP
|
||||
NONE, //143 KEY_WAKEUP
|
||||
NONE, //144 KEY_FILE
|
||||
NONE, //145 KEY_SENDFILE
|
||||
NONE, //146 KEY_DELETEFILE
|
||||
NONE, //147 KEY_XFER
|
||||
NONE, //148 KEY_PROG1
|
||||
NONE, //149 KEY_PROG2
|
||||
NONE, //150 KEY_WWW
|
||||
NONE, //151 KEY_MSDOS
|
||||
NONE, //152 KEY_SCREENLOCK
|
||||
NONE, //153 KEY_DIRECTION
|
||||
NONE, //154 KEY_CYCLEWINDOWS
|
||||
NONE, //155 KEY_MAIL
|
||||
NONE, //156 KEY_BOOKMARKS
|
||||
NONE, //157 KEY_COMPUTER
|
||||
NONE, //158 KEY_BACK
|
||||
NONE, //159 KEY_FORWARD
|
||||
NONE, //160 KEY_CLOSECD
|
||||
NONE, //161 KEY_EJECTCD
|
||||
NONE, //162 KEY_EJECTCLOSECD
|
||||
NONE, //163 KEY_NEXTSONG
|
||||
NONE, //164 KEY_PLAYPAUSE
|
||||
NONE, //165 KEY_PREVIOUSSONG
|
||||
NONE, //166 KEY_STOPCD
|
||||
NONE, //167 KEY_RECORD
|
||||
NONE, //168 KEY_REWIND
|
||||
NONE, //169 KEY_PHONE
|
||||
NONE, //170 KEY_ISO
|
||||
NONE, //171 KEY_CONFIG
|
||||
NONE, //172 KEY_HOMEPAGE
|
||||
NONE, //173 KEY_REFRESH
|
||||
NONE, //174 KEY_EXIT
|
||||
NONE, //175 KEY_MOVE
|
||||
NONE, //176 KEY_EDIT
|
||||
NONE, //177 KEY_SCROLLUP
|
||||
NONE, //178 KEY_SCROLLDOWN
|
||||
NONE, //179 KEY_KPLEFTPAREN
|
||||
NONE, //180 KEY_KPRIGHTPAREN
|
||||
NONE, //181 KEY_NEW
|
||||
NONE, //182 KEY_REDO
|
||||
NONE, //183 KEY_F13
|
||||
NONE, //184 KEY_F14
|
||||
NONE, //185 KEY_F15
|
||||
NONE, //186 KEY_F16
|
||||
NONE, //187 KEY_F17
|
||||
NONE, //188 KEY_F18
|
||||
NONE, //189 KEY_F19
|
||||
NONE, //190 KEY_F20
|
||||
NONE, //191 KEY_F21
|
||||
NONE, //192 KEY_F22
|
||||
NONE, //193 KEY_F23
|
||||
NONE, //194 KEY_F24
|
||||
NONE, //195 ???
|
||||
NONE, //196 ???
|
||||
NONE, //197 ???
|
||||
NONE, //198 ???
|
||||
NONE, //199 ???
|
||||
NONE, //200 KEY_PLAYCD
|
||||
NONE, //201 KEY_PAUSECD
|
||||
NONE, //202 KEY_PROG3
|
||||
NONE, //203 KEY_PROG4
|
||||
NONE, //204 KEY_DASHBOARD
|
||||
NONE, //205 KEY_SUSPEND
|
||||
NONE, //206 KEY_CLOSE
|
||||
NONE, //207 KEY_PLAY
|
||||
NONE, //208 KEY_FASTFORWARD
|
||||
NONE, //209 KEY_BASSBOOST
|
||||
0x46, //210 KEY_PRINT
|
||||
NONE, //211 KEY_HP
|
||||
NONE, //212 KEY_CAMERA
|
||||
NONE, //213 KEY_SOUND
|
||||
NONE, //214 KEY_QUESTION
|
||||
NONE, //215 KEY_EMAIL
|
||||
NONE, //216 KEY_CHAT
|
||||
NONE, //217 KEY_SEARCH
|
||||
NONE, //218 KEY_CONNECT
|
||||
NONE, //219 KEY_FINANCE
|
||||
NONE, //220 KEY_SPORT
|
||||
NONE, //221 KEY_SHOP
|
||||
NONE, //222 KEY_ALTERASE
|
||||
NONE, //223 KEY_CANCEL
|
||||
NONE, //224 KEY_BRIGHT_DOWN
|
||||
NONE, //225 KEY_BRIGHT_UP
|
||||
NONE, //226 KEY_MEDIA
|
||||
NONE, //227 KEY_SWITCHVIDEO
|
||||
NONE, //228 KEY_DILLUMTOGGLE
|
||||
NONE, //229 KEY_DILLUMDOWN
|
||||
NONE, //230 KEY_DILLUMUP
|
||||
NONE, //231 KEY_SEND
|
||||
NONE, //232 KEY_REPLY
|
||||
NONE, //233 KEY_FORWARDMAIL
|
||||
NONE, //234 KEY_SAVE
|
||||
NONE, //235 KEY_DOCUMENTS
|
||||
NONE, //236 KEY_BATTERY
|
||||
NONE, //237 KEY_BLUETOOTH
|
||||
NONE, //238 KEY_WLAN
|
||||
NONE, //239 KEY_UWB
|
||||
NONE, //240 KEY_UNKNOWN
|
||||
NONE, //241 KEY_VIDEO_NEXT
|
||||
NONE, //242 KEY_VIDEO_PREV
|
||||
NONE, //243 KEY_BRIGHT_CYCLE
|
||||
NONE, //244 KEY_BRIGHT_AUTO
|
||||
NONE, //245 KEY_DISPLAY_OFF
|
||||
NONE, //246 KEY_WWAN
|
||||
NONE, //247 KEY_RFKILL
|
||||
NONE, //248 KEY_MICMUTE
|
||||
NONE, //249 ???
|
||||
NONE, //250 ???
|
||||
NONE, //251 ???
|
||||
NONE, //252 ???
|
||||
NONE, //253 ???
|
||||
NONE, //254 ???
|
||||
NONE //255 ???
|
||||
};
|
||||
|
||||
int mfd = -1;
|
||||
int mwd = -1;
|
||||
|
||||
static int set_watch()
|
||||
{
|
||||
mwd = -1;
|
||||
mfd = inotify_init();
|
||||
if (mfd < 0)
|
||||
{
|
||||
printf("ERR: inotify_init");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mwd = inotify_add_watch(mfd, "/dev/input",
|
||||
IN_MODIFY | IN_CREATE | IN_DELETE);
|
||||
|
||||
if (mwd < 0)
|
||||
{
|
||||
printf("ERR: inotify_add_watch");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return mfd;
|
||||
}
|
||||
|
||||
#define EVENT_SIZE ( sizeof (struct inotify_event) )
|
||||
#define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
|
||||
|
||||
static int check_devs()
|
||||
{
|
||||
int result = 0;
|
||||
int length, i = 0;
|
||||
char buffer[BUF_LEN];
|
||||
length = read(mfd, buffer, BUF_LEN);
|
||||
|
||||
if (length < 0)
|
||||
{
|
||||
printf("ERR: read\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (i<length)
|
||||
{
|
||||
struct inotify_event *event = (struct inotify_event *) &buffer[i];
|
||||
if (event->len)
|
||||
{
|
||||
if (event->mask & IN_CREATE)
|
||||
{
|
||||
result = 1;
|
||||
if (event->mask & IN_ISDIR)
|
||||
{
|
||||
printf("The directory %s was created.\n", event->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("The file %s was created.\n", event->name);
|
||||
}
|
||||
}
|
||||
else if (event->mask & IN_DELETE)
|
||||
{
|
||||
result = 1;
|
||||
if (event->mask & IN_ISDIR)
|
||||
{
|
||||
printf("The directory %s was deleted.\n", event->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("The file %s was deleted.\n", event->name);
|
||||
}
|
||||
}
|
||||
/*
|
||||
else if ( event->mask & IN_MODIFY )
|
||||
{
|
||||
result = 1;
|
||||
if ( event->mask & IN_ISDIR )
|
||||
{
|
||||
printf( "The directory %s was modified.\n", event->name );
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "The file %s was modified.\n", event->name );
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
i += EVENT_SIZE + event->len;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void INThandler()
|
||||
{
|
||||
printf("\nExiting...\n");
|
||||
|
||||
if (mwd >= 0) inotify_rm_watch(mfd, mwd);
|
||||
if (mfd >= 0) close(mfd);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#define test_bit(bit, array) (array [bit / 8] & (1 << (bit % 8)))
|
||||
|
||||
static char has_led(int fd)
|
||||
{
|
||||
unsigned char evtype_b[(EV_MAX + 7) / 8];
|
||||
if (fd<0) return 0;
|
||||
|
||||
memset(&evtype_b, 0, sizeof(evtype_b));
|
||||
if (ioctl(fd, EVIOCGBIT(0, sizeof(evtype_b)), evtype_b) < 0)
|
||||
{
|
||||
printf("ERR: evdev ioctl.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (test_bit(EV_LED, evtype_b))
|
||||
{
|
||||
printf("has LEDs.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char leds_state = 0;
|
||||
void set_kbdled(int mask, int state)
|
||||
{
|
||||
leds_state = state ? leds_state | (mask&HID_LED_MASK) : leds_state & ~(mask&HID_LED_MASK);
|
||||
}
|
||||
|
||||
int get_kbdled(int mask)
|
||||
{
|
||||
return (leds_state & (mask&HID_LED_MASK)) ? 1 : 0;
|
||||
}
|
||||
|
||||
int toggle_kbdled(int mask)
|
||||
{
|
||||
int state = !get_kbdled(mask);
|
||||
set_kbdled(mask, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
int mapping = 0;
|
||||
int mapping_button;
|
||||
int mapping_dev;
|
||||
|
||||
void start_map_setting()
|
||||
{
|
||||
mapping_button = 0;
|
||||
mapping = 1;
|
||||
mapping_dev = -1;
|
||||
}
|
||||
|
||||
int get_map_button()
|
||||
{
|
||||
return mapping_button;
|
||||
}
|
||||
|
||||
void finish_map_setting()
|
||||
{
|
||||
mapping = 0;
|
||||
if (mapping_dev<0) return;
|
||||
|
||||
char name[32];
|
||||
sprintf(name, "input_%04x_%04x.map", input[mapping_dev].vid, input[mapping_dev].pid);
|
||||
FileSave(name, &input[mapping_dev].map, sizeof(input[mapping_dev].map));
|
||||
}
|
||||
|
||||
uint16_t get_map_vid()
|
||||
{
|
||||
return input[mapping_dev].vid;
|
||||
}
|
||||
|
||||
uint16_t get_map_pid()
|
||||
{
|
||||
return input[mapping_dev].pid;
|
||||
}
|
||||
|
||||
#define KEY_EMU_LEFT (KEY_MAX+1)
|
||||
#define KEY_EMU_RIGHT (KEY_MAX+2)
|
||||
#define KEY_EMU_UP (KEY_MAX+3)
|
||||
#define KEY_EMU_DOWN (KEY_MAX+4)
|
||||
|
||||
static char joy[2] = { 0 };
|
||||
static void input_cb(struct input_event *ev, int dev);
|
||||
|
||||
static void joy_digital(int num, uint16_t mask, char press)
|
||||
{
|
||||
if (num < 2)
|
||||
{
|
||||
if (user_io_osd_is_visible() || (mask == JOY_OSD))
|
||||
{
|
||||
memset(joy, 0, sizeof(joy));
|
||||
struct input_event ev;
|
||||
ev.type = EV_KEY;
|
||||
ev.value = press;
|
||||
switch (mask)
|
||||
{
|
||||
case JOY_RIGHT:
|
||||
ev.code = KEY_RIGHT;
|
||||
break;
|
||||
|
||||
case JOY_LEFT:
|
||||
ev.code = KEY_LEFT;
|
||||
break;
|
||||
|
||||
case JOY_UP:
|
||||
ev.code = KEY_UP;
|
||||
break;
|
||||
|
||||
case JOY_DOWN:
|
||||
ev.code = KEY_DOWN;
|
||||
break;
|
||||
|
||||
case JOY_BTN1:
|
||||
ev.code = KEY_ENTER;
|
||||
break;
|
||||
|
||||
case JOY_BTN2:
|
||||
ev.code = KEY_ESC;
|
||||
break;
|
||||
|
||||
case JOY_BTN3:
|
||||
ev.code = KEY_BACKSPACE;
|
||||
break;
|
||||
|
||||
case JOY_OSD:
|
||||
ev.code = KEY_F12;
|
||||
break;
|
||||
default:
|
||||
ev.code = 0;
|
||||
}
|
||||
|
||||
input_cb(&ev, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (press) joy[num] |= (char)mask;
|
||||
else joy[num] &= ~(char)mask;
|
||||
user_io_joystick(num, joy[num]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void input_cb(struct input_event *ev, int dev)
|
||||
{
|
||||
static int key_mapped = 0;
|
||||
static uint8_t modifiers = 0;
|
||||
static char keys[6] = { 0,0,0,0,0,0 };
|
||||
static unsigned char mouse_btn = 0;
|
||||
|
||||
switch (ev->type)
|
||||
{
|
||||
case EV_KEY:
|
||||
{
|
||||
if (ev->code == 272)
|
||||
{
|
||||
if (ev->value <= 1)
|
||||
{
|
||||
mouse_btn = (mouse_btn & ~1) | ev->value;
|
||||
user_io_mouse(mouse_btn, 0, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev->code == 273)
|
||||
{
|
||||
if (ev->value <= 1)
|
||||
{
|
||||
mouse_btn = (mouse_btn & ~2) | (ev->value << 1);
|
||||
user_io_mouse(mouse_btn, 0, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int key = (ev->code < (sizeof(ev2usb) / sizeof(ev2usb[0]))) ? ev2usb[ev->code] : NONE;
|
||||
if ((key != NONE))
|
||||
{
|
||||
if (ev->value > 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (key & MODMASK)
|
||||
{
|
||||
modifiers = (ev->value) ? modifiers | (uint8_t)(key >> 8) : modifiers & ~(uint8_t)(key >> 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ev->value)
|
||||
{
|
||||
int found = 0;
|
||||
for (int i = 0; i < (sizeof(keys) / sizeof(keys[0])); i++) if (keys[i] == (uint8_t)key) found = 1;
|
||||
|
||||
if (!found)
|
||||
{
|
||||
for (int i = 0; i < (sizeof(keys) / sizeof(keys[0])); i++)
|
||||
{
|
||||
if (!keys[i])
|
||||
{
|
||||
keys[i] = (uint8_t)key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < (sizeof(keys) / sizeof(keys[0])); i++) if (keys[i] == (uint8_t)key) keys[i] = 0;
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
for (int i = 0; i < (sizeof(keys) / sizeof(keys[0])); i++) if (keys[i]) keys[j++] = keys[i];
|
||||
while (j < (sizeof(keys) / sizeof(keys[0]))) keys[j++] = 0;
|
||||
}
|
||||
|
||||
user_io_kbd(modifiers, keys, input[dev].vid, input[dev].pid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_REL:
|
||||
{
|
||||
switch (ev->code)
|
||||
{
|
||||
case 0:
|
||||
//printf("Mouse PosX: %d\n", ev->value);
|
||||
user_io_mouse(mouse_btn, ev->value, 0);
|
||||
return;
|
||||
case 1:
|
||||
//printf("Mouse PosY: %d\n", ev->value);
|
||||
user_io_mouse(mouse_btn, 0, ev->value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (!input[dev].has_map)
|
||||
{
|
||||
char name[32];
|
||||
sprintf(name, "input_%04x_%04x.map", input[dev].vid, input[dev].pid);
|
||||
if (!FileLoad(name, &input[dev].map, sizeof(input[dev].map)))
|
||||
{
|
||||
memset(&input[dev].map, 0, sizeof(input[dev].map));
|
||||
}
|
||||
input[dev].has_map = 1;
|
||||
}
|
||||
|
||||
//joystick
|
||||
if (mapping && (mapping_dev >=0 || ev->value))
|
||||
{
|
||||
if (ev->type == EV_KEY && ev->value <= 1 && ev->code >= BTN_JOYSTICK)
|
||||
{
|
||||
if (mapping_dev < 0) mapping_dev = dev;
|
||||
if (mapping_dev == dev && mapping_button < 9)
|
||||
{
|
||||
if (ev->value)
|
||||
{
|
||||
if(!mapping_button) memset(&input[dev].map, 0, sizeof(input[dev].map));
|
||||
|
||||
int found = 0;
|
||||
for (int i = 0; i < mapping_button; i++) if (input[dev].map[i] == ev->code) found = 1;
|
||||
|
||||
if (!found)
|
||||
{
|
||||
input[dev].map[mapping_button] = ev->code;
|
||||
key_mapped = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(key_mapped) mapping_button++;
|
||||
key_mapped = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
key_mapped = 0;
|
||||
switch (ev->type)
|
||||
{
|
||||
//buttons, digital directions
|
||||
case EV_KEY:
|
||||
if (ev->value <= 1)
|
||||
{
|
||||
if (first_joystick < 0) first_joystick = dev;
|
||||
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
if (ev->code == input[dev].map[i])
|
||||
{
|
||||
joy_digital((first_joystick == dev) ? 0 : 1, 1<<i, ev->value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
//analog joystick
|
||||
case EV_ABS:
|
||||
// skip if first joystick is not defined.
|
||||
if (first_joystick < 0) break;
|
||||
|
||||
// TODO:
|
||||
// 1) add analog axis mapping (input[dev].map[16], input[dev].map[17])
|
||||
// 2) enable invertion
|
||||
|
||||
if (ev->code == 0) // x
|
||||
{
|
||||
int offset = 0;
|
||||
if (ev->value < 127 || ev->value>129) offset = ev->value - 128;
|
||||
//joy_analog((first_joystick == dev) ? 0 : 1, 0, offset);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev->code == 1) // y
|
||||
{
|
||||
int offset = 0;
|
||||
if (ev->value < 127 || ev->value>129) offset = ev->value - 128;
|
||||
//joy_analog((first_joystick == dev) ? 0 : 1, 1, offset);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t read_hex(char *filename)
|
||||
{
|
||||
FILE *in;
|
||||
unsigned int value;
|
||||
|
||||
in = fopen(filename, "rb");
|
||||
if (!in) return 0;
|
||||
|
||||
if (fscanf(in, "%x", &value) == 1)
|
||||
{
|
||||
fclose(in);
|
||||
return (uint16_t)value;
|
||||
}
|
||||
fclose(in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void getVidPid(int num, uint16_t* vid, uint16_t* pid)
|
||||
{
|
||||
char name[256];
|
||||
sprintf(name, "/sys/class/input/event%d/device/id/vendor", num);
|
||||
*vid = read_hex(name);
|
||||
sprintf(name, "/sys/class/input/event%d/device/id/product", num);
|
||||
*pid = read_hex(name);
|
||||
}
|
||||
|
||||
int input_poll(int getchar)
|
||||
{
|
||||
static struct pollfd pool[NUMDEV + 1];
|
||||
static char cur_leds = 0;
|
||||
static int state = 0;
|
||||
|
||||
char devname[20];
|
||||
struct input_event ev;
|
||||
|
||||
if (state == 0)
|
||||
{
|
||||
signal(SIGINT, INThandler);
|
||||
pool[NUMDEV].fd = set_watch();
|
||||
pool[NUMDEV].events = POLLIN;
|
||||
state++;
|
||||
}
|
||||
|
||||
if (state == 1)
|
||||
{
|
||||
printf("Open up to %d input devices.\n", NUMDEV);
|
||||
for (int i = 0; i<NUMDEV; i++)
|
||||
{
|
||||
sprintf(devname, "/dev/input/event%d", i);
|
||||
pool[i].fd = open(devname, O_RDWR);
|
||||
pool[i].events = POLLIN;
|
||||
memset(&input[i], 0, sizeof(input[i]));
|
||||
input[i].led = has_led(pool[i].fd);
|
||||
if (pool[i].fd > 0) getVidPid(i, &input[i].vid, &input[i].pid);
|
||||
if (pool[i].fd > 0) printf("opened %s (%04x:%04x)\n", devname, input[i].vid, input[i].pid);
|
||||
}
|
||||
|
||||
cur_leds |= 0x80;
|
||||
state++;
|
||||
}
|
||||
|
||||
if (state == 2)
|
||||
{
|
||||
int return_value = poll(pool, NUMDEV + 1, 0);
|
||||
if (return_value < 0)
|
||||
{
|
||||
printf("ERR: poll\n");
|
||||
}
|
||||
else if (return_value > 0)
|
||||
{
|
||||
if ((pool[NUMDEV].revents & POLLIN) && check_devs())
|
||||
{
|
||||
printf("Close all devices.\n");
|
||||
for (int i = 0; i<NUMDEV; i++)
|
||||
{
|
||||
if (pool[i].fd >= 0) close(pool[i].fd);
|
||||
}
|
||||
state = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i<NUMDEV; i++)
|
||||
{
|
||||
if ((pool[i].fd >= 0) && (pool[i].revents & POLLIN))
|
||||
{
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
if (read(pool[i].fd, &ev, sizeof(ev)) == sizeof(ev))
|
||||
{
|
||||
if (getchar)
|
||||
{
|
||||
if (ev.type == EV_KEY && ev.value >= 1)
|
||||
{
|
||||
return ev.code;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_menu_core())
|
||||
{
|
||||
switch (ev.type)
|
||||
{
|
||||
//keyboard, buttons
|
||||
case EV_KEY:
|
||||
printf("Input event: type=EV_KEY, code=%d(%x), value=%d\n", ev.code, ev.code, ev.value);
|
||||
break;
|
||||
|
||||
//mouse
|
||||
case EV_REL:
|
||||
printf("Input event: type=EV_REL, Axis=%d, Offset:=%d\n", ev.code, ev.value);
|
||||
break;
|
||||
|
||||
case EV_SYN:
|
||||
case EV_MSC:
|
||||
break;
|
||||
|
||||
//analog joystick
|
||||
case EV_ABS:
|
||||
if (ev.code == 61) break; //ps3 accel axis
|
||||
if (ev.code == 60) break; //ps3 accel axis
|
||||
if (ev.code == 59) break; //ps3 accel axis
|
||||
|
||||
//reduce spam on PS3 gamepad
|
||||
if (input[i].vid == 0x054c && input[i].pid == 0x0268)
|
||||
{
|
||||
if (ev.code <= 5 && ev.value > 118 && ev.value < 138) break;
|
||||
}
|
||||
|
||||
printf("Input event: type=EV_ABS, Axis=%d, Offset:=%d\n", ev.code, ev.value);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Input event: type=%d, code=%d(%x), value=%d(%x)\n", ev.type, ev.code, ev.code, ev.value, ev.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
input_cb(&ev, i);
|
||||
|
||||
//sumulate digital directions from analog
|
||||
if (ev.type == EV_ABS)
|
||||
{
|
||||
// some pads use axis 16 for L/R PAD, axis 17 for U/D PAD
|
||||
// emulate PAD on axis 0/1
|
||||
|
||||
char l, r, u, d;
|
||||
l = r = u = d = 0;
|
||||
|
||||
if(ev.code == 0 || ev.code == 16) // x
|
||||
{
|
||||
if ((ev.code == 0 && ev.value < 90) || (ev.code == 16 && ev.value == -1)) l = 1;
|
||||
if ((ev.code == 0 && ev.value > 164) || (ev.code == 16 && ev.value == 1)) r = 1;
|
||||
|
||||
ev.type = EV_KEY;
|
||||
if (input[i].last_l != l)
|
||||
{
|
||||
ev.code = KEY_EMU_LEFT;
|
||||
ev.value = l;
|
||||
input_cb(&ev, i);
|
||||
input[i].last_l = l;
|
||||
}
|
||||
|
||||
if (input[i].last_r != r)
|
||||
{
|
||||
ev.code = KEY_EMU_RIGHT;
|
||||
ev.value = r;
|
||||
input_cb(&ev, i);
|
||||
input[i].last_r = r;
|
||||
}
|
||||
}
|
||||
|
||||
if (ev.code == 1 || ev.code == 17) // y
|
||||
{
|
||||
if ((ev.code == 1 && ev.value < 90) || (ev.code == 17 && ev.value == -1)) u = 1;
|
||||
if ((ev.code == 1 && ev.value > 164) || (ev.code == 17 && ev.value == 1)) d = 1;
|
||||
|
||||
ev.type = EV_KEY;
|
||||
if (input[i].last_u != u)
|
||||
{
|
||||
ev.code = KEY_EMU_UP;
|
||||
ev.value = u;
|
||||
input_cb(&ev, i);
|
||||
input[i].last_u = u;
|
||||
}
|
||||
|
||||
if (input[i].last_d != d)
|
||||
{
|
||||
ev.code = KEY_EMU_DOWN;
|
||||
ev.value = d;
|
||||
input_cb(&ev, i);
|
||||
input[i].last_d = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cur_leds != leds_state)
|
||||
{
|
||||
cur_leds = leds_state;
|
||||
for (int i = 0; i<NUMDEV; i++)
|
||||
{
|
||||
if (input[i].led)
|
||||
{
|
||||
ev.type = EV_LED;
|
||||
|
||||
ev.code = LED_SCROLLL;
|
||||
ev.value = (cur_leds&HID_LED_SCROLL_LOCK) ? 1 : 0;
|
||||
write(pool[i].fd, &ev, sizeof(struct input_event));
|
||||
|
||||
ev.code = LED_NUML;
|
||||
ev.value = (cur_leds&HID_LED_NUM_LOCK) ? 1 : 0;
|
||||
write(pool[i].fd, &ev, sizeof(struct input_event));
|
||||
|
||||
ev.code = LED_CAPSL;
|
||||
ev.value = (cur_leds&HID_LED_CAPS_LOCK) ? 1 : 0;
|
||||
write(pool[i].fd, &ev, sizeof(struct input_event));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
input.h
Normal file
23
input.h
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
#ifndef EVINPUT_H
|
||||
#define EVINPUT_H
|
||||
|
||||
#define HID_LED_NUM_LOCK 1
|
||||
#define HID_LED_CAPS_LOCK 2
|
||||
#define HID_LED_SCROLL_LOCK 4
|
||||
#define HID_LED_MASK 7
|
||||
|
||||
void set_kbdled(int mask, int state);
|
||||
int get_kbdled(int mask);
|
||||
int toggle_kbdled(int mask);
|
||||
|
||||
int input_poll(int getchar);
|
||||
|
||||
|
||||
void start_map_setting();
|
||||
int get_map_button();
|
||||
void finish_map_setting();
|
||||
uint16_t get_map_vid();
|
||||
uint16_t get_map_pid();
|
||||
|
||||
#endif
|
||||
504
keycodes.h
Normal file
504
keycodes.h
Normal file
@@ -0,0 +1,504 @@
|
||||
// http://wiki.amigaos.net/index.php/Keymap_Library
|
||||
// http://www.win.tue.nl/~aeb/linux/kbd/scancodes-14.html
|
||||
|
||||
#include "osd.h"
|
||||
|
||||
#define MISS 0xff
|
||||
#define KEYCODE_MAX (0x6f)
|
||||
|
||||
// The original minimig had the keyboard connected to the FPGA. Thus all key events (even for OSD)
|
||||
// came from the FPGA core. The MIST has the keyboard attached to the arm controller. To be compatible
|
||||
// with the minimig core all keys (incl. OSD!) are forwarded to the FPGA and the OSD keys are returned.
|
||||
// These keys are tagged with the "OSD" flag
|
||||
// The atari/mist core does not forwards keys through the FPGA but queues them inside the arm controller.
|
||||
// Keys flagged with "OSD_OPEN" are used to open the OSD in non-minimig. They can have a keycode which
|
||||
// will be sent into the core
|
||||
|
||||
#define OSD 0x0100 // to be used by OSD, not the core itself
|
||||
#define OSD_OPEN 0x0200 // OSD key not forwarded to core, but queued in arm controller
|
||||
#define CAPS_LOCK_TOGGLE 0x0400 // caps lock toggle behaviour
|
||||
#define NUM_LOCK_TOGGLE 0x0800
|
||||
#define EXT 0x1000 // extended PS/2 keycode
|
||||
|
||||
// amiga unmapped:
|
||||
// 0x5a KP-( (mapped on Keyrah)
|
||||
// 0x5b KP-) (mapped on Keyrah)
|
||||
// codes >= 0x69 are for OSD only and are not sent to the amiga itself
|
||||
|
||||
// keycode translation table
|
||||
const unsigned short usb2ami[] = {
|
||||
MISS, // 00: NoEvent
|
||||
MISS, // 01: Overrun Error
|
||||
MISS, // 02: POST fail
|
||||
MISS, // 03: ErrorUndefined
|
||||
0x20, // 04: a
|
||||
0x35, // 05: b
|
||||
0x33, // 06: c
|
||||
0x22, // 07: d
|
||||
0x12, // 08: e
|
||||
0x23, // 09: f
|
||||
0x24, // 0a: g
|
||||
0x25, // 0b: h
|
||||
0x17, // 0c: i
|
||||
0x26, // 0d: j
|
||||
0x27, // 0e: k
|
||||
0x28, // 0f: l
|
||||
0x37, // 10: m
|
||||
0x36, // 11: n
|
||||
0x18, // 12: o
|
||||
0x19, // 13: p
|
||||
0x10, // 14: q
|
||||
0x13, // 15: r
|
||||
0x21, // 16: s
|
||||
0x14, // 17: t
|
||||
0x16, // 18: u
|
||||
0x34, // 19: v
|
||||
0x11, // 1a: w
|
||||
0x32, // 1b: x
|
||||
0x15, // 1c: y
|
||||
0x31, // 1d: z
|
||||
0x01, // 1e: 1
|
||||
0x02, // 1f: 2
|
||||
0x03, // 20: 3
|
||||
0x04, // 21: 4
|
||||
0x05, // 22: 5
|
||||
0x06, // 23: 6
|
||||
0x07, // 24: 7
|
||||
0x08, // 25: 8
|
||||
0x09, // 26: 9
|
||||
0x0a, // 27: 0
|
||||
0x44, // 28: Return
|
||||
0x45, // 29: Escape
|
||||
0x41, // 2a: Backspace
|
||||
0x42, // 2b: Tab
|
||||
0x40, // 2c: Space
|
||||
0x0b, // 2d: -
|
||||
0x0c, // 2e: =
|
||||
0x1a, // 2f: [
|
||||
0x1b, // 30: ]
|
||||
0x0d, // 31: backslash (only on us keyboards)
|
||||
0x2b, // 32: Europe 1 (only on international keyboards)
|
||||
0x29, // 33: ;
|
||||
0x2a, // 34: '
|
||||
0x00, // 35: `
|
||||
0x38, // 36: ,
|
||||
0x39, // 37: .
|
||||
0x3a, // 38: /
|
||||
0x62 | CAPS_LOCK_TOGGLE, // 39: Caps Lock
|
||||
0x50, // 3a: F1
|
||||
0x51, // 3b: F2
|
||||
0x52, // 3c: F3
|
||||
0x53, // 3d: F4
|
||||
0x54, // 3e: F5
|
||||
0x55, // 3f: F6
|
||||
0x56, // 40: F7
|
||||
0x57, // 41: F8
|
||||
0x58, // 42: F9
|
||||
0x59, // 43: F10
|
||||
0x5f, // 44: F11
|
||||
OSD_OPEN, // 45: F12 (OSD)
|
||||
0x6e | OSD, // 46: Print Screen (OSD)
|
||||
NUM_LOCK_TOGGLE, // 47: Scroll Lock (OSD)
|
||||
0x6f | OSD, // 48: Pause
|
||||
0x0d, // 49: backslash to avoid panic in Germany ;)
|
||||
0x6a, // 4a: Home
|
||||
0x6c | OSD, // 4b: Page Up (OSD)
|
||||
0x46, // 4c: Delete
|
||||
MISS, // 4d: End
|
||||
0x6d | OSD, // 4e: Page Down (OSD)
|
||||
0x4e, // 4f: Right Arrow
|
||||
0x4f, // 50: Left Arrow
|
||||
0x4d, // 51: Down Arrow
|
||||
0x4c, // 52: Up Arrow
|
||||
NUM_LOCK_TOGGLE, // 53: Num Lock
|
||||
0x5c, // 54: KP /
|
||||
0x5d, // 55: KP *
|
||||
0x4a, // 56: KP -
|
||||
0x5e, // 57: KP +
|
||||
0x43, // 58: KP Enter
|
||||
0x1d, // 59: KP 1
|
||||
0x1e, // 5a: KP 2
|
||||
0x1f, // 5b: KP 3
|
||||
0x2d, // 5c: KP 4
|
||||
0x2e, // 5d: KP 5
|
||||
0x2f, // 5e: KP 6
|
||||
0x3d, // 5f: KP 7
|
||||
0x3e, // 60: KP 8
|
||||
0x3f, // 61: KP 9
|
||||
0x0f, // 62: KP 0
|
||||
0x3c, // 63: KP .
|
||||
0x30, // 64: Europe 2
|
||||
KEY_MENU | OSD, // 65: App
|
||||
MISS, // 66: Power
|
||||
MISS, // 67: KP =
|
||||
0x5a, // 68: KP (
|
||||
0x5b, // 69: KP )
|
||||
MISS, // 6a: F15
|
||||
0x5f, // 6b: help (for keyrah)
|
||||
NUM_LOCK_TOGGLE | 1, // 6c: F17
|
||||
NUM_LOCK_TOGGLE | 2, // 6d: F18
|
||||
NUM_LOCK_TOGGLE | 3, // 6e: F19
|
||||
NUM_LOCK_TOGGLE | 4 // 6f: F20
|
||||
};
|
||||
|
||||
// unmapped atari keys:
|
||||
// 0x63 KP (
|
||||
// 0x64 KP )
|
||||
|
||||
// keycode translation table for atari
|
||||
const unsigned short usb2atari[] = {
|
||||
MISS, // 00: NoEvent
|
||||
MISS, // 01: Overrun Error
|
||||
MISS, // 02: POST fail
|
||||
MISS, // 03: ErrorUndefined
|
||||
0x1e, // 04: a
|
||||
0x30, // 05: b
|
||||
0x2e, // 06: c
|
||||
0x20, // 07: d
|
||||
0x12, // 08: e
|
||||
0x21, // 09: f
|
||||
0x22, // 0a: g
|
||||
0x23, // 0b: h
|
||||
0x17, // 0c: i
|
||||
0x24, // 0d: j
|
||||
0x25, // 0e: k
|
||||
0x26, // 0f: l
|
||||
0x32, // 10: m
|
||||
0x31, // 11: n
|
||||
0x18, // 12: o
|
||||
0x19, // 13: p
|
||||
0x10, // 14: q
|
||||
0x13, // 15: r
|
||||
0x1f, // 16: s
|
||||
0x14, // 17: t
|
||||
0x16, // 18: u
|
||||
0x2f, // 19: v
|
||||
0x11, // 1a: w
|
||||
0x2d, // 1b: x
|
||||
0x15, // 1c: y
|
||||
0x2c, // 1d: z
|
||||
0x02, // 1e: 1
|
||||
0x03, // 1f: 2
|
||||
0x04, // 20: 3
|
||||
0x05, // 21: 4
|
||||
0x06, // 22: 5
|
||||
0x07, // 23: 6
|
||||
0x08, // 24: 7
|
||||
0x09, // 25: 8
|
||||
0x0a, // 26: 9
|
||||
0x0b, // 27: 0
|
||||
0x1c, // 28: Return
|
||||
0x01, // 29: Escape
|
||||
0x0e, // 2a: Backspace
|
||||
0x0f, // 2b: Tab
|
||||
0x39, // 2c: Space
|
||||
0x0c, // 2d: -
|
||||
0x0d, // 2e: =
|
||||
0x1a, // 2f: [
|
||||
0x1b, // 30: ]
|
||||
0x29, // 31: backslash, only on us keyboard
|
||||
0x29, // 32: Europe 1, only on int. keyboard
|
||||
0x27, // 33: ;
|
||||
0x28, // 34: '
|
||||
0x2b, // 35: `
|
||||
0x33, // 36: ,
|
||||
0x34, // 37: .
|
||||
0x35, // 38: /
|
||||
0x3a | CAPS_LOCK_TOGGLE, // 39: Caps Lock
|
||||
0x3b, // 3a: F1
|
||||
0x3c, // 3b: F2
|
||||
0x3d, // 3c: F3
|
||||
0x3e, // 3d: F4
|
||||
0x3f, // 3e: F5
|
||||
0x40, // 3f: F6
|
||||
0x41, // 40: F7
|
||||
0x42, // 41: F8
|
||||
0x43, // 42: F9
|
||||
0x44, // 43: F10
|
||||
MISS, // 44: F11
|
||||
OSD_OPEN, // 45: F12
|
||||
MISS, // 46: Print Screen
|
||||
NUM_LOCK_TOGGLE, // 47: Scroll Lock
|
||||
MISS, // 48: Pause
|
||||
0x52, // 49: Insert
|
||||
0x47, // 4a: Home
|
||||
0x62, // 4b: Page Up
|
||||
0x53, // 4c: Delete
|
||||
MISS, // 4d: End
|
||||
0x61, // 4e: Page Down
|
||||
0x4d, // 4f: Right Arrow
|
||||
0x4b, // 50: Left Arrow
|
||||
0x50, // 51: Down Arrow
|
||||
0x48, // 52: Up Arrow
|
||||
NUM_LOCK_TOGGLE, // 53: Num Lock
|
||||
0x65, // 54: KP /
|
||||
0x66, // 55: KP *
|
||||
0x4a, // 56: KP -
|
||||
0x4e, // 57: KP +
|
||||
0x72, // 58: KP Enter
|
||||
0x6d, // 59: KP 1
|
||||
0x6e, // 5a: KP 2
|
||||
0x6f, // 5b: KP 3
|
||||
0x6a, // 5c: KP 4
|
||||
0x6b, // 5d: KP 5
|
||||
0x6c, // 5e: KP 6
|
||||
0x67, // 5f: KP 7
|
||||
0x68, // 60: KP 8
|
||||
0x69, // 61: KP 9
|
||||
0x70, // 62: KP 0
|
||||
0x71, // 63: KP .
|
||||
0x60, // 64: Europe 2
|
||||
OSD_OPEN, // 65: App
|
||||
MISS, // 66: Power
|
||||
MISS, // 67: KP =
|
||||
MISS, // 68: F13
|
||||
MISS, // 69: F14
|
||||
MISS, // 6a: F15
|
||||
0x52, // 6b: insert (for keyrah)
|
||||
NUM_LOCK_TOGGLE | 1, // 6c: F17
|
||||
NUM_LOCK_TOGGLE | 2, // 6d: F18
|
||||
NUM_LOCK_TOGGLE | 3, // 6e: F19
|
||||
NUM_LOCK_TOGGLE | 4 // 6f: F20
|
||||
};
|
||||
|
||||
// keycode translation table for ps2 emulation
|
||||
const unsigned short usb2ps2[] = {
|
||||
MISS, // 00: NoEvent
|
||||
MISS, // 01: Overrun Error
|
||||
MISS, // 02: POST fail
|
||||
MISS, // 03: ErrorUndefined
|
||||
0x1c, // 04: a
|
||||
0x32, // 05: b
|
||||
0x21, // 06: c
|
||||
0x23, // 07: d
|
||||
0x24, // 08: e
|
||||
0x2b, // 09: f
|
||||
0x34, // 0a: g
|
||||
0x33, // 0b: h
|
||||
0x43, // 0c: i
|
||||
0x3b, // 0d: j
|
||||
0x42, // 0e: k
|
||||
0x4b, // 0f: l
|
||||
0x3a, // 10: m
|
||||
0x31, // 11: n
|
||||
0x44, // 12: o
|
||||
0x4d, // 13: p
|
||||
0x15, // 14: q
|
||||
0x2d, // 15: r
|
||||
0x1b, // 16: s
|
||||
0x2c, // 17: t
|
||||
0x3c, // 18: u
|
||||
0x2a, // 19: v
|
||||
0x1d, // 1a: w
|
||||
0x22, // 1b: x
|
||||
0x35, // 1c: y
|
||||
0x1a, // 1d: z
|
||||
0x16, // 1e: 1
|
||||
0x1e, // 1f: 2
|
||||
0x26, // 20: 3
|
||||
0x25, // 21: 4
|
||||
0x2e, // 22: 5
|
||||
0x36, // 23: 6
|
||||
0x3d, // 24: 7
|
||||
0x3e, // 25: 8
|
||||
0x46, // 26: 9
|
||||
0x45, // 27: 0
|
||||
0x5a, // 28: Return
|
||||
0x76, // 29: Escape
|
||||
0x66, // 2a: Backspace
|
||||
0x0d, // 2b: Tab
|
||||
0x29, // 2c: Space
|
||||
0x4e, // 2d: -
|
||||
0x55, // 2e: =
|
||||
0x54, // 2f: [
|
||||
0x5b, // 30: ]
|
||||
0x5d, // 31: backslash
|
||||
0x5d, // 32: Europe 1
|
||||
0x4c, // 33: ;
|
||||
0x52, // 34: '
|
||||
0x0e, // 35: `
|
||||
0x41, // 36: ,
|
||||
0x49, // 37: .
|
||||
0x4a, // 38: /
|
||||
0x58, // 39: Caps Lock
|
||||
0x05, // 3a: F1
|
||||
0x06, // 3b: F2
|
||||
0x04, // 3c: F3
|
||||
0x0c, // 3d: F4
|
||||
0x03, // 3e: F5
|
||||
0x0b, // 3f: F6
|
||||
0x83, // 40: F7
|
||||
0x0a, // 41: F8
|
||||
0x01, // 42: F9
|
||||
0x09, // 43: F10
|
||||
0x78, // 44: F11
|
||||
OSD_OPEN | 0x07, // 45: F12 (OSD)
|
||||
EXT | 0x7c, // 46: Print Screen
|
||||
NUM_LOCK_TOGGLE, // 47: Scroll Lock
|
||||
0x77, // 48: Pause (special key handled inside user_io)
|
||||
EXT | 0x70, // 49: Insert
|
||||
EXT | 0x6c, // 4a: Home
|
||||
EXT | 0x7d, // 4b: Page Up
|
||||
EXT | 0x71, // 4c: Delete
|
||||
EXT | 0x69, // 4d: End
|
||||
EXT | 0x7a, // 4e: Page Down
|
||||
EXT | 0x74, // 4f: Right Arrow
|
||||
EXT | 0x6b, // 50: Left Arrow
|
||||
EXT | 0x72, // 51: Down Arrow
|
||||
EXT | 0x75, // 52: Up Arrow
|
||||
NUM_LOCK_TOGGLE, // 53: Num Lock
|
||||
EXT | 0x4a, // 54: KP /
|
||||
0x7c, // 55: KP *
|
||||
0x7b, // 56: KP -
|
||||
0x79, // 57: KP +
|
||||
EXT | 0x5a, // 58: KP Enter
|
||||
0x69, // 59: KP 1
|
||||
0x72, // 5a: KP 2
|
||||
0x7a, // 5b: KP 3
|
||||
0x6b, // 5c: KP 4
|
||||
0x73, // 5d: KP 5
|
||||
0x74, // 5e: KP 6
|
||||
0x6c, // 5f: KP 7
|
||||
0x75, // 60: KP 8
|
||||
0x7d, // 61: KP 9
|
||||
0x70, // 62: KP 0
|
||||
0x71, // 63: KP .
|
||||
0x61, // 64: Europe 2
|
||||
OSD_OPEN | EXT | 0x2f, // 65: App
|
||||
EXT | 0x37, // 66: Power
|
||||
0x0f, // 67: KP =
|
||||
0x77, // 68: Num Lock
|
||||
0x7e, // 69: Scroll Lock
|
||||
0x18, // 6a: F15
|
||||
EXT | 0x70, // 6b: insert (for keyrah)
|
||||
NUM_LOCK_TOGGLE | 1, // 6c: F17
|
||||
NUM_LOCK_TOGGLE | 2, // 6d: F18
|
||||
NUM_LOCK_TOGGLE | 3, // 6e: F19
|
||||
NUM_LOCK_TOGGLE | 4 // 6f: F20
|
||||
};
|
||||
|
||||
// Archimedes unmapped keys
|
||||
// Missing sterling
|
||||
// Missing kp_hash
|
||||
// Missing button_1
|
||||
// Missing button_2
|
||||
// Missing button_3
|
||||
// Missing button_4
|
||||
// Missing button_5
|
||||
|
||||
// keycode translation table
|
||||
const unsigned short usb2archie[] = {
|
||||
MISS, // 00: NoEvent
|
||||
MISS, // 01: Overrun Error
|
||||
MISS, // 02: POST fail
|
||||
MISS, // 03: ErrorUndefined
|
||||
0x3c, // 04: a
|
||||
0x52, // 05: b
|
||||
0x50, // 06: c
|
||||
0x3e, // 07: d
|
||||
0x29, // 08: e
|
||||
0x3f, // 09: f
|
||||
0x40, // 0a: g
|
||||
0x41, // 0b: h
|
||||
0x2e, // 0c: i
|
||||
0x42, // 0d: j
|
||||
0x43, // 0e: k
|
||||
0x44, // 0f: l
|
||||
0x54, // 10: m
|
||||
0x53, // 11: n
|
||||
0x2f, // 12: o
|
||||
0x30, // 13: p
|
||||
0x27, // 14: q
|
||||
0x2a, // 15: r
|
||||
0x3d, // 16: s
|
||||
0x2b, // 17: t
|
||||
0x2d, // 18: u
|
||||
0x51, // 19: v
|
||||
0x28, // 1a: w
|
||||
0x4f, // 1b: x
|
||||
0x2c, // 1c: y
|
||||
0x4e, // 1d: z
|
||||
0x11, // 1e: 1
|
||||
0x12, // 1f: 2
|
||||
0x13, // 20: 3
|
||||
0x14, // 21: 4
|
||||
0x15, // 22: 5
|
||||
0x16, // 23: 6
|
||||
0x17, // 24: 7
|
||||
0x18, // 25: 8
|
||||
0x19, // 26: 9
|
||||
0x1a, // 27: 0
|
||||
0x47, // 28: Return
|
||||
0x00, // 29: Escape
|
||||
0x1e, // 2a: Backspace
|
||||
0x26, // 2b: Tab
|
||||
0x5f, // 2c: Space
|
||||
0x1b, // 2d: -
|
||||
0x1c, // 2e: =
|
||||
0x31, // 2f: [
|
||||
0x32, // 30: ]
|
||||
0x33, // 31: backslash (only on us keyboards)
|
||||
0x33, // 32: Europe 1 (only on international kbds)
|
||||
0x45, // 33: ;
|
||||
0x46, // 34: '
|
||||
0x10, // 35: `
|
||||
0x55, // 36: ,
|
||||
0x56, // 37: .
|
||||
0x57, // 38: /
|
||||
0x5d, // 39: Caps Lock
|
||||
0x01, // 3a: F1
|
||||
0x02, // 3b: F2
|
||||
0x03, // 3c: F3
|
||||
0x04, // 3d: F4
|
||||
0x05, // 3e: F5
|
||||
0x06, // 3f: F6
|
||||
0x07, // 40: F7
|
||||
0x08, // 41: F8
|
||||
0x09, // 42: F9
|
||||
0x0a, // 43: F10
|
||||
0x0b, // 44: F11
|
||||
0x0c, // 45: F12 - Used heavily by the archie... OSD moved to printscreen.
|
||||
// 0x0d, // 46: Print Screen
|
||||
OSD_OPEN, // 46: Print Screen
|
||||
0x0e, // 47: Scroll Lock
|
||||
0x0f, // 48: Pause
|
||||
0x1f, // 49: Insert
|
||||
0x20, // 4a: Home
|
||||
0x21, // 4b: Page Up
|
||||
0x34, // 4c: Delete
|
||||
0x35, // 4d: End
|
||||
0x36, // 4e: Page Down
|
||||
0x64, // 4f: Right Arrow
|
||||
0x62, // 50: Left Arrow
|
||||
0x63, // 51: Down Arrow
|
||||
0x59, // 52: Up Arrow
|
||||
0x22, // 53: Num Lock
|
||||
0x23, // 54: KP /
|
||||
0x24, // 55: KP *
|
||||
0x3a, // 56: KP -
|
||||
0x4b, // 57: KP +
|
||||
0x67, // 58: KP Enter
|
||||
0x5a, // 59: KP 1
|
||||
0x5b, // 5a: KP 2
|
||||
0x5c, // 5b: KP 3
|
||||
0x48, // 5c: KP 4
|
||||
0x49, // 5d: KP 5
|
||||
0x4a, // 5e: KP 6
|
||||
0x37, // 5f: KP 7
|
||||
0x38, // 60: KP 8
|
||||
0x39, // 61: KP 9
|
||||
0x65, // 62: KP 0
|
||||
0x66, // 63: KP decimal
|
||||
MISS, // 64: Europe 2
|
||||
0x72, // 65: App (maps to middle mouse button)
|
||||
MISS, // 66: Power
|
||||
MISS, // 67: KP =
|
||||
MISS, // 68: F13
|
||||
MISS, // 69: F14
|
||||
MISS, // 6a: F15
|
||||
0x1f, // 6b: insert (for keyrah)
|
||||
MISS, // 6c: F17
|
||||
MISS, // 6d: F18
|
||||
MISS, // 6e: F19
|
||||
MISS, // 6f: F20
|
||||
};
|
||||
143
logo.h
Normal file
143
logo.h
Normal file
@@ -0,0 +1,143 @@
|
||||
#ifndef LOGO_H
|
||||
#define LOGO_H
|
||||
const unsigned char logodata[5][227] = {
|
||||
{ 0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,
|
||||
0x00,0x80,0xE0,0xE0,0xF0,0xF0,0xF8,0xF8,0xF8,0xFC,0xFC,0xFC,0xFC,0xF8,0xF8,0xF8,0xF0,0xF0,0xE0,
|
||||
0xE0,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00 },
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x40,
|
||||
0x40,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
|
||||
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,
|
||||
0x40,0x41,0xC3,0xC7,0xC7,0xCF,0xCF,0xCF,0xCF,0xDF,0xDF,0xDF,0xDF,0xCF,0xCF,0xCF,0xCF,0xC7,0xC7,
|
||||
0x43,0x41,0x40,0x40,0x40,0x40,0x00,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE0,
|
||||
0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0xC0,
|
||||
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
|
||||
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
|
||||
0xC0,0xE0,0xF8,0x3E,0x1F,0x0F,0x07,0x1F,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xF8,
|
||||
0xE0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0xC0,0xC0,0x60,0x70,
|
||||
0x30,0x38,0x1C,0x1C,0x8C,0xF6,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x1F,
|
||||
0x0F,0x03,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
|
||||
0xE0,0xF0,0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x0F,0x07,0x03,0x01,0x00,0x00,
|
||||
0x00,0x00,0x00,0x7E,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xE7,
|
||||
0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0x83,0x83,0x83,0x83,0x83,0x87,0x07,0x07,0x07,0x00,0x00,0x07,
|
||||
0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0xF0,0xFC,0x3E,0x1F,
|
||||
0x07,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFE,0x70,0x60,0x30,0x38,0x38,0x1C,0x0C,0x0E,0x07,0x07,0x03,0x01,0x01,0x00,0x80,0xE0,
|
||||
0xF0,0xF8,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x0F,0x07,0x03,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xF0,0xF8,0xFC,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x1F,0x07,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0xC0,0xC1,0xC1,0xC3,0xC3,0xC3,0xC3,0xC7,0xC7,0xC7,0x87,0x87,0x8F,0x8F,0x8F,
|
||||
0xCF,0xDF,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFE,0xFC,0x70,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x0C,0x0C,0x0C,0x0E,0x0F,0x0F,0x0F,0x0F,0x0C,0x0C,0x08,
|
||||
0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0F,0x0F,0x07,0x07,0x03,0x03,
|
||||
0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x0C,0x0C,0x0C,0x0E,0x0F,0x0F,
|
||||
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0D,0x0C,0x08,0x08,0x08,0x08,0x08,0x00,0x00,
|
||||
0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x0C,0x0C,0x0C,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
|
||||
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0C,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
|
||||
0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x07,0x07,0x07,0x03,0x03,0x03,0x03,0x01,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
|
||||
0x0F,0x0F,0x0F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
|
||||
};
|
||||
#endif
|
||||
/* -- original MINIMIG logo, we keep only one to save some space on the firmware binary
|
||||
const unsigned char logodata_minimig[5][227] = {
|
||||
{0xFF, 0x00, 0x80, 0xc0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
|
||||
0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0,
|
||||
0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x83, 0x83, 0x83, 0x83, 0x83,
|
||||
0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x83, 0x83, 0x83, 0x83,
|
||||
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x83,
|
||||
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x00, 0x00, 0x80, 0x83, 0x87, 0x87, 0x8f, 0x8f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x0f,
|
||||
0x0f, 0x07, 0x07, 0x03, 0x00, 0x00, 0x00, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x83, 0x83,
|
||||
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x83,
|
||||
0x83, 0x03, 0x03},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xf0,
|
||||
0x7c, 0x1e, 0x07, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xc0, 0x00, 0x00, 0x00, 0x80,
|
||||
0x80, 0xc0, 0x60, 0x20, 0x30, 0x18, 0x8c, 0xc4, 0xf6, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f,
|
||||
0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe0, 0xf0, 0xfc, 0xff, 0xff, 0xff,
|
||||
0xff, 0x3f, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe0, 0xf0, 0x3c,
|
||||
0x0e, 0x07, 0x03, 0x07, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80,
|
||||
0x00, 0x00, 0x00, 0xc0, 0xf0, 0x38, 0x1e, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0xe0, 0xf0, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x80, 0xc0, 0xf0, 0x7c, 0x1e, 0x07, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xfc, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0x60, 0x20, 0x30, 0x18, 0x8c, 0xc4, 0xf6, 0xfb,
|
||||
0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||
0xc0, 0xf0, 0xf8, 0xfe, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xe0, 0xf0, 0xf8, 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, 0x3e, 0x1f, 0x0f, 0x07, 0x07, 0x03, 0x03, 0x01,
|
||||
0x01, 0x41, 0x41, 0x40, 0x40, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, 0xc1, 0xc1, 0xc3, 0x47, 0x47, 0x43,
|
||||
0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x38, 0x3e, 0x2f, 0x23, 0x20,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x3f, 0x3f, 0x1f, 0x1f, 0x0f, 0x07, 0x06, 0x03, 0x21, 0x21,
|
||||
0x20, 0x20, 0x20, 0x30, 0x38, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x27, 0x21, 0x20, 0x00,
|
||||
0x00, 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x3c, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x27, 0x21,
|
||||
0x20, 0x20, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x3c, 0x3f, 0x27, 0x21, 0x20, 0x20,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f,
|
||||
0x3f, 0x1e, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x3c, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x27, 0x21, 0x20, 0x20, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x30,
|
||||
0x30, 0x38, 0x3e, 0x2f, 0x23, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x3f, 0x3f, 0x1f, 0x1f,
|
||||
0x0f, 0x07, 0x06, 0x03, 0x21, 0x21, 0x20, 0x20, 0x20, 0x30, 0x38, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x27, 0x21, 0x20, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x3e, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x27, 0x21, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x07, 0x0f, 0x0f, 0x1f, 0x1f, 0x1f, 0x3f, 0x38, 0x38, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x30, 0x38, 0x3c, 0x3f, 0x3f, 0x3f, 0x1f, 0x1f, 0x0f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18}
|
||||
};*/
|
||||
172
main.c
Normal file
172
main.c
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
Copyright 2005, 2006, 2007 Dennis van Weeren
|
||||
Copyright 2008, 2009 Jakub Bednarski
|
||||
Copyright 2012 Till Harbaum
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include "string.h"
|
||||
#include "errors.h"
|
||||
#include "hardware.h"
|
||||
#include "file_io.h"
|
||||
#include "osd.h"
|
||||
#include "fdd.h"
|
||||
#include "hdd.h"
|
||||
#include "menu.h"
|
||||
#include "user_io.h"
|
||||
#include "tos.h"
|
||||
#include "debug.h"
|
||||
#include "mist_cfg.h"
|
||||
#include "input.h"
|
||||
#include "fpga_io.h"
|
||||
#include "boot.h"
|
||||
|
||||
const char version[] = { "$VER:HPS" VDATE };
|
||||
|
||||
unsigned char Error;
|
||||
|
||||
void FatalError(unsigned long error)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
iprintf("Fatal error: %lu\n", error);
|
||||
|
||||
while (1)
|
||||
{
|
||||
for (i = 0; i < error; i++)
|
||||
{
|
||||
DISKLED_ON;
|
||||
WaitTimer(250);
|
||||
DISKLED_OFF;
|
||||
WaitTimer(250);
|
||||
}
|
||||
WaitTimer(1000);
|
||||
}
|
||||
}
|
||||
|
||||
void HandleDisk(void)
|
||||
{
|
||||
unsigned char c1, c2;
|
||||
|
||||
EnableFpga();
|
||||
uint16_t tmp = spi_w(0);
|
||||
c1 = (uint8_t)(tmp>>8); // cmd request and drive number
|
||||
c2 = (uint8_t)tmp; // track number
|
||||
spi_w(0);
|
||||
spi_w(0);
|
||||
DisableFpga();
|
||||
|
||||
HandleFDD(c1, c2);
|
||||
HandleHDD(c1, c2);
|
||||
|
||||
UpdateDriveStatus();
|
||||
}
|
||||
|
||||
void core_init()
|
||||
{
|
||||
user_io_detect_core_type();
|
||||
|
||||
mist_ini_parse();
|
||||
user_io_send_buttons(1);
|
||||
|
||||
if (user_io_core_type() == CORE_TYPE_MINIMIG2)
|
||||
{
|
||||
BootInit();
|
||||
|
||||
} // end of minimig setup
|
||||
|
||||
if (user_io_core_type() == CORE_TYPE_MIST)
|
||||
{
|
||||
puts("Running mist setup");
|
||||
tos_upload(NULL);
|
||||
|
||||
// end of mist setup
|
||||
}
|
||||
|
||||
if (user_io_core_type() == CORE_TYPE_ARCHIE)
|
||||
{
|
||||
puts("Running archimedes setup");
|
||||
} // end of archimedes setup
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
uint8_t mmc_ok = 0;
|
||||
|
||||
fpga_io_init();
|
||||
|
||||
DISKLED_OFF;
|
||||
|
||||
iprintf("\nMinimig by Dennis van Weeren");
|
||||
iprintf("\nARM Controller by Jakub Bednarski\n\n");
|
||||
iprintf("Version %s\n\n", version + 5);
|
||||
|
||||
FindStorage();
|
||||
|
||||
user_io_init();
|
||||
tos_config_init();
|
||||
core_init();
|
||||
|
||||
while(1)
|
||||
{
|
||||
//printf("fpga_ready:%d\n", fpga_ready());
|
||||
if(!fpga_ready())
|
||||
{
|
||||
printf("FPGA is not ready. JTAG uploading?\n");
|
||||
printf("Waiting for FPGA to be ready...\n");
|
||||
|
||||
//reset GPO to default value
|
||||
fpga_gpo_write(0);
|
||||
|
||||
while (!fpga_ready())
|
||||
{
|
||||
sleep(1);
|
||||
}
|
||||
reboot(0);
|
||||
}
|
||||
|
||||
user_io_poll();
|
||||
input_poll(0);
|
||||
|
||||
switch (user_io_core_type())
|
||||
{
|
||||
// MIST (atari) core supports the same UI as Minimig
|
||||
case CORE_TYPE_MIST:
|
||||
HandleUI();
|
||||
break;
|
||||
|
||||
// call original minimig handlers if minimig core is found
|
||||
case CORE_TYPE_MINIMIG2:
|
||||
HandleDisk();
|
||||
HandleUI();
|
||||
break;
|
||||
|
||||
// 8 bit cores can also have a ui if a valid config string can be read from it
|
||||
case CORE_TYPE_8BIT:
|
||||
if(user_io_is_8bit_with_config_string()) HandleUI();
|
||||
break;
|
||||
|
||||
// Archie core will get its own treatment one day ...
|
||||
case CORE_TYPE_ARCHIE:
|
||||
HandleUI();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
125
menu.h
Normal file
125
menu.h
Normal file
@@ -0,0 +1,125 @@
|
||||
#ifndef MENU_H
|
||||
#define MENU_H
|
||||
|
||||
#include "fdd.h" // for adfTYPE definition
|
||||
|
||||
/*menu states*/
|
||||
enum MENU
|
||||
{
|
||||
MENU_NONE1,
|
||||
MENU_NONE2,
|
||||
MENU_MAIN1,
|
||||
MENU_MAIN2,
|
||||
MENU_FILE_SELECT1,
|
||||
MENU_FILE_SELECT2,
|
||||
MENU_FILE_SELECTED,
|
||||
MENU_RESET1,
|
||||
MENU_RESET2,
|
||||
MENU_RECONF1,
|
||||
MENU_RECONF2,
|
||||
MENU_SETTINGS1,
|
||||
MENU_SETTINGS2,
|
||||
MENU_ROMFILE_SELECTED,
|
||||
MENU_ROMFILE_SELECTED1,
|
||||
MENU_ROMFILE_SELECTED2,
|
||||
MENU_SETTINGS_VIDEO1,
|
||||
MENU_SETTINGS_VIDEO2,
|
||||
MENU_SETTINGS_MEMORY1,
|
||||
MENU_SETTINGS_MEMORY2,
|
||||
MENU_SETTINGS_CHIPSET1,
|
||||
MENU_SETTINGS_CHIPSET2,
|
||||
MENU_SETTINGS_DRIVES1,
|
||||
MENU_SETTINGS_DRIVES2,
|
||||
MENU_SETTINGS_HARDFILE1,
|
||||
MENU_SETTINGS_HARDFILE2,
|
||||
MENU_HARDFILE_SELECT1,
|
||||
MENU_HARDFILE_SELECT2,
|
||||
MENU_HARDFILE_SELECTED,
|
||||
MENU_HARDFILE_EXIT,
|
||||
MENU_HARDFILE_CHANGED1,
|
||||
MENU_HARDFILE_CHANGED2,
|
||||
MENU_SYNTHRDB1,
|
||||
MENU_SYNTHRDB2,
|
||||
MENU_SYNTHRDB2_1,
|
||||
MENU_SYNTHRDB2_2,
|
||||
MENU_LOADCONFIG_1,
|
||||
MENU_LOADCONFIG_2,
|
||||
MENU_SAVECONFIG_1,
|
||||
MENU_SAVECONFIG_2,
|
||||
MENU_FIRMWARE1,
|
||||
MENU_FIRMWARE2,
|
||||
MENU_FIRMWARE_CORE_FILE_SELECTED,
|
||||
MENU_ERROR,
|
||||
MENU_INFO,
|
||||
MENU_STORAGE,
|
||||
MENU_JOYDIGMAP,
|
||||
MENU_JOYDIGMAP1,
|
||||
|
||||
// Mist/atari specific pages
|
||||
MENU_MIST_MAIN1,
|
||||
MENU_MIST_MAIN2,
|
||||
MENU_MIST_MAIN_FILE_SELECTED,
|
||||
MENU_MIST_STORAGE1,
|
||||
MENU_MIST_STORAGE2,
|
||||
MENU_MIST_STORAGE_FILE_SELECTED,
|
||||
MENU_MIST_SYSTEM1,
|
||||
MENU_MIST_SYSTEM2,
|
||||
MENU_MIST_SYSTEM_FILE_SELECTED,
|
||||
MENU_MIST_VIDEO1,
|
||||
MENU_MIST_VIDEO2,
|
||||
MENU_MIST_VIDEO_ADJUST1,
|
||||
MENU_MIST_VIDEO_ADJUST2,
|
||||
|
||||
// archimedes menu entries
|
||||
MENU_ARCHIE_MAIN1,
|
||||
MENU_ARCHIE_MAIN2,
|
||||
MENU_ARCHIE_MAIN_FILE_SELECTED,
|
||||
|
||||
// 8bit menu entries
|
||||
MENU_8BIT_MAIN1,
|
||||
MENU_8BIT_MAIN2,
|
||||
MENU_8BIT_MAIN_FILE_SELECTED,
|
||||
MENU_8BIT_MAIN_IMAGE_SELECTED,
|
||||
MENU_8BIT_SYSTEM1,
|
||||
MENU_8BIT_SYSTEM2,
|
||||
MENU_8BIT_ABOUT1,
|
||||
MENU_8BIT_ABOUT2,
|
||||
MENU_8BIT_CONTROLLERS1,
|
||||
MENU_8BIT_CONTROLLERS2,
|
||||
MENU_8BIT_JOYTEST_A1,
|
||||
MENU_8BIT_JOYTEST_A2,
|
||||
MENU_8BIT_JOYTEST_B1,
|
||||
MENU_8BIT_JOYTEST_B2,
|
||||
MENU_8BIT_KEYTEST1,
|
||||
MENU_8BIT_KEYTEST2,
|
||||
MENU_8BIT_USB1,
|
||||
MENU_8BIT_USB2,
|
||||
MENU_8BIT_TURBO1,
|
||||
MENU_8BIT_TURBO2,
|
||||
MENU_8BIT_CHRTEST1,
|
||||
MENU_8BIT_CHRTEST2
|
||||
};
|
||||
|
||||
// UI strings, used by boot messages
|
||||
extern const char *config_filter_msg[];
|
||||
extern const char *config_memory_chip_msg[];
|
||||
extern const char *config_memory_slow_msg[];
|
||||
extern const char *config_memory_fast_msg[];
|
||||
extern const char *config_scanline_msg[];
|
||||
extern const char *config_cpu_msg[];
|
||||
extern const char *config_hdf_msg[];
|
||||
extern const char *config_chipset_msg[];
|
||||
|
||||
|
||||
|
||||
void InsertFloppy(adfTYPE *drive, char* path);
|
||||
void HandleUI(void);
|
||||
void PrintDirectory(void);
|
||||
void ScrollLongName(void);
|
||||
void InfoMessage(char *message);
|
||||
void ShowSplash();
|
||||
void HideSplash();
|
||||
void EjectAllFloppies();
|
||||
|
||||
#endif
|
||||
|
||||
44
mist_cfg.c
Normal file
44
mist_cfg.c
Normal file
@@ -0,0 +1,44 @@
|
||||
// mist_cfg.c
|
||||
// 2015, rok.krajnc@gmail.com
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include "ini_parser.h"
|
||||
#include "mist_cfg.h"
|
||||
#include "user_io.h"
|
||||
|
||||
void mist_ini_parse()
|
||||
{
|
||||
memset(&mist_cfg, 0, sizeof(mist_cfg));
|
||||
ini_parse(&mist_ini_cfg);
|
||||
}
|
||||
|
||||
mist_cfg_t mist_cfg = { 0 };
|
||||
|
||||
// mist ini sections
|
||||
const ini_section_t mist_ini_sections[] =
|
||||
{
|
||||
{ 1, "MiSTer" }
|
||||
};
|
||||
|
||||
// mist ini vars
|
||||
const ini_var_t mist_ini_vars[] = {
|
||||
{ "YPBPR", (void*)(&(mist_cfg.ypbpr)), UINT8, 0, 1, 1 },
|
||||
{ "COMPOSITE_SYNC", (void*)(&(mist_cfg.csync)), UINT8, 0, 1, 1 },
|
||||
{ "FORCED_SCANDOUBLER", (void*)(&(mist_cfg.forced_scandoubler)), UINT8, 0, 1, 1 },
|
||||
{ "VGA_SCALER", (void*)(&(mist_cfg.vga_scaler)), UINT8, 0, 1, 1 },
|
||||
{ "KEYRAH_MODE", (void*)(&(mist_cfg.keyrah_mode)), UINT32, 0, 0xFFFFFFFF, 1 },
|
||||
{ "RESET_COMBO", (void*)(&(mist_cfg.reset_combo)), UINT8, 0, 2, 1 },
|
||||
{ "KEY_MENU_AS_RGUI", (void*)(&(mist_cfg.key_menu_as_rgui)), UINT8, 0, 1, 1 },
|
||||
{ "KEY_REMAP", (void*)user_io_key_remap, CUSTOM_HANDLER, 0, 0, 1 },
|
||||
{ "VIDEO_MODE", (void*)(&(mist_cfg.video_mode)), UINT8, 0, 9, 1 },
|
||||
};
|
||||
|
||||
// mist ini config
|
||||
const ini_cfg_t mist_ini_cfg = {
|
||||
"MiSTer.ini",
|
||||
mist_ini_sections,
|
||||
mist_ini_vars,
|
||||
(int)(sizeof(mist_ini_sections) / sizeof(ini_section_t)),
|
||||
(int)(sizeof(mist_ini_vars) / sizeof(ini_var_t))
|
||||
};
|
||||
37
mist_cfg.h
Normal file
37
mist_cfg.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// mist_cfg.h
|
||||
// 2015, rok.krajnc@gmail.com
|
||||
|
||||
|
||||
#ifndef __MIST_CFG_H__
|
||||
#define __MIST_CFG_H__
|
||||
|
||||
|
||||
//// includes ////
|
||||
#include <inttypes.h>
|
||||
#include "ini_parser.h"
|
||||
|
||||
|
||||
//// type definitions ////
|
||||
typedef struct {
|
||||
uint32_t keyrah_mode;
|
||||
uint8_t forced_scandoubler;
|
||||
uint8_t key_menu_as_rgui;
|
||||
uint8_t reset_combo;
|
||||
uint8_t ypbpr;
|
||||
uint8_t csync;
|
||||
uint8_t vga_scaler;
|
||||
uint8_t video_mode;
|
||||
} mist_cfg_t;
|
||||
|
||||
|
||||
//// functions ////
|
||||
void mist_ini_parse();
|
||||
|
||||
|
||||
//// global variables ////
|
||||
extern const ini_cfg_t mist_ini_cfg;
|
||||
extern mist_cfg_t mist_cfg;
|
||||
|
||||
|
||||
#endif // __MIST_CFG_H__
|
||||
|
||||
700
osd.c
Normal file
700
osd.c
Normal file
@@ -0,0 +1,700 @@
|
||||
/*
|
||||
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/>.
|
||||
|
||||
This is the Minimig OSD (on-screen-display) handler.
|
||||
|
||||
2012-02-09 - Split character rom out to separate header file, with upper 128 entries
|
||||
as rotated copies of the first 128 entries. -- AMR
|
||||
|
||||
29-12-2006 - created
|
||||
30-12-2006 - improved and simplified
|
||||
-- JB --
|
||||
2008-10-04 - ARM version
|
||||
2008-10-26 - added cpu and floppy configuration functions
|
||||
2008-12-31 - added enable HDD command
|
||||
2009-02-03 - full keyboard support
|
||||
2009-06-23 - hires OSD display
|
||||
2009-08-23 - adapted ConfigIDE() - support for 2 hardfiles
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "osd.h"
|
||||
#include "spi.h"
|
||||
|
||||
#include "charrom.h"
|
||||
#include "logo.h"
|
||||
#include "user_io.h"
|
||||
#include "hardware.h"
|
||||
|
||||
|
||||
// conversion table of Amiga keyboard scan codes to ASCII codes
|
||||
const char keycode_table[128] =
|
||||
{
|
||||
0,'1','2','3','4','5','6','7','8','9','0', 0, 0, 0, 0, 0,
|
||||
'Q','W','E','R','T','Y','U','I','O','P', 0, 0, 0, 0, 0, 0,
|
||||
'A','S','D','F','G','H','J','K','L', 0, 0, 0, 0, 0, 0, 0,
|
||||
0,'Z','X','C','V','B','N','M', 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
static int osd_size = 8;
|
||||
|
||||
void OsdSetSize(int n)
|
||||
{
|
||||
osd_size = n;
|
||||
}
|
||||
|
||||
int OsdGetSize()
|
||||
{
|
||||
return osd_size;
|
||||
}
|
||||
|
||||
struct star
|
||||
{
|
||||
int x, y;
|
||||
int dx, dy;
|
||||
};
|
||||
|
||||
struct star stars[64];
|
||||
|
||||
char framebuffer[16][256];
|
||||
void framebuffer_clear()
|
||||
{
|
||||
memset(framebuffer, 0, sizeof(framebuffer));
|
||||
}
|
||||
|
||||
void framebuffer_plot(int x, int y)
|
||||
{
|
||||
y = (y * osd_size) / 8;
|
||||
framebuffer[y / 8][x] |= (1 << (y & 7));
|
||||
}
|
||||
|
||||
void StarsInit()
|
||||
{
|
||||
srand(time(NULL));
|
||||
for (int i = 0; i<64; ++i)
|
||||
{
|
||||
stars[i].x = (rand() % 228) << 4; // X centre
|
||||
stars[i].y = (rand() % 56) << 4; // Y centre
|
||||
stars[i].dx = -(rand() & 7) - 3;
|
||||
stars[i].dy = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void StarsUpdate()
|
||||
{
|
||||
framebuffer_clear();
|
||||
for (int i = 0; i<64; ++i)
|
||||
{
|
||||
stars[i].x += stars[i].dx;
|
||||
stars[i].y += stars[i].dy;
|
||||
if ((stars[i].x<0) || (stars[i].x>(228 << 4)) ||
|
||||
(stars[i].y<0) || (stars[i].y>(56 << 4)))
|
||||
{
|
||||
stars[i].x = 228 << 4;
|
||||
stars[i].y = (rand() % 56) << 4;
|
||||
stars[i].dx = -(rand() & 7) - 3;
|
||||
stars[i].dy = 0;
|
||||
}
|
||||
framebuffer_plot(stars[i].x >> 4, stars[i].y >> 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// time delay after which file/dir name starts to scroll
|
||||
#define SCROLL_DELAY 1000
|
||||
#define SCROLL_DELAY2 10
|
||||
#define SCROLL_DELAY3 50
|
||||
|
||||
static unsigned long scroll_offset = 0; // file/dir name scrolling position
|
||||
static unsigned long scroll_timer = 0; // file/dir name scrolling timer
|
||||
|
||||
static int arrow;
|
||||
static unsigned char titlebuffer[128];
|
||||
|
||||
static void rotatechar(unsigned char *in, unsigned char *out)
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
for (b = 0; b<8; ++b)
|
||||
{
|
||||
a = 0;
|
||||
for (c = 0; c<8; ++c)
|
||||
{
|
||||
a <<= 1;
|
||||
a |= (in[c] >> b) & 1;
|
||||
}
|
||||
out[b] = a;
|
||||
}
|
||||
}
|
||||
|
||||
#define OSDHEIGHT (osd_size*8)
|
||||
|
||||
void OsdSetTitle(char *s, int a)
|
||||
{
|
||||
// Compose the title, condensing character gaps
|
||||
arrow = a;
|
||||
int zeros = 0;
|
||||
int i = 0, j = 0;
|
||||
int outp = 0;
|
||||
while (1)
|
||||
{
|
||||
int c = s[i++];
|
||||
if (c && (outp<OSDHEIGHT))
|
||||
{
|
||||
unsigned char *p = &charfont[c][0];
|
||||
for (j = 0; j<8; ++j)
|
||||
{
|
||||
unsigned char nc = *p++;
|
||||
if (nc)
|
||||
{
|
||||
zeros = 0;
|
||||
titlebuffer[outp++] = nc;
|
||||
}
|
||||
else if (zeros == 0)
|
||||
{
|
||||
titlebuffer[outp++] = 0;
|
||||
zeros = 1;
|
||||
}
|
||||
if (outp>63)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
for (i = outp; i<OSDHEIGHT; i++)
|
||||
{
|
||||
titlebuffer[i] = 0;
|
||||
}
|
||||
|
||||
// Now centre it:
|
||||
int c = (OSDHEIGHT - 1 - outp) / 2;
|
||||
memmove(titlebuffer + c, titlebuffer, outp);
|
||||
|
||||
for (i = 0; i<c; ++i)
|
||||
titlebuffer[i] = 0;
|
||||
|
||||
// Finally rotate it.
|
||||
for (i = 0; i<OSDHEIGHT; i += 8)
|
||||
{
|
||||
unsigned char tmp[8];
|
||||
rotatechar(&titlebuffer[i], tmp);
|
||||
for (c = 0; c<8; ++c)
|
||||
{
|
||||
titlebuffer[i + c] = tmp[c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OsdWrite(unsigned char n, char *s, unsigned char invert, unsigned char stipple)
|
||||
{
|
||||
OsdWriteOffset(n, s, invert, stipple, 0, 0);
|
||||
}
|
||||
|
||||
// write a null-terminated string <s> to the OSD buffer starting at line <n>
|
||||
void OsdWriteOffset(unsigned char n, char *s, unsigned char invert, unsigned char stipple, char offset, char leftchar)
|
||||
{
|
||||
//printf("OsdWriteOffset(%d)\n", n);
|
||||
unsigned short i;
|
||||
unsigned char b;
|
||||
const unsigned char *p;
|
||||
unsigned char stipplemask = 0xff;
|
||||
int linelimit = OSDLINELEN;
|
||||
int arrowmask = arrow;
|
||||
if (n == (osd_size-1) && (arrow & OSD_ARROW_RIGHT))
|
||||
linelimit -= 22;
|
||||
|
||||
if (stipple) {
|
||||
stipplemask = 0x55;
|
||||
stipple = 0xff;
|
||||
}
|
||||
else
|
||||
stipple = 0;
|
||||
|
||||
// select buffer and line to write to
|
||||
if (!is_minimig())
|
||||
spi_osd_cmd_cont(MM1_OSDCMDWRITE | n);
|
||||
else
|
||||
spi_osd_cmd32_cont(OSD_CMD_OSD_WR, n);
|
||||
|
||||
if (invert) invert = 255;
|
||||
|
||||
i = 0;
|
||||
// send all characters in string to OSD
|
||||
while (1)
|
||||
{
|
||||
if (i == 0)
|
||||
{ // Render sidestripe
|
||||
unsigned char j;
|
||||
unsigned char tmp[8];
|
||||
|
||||
if (leftchar)
|
||||
{
|
||||
unsigned char tmp2[8];
|
||||
memcpy(tmp2, charfont[leftchar], 8);
|
||||
rotatechar(tmp2, tmp);
|
||||
p = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = &titlebuffer[(osd_size - 1 - n) * 8];
|
||||
}
|
||||
|
||||
spi16(0xffff); // left white border
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
spi_n(255 ^ *p++, 2);
|
||||
|
||||
spi16(0xffff); // right white border
|
||||
spi16(0x0000); // blue gap
|
||||
i += 22;
|
||||
}
|
||||
else if (n == (osd_size-1) && (arrowmask & OSD_ARROW_LEFT)) { // Draw initial arrow
|
||||
unsigned char b;
|
||||
|
||||
spi24(0x00);
|
||||
p = &charfont[0x10][0];
|
||||
for (b = 0; b<8; b++) spi8(*p++ << offset);
|
||||
p = &charfont[0x14][0];
|
||||
for (b = 0; b<8; b++) spi8(*p++ << offset);
|
||||
spi24(0x00);
|
||||
spi_n(invert, 2);
|
||||
i += 24;
|
||||
arrowmask &= ~OSD_ARROW_LEFT;
|
||||
if (*s++ == 0) break; // Skip 3 characters, to keep alignent the same.
|
||||
if (*s++ == 0) break;
|
||||
if (*s++ == 0) break;
|
||||
}
|
||||
else {
|
||||
b = *s++;
|
||||
|
||||
if (b == 0) // end of string
|
||||
break;
|
||||
|
||||
else if (b == 0x0d || b == 0x0a) { // cariage return / linefeed, go to next line
|
||||
// increment line counter
|
||||
if (++n >= linelimit)
|
||||
n = 0;
|
||||
|
||||
// send new line number to OSD
|
||||
DisableOsd();
|
||||
|
||||
if (!is_minimig())
|
||||
spi_osd_cmd_cont(MM1_OSDCMDWRITE | n);
|
||||
else
|
||||
spi_osd_cmd32_cont(OSD_CMD_OSD_WR, n);
|
||||
}
|
||||
else if (i<(linelimit - 8)) { // normal character
|
||||
unsigned char c;
|
||||
p = &charfont[b][0];
|
||||
for (c = 0; c<8; c++) {
|
||||
spi8(((*p++ << offset)&stipplemask) ^ invert);
|
||||
stipplemask ^= stipple;
|
||||
}
|
||||
i += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < linelimit; i++) // clear end of line
|
||||
{
|
||||
spi8(invert);
|
||||
}
|
||||
|
||||
if (n == (osd_size-1) && (arrowmask & OSD_ARROW_RIGHT))
|
||||
{ // Draw final arrow if needed
|
||||
unsigned char c;
|
||||
spi24(0x00);
|
||||
p = &charfont[0x15][0];
|
||||
for (c = 0; c<8; c++) spi8(*p++ << offset);
|
||||
p = &charfont[0x11][0];
|
||||
for (c = 0; c<8; c++) spi8(*p++ << offset);
|
||||
spi24(0x00);
|
||||
i += 22;
|
||||
}
|
||||
|
||||
// deselect OSD SPI device
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
void OsdDrawLogo(unsigned char n, char row, char superimpose)
|
||||
{
|
||||
unsigned short i;
|
||||
const unsigned char *p;
|
||||
int linelimit = OSDLINELEN;
|
||||
|
||||
int mag = (osd_size / 8);
|
||||
n = n * mag;
|
||||
|
||||
// select buffer and line to write to
|
||||
if (!is_minimig())
|
||||
{
|
||||
spi_osd_cmd_cont(MM1_OSDCMDWRITE | n);
|
||||
}
|
||||
else
|
||||
{
|
||||
spi_osd_cmd32_cont(OSD_CMD_OSD_WR, n);
|
||||
}
|
||||
|
||||
for (int k = 0; k < mag; k++)
|
||||
{
|
||||
unsigned char bt = 0;
|
||||
const unsigned char *lp = logodata[row];
|
||||
int bytes = sizeof(logodata[0]);
|
||||
if (row >= (sizeof(logodata) / sizeof(logodata[0]))) lp = 0;
|
||||
|
||||
char *bg = framebuffer[n + k];
|
||||
|
||||
i = 0;
|
||||
while(i < linelimit)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
unsigned char j;
|
||||
p = &titlebuffer[(osd_size - 1 - n - k) * 8];
|
||||
spi16(0xffff); // left white border
|
||||
for (j = 0; j<8; j++) spi_n(255 ^ *p++, 2);
|
||||
spi16(0xffff); // right white border
|
||||
spi16(0x0000); // blue gap
|
||||
i += 22;
|
||||
}
|
||||
|
||||
if(lp && bytes)
|
||||
{
|
||||
bt = *lp++;
|
||||
if(mag > 1)
|
||||
{
|
||||
if (k) bt >>= 4;
|
||||
bt = (bt & 1) | ((bt & 1) << 1) | ((bt & 2) << 1) | ((bt & 2) << 2) | ((bt & 4) << 2) | ((bt & 4) << 3) | ((bt & 8) << 3) | ((bt & 8) << 4);
|
||||
}
|
||||
bytes--;
|
||||
}
|
||||
|
||||
spi8(bt | *bg++);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// deselect OSD SPI device
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
// write a null-terminated string <s> to the OSD buffer starting at line <n>
|
||||
void OSD_PrintText(unsigned char line, char *text, unsigned long start, unsigned long width, unsigned long offset, unsigned char invert)
|
||||
{
|
||||
// line : OSD line number (0-7)
|
||||
// text : pointer to null-terminated string
|
||||
// start : start position (in pixels)
|
||||
// width : printed text length in pixels
|
||||
// offset : scroll offset in pixels counting from the start of the string (0-7)
|
||||
// invert : invertion flag
|
||||
|
||||
const unsigned char *p;
|
||||
int i, j;
|
||||
|
||||
// select buffer and line to write to
|
||||
if (!is_minimig())
|
||||
spi_osd_cmd_cont(MM1_OSDCMDWRITE | line);
|
||||
else
|
||||
spi_osd_cmd32_cont(OSD_CMD_OSD_WR, line);
|
||||
|
||||
if (invert)
|
||||
invert = 0xff;
|
||||
|
||||
p = &titlebuffer[(osd_size - 1 - line) * 8];
|
||||
if (start>2) {
|
||||
spi16(0xffff);
|
||||
start -= 2;
|
||||
}
|
||||
|
||||
i = start>16 ? 16 : start;
|
||||
for (j = 0; j<(i / 2); ++j)
|
||||
spi_n(255 ^ *p++, 2);
|
||||
|
||||
if (i & 1)
|
||||
spi8(255 ^ *p);
|
||||
start -= i;
|
||||
|
||||
if (start>2) {
|
||||
spi16(0xffff);
|
||||
start -= 2;
|
||||
}
|
||||
|
||||
while (start--)
|
||||
spi8(0x00);
|
||||
|
||||
if (offset) {
|
||||
width -= 8 - offset;
|
||||
p = &charfont[*text++][offset];
|
||||
for (; offset < 8; offset++)
|
||||
spi8(*p++^invert);
|
||||
}
|
||||
|
||||
while (width > 8) {
|
||||
unsigned char b;
|
||||
p = &charfont[*text++][0];
|
||||
for (b = 0; b<8; b++) spi8(*p++^invert);
|
||||
width -= 8;
|
||||
}
|
||||
|
||||
if (width) {
|
||||
p = &charfont[*text++][0];
|
||||
while (width--)
|
||||
spi8(*p++^invert);
|
||||
}
|
||||
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
// clear OSD frame buffer
|
||||
void OsdClear(void)
|
||||
{
|
||||
// select buffer to write to
|
||||
if (!is_minimig())
|
||||
spi_osd_cmd_cont(MM1_OSDCMDWRITE | 0x18);
|
||||
else
|
||||
spi_osd_cmd32_cont(OSD_CMD_OSD_WR, 0x18);
|
||||
|
||||
// clear buffer
|
||||
spi_n(0x00, OSDLINELEN * OSDNLINE);
|
||||
|
||||
// deselect OSD SPI device
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
// enable displaying of OSD
|
||||
void OsdEnable(unsigned char mode)
|
||||
{
|
||||
user_io_osd_key_enable(mode & DISABLE_KEYBOARD);
|
||||
|
||||
if (!is_minimig())
|
||||
spi_osd_cmd(MM1_OSDCMDENABLE | (mode & DISABLE_KEYBOARD));
|
||||
else
|
||||
spi_osd_cmd8(OSD_CMD_OSD, 0x01 | (mode & DISABLE_KEYBOARD));
|
||||
}
|
||||
|
||||
// disable displaying of OSD
|
||||
void OsdDisable(void)
|
||||
{
|
||||
user_io_osd_key_enable(0);
|
||||
|
||||
if (!is_minimig())
|
||||
spi_osd_cmd(MM1_OSDCMDDISABLE);
|
||||
else
|
||||
spi_osd_cmd8(OSD_CMD_OSD, 0x00);
|
||||
}
|
||||
|
||||
void OsdReset(unsigned char boot)
|
||||
{
|
||||
spi_osd_cmd8(OSD_CMD_RST, 0x01);
|
||||
spi_osd_cmd8(OSD_CMD_RST, 0x00);
|
||||
}
|
||||
|
||||
void MM1_ConfigFilter(unsigned char lores, unsigned char hires) {
|
||||
spi_osd_cmd(MM1_OSDCMDCFGFLT | ((hires & 0x03) << 2) | (lores & 0x03));
|
||||
}
|
||||
|
||||
void ConfigVideo(unsigned char hires, unsigned char lores, unsigned char scanlines)
|
||||
{
|
||||
spi_osd_cmd16(OSD_CMD_VID, (((scanlines >> 6) & 0x03) << 10) | (((scanlines >> 4) & 0x03) << 8) | (((scanlines >> 2) & 0x03) << 6) | ((hires & 0x03) << 4) | ((lores & 0x03) << 2) | (scanlines & 0x03));
|
||||
}
|
||||
|
||||
void ConfigMemory(unsigned char memory)
|
||||
{
|
||||
spi_osd_cmd8(OSD_CMD_MEM, memory);
|
||||
}
|
||||
|
||||
void ConfigCPU(unsigned char cpu)
|
||||
{
|
||||
spi_osd_cmd8(OSD_CMD_CPU, cpu & 0x0f);
|
||||
}
|
||||
|
||||
void ConfigChipset(unsigned char chipset)
|
||||
{
|
||||
spi_osd_cmd8(OSD_CMD_CHIP, chipset & 0x1f);
|
||||
}
|
||||
|
||||
void ConfigFloppy(unsigned char drives, unsigned char speed)
|
||||
{
|
||||
spi_osd_cmd8(OSD_CMD_FLP, ((drives & 0x03) << 2) | (speed & 0x03));
|
||||
}
|
||||
|
||||
void MM1_ConfigScanlines(unsigned char scanlines)
|
||||
{
|
||||
spi_osd_cmd(MM1_OSDCMDCFGSCL | (scanlines & 0x0F));
|
||||
}
|
||||
|
||||
void ConfigIDE(unsigned char gayle, unsigned char master, unsigned char slave)
|
||||
{
|
||||
spi_osd_cmd8(OSD_CMD_HDD, (slave ? 4 : 0) | (master ? 2 : 0) | (gayle ? 1 : 0));
|
||||
}
|
||||
|
||||
void ConfigAutofire(unsigned char autofire)
|
||||
{
|
||||
spi_osd_cmd8(OSD_CMD_JOY, autofire & 0x07);
|
||||
}
|
||||
|
||||
static unsigned char disable_menu = 0;
|
||||
|
||||
// get key status
|
||||
unsigned char OsdGetCtrl(void)
|
||||
{
|
||||
static unsigned char c2;
|
||||
static unsigned long delay;
|
||||
static unsigned long repeat;
|
||||
static unsigned char repeat2;
|
||||
unsigned char c1, c;
|
||||
|
||||
c1 = OsdKeyGet();
|
||||
|
||||
// OsdKeyGet permanently returns the last key event.
|
||||
|
||||
// generate normal "key-pressed" event
|
||||
c = 0;
|
||||
if (c1 != c2)
|
||||
c = c1;
|
||||
|
||||
c2 = c1;
|
||||
// inject a fake "MENU_KEY" if no menu is visible and the menu key is loaded
|
||||
if (!user_io_osd_is_visible() && is_menu_core())
|
||||
c = KEY_MENU;
|
||||
|
||||
// generate repeat "key-pressed" events
|
||||
if ((c1 & KEY_UPSTROKE) || (!c1))
|
||||
repeat = GetTimer(REPEATDELAY);
|
||||
else if (CheckTimer(repeat)) {
|
||||
repeat = GetTimer(REPEATRATE);
|
||||
if (c1 == KEY_UP || c1 == KEY_DOWN)
|
||||
c = c1;
|
||||
repeat2++;
|
||||
if (repeat2 == 2)
|
||||
{
|
||||
repeat2 = 0;
|
||||
if (c1 == KEY_PGUP || c1 == KEY_PGDN || c1 == KEY_LEFT || c1 == KEY_RIGHT || GetASCIIKey(c1))
|
||||
c = c1;
|
||||
}
|
||||
}
|
||||
|
||||
// currently no key pressed
|
||||
if (!c)
|
||||
{
|
||||
static unsigned char last_but = 0;
|
||||
if (!disable_menu)
|
||||
{
|
||||
unsigned char but = user_io_menu_button();
|
||||
if (!but && last_but) c = KEY_MENU;
|
||||
last_but = but;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_but = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
void OsdDisableMenuButton(unsigned char disable)
|
||||
{
|
||||
disable_menu = disable;
|
||||
}
|
||||
|
||||
unsigned char GetASCIIKey(unsigned char keycode)
|
||||
{
|
||||
if (keycode & KEY_UPSTROKE)
|
||||
return 0;
|
||||
|
||||
return keycode_table[keycode & 0x7F];
|
||||
}
|
||||
|
||||
void ScrollText(char n, const char *str, int off, int len, int max_len, unsigned char invert)
|
||||
{
|
||||
// this function is called periodically when a string longer than the window is displayed.
|
||||
|
||||
#define BLANKSPACE 10 // number of spaces between the end and start of repeated name
|
||||
|
||||
char s[40];
|
||||
long offset;
|
||||
if (!max_len) max_len = 30;
|
||||
|
||||
if (str && str[0] && CheckTimer(scroll_timer)) // scroll if long name and timer delay elapsed
|
||||
{
|
||||
scroll_timer = GetTimer(SCROLL_DELAY2); // reset scroll timer to repeat delay
|
||||
|
||||
scroll_offset++; // increase scroll position (1 pixel unit)
|
||||
memset(s, ' ', 32); // clear buffer
|
||||
|
||||
if (!len) len = strlen(str); // get name length
|
||||
|
||||
if (off+len > max_len) // scroll name if longer than display size
|
||||
{
|
||||
// reset scroll position if it exceeds predefined maximum
|
||||
if (scroll_offset >= (len + BLANKSPACE) << 3) scroll_offset = 0;
|
||||
|
||||
offset = scroll_offset >> 3; // get new starting character of the name (scroll_offset is no longer in 2 pixel unit)
|
||||
len -= offset; // remaining number of characters in the name
|
||||
if (len>max_len) len = max_len;
|
||||
if (len > 0) strncpy(s, &str[offset], len); // copy name substring
|
||||
|
||||
if (len < max_len - BLANKSPACE) // file name substring and blank space is shorter than display line size
|
||||
{
|
||||
strncpy(s + len + BLANKSPACE, str, max_len - len - BLANKSPACE); // repeat the name after its end and predefined number of blank space
|
||||
}
|
||||
|
||||
OSD_PrintText(n, s, 22, (max_len - 1) << 3, (scroll_offset & 0x7), invert); // OSD print function with pixel precision
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollReset()
|
||||
{
|
||||
scroll_timer = GetTimer(SCROLL_DELAY); // set timer to start name scrolling after predefined time delay
|
||||
scroll_offset = 0; // start scrolling from the start
|
||||
}
|
||||
|
||||
/* the Atari core handles OSD keys competely inside the core */
|
||||
static unsigned char osd_key;
|
||||
|
||||
void OsdKeySet(unsigned char c) {
|
||||
// iprintf("OSD enqueue: %x\n", c);
|
||||
osd_key = c;
|
||||
}
|
||||
|
||||
unsigned char OsdKeyGet() {
|
||||
return osd_key;
|
||||
}
|
||||
|
||||
|
||||
/* core currently loaded */
|
||||
static char lastcorename[261 + 10] = "CORE";
|
||||
void OsdCoreNameSet(const char* str) {
|
||||
siprintf(lastcorename, "%s", str);
|
||||
}
|
||||
char* OsdCoreName() {
|
||||
return lastcorename;
|
||||
}
|
||||
147
osd.h
Normal file
147
osd.h
Normal file
@@ -0,0 +1,147 @@
|
||||
#ifndef OSD_H_INCLUDED
|
||||
#define OSD_H_INCLUDED
|
||||
|
||||
/*constants*/
|
||||
#define OSDCTRLUP 0x01 /*OSD up control*/
|
||||
#define OSDCTRLDOWN 0x02 /*OSD down control*/
|
||||
#define OSDCTRLSELECT 0x04 /*OSD select control*/
|
||||
#define OSDCTRLMENU 0x08 /*OSD menu control*/
|
||||
#define OSDCTRLRIGHT 0x10 /*OSD right control*/
|
||||
#define OSDCTRLLEFT 0x20 /*OSD left control*/
|
||||
|
||||
// some constants
|
||||
#define OSDNLINE 8 // number of lines of OSD
|
||||
#define OSDLINELEN 256 // single line length in bytes
|
||||
|
||||
// ---- old Minimig v1 constants -------
|
||||
#define MM1_OSDCMDREAD 0x00 // OSD read controller/key status
|
||||
#define MM1_OSDCMDWRITE 0x20 // OSD write video data command
|
||||
#define MM1_OSDCMDENABLE 0x41 // OSD enable command
|
||||
#define MM1_OSDCMDDISABLE 0x40 // OSD disable command
|
||||
#define MM1_OSDCMDRST 0x80 // OSD reset command
|
||||
#define MM1_OSDCMDAUTOFIRE 0x84 // OSD autofire command
|
||||
#define MM1_OSDCMDCFGSCL 0xA0 // OSD settings: scanlines effect
|
||||
#define MM1_OSDCMDCFGIDE 0xB0 // OSD enable HDD command
|
||||
#define MM1_OSDCMDCFGFLP 0xC0 // OSD settings: floppy config
|
||||
#define MM1_OSDCMDCFGCHP 0xD0 // OSD settings: chipset config
|
||||
#define MM1_OSDCMDCFGFLT 0xE0 // OSD settings: filter
|
||||
#define MM1_OSDCMDCFGMEM 0xF0 // OSD settings: memory config
|
||||
#define MM1_OSDCMDCFGCPU 0xFC // OSD settings: CPU config
|
||||
|
||||
// ---- new Minimig v2 constants -------
|
||||
#define OSD_CMD_READ 0x00
|
||||
#define OSD_CMD_RST 0x08
|
||||
#define OSD_CMD_CLK 0x18
|
||||
#define OSD_CMD_OSD 0x28
|
||||
#define OSD_CMD_CHIP 0x04
|
||||
#define OSD_CMD_CPU 0x14
|
||||
#define OSD_CMD_MEM 0x24
|
||||
#define OSD_CMD_VID 0x34
|
||||
#define OSD_CMD_FLP 0x44
|
||||
#define OSD_CMD_HDD 0x54
|
||||
#define OSD_CMD_JOY 0x64
|
||||
#define OSD_CMD_OSD_WR 0x0c
|
||||
#define OSD_CMD_WR 0x1c
|
||||
#define OSD_CMD_VERSION 0x88
|
||||
|
||||
#define DISABLE_KEYBOARD 0x02 // disable keyboard while OSD is active
|
||||
|
||||
#define REPEATDELAY 500 // repeat delay in 1ms units
|
||||
#define REPEATRATE 50 // repeat rate in 1ms units
|
||||
#define BUTTONDELAY 20 // repeat rate in 1ms units
|
||||
|
||||
#define KEY_UPSTROKE 0x80
|
||||
#define KEY_MENU 0x69
|
||||
#define KEY_PGUP 0x6C
|
||||
#define KEY_PGDN 0x6D
|
||||
#define KEY_HOME 0x6A
|
||||
#define KEY_ESC 0x45
|
||||
#define KEY_KPENTER 0x43
|
||||
#define KEY_ENTER 0x44
|
||||
#define KEY_BACK 0x41
|
||||
#define KEY_SPACE 0x40
|
||||
#define KEY_UP 0x4C
|
||||
#define KEY_DOWN 0x4D
|
||||
#define KEY_LEFT 0x4F
|
||||
#define KEY_RIGHT 0x4E
|
||||
#define KEY_F1 0x50
|
||||
#define KEY_F2 0x51
|
||||
#define KEY_F3 0x52
|
||||
#define KEY_F4 0x53
|
||||
#define KEY_F5 0x54
|
||||
#define KEY_F6 0x55
|
||||
#define KEY_F7 0x56
|
||||
#define KEY_F8 0x57
|
||||
#define KEY_F9 0x58
|
||||
#define KEY_F10 0x59
|
||||
#define KEY_CTRL 0x63
|
||||
#define KEY_LALT 0x64
|
||||
#define KEY_KPPLUS 0x5E
|
||||
#define KEY_KPMINUS 0x4A
|
||||
#define KEY_KP0 0x0F
|
||||
|
||||
#define CONFIG_TURBO 1
|
||||
#define CONFIG_NTSC 2
|
||||
#define CONFIG_A1000 4
|
||||
#define CONFIG_ECS 8
|
||||
#define CONFIG_AGA 16
|
||||
|
||||
#define CONFIG_FLOPPY1X 0
|
||||
#define CONFIG_FLOPPY2X 1
|
||||
|
||||
#define RESET_NORMAL 0
|
||||
#define RESET_BOOTLOADER 1
|
||||
|
||||
#define OSD_ARROW_LEFT 1
|
||||
#define OSD_ARROW_RIGHT 2
|
||||
|
||||
#define OSD_TURBO_STEP 50
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/*functions*/
|
||||
void OsdSetTitle(char *s, int arrow); // arrow > 0 = display right arrow in bottom right, < 0 = display left arrow
|
||||
void OsdWrite(unsigned char n, char *s, unsigned char inver, unsigned char stipple);
|
||||
void OsdWriteOffset(unsigned char n, char *s, unsigned char inver, unsigned char stipple, char offset, char leftchar); // Used for scrolling "Exit" text downwards...
|
||||
void OsdClear(void);
|
||||
void OsdEnable(unsigned char mode);
|
||||
void OsdDisable(void);
|
||||
void OsdWaitVBL(void);
|
||||
void OsdReset(unsigned char boot);
|
||||
void ConfigFilter(unsigned char lores, unsigned char hires);
|
||||
void OsdReconfig(); // Reset to Chameleon core.
|
||||
// deprecated functions from Minimig 1
|
||||
void MM1_ConfigFilter(unsigned char lores, unsigned char hires);
|
||||
void MM1_ConfigScanlines(unsigned char scanlines);
|
||||
void ConfigVideo(unsigned char hires, unsigned char lores, unsigned char scanlines);
|
||||
void ConfigMemory(unsigned char memory);
|
||||
void ConfigCPU(unsigned char cpu);
|
||||
void ConfigChipset(unsigned char chipset);
|
||||
void ConfigFloppy(unsigned char drives, unsigned char speed);
|
||||
void ConfigIDE(unsigned char gayle, unsigned char master, unsigned char slave);
|
||||
void ConfigAutofire(unsigned char autofire);
|
||||
unsigned char OsdGetCtrl(void);
|
||||
void OsdDisableMenuButton(unsigned char disable);
|
||||
unsigned char GetASCIIKey(unsigned char c);
|
||||
void OSD_PrintText(unsigned char line, char *text, unsigned long start, unsigned long width, unsigned long offset, unsigned char invert);
|
||||
void OsdWriteDoubleSize(unsigned char n, char *s, unsigned char pass);
|
||||
//void OsdDrawLogo(unsigned char n, char row);
|
||||
void OsdDrawLogo(unsigned char n, char row, char superimpose);
|
||||
void ScrollText(char n, const char *str, int off, int len, int max_len, unsigned char invert);
|
||||
void ScrollReset();
|
||||
void StarsInit();
|
||||
void StarsUpdate();
|
||||
|
||||
void OsdKeySet(unsigned char);
|
||||
unsigned char OsdKeyGet();
|
||||
|
||||
// get/set core currently loaded
|
||||
void OsdCoreNameSet(const char* str);
|
||||
char* OsdCoreName();
|
||||
void OsdSetSize(int n);
|
||||
int OsdGetSize();
|
||||
|
||||
#define OsdIsBig (OsdGetSize()>8)
|
||||
|
||||
#endif
|
||||
|
||||
314
spi.c
Normal file
314
spi.c
Normal file
@@ -0,0 +1,314 @@
|
||||
#include "spi.h"
|
||||
#include "hardware.h"
|
||||
#include "fpga_io.h"
|
||||
|
||||
#define SSPI_STROBE (1<<17)
|
||||
#define SSPI_ACK SSPI_STROBE
|
||||
|
||||
#define SSPI_FPGA_EN (1<<18)
|
||||
#define SSPI_OSD_EN (1<<19)
|
||||
#define SSPI_IO_EN (1<<20)
|
||||
#define SSPI_DM_EN (1<<21)
|
||||
|
||||
#define SWAPW(a) ((((a)<<8)&0xff00)|(((a)>>8)&0x00ff))
|
||||
|
||||
static void spi_en(uint32_t mask, uint32_t en)
|
||||
{
|
||||
uint32_t gpo = fpga_gpo_read();
|
||||
fpga_gpo_write(en ? gpo | mask : gpo & ~mask);
|
||||
}
|
||||
|
||||
uint16_t spi_w(uint16_t word)
|
||||
{
|
||||
uint32_t gpo = (fpga_gpo_read() & ~(0xFFFF | SSPI_STROBE)) | word;
|
||||
|
||||
fpga_gpo_write(gpo);
|
||||
fpga_gpo_write(gpo | SSPI_STROBE);
|
||||
|
||||
int gpi;
|
||||
do
|
||||
{
|
||||
gpi = fpga_gpi_read();
|
||||
if (gpi < 0)
|
||||
{
|
||||
printf("GPI[31]==1. FPGA is uninitialized?\n");
|
||||
return 0;
|
||||
}
|
||||
} while (!(gpi & SSPI_ACK));
|
||||
|
||||
fpga_gpo_write(gpo);
|
||||
|
||||
do
|
||||
{
|
||||
gpi = fpga_gpi_read();
|
||||
if (gpi < 0)
|
||||
{
|
||||
printf("GPI[31]==1. FPGA is uninitialized?\n");
|
||||
return 0;
|
||||
}
|
||||
} while (gpi & SSPI_ACK);
|
||||
|
||||
return (uint16_t)gpi;
|
||||
}
|
||||
|
||||
void spi_init(int enable)
|
||||
{
|
||||
printf("Init SPI.\n");
|
||||
}
|
||||
|
||||
uint8_t spi_b(uint8_t parm)
|
||||
{
|
||||
return (uint8_t)spi_w(parm);
|
||||
}
|
||||
|
||||
void EnableFpga()
|
||||
{
|
||||
spi_en(SSPI_FPGA_EN, 1);
|
||||
}
|
||||
|
||||
void DisableFpga()
|
||||
{
|
||||
spi_en(SSPI_FPGA_EN, 0);
|
||||
}
|
||||
|
||||
void EnableOsd()
|
||||
{
|
||||
spi_en(SSPI_OSD_EN, 1);
|
||||
}
|
||||
|
||||
void DisableOsd()
|
||||
{
|
||||
spi_en(SSPI_OSD_EN, 0);
|
||||
}
|
||||
|
||||
void EnableIO()
|
||||
{
|
||||
spi_en(SSPI_IO_EN, 1);
|
||||
}
|
||||
|
||||
void DisableIO()
|
||||
{
|
||||
spi_en(SSPI_IO_EN, 0);
|
||||
}
|
||||
|
||||
void EnableDMode()
|
||||
{
|
||||
spi_en(SSPI_DM_EN, 1);
|
||||
}
|
||||
|
||||
void DisableDMode()
|
||||
{
|
||||
spi_en(SSPI_DM_EN, 0);
|
||||
}
|
||||
|
||||
uint8_t spi_in()
|
||||
{
|
||||
return spi_b(0);
|
||||
}
|
||||
|
||||
void spi8(uint8_t parm)
|
||||
{
|
||||
spi_b(parm);
|
||||
}
|
||||
|
||||
void spi16(uint16_t parm)
|
||||
{
|
||||
spi8(parm >> 8);
|
||||
spi8(parm >> 0);
|
||||
}
|
||||
|
||||
void spi24(uint32_t parm)
|
||||
{
|
||||
spi8(parm >> 16);
|
||||
spi8(parm >> 8);
|
||||
spi8(parm >> 0);
|
||||
}
|
||||
|
||||
void spi32(uint32_t parm)
|
||||
{
|
||||
spi8(parm >> 24);
|
||||
spi8(parm >> 16);
|
||||
spi8(parm >> 8);
|
||||
spi8(parm >> 0);
|
||||
}
|
||||
|
||||
// little endian: lsb first
|
||||
void spi32le(uint32_t parm)
|
||||
{
|
||||
spi8(parm >> 0);
|
||||
spi8(parm >> 8);
|
||||
spi8(parm >> 16);
|
||||
spi8(parm >> 24);
|
||||
}
|
||||
|
||||
/* OSD related SPI functions */
|
||||
void spi_osd_cmd_cont(uint8_t cmd)
|
||||
{
|
||||
EnableOsd();
|
||||
spi8(cmd);
|
||||
}
|
||||
|
||||
void spi_osd_cmd(uint8_t cmd)
|
||||
{
|
||||
spi_osd_cmd_cont(cmd);
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
void spi_osd_cmd8_cont(uint8_t cmd, uint8_t parm)
|
||||
{
|
||||
EnableOsd();
|
||||
spi8(cmd);
|
||||
spi8(parm);
|
||||
}
|
||||
|
||||
void spi_osd_cmd8(uint8_t cmd, uint8_t parm)
|
||||
{
|
||||
spi_osd_cmd8_cont(cmd, parm);
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
void spi_osd_cmd16(uint8_t cmd, uint16_t parm)
|
||||
{
|
||||
EnableOsd();
|
||||
spi8(cmd);
|
||||
spi_w(parm);
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
void spi_osd_cmd32_cont(uint8_t cmd, uint32_t parm)
|
||||
{
|
||||
EnableOsd();
|
||||
spi8(cmd);
|
||||
spi32(parm);
|
||||
}
|
||||
|
||||
void spi_osd_cmd32(uint8_t cmd, uint32_t parm)
|
||||
{
|
||||
spi_osd_cmd32_cont(cmd, parm);
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
void spi_osd_cmd32le_cont(uint8_t cmd, uint32_t parm)
|
||||
{
|
||||
EnableOsd();
|
||||
spi8(cmd);
|
||||
spi32le(parm);
|
||||
}
|
||||
|
||||
void spi_osd_cmd32le(uint8_t cmd, uint32_t parm)
|
||||
{
|
||||
spi_osd_cmd32le_cont(cmd, parm);
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
/* User_io related SPI functions */
|
||||
void spi_uio_cmd_cont(uint8_t cmd)
|
||||
{
|
||||
EnableIO();
|
||||
spi8(cmd);
|
||||
}
|
||||
|
||||
void spi_uio_cmd(uint8_t cmd)
|
||||
{
|
||||
spi_uio_cmd_cont(cmd);
|
||||
DisableIO();
|
||||
}
|
||||
|
||||
void spi_uio_cmd8_cont(uint8_t cmd, uint8_t parm)
|
||||
{
|
||||
EnableIO();
|
||||
spi8(cmd);
|
||||
spi8(parm);
|
||||
}
|
||||
|
||||
void spi_uio_cmd8(uint8_t cmd, uint8_t parm)
|
||||
{
|
||||
spi_uio_cmd8_cont(cmd, parm);
|
||||
DisableIO();
|
||||
}
|
||||
|
||||
void spi_uio_cmd32(uint8_t cmd, uint32_t parm, int wide)
|
||||
{
|
||||
EnableIO();
|
||||
spi8(cmd);
|
||||
if (wide)
|
||||
{
|
||||
spi_w((uint16_t)parm);
|
||||
spi_w((uint16_t)(parm >> 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
spi8(parm);
|
||||
spi8(parm >> 8);
|
||||
spi8(parm >> 16);
|
||||
spi8(parm >> 24);
|
||||
}
|
||||
DisableIO();
|
||||
}
|
||||
|
||||
void spi_n(uint8_t value, uint16_t cnt)
|
||||
{
|
||||
while (cnt--) spi8(value);
|
||||
}
|
||||
|
||||
void spi_read(uint8_t *addr, uint16_t len, int wide)
|
||||
{
|
||||
if (wide)
|
||||
{
|
||||
uint16_t len16 = len >> 1;
|
||||
uint16_t *a16 = (uint16_t*)addr;
|
||||
while (len16--) *a16++ = spi_w(0);
|
||||
if (len & 1) *((uint8_t*)a16) = spi_w(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (len--) *addr++ = spi_b(0);
|
||||
}
|
||||
}
|
||||
|
||||
void spi_write(uint8_t *addr, uint16_t len, int wide)
|
||||
{
|
||||
if (wide)
|
||||
{
|
||||
uint16_t len16 = len >> 1;
|
||||
uint16_t *a16 = (uint16_t*)addr;
|
||||
while (len16--) spi_w(*a16++);
|
||||
if(len & 1) spi_w(*((uint8_t*)a16));
|
||||
}
|
||||
else
|
||||
{
|
||||
while (len--) spi8(*addr++);
|
||||
}
|
||||
}
|
||||
|
||||
void spi_block_read(uint8_t *addr, int wide)
|
||||
{
|
||||
spi_read(addr, 512, wide);
|
||||
}
|
||||
|
||||
void spi_block_write(uint8_t *addr, int wide)
|
||||
{
|
||||
spi_write(addr, 512, wide);
|
||||
}
|
||||
|
||||
void spi_block_write_16be(uint16_t *addr)
|
||||
{
|
||||
uint16_t len = 256;
|
||||
uint16_t tmp;
|
||||
while (len--)
|
||||
{
|
||||
tmp = *addr++;
|
||||
spi_w(SWAPW(tmp));
|
||||
}
|
||||
}
|
||||
|
||||
void spi_block_read_16be(uint16_t *addr)
|
||||
{
|
||||
uint16_t len = 256;
|
||||
uint16_t tmp;
|
||||
while (len--)
|
||||
{
|
||||
tmp = spi_w(0xFFFF);
|
||||
*addr++ = SWAPW(tmp);
|
||||
}
|
||||
}
|
||||
59
spi.h
Normal file
59
spi.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef SPI_H
|
||||
#define SPI_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/* main init functions */
|
||||
void spi_init(int enable);
|
||||
|
||||
/* chip select functions */
|
||||
void EnableFpga();
|
||||
void DisableFpga();
|
||||
void EnableOsd();
|
||||
void DisableOsd();
|
||||
void EnableDMode();
|
||||
void DisableDMode();
|
||||
void EnableIO();
|
||||
void DisableIO();
|
||||
|
||||
// base functions
|
||||
uint8_t spi_b(uint8_t parm);
|
||||
uint16_t spi_w(uint16_t word);
|
||||
|
||||
// input only helper
|
||||
uint8_t spi_in();
|
||||
|
||||
void spi8(uint8_t parm);
|
||||
void spi16(uint16_t parm);
|
||||
void spi24(uint32_t parm);
|
||||
void spi32(uint32_t parm);
|
||||
void spi32le(uint32_t parm);
|
||||
void spi_n(uint8_t value, uint16_t cnt);
|
||||
|
||||
/* block transfer functions */
|
||||
void spi_block_read(uint8_t *addr, int wide);
|
||||
void spi_read(uint8_t *addr, uint16_t len, int wide);
|
||||
void spi_block_write(uint8_t *addr, int wide);
|
||||
void spi_write(uint8_t *addr, uint16_t len, int wide);
|
||||
void spi_block_write_16be(uint16_t *addr);
|
||||
void spi_block_read_16be(uint16_t *addr);
|
||||
|
||||
/* OSD related SPI functions */
|
||||
void spi_osd_cmd_cont(uint8_t cmd);
|
||||
void spi_osd_cmd(uint8_t cmd);
|
||||
void spi_osd_cmd8_cont(uint8_t cmd, uint8_t parm);
|
||||
void spi_osd_cmd8(uint8_t cmd, uint8_t parm);
|
||||
void spi_osd_cmd16(uint8_t cmd, uint16_t parm);
|
||||
void spi_osd_cmd32_cont(uint8_t cmd, uint32_t parm);
|
||||
void spi_osd_cmd32(uint8_t cmd, uint32_t parm);
|
||||
void spi_osd_cmd32le_cont(uint8_t cmd, uint32_t parm);
|
||||
void spi_osd_cmd32le(uint8_t cmd, uint32_t parm);
|
||||
|
||||
/* User_io related SPI functions */
|
||||
void spi_uio_cmd_cont(uint8_t cmd);
|
||||
void spi_uio_cmd(uint8_t cmd);
|
||||
void spi_uio_cmd8(uint8_t cmd, uint8_t parm);
|
||||
void spi_uio_cmd8_cont(uint8_t cmd, uint8_t parm);
|
||||
void spi_uio_cmd32(uint8_t cmd, uint32_t parm, int wide);
|
||||
|
||||
#endif // SPI_H
|
||||
365
state.c
Normal file
365
state.c
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
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/>.
|
||||
|
||||
This code keeps status of MiST state
|
||||
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "stdio.h"
|
||||
|
||||
#include "state.h"
|
||||
#include "osd.h"
|
||||
#include "hardware.h"
|
||||
|
||||
//#include "charrom.h"
|
||||
|
||||
|
||||
|
||||
// for I/O
|
||||
static mist_joystick_t mist_joystick_temp = {
|
||||
.vid = 0,
|
||||
.pid = 0,
|
||||
.num_buttons = 1, // DB9 has 1 button
|
||||
.state = 0,
|
||||
.state_extra = 0,
|
||||
.usb_state = 0,
|
||||
.usb_state_extra = 0,
|
||||
.turbo = 0,
|
||||
.turbo_counter = 0,
|
||||
.turbo_mask = 0x30, // A and B buttons
|
||||
.turbo_state = 0xFF // flip state (0 or 1)
|
||||
};
|
||||
|
||||
/* latest joystick state */
|
||||
static mist_joystick_t mist_joysticks[3] = { // 3rd one is dummy, used to store defaults
|
||||
{
|
||||
.vid = 0,
|
||||
.pid = 0,
|
||||
.num_buttons = 1, // DB9 has 1 button
|
||||
.state = 0,
|
||||
.state_extra = 0,
|
||||
.usb_state = 0,
|
||||
.usb_state_extra = 0,
|
||||
.turbo = 0,
|
||||
.turbo_counter = 0,
|
||||
.turbo_mask = 0x30, // A and B buttons
|
||||
.turbo_state = 0xFF // flip state (0 or 1)
|
||||
},
|
||||
{
|
||||
.vid = 0,
|
||||
.pid = 0,
|
||||
.num_buttons = 1, // DB9 has 1 button
|
||||
.state = 0,
|
||||
.state_extra = 0,
|
||||
.usb_state = 0,
|
||||
.usb_state_extra = 0,
|
||||
.turbo = 0,
|
||||
.turbo_counter = 0,
|
||||
.turbo_mask = 0x30, // A and B buttons
|
||||
.turbo_state = 0xFF // flip state (0 or 1)
|
||||
},
|
||||
{
|
||||
.vid = 0,
|
||||
.pid = 0,
|
||||
.num_buttons = 1, // DB9 has 1 button
|
||||
.state = 0,
|
||||
.state_extra = 0,
|
||||
.usb_state = 0,
|
||||
.usb_state_extra = 0,
|
||||
.turbo = 0,
|
||||
.turbo_counter = 0,
|
||||
.turbo_mask = 0x30, // A and B buttons
|
||||
.turbo_state = 0xFF // flip state (0 or 1)
|
||||
}
|
||||
};
|
||||
|
||||
void joy_reset(mist_joystick_t joy) {
|
||||
joy.vid = 0;
|
||||
joy.pid = 0;
|
||||
joy.num_buttons = 1; // DB9 has 1 button
|
||||
joy.state = 0;
|
||||
joy.state_extra = 0;
|
||||
joy.usb_state = 0;
|
||||
joy.usb_state_extra = 0;
|
||||
joy.turbo = 0;
|
||||
joy.turbo_counter = 0;
|
||||
joy.turbo_mask = 0x30; // A and B buttons
|
||||
joy.turbo_state = 0xFF; // flip state (0 or 1)
|
||||
}
|
||||
|
||||
// sets a joystick to input status
|
||||
void StateJoyCopy(uint8_t num_joy, mist_joystick_t* joy) {
|
||||
mist_joystick_t mine;
|
||||
if (num_joy>1) return;
|
||||
if (!joy) return;
|
||||
mine = mist_joysticks[num_joy];
|
||||
mine.vid = joy->vid;
|
||||
mine.pid = joy->pid;
|
||||
mine.num_buttons = joy->num_buttons;
|
||||
mine.state = joy->state;
|
||||
mine.state_extra = joy->state_extra;
|
||||
mine.usb_state = joy->usb_state;
|
||||
mine.usb_state_extra = joy->usb_state_extra;
|
||||
mine.turbo = joy->turbo;
|
||||
mine.turbo_counter = joy->turbo_counter;
|
||||
mine.turbo_mask = joy->turbo_mask;
|
||||
mine.turbo_state = joy->turbo_state;
|
||||
}
|
||||
|
||||
void StateJoyRead(uint8_t num_joy, mist_joystick_t* joy) {
|
||||
mist_joystick_t mine;
|
||||
if (num_joy>1) return;
|
||||
if (!joy) return;
|
||||
mine = mist_joysticks[num_joy];
|
||||
joy->vid = mine.vid;
|
||||
joy->pid = mine.pid;
|
||||
joy->num_buttons = mine.num_buttons;
|
||||
joy->state = mine.state;
|
||||
joy->state_extra = mine.state_extra;
|
||||
joy->usb_state = mine.usb_state;
|
||||
joy->usb_state_extra = mine.usb_state_extra;
|
||||
joy->turbo = mine.turbo;
|
||||
joy->turbo_counter = mine.turbo_counter;
|
||||
joy->turbo_mask = mine.turbo_mask;
|
||||
joy->turbo_state = mine.turbo_state;
|
||||
}
|
||||
|
||||
// returns a copy of a status structure
|
||||
mist_joystick_t StateJoyGetStructure(uint8_t num_joy) {
|
||||
StateJoyRead(num_joy, &mist_joystick_temp);
|
||||
return mist_joystick_temp;
|
||||
}
|
||||
|
||||
// applies the turbo to a given joystick
|
||||
mist_joystick_t StateJoyUpdateTurboStructure(uint8_t num_joy) {
|
||||
StateJoyRead(num_joy, &mist_joystick_temp);
|
||||
StateTurboUpdate(&mist_joystick_temp);
|
||||
//mist_joystick_t mine = mist_joystick_temp;
|
||||
StateJoyCopy(num_joy, &mist_joystick_temp);
|
||||
}
|
||||
|
||||
uint8_t StateJoyStructureState(uint8_t num_joy) {
|
||||
mist_joystick_t mine;
|
||||
mine = StateJoyGetStructure(num_joy);
|
||||
return mine.state;
|
||||
}
|
||||
|
||||
/* latest joystick state */
|
||||
static uint8_t osd_joy;
|
||||
static uint8_t osd_joy_extra;
|
||||
static uint8_t osd_joy2;
|
||||
static uint8_t osd_joy_extra2;
|
||||
void StateJoySet(uint8_t c, uint8_t joy_num) {
|
||||
//iprintf("OSD joy: %x\n", c);
|
||||
if (joy_num == 0)
|
||||
osd_joy = c;
|
||||
else
|
||||
osd_joy2 = c;
|
||||
}
|
||||
void StateJoySetExtra(uint8_t c, uint8_t joy_num) {
|
||||
if (joy_num == 0)
|
||||
osd_joy_extra = c;
|
||||
else
|
||||
osd_joy_extra2 = c;
|
||||
}
|
||||
uint8_t StateJoyGet(uint8_t joy_num) {
|
||||
return joy_num == 0 ? osd_joy : osd_joy2;
|
||||
}
|
||||
uint8_t StateJoyGetExtra(uint8_t joy_num) {
|
||||
return joy_num == 0 ? osd_joy_extra : osd_joy_extra2;
|
||||
}
|
||||
|
||||
static uint8_t raw_usb_joy; // four directions and 4 buttons
|
||||
static uint8_t raw_usb_joy_extra; // eight extra buttons
|
||||
static uint8_t raw_usb_joy_b; // four directions and 4 buttons
|
||||
static uint8_t raw_usb_joy_extra_b; // eight extra buttons
|
||||
void StateUsbJoySet(uint8_t usbjoy, uint8_t usbextra, uint8_t joy_num) {
|
||||
if (joy_num == 0) {
|
||||
raw_usb_joy = usbjoy;
|
||||
raw_usb_joy_extra = usbextra;
|
||||
}
|
||||
else {
|
||||
raw_usb_joy_b = usbjoy;
|
||||
raw_usb_joy_extra_b = usbextra;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t StateUsbJoyGet(uint8_t joy_num) {
|
||||
return (joy_num == 0) ? raw_usb_joy : raw_usb_joy_b;
|
||||
}
|
||||
uint8_t StateUsbJoyGetExtra(uint8_t joy_num) {
|
||||
return (joy_num == 0) ? raw_usb_joy_extra : raw_usb_joy_extra_b;
|
||||
}
|
||||
|
||||
static uint16_t usb_vid;
|
||||
static uint16_t usb_pid;
|
||||
static uint8_t num_buttons;
|
||||
static uint16_t usb_vid_b;
|
||||
static uint16_t usb_pid_b;
|
||||
static uint8_t num_buttons_b;
|
||||
void StateUsbIdSet(uint16_t vid, uint16_t pid, uint8_t num, uint8_t joy_num) {
|
||||
if (joy_num == 0) {
|
||||
usb_vid = vid;
|
||||
usb_pid = pid;
|
||||
num_buttons = num;
|
||||
}
|
||||
else {
|
||||
usb_vid_b = vid;
|
||||
usb_pid_b = pid;
|
||||
num_buttons_b = num;
|
||||
}
|
||||
}
|
||||
uint16_t StateUsbVidGet(uint8_t joy_num) {
|
||||
return joy_num == 0 ? usb_vid : usb_vid_b;
|
||||
}
|
||||
uint16_t StateUsbPidGet(uint8_t joy_num) {
|
||||
return joy_num == 0 ? usb_pid : usb_pid_b;
|
||||
}
|
||||
uint8_t StateUsbGetNumButtons(uint8_t joy_num) {
|
||||
return (joy_num == 0) ? num_buttons : num_buttons_b;
|
||||
}
|
||||
|
||||
// return joystick state take into account turbo settings
|
||||
void StateJoyState(uint8_t joy_num, mist_joystick_t* joy) {
|
||||
mist_joystick_t mine;
|
||||
if (joy_num>1) return;
|
||||
if (!joy) return;
|
||||
joy->vid = StateUsbVidGet(joy_num);
|
||||
joy->pid = StateUsbPidGet(joy_num);
|
||||
//joy.num_buttons=1; // DB9 has 1 button
|
||||
joy->state = StateUsbPidGet(joy_num);
|
||||
joy->state_extra = StateJoyGetExtra(joy_num);
|
||||
joy->usb_state = StateUsbJoyGet(joy_num);
|
||||
joy->usb_state_extra = (joy_num);
|
||||
//apply turbo status
|
||||
joy->state = StateUsbPidGet(joy_num);
|
||||
if (joy->turbo > 0) {
|
||||
joy->state &= joy->turbo_state;
|
||||
}
|
||||
// chache into current static scope
|
||||
StateJoyCopy(joy_num, joy);
|
||||
}
|
||||
|
||||
/* handle button's turbo timers */
|
||||
void StateTurboUpdate(mist_joystick_t* joy) {
|
||||
if (!joy) return;
|
||||
if (joy->turbo == 0) return; // nothing to do
|
||||
joy->turbo_counter += 1;
|
||||
if (joy->turbo_counter > joy->turbo) {
|
||||
joy->turbo_counter = 0;
|
||||
joy->turbo_state ^= joy->turbo_mask;
|
||||
}
|
||||
}
|
||||
/* reset all turbo timers and state */
|
||||
void StateTurboReset(mist_joystick_t* joy) {
|
||||
if (!joy) return;
|
||||
joy->turbo_counter = 0;
|
||||
joy->turbo_state = 0xFF;
|
||||
}
|
||||
/* set a specific turbo mask and timeout */
|
||||
void StateTurboSet(mist_joystick_t* joy, uint16_t turbo, uint16_t mask) {
|
||||
if (!joy) return;
|
||||
StateTurboReset(joy);
|
||||
joy->turbo = turbo;
|
||||
joy->turbo_mask = mask;
|
||||
}
|
||||
|
||||
// Keep track of connected sticks
|
||||
uint8_t joysticks = 0;
|
||||
uint8_t StateNumJoysticks() {
|
||||
return joysticks;
|
||||
}
|
||||
|
||||
void StateNumJoysticksSet(uint8_t num) {
|
||||
joysticks = num;
|
||||
}
|
||||
|
||||
/* keyboard data */
|
||||
static uint8_t key_modifier = 0;
|
||||
static uint8_t key_pressed[6] = { 0,0,0,0,0,0 };
|
||||
static uint16_t keys_ps2[6] = { 0,0,0,0,0,0 };
|
||||
|
||||
void StateKeyboardPressedPS2(uint16_t *keycodes) {
|
||||
unsigned i = 0;
|
||||
for (i = 0; i<6; i++) {
|
||||
keycodes[i] = keys_ps2[i];
|
||||
}
|
||||
}
|
||||
void StateKeyboardSet(uint8_t modifier, uint8_t* keycodes, uint16_t* keycodes_ps2) {
|
||||
unsigned i = 0, j = 0;
|
||||
key_modifier = modifier;
|
||||
for (i = 0; i<6; i++) {
|
||||
//iprintf("Key N=%d, USB=%x, PS2=%x\n", i, keycodes[i], keycodes_ps2[i]);
|
||||
if (((keycodes[i] & 0xFF) != 0xFF) && (keycodes[i] & 0xFF)) {
|
||||
key_pressed[j] = keycodes[i];
|
||||
if ((keycodes_ps2[i] & 0xFF) != 0xFF) {
|
||||
// translate EXT into 0E
|
||||
if (0x1000 & keycodes_ps2[i]) {
|
||||
keys_ps2[j++] = (keycodes_ps2[i] & 0xFF) | 0xE000;
|
||||
}
|
||||
else {
|
||||
keys_ps2[j++] = keycodes_ps2[i] & 0xFF;
|
||||
}
|
||||
}
|
||||
else {
|
||||
keys_ps2[j++] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (j<6) {
|
||||
key_pressed[j] = 0;
|
||||
keys_ps2[j++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t StateKeyboardModifiers() {
|
||||
return key_modifier;
|
||||
}
|
||||
void StateKeyboardPressed(uint8_t *keycodes) {
|
||||
uint8_t i = 0;
|
||||
for (i = 0; i<6; i++)
|
||||
keycodes[i] = key_pressed[i];
|
||||
}
|
||||
|
||||
|
||||
/* core currently loaded */
|
||||
static char lastcorename[261 + 10] = "CORE";
|
||||
void StateCoreNameSet(const char* str) {
|
||||
siprintf(lastcorename, "%s", str);
|
||||
}
|
||||
char* StateCoreName() {
|
||||
return lastcorename;
|
||||
}
|
||||
|
||||
// clear all states
|
||||
void StateReset() {
|
||||
strcpy(lastcorename, "CORE");
|
||||
//State_key = 0;
|
||||
//joysticks=0;
|
||||
key_modifier = 0;
|
||||
for (int i = 0; i<6; i++) {
|
||||
key_pressed[i] = 0;
|
||||
keys_ps2[i] = 0;
|
||||
}
|
||||
//joy_reset(mist_joy[0]);
|
||||
//joy_reset(mist_joy[1]);
|
||||
//joy_reset(mist_joy[2]);
|
||||
}
|
||||
82
state.h
Normal file
82
state.h
Normal file
@@ -0,0 +1,82 @@
|
||||
#ifndef STATE_H_INCLUDED
|
||||
#define STATE_H_INCLUDED
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
void StateReset();
|
||||
|
||||
//// type definitions ////
|
||||
typedef struct {
|
||||
uint16_t vid; // USB vendor ID
|
||||
uint16_t pid; // USB product ID
|
||||
uint8_t num_buttons; // number of physical buttons reported by HID parsing
|
||||
uint8_t state; // virtual joystick: current state of 4 direction + 4 first buttons
|
||||
uint8_t state_extra; // current state of 8 more buttons
|
||||
uint8_t usb_state; // raw USB state of direction and buttons
|
||||
uint8_t usb_state_extra; // raw USB state of 8 more buttons
|
||||
uint16_t turbo; // 0 if disabled, otherwise max number to flip state
|
||||
uint16_t turbo_counter; // increased when using turbo, flips state when passing turbo
|
||||
uint8_t turbo_mask; // buttons subject to turbo
|
||||
uint8_t turbo_state; // current mask to apply
|
||||
|
||||
} mist_joystick_t;
|
||||
|
||||
|
||||
|
||||
/*****
|
||||
* Various functions to retrieve hardware state from the State
|
||||
*/
|
||||
|
||||
// USB raw data for joystick
|
||||
void StateUsbJoySet(uint8_t usbjoy, uint8_t usbextra, uint8_t joy_num);
|
||||
void StateUsbIdSet(uint16_t vid, uint16_t pid, uint8_t num_buttons, uint8_t joy_num);
|
||||
uint8_t StateUsbJoyGet(uint8_t joy_num);
|
||||
uint8_t StateUsbJoyGetExtra(uint8_t joy_num);
|
||||
uint8_t StateUsbGetNumButtons(uint8_t joy_num);
|
||||
uint16_t StateUsbVidGet(uint8_t joy_num);
|
||||
uint16_t StateUsbPidGet(uint8_t joy_num);
|
||||
|
||||
|
||||
// State of first (virtual) internal joystisk i.e. after mapping
|
||||
void StateJoySet(uint8_t c, uint8_t joy_num);
|
||||
void StateJoySetExtra(uint8_t c, uint8_t joy_num);
|
||||
uint8_t StateJoyGet(uint8_t joy_num);
|
||||
uint8_t StateJoyGetExtra(uint8_t joy_num);
|
||||
|
||||
// turbo button functions
|
||||
void StateTurboUpdate(mist_joystick_t* joy);
|
||||
void StateTurboReset(mist_joystick_t* joy);
|
||||
void StateTurboSet(mist_joystick_t* joy, uint16_t turbo, uint16_t mask);
|
||||
mist_joystick_t StateJoyUpdateTurboStructure(uint8_t num_joy);
|
||||
void StateJoyRead(uint8_t num_joy, mist_joystick_t* joy);
|
||||
void StateJoyCopy(uint8_t num_joy, mist_joystick_t* joy);
|
||||
uint8_t StateJoyStructureState(uint8_t num_joy);
|
||||
|
||||
|
||||
// Keep track of connected sticks
|
||||
uint8_t StateNumJoysticks();
|
||||
void StateNumJoysticksSet(uint8_t num);
|
||||
|
||||
// to get data
|
||||
void StateJoyState(uint8_t joy_num, mist_joystick_t* joy); // directions and 4 buttons, reflecting turbo settings
|
||||
|
||||
/*
|
||||
// turbo function
|
||||
void StateTurboUpdate(uint8_t joy_num);
|
||||
void StateTurboReset(uint8_t joy_num);
|
||||
void StateTurboSet ( uint16_t turbo, uint16_t mask, uint8_t joy_num );
|
||||
|
||||
*/
|
||||
|
||||
// keyboard status
|
||||
void StateKeyboardSet(uint8_t modifier, uint8_t* pressed, uint16_t* pressed_ps2); //get usb and ps2 codes
|
||||
uint8_t StateKeyboardModifiers();
|
||||
void StateKeyboardPressed(uint8_t *pressed);
|
||||
void StateKeyboardPressedPS2(uint16_t *keycodes);
|
||||
|
||||
// get/set core currently loaded
|
||||
void StateCoreNameSet(const char* str);
|
||||
char* StateCoreName();
|
||||
|
||||
#endif
|
||||
|
||||
107
tos.h
Normal file
107
tos.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#ifndef TOS_H
|
||||
#define TOS_H
|
||||
|
||||
#include "file_io.h"
|
||||
|
||||
// FPGA spi cmommands
|
||||
#define MIST_INVALID 0x00
|
||||
|
||||
// memory interface
|
||||
#define MIST_SET_ADDRESS 0x01
|
||||
#define MIST_WRITE_MEMORY 0x02
|
||||
#define MIST_READ_MEMORY 0x03
|
||||
#define MIST_SET_CONTROL 0x04
|
||||
#define MIST_GET_DMASTATE 0x05 // reads state of dma and floppy controller
|
||||
#define MIST_ACK_DMA 0x06 // acknowledge a dma command
|
||||
#define MIST_BUS_REQ 0x07 // request bus
|
||||
#define MIST_BUS_REL 0x08 // release bus
|
||||
#define MIST_SET_VADJ 0x09
|
||||
#define MIST_NAK_DMA 0x0a // reject a dma command
|
||||
|
||||
// tos sysconfig bits:
|
||||
// 0 - RESET
|
||||
// 1-3 - Memory configuration
|
||||
// 4-5 - CPU configuration
|
||||
// 6-7 - Floppy A+B write protection
|
||||
// 8 - Color/Monochrome mode
|
||||
// 9 - PAL mode in 56 or 50 Hz
|
||||
// 10-17 - ACSI device enable
|
||||
|
||||
// memory configurations (0x02/0x04/0x08)
|
||||
// (currently 4MB are fixed and cannot be changed)
|
||||
#define TOS_MEMCONFIG_512K (0<<1) // not yet supported
|
||||
#define TOS_MEMCONFIG_1M (1<<1) // not yet supported
|
||||
#define TOS_MEMCONFIG_2M (2<<1) // not yet supported
|
||||
#define TOS_MEMCONFIG_4M (3<<1) // not yet supported
|
||||
#define TOS_MEMCONFIG_8M (4<<1)
|
||||
#define TOS_MEMCONFIG_14M (5<<1)
|
||||
#define TOS_MEMCONFIG_RES0 (6<<1) // reserved
|
||||
#define TOS_MEMCONFIG_RES1 (7<<1) // reserved
|
||||
|
||||
// cpu configurations (0x10/0x20)
|
||||
#define TOS_CPUCONFIG_68000 (0<<4)
|
||||
#define TOS_CPUCONFIG_68010 (1<<4)
|
||||
#define TOS_CPUCONFIG_RESERVED (2<<4)
|
||||
#define TOS_CPUCONFIG_68020 (3<<4)
|
||||
|
||||
// control bits (all control bits have unknown state after core startup)
|
||||
#define TOS_CONTROL_CPU_RESET 0x00000001
|
||||
#define TOS_CONTROL_FDC_WR_PROT_A 0x00000040
|
||||
#define TOS_CONTROL_FDC_WR_PROT_B 0x00000080
|
||||
#define TOS_CONTROL_VIDEO_COLOR 0x00000100 // input to mfp
|
||||
#define TOS_CONTROL_PAL50HZ 0x00000200 // display pal at 50hz (56 hz otherwise)
|
||||
|
||||
// up to eight acsi devices can be enabled
|
||||
#define TOS_ACSI0_ENABLE 0x00000400
|
||||
#define TOS_ACSI1_ENABLE 0x00000800
|
||||
#define TOS_ACSI2_ENABLE 0x00001000
|
||||
#define TOS_ACSI3_ENABLE 0x00002000
|
||||
#define TOS_ACSI4_ENABLE 0x00004000
|
||||
#define TOS_ACSI5_ENABLE 0x00008000
|
||||
#define TOS_ACSI6_ENABLE 0x00010000
|
||||
#define TOS_ACSI7_ENABLE 0x00020000
|
||||
|
||||
#define TOS_CONTROL_TURBO 0x00040000
|
||||
#define TOS_CONTROL_BLITTER 0x00080000
|
||||
|
||||
#define TOS_CONTROL_SCANLINES0 0x00100000 // 0 = off, 1 = 25%, 2 = 50%, 3 = 75%
|
||||
#define TOS_CONTROL_SCANLINES1 0x00200000
|
||||
#define TOS_CONTROL_SCANLINES (TOS_CONTROL_SCANLINES0|TOS_CONTROL_SCANLINES1)
|
||||
|
||||
#define TOS_CONTROL_STEREO 0x00400000
|
||||
#define TOS_CONTROL_STE 0x00800000
|
||||
#define TOS_CONTROL_MSTE 0x01000000
|
||||
#define TOS_CONTROL_ETHERNET 0x02000000
|
||||
|
||||
// USB redirection modes
|
||||
// (NONE=0, RS232=1, PARALLEL=2, MIDI=3)
|
||||
#define TOS_CONTROL_REDIR0 0x04000000
|
||||
#define TOS_CONTROL_REDIR1 0x08000000
|
||||
|
||||
#define TOS_CONTROL_VIKING 0x10000000 // Viking graphics card
|
||||
|
||||
unsigned long tos_system_ctrl(void);
|
||||
|
||||
void tos_upload(char *);
|
||||
void tos_poll();
|
||||
void tos_update_sysctrl(unsigned long);
|
||||
char *tos_get_disk_name(char);
|
||||
char tos_disk_is_inserted(char index);
|
||||
void tos_insert_disk(char i, char *name);
|
||||
void tos_eject_all();
|
||||
void tos_select_hdd_image(char i, char *name);
|
||||
void tos_set_direct_hdd(char on);
|
||||
char tos_get_direct_hdd();
|
||||
void tos_reset(char cold);
|
||||
char *tos_get_image_name();
|
||||
char *tos_get_cartridge_name();
|
||||
char tos_cartridge_is_inserted();
|
||||
void tos_load_cartridge(char *);
|
||||
|
||||
void tos_set_video_adjust(char axis, char value);
|
||||
char tos_get_video_adjust(char axis);
|
||||
|
||||
void tos_config_init(void);
|
||||
void tos_config_save(void);
|
||||
|
||||
#endif
|
||||
192
user_io.h
Normal file
192
user_io.h
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* user_io.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef USER_IO_H
|
||||
#define USER_IO_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "file_io.h"
|
||||
|
||||
#define UIO_STATUS 0x00
|
||||
#define UIO_BUT_SW 0x01
|
||||
|
||||
// codes as used by minimig (amiga)
|
||||
#define UIO_JOYSTICK0 0x02 // also used by 8 bit
|
||||
#define UIO_JOYSTICK1 0x03 // -"-
|
||||
#define UIO_MOUSE 0x04 // -"-
|
||||
#define UIO_KEYBOARD 0x05 // -"-
|
||||
#define UIO_KBD_OSD 0x06 // keycodes used by OSD only
|
||||
|
||||
// codes as used by MiST (atari)
|
||||
// directions (in/out) are from an io controller view
|
||||
#define UIO_IKBD_OUT 0x02
|
||||
#define UIO_IKBD_IN 0x03
|
||||
#define UIO_SERIAL_OUT 0x04
|
||||
#define UIO_SERIAL_IN 0x05
|
||||
#define UIO_PARALLEL_IN 0x06
|
||||
#define UIO_MIDI_OUT 0x07
|
||||
#define UIO_MIDI_IN 0x08
|
||||
#define UIO_ETH_MAC 0x09
|
||||
#define UIO_ETH_STATUS 0x0a
|
||||
#define UIO_ETH_FRM_IN 0x0b
|
||||
#define UIO_ETH_FRM_OUT 0x0c
|
||||
#define UIO_SERIAL_STAT 0x0d
|
||||
|
||||
#define UIO_JOYSTICK2 0x10 // also used by minimig and 8 bit
|
||||
#define UIO_JOYSTICK3 0x11 // -"-
|
||||
#define UIO_JOYSTICK4 0x12 // -"-
|
||||
#define UIO_JOYSTICK5 0x13 // -"-
|
||||
|
||||
// codes as currently used by 8bit only
|
||||
#define UIO_GET_STRING 0x14
|
||||
#define UIO_SET_STATUS 0x15
|
||||
#define UIO_GET_SDSTAT 0x16 // read status of sd card emulation
|
||||
#define UIO_SECTOR_RD 0x17 // SD card sector read
|
||||
#define UIO_SECTOR_WR 0x18 // SD card sector write
|
||||
#define UIO_SET_SDCONF 0x19 // send SD card configuration (CSD, CID)
|
||||
#define UIO_ASTICK 0x1a
|
||||
#define UIO_SIO_IN 0x1b // serial in
|
||||
#define UIO_SET_SDSTAT 0x1c // set sd card status
|
||||
#define UIO_SET_SDINFO 0x1d // send info about mounted image
|
||||
#define UIO_SET_STATUS2 0x1e // 32bit status
|
||||
#define UIO_GET_KBD_LED 0x1f // keyboard LEDs control
|
||||
#define UIO_SET_VIDEO 0x20 // set HDMI video mode 0: 1280x720p60(TV), 1: 1280x1024p60(PC), 2-255: reserved
|
||||
|
||||
// codes as used by 8bit (atari 800, zx81) via SS2
|
||||
#define UIO_GET_STATUS 0x50
|
||||
#define UIO_SECTOR_SND 0x51
|
||||
#define UIO_SECTOR_RCV 0x52
|
||||
#define UIO_FILE_TX 0x53
|
||||
#define UIO_FILE_TX_DAT 0x54
|
||||
#define UIO_FILE_INDEX 0x55
|
||||
#define UIO_FILE_INFO 0x56
|
||||
|
||||
#define JOY_RIGHT 0x01
|
||||
#define JOY_LEFT 0x02
|
||||
#define JOY_DOWN 0x04
|
||||
#define JOY_UP 0x08
|
||||
#define JOY_BTN_SHIFT 4
|
||||
#define JOY_BTN1 0x10
|
||||
#define JOY_BTN2 0x20
|
||||
#define JOY_BTN3 0x40
|
||||
#define JOY_BTN4 0x80
|
||||
#define JOY_OSD 0x100
|
||||
#define JOY_MOVE (JOY_RIGHT|JOY_LEFT|JOY_UP|JOY_DOWN)
|
||||
|
||||
#define BUTTON1 0x01
|
||||
#define BUTTON2 0x02
|
||||
|
||||
// virtual gamepad buttons
|
||||
#define JOY_A JOY_BTN1
|
||||
#define JOY_B JOY_BTN2
|
||||
#define JOY_SELECT JOY_BTN3
|
||||
#define JOY_START JOY_BTN4
|
||||
#define JOY_X 0x100
|
||||
#define JOY_Y 0x200
|
||||
#define JOY_L 0x400
|
||||
#define JOY_R 0x800
|
||||
#define JOY_L2 0x1000
|
||||
#define JOY_R2 0x2000
|
||||
#define JOY_L3 0x4000
|
||||
#define JOY_R3 0x8000
|
||||
|
||||
// keyboard LEDs control
|
||||
#define KBD_LED_CAPS_CONTROL 0x01
|
||||
#define KBD_LED_CAPS_STATUS 0x02
|
||||
#define KBD_LED_CAPS_MASK (KBD_LED_CAPS_CONTROL | KBD_LED_CAPS_STATUS)
|
||||
#define KBD_LED_NUM_CONTROL 0x04
|
||||
#define KBD_LED_NUM_STATUS 0x08
|
||||
#define KBD_LED_NUM_MASK (KBD_LED_NUM_CONTROL | KBD_LED_NUM_STATUS)
|
||||
#define KBD_LED_SCRL_CONTROL 0x10
|
||||
#define KBD_LED_SCRL_STATUS 0x20
|
||||
#define KBD_LED_SCRL_MASK (KBD_LED_SCRL_CONTROL | KBD_LED_SCRL_STATUS)
|
||||
#define KBD_LED_FLAG_MASK 0xC0
|
||||
#define KBD_LED_FLAG_STATUS 0x40
|
||||
|
||||
#define CONF_VGA_SCALER 0x04
|
||||
#define CONF_CSYNC 0x08
|
||||
#define CONF_FORCED_SCANDOUBLER 0x10
|
||||
#define CONF_YPBPR 0x20
|
||||
|
||||
// core type value should be unlikely to be returned by broken cores
|
||||
#define CORE_TYPE_UNKNOWN 0x55
|
||||
#define CORE_TYPE_DUMB 0xa0 // core without any io controller interaction
|
||||
#define CORE_TYPE_PACE 0xa2 // core from pacedev.net (joystick only)
|
||||
#define CORE_TYPE_MIST 0xa3 // mist atari st core
|
||||
#define CORE_TYPE_8BIT 0xa4 // atari 800/c64 like core
|
||||
#define CORE_TYPE_MINIMIG2 0xa5 // new Minimig with AGA
|
||||
#define CORE_TYPE_ARCHIE 0xa6 // Acorn Archimedes
|
||||
|
||||
// user io status bits (currently only used by 8bit)
|
||||
#define UIO_STATUS_RESET 0x01
|
||||
|
||||
#define UIO_STOP_BIT_1 0
|
||||
#define UIO_STOP_BIT_1_5 1
|
||||
#define UIO_STOP_BIT_2 2
|
||||
|
||||
#define UIO_PARITY_NONE 0
|
||||
#define UIO_PARITY_ODD 1
|
||||
#define UIO_PARITY_EVEN 2
|
||||
#define UIO_PARITY_MARK 3
|
||||
#define UIO_PARITY_SPACE 4
|
||||
|
||||
#define UIO_PRIORITY_KEYBOARD 0
|
||||
#define UIO_PRIORITY_GAMEPAD 1
|
||||
|
||||
|
||||
// serial status data type returned from the core
|
||||
typedef struct {
|
||||
uint32_t bitrate; // 300, 600 ... 115200
|
||||
uint8_t datasize; // 5,6,7,8 ...
|
||||
uint8_t parity;
|
||||
uint8_t stopbits;
|
||||
uint8_t fifo_stat; // space in cores input fifo
|
||||
} __attribute__((packed)) serial_status_t;
|
||||
|
||||
void user_io_init();
|
||||
void user_io_detect_core_type();
|
||||
unsigned char user_io_core_type();
|
||||
char is_minimig();
|
||||
char user_io_is_8bit_with_config_string();
|
||||
void user_io_poll();
|
||||
char user_io_menu_button();
|
||||
char user_io_button_dip_switch1();
|
||||
char user_io_user_button();
|
||||
void user_io_osd_key_enable(char);
|
||||
void user_io_serial_tx(char *, uint16_t);
|
||||
char *user_io_8bit_get_string(char);
|
||||
unsigned long user_io_8bit_set_status(unsigned long, unsigned long);
|
||||
void user_io_file_tx(char *, unsigned char);
|
||||
void user_io_sd_set_config(void);
|
||||
char user_io_dip_switch1(void);
|
||||
char user_io_serial_status(serial_status_t *, uint8_t);
|
||||
void user_io_file_mount(char *name);
|
||||
char *user_io_get_core_name();
|
||||
char is_menu_core();
|
||||
|
||||
// io controllers interface for FPGA ethernet emulation using usb ethernet
|
||||
// devices attached to the io controller (ethernec emulation)
|
||||
void user_io_eth_send_mac(uint8_t *);
|
||||
uint32_t user_io_eth_get_status(void);
|
||||
void user_io_eth_send_rx_frame(uint8_t *, uint16_t);
|
||||
void user_io_eth_receive_tx_frame(uint8_t *, uint16_t);
|
||||
|
||||
// hooks from the usb layer
|
||||
void user_io_mouse(unsigned char b, int16_t x, int16_t y);
|
||||
void user_io_kbd(unsigned char m, unsigned char *k, unsigned short vid, unsigned short pid);
|
||||
char* user_io_create_config_name();
|
||||
void user_io_digital_joystick(unsigned char, unsigned char);
|
||||
void user_io_analog_joystick(unsigned char, char, char);
|
||||
char user_io_osd_is_visible();
|
||||
void user_io_send_buttons(char);
|
||||
void user_io_joystick(unsigned char joystick, unsigned char map);
|
||||
|
||||
void user_io_key_remap(char *);
|
||||
void add_modifiers(uint8_t mod, uint16_t* keys_ps2);
|
||||
|
||||
void user_io_set_index(unsigned char index);
|
||||
unsigned char user_io_ext_idx(char *, char*);
|
||||
|
||||
#endif // USER_IO_H
|
||||
Reference in New Issue
Block a user