1
0
mirror of https://github.com/mist-devel/mist-firmware.git synced 2026-05-03 23:09:45 +00:00

Firmware import

This commit is contained in:
harbaum
2013-03-25 13:53:52 +00:00
commit 3aab54f326
58 changed files with 18213 additions and 0 deletions

135
AT91SAM7S256-ROM.ld Normal file
View File

@@ -0,0 +1,135 @@
/*---------------------------------------------------------------------------*/
/*- ATMEL Microcontroller Software Support - ROUSSET - */
/*---------------------------------------------------------------------------*/
/* The software is delivered "AS IS" without warranty or condition of any */
/* kind, either express, implied or statutory. This includes without */
/* limitation any warranty or condition with respect to merchantability or */
/* fitness for any particular purpose, or against the infringements of */
/* intellectual property rights of others. */
/*---------------------------------------------------------------------------*/
/*- File source : GCC_FLASH.ld */
/*- Object : Linker Script File for Flash Workspace */
/*- Compilation flag : None */
/*- */
/*- 1.0 11/Mar/05 JPP : Creation S256 */
/*---------------------------------------------------------------------------*/
/*
24-02-2006 Ewout Boks. Adapted from AT91SAM7S64-RAM.ld script by M. Thomas.
- Changed the memory sections to model the AT91SAM7S256 .
- tested succesfully with AT91SAM7 GPIO Example and PEEDI debugger
on AT91SAM7S-EK equipped with AT91SAM7S256
*/
/* Memory Definitions */
MEMORY
{
FLASH (rx) : ORIGIN = 0x00100000, LENGTH = 0x00040000
DATA (rw) : ORIGIN = 0x00200000, LENGTH = 0x00010000
STACK (rw) : ORIGIN = 0x00210000, LENGTH = 0x00000000
}
/* Section Definitions */
SECTIONS
{
/* first section is .text which is used for code */
. = 0x0000000;
.text : { *Cstartup.o (.text) }>FLASH =0
.text :
{
*(.text) /* remaining code */
*(.glue_7t) *(.glue_7)
} >FLASH
. = ALIGN(4);
/* .rodata section which is used for read-only data (constants) */
.rodata :
{
*(.rodata)
} >FLASH
. = ALIGN(4);
_etext = . ;
PROVIDE (etext = .);
/* .data section which is used for initialized data */
.data : AT (_etext)
{
_data = . ;
*(.data)
SORT(CONSTRUCTORS)
. = ALIGN(4);
*(.ramsection) /* "RAM-Functions" */ /* added by mthomas */
} >DATA
. = ALIGN(4);
_edata = . ;
PROVIDE (edata = .);
/* .bss section which is used for uninitialized data */
.bss :
{
__bss_start = . ;
__bss_start__ = . ;
*(.bss)
*(COMMON)
}
. = ALIGN(4);
__bss_end__ = . ;
__end__ = . ;
_end = .;
PROVIDE (end = .);
. = ALIGN(4);
.int_data :
{
*(.internal_ram_top)
}> STACK
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
}

2233
AT91SAM7S256.h Normal file

File diff suppressed because it is too large Load Diff

302
Cstartup.S Normal file
View File

@@ -0,0 +1,302 @@
/*------------------------------------------------------------------------------
//*- ATMEL Microcontroller Software Support - ROUSSET -
//*------------------------------------------------------------------------------
//* The software is delivered "AS IS" without warranty or condition of any
//* kind, either express, implied or statutory. This includes without
//* limitation any warranty or condition with respect to merchantability or
//* fitness for any particular purpose, or against the infringements of
//* intellectual property rights of others.
//*-----------------------------------------------------------------------------
//*- File source : Cstartup.s
//*- Object : Generic CStartup for KEIL and GCC No Use REMAP
//*- Compilation flag : None
//*-
//*- 1.0 10/Mar/05 JPP : Creation
//*- 1.1 01/Apr/05 JPP : save SPSR
//*-----------------------------------------------------------------------------*/
.equ IRQ_Stack_Size, 0x00000060
/* #include "AT91SAM7S256_inc.h" */
.equ AIC_IVR, (256)
.equ AIC_FVR, (260)
.equ AIC_EOICR, (304)
.equ AT91C_BASE_AIC, (0xFFFFF000)
#;------------------------------------------------------------------------------
#;- Section Definition
#;-----------------
#;- Section
#;- .internal_ram_top Top_Stack: used by the cstartup for vector initalisation
#;- management defined by ld and affect from ldscript
#;------------------------------------------------------------------------------
.section .internal_ram_top
.code 32
.align 0
.global Top_Stack
Top_Stack:
/*------------------------------------------------------------------------------
*- Area Definition
*------------------------------------------------------------------------------
* .text is used instead of .section .text so it works with arm-aout too. */
.section .reset
.text
.global _startup
.func _startup
_startup:
reset:
/*------------------------------------------------------------------------------
//*- Exception vectors
//*--------------------
//*- These vectors can be read at address 0 or at RAM address
//*- They ABSOLUTELY requires to be in relative addresssing mode in order to
//*- guarantee a valid jump. For the moment, all are just looping.
//*- If an exception occurs before remap, this would result in an infinite loop.
//*- To ensure if a exeption occurs before start application to infinite loop.
//*------------------------------------------------------------------------------*/
B InitReset /* 0x00 Reset handler */
undefvec:
B undefvec /* 0x04 Undefined Instruction */
swivec:
B swivec /* 0x08 Software Interrupt */
pabtvec:
B pabtvec /* 0x0C Prefetch Abort */
dabtvec:
B dabtvec /* 0x10 Data Abort */
rsvdvec:
B rsvdvec /* 0x14 reserved */
irqvec:
B IRQ_Handler_Entry /* 0x18 IRQ */
fiqvec: /* 0x1c FIQ */
/*------------------------------------------------------------------------------
//*- Function : FIQ_Handler_Entry
//*- Treatments : FIQ Controller Interrupt Handler.
//*- Called Functions : AIC_FVR[interrupt]
//*------------------------------------------------------------------------------*/
FIQ_Handler_Entry:
/*- Switch in SVC/User Mode to allow User Stack access for C code */
/* because the FIQ is not yet acknowledged*/
/*- Save and r0 in FIQ_Register */
mov r9,r0
ldr r0 , [r8, #AIC_FVR]
msr CPSR_c,#I_BIT | F_BIT | ARM_MODE_SVC
/*- Save scratch/used registers and LR in User Stack */
stmfd sp!, { r1-r3, r12, lr}
/*- Branch to the routine pointed by the AIC_FVR */
mov r14, pc
bx r0
/*- Restore scratch/used registers and LR from User Stack */
ldmia sp!, { r1-r3, r12, lr}
/*- Leave Interrupts disabled and switch back in FIQ mode */
msr CPSR_c, #I_BIT | F_BIT | ARM_MODE_FIQ
/*- Restore the R0 ARM_MODE_SVC register */
mov r0,r9
/*- Restore the Program Counter using the LR_fiq directly in the PC */
subs pc,lr,#4
.align 0
.RAM_TOP:
.word Top_Stack
InitReset:
/*------------------------------------------------------------------------------
/*- Low level Init (PMC, AIC, ? ....) by C function AT91F_LowLevelInit
/*------------------------------------------------------------------------------*/
.extern AT91F_LowLevelInit
/*- minumum C initialization */
/*- call AT91F_LowLevelInit( void) */
ldr r13,.RAM_TOP /* temporary stack in internal RAM */
/*--Call Low level init function in ABSOLUTE through the Interworking */
ldr r0,=AT91F_LowLevelInit
mov lr, pc
bx r0
/*------------------------------------------------------------------------------
//*- Stack Sizes Definition
//*------------------------
//*- Interrupt Stack requires 2 words x 8 priority level x 4 bytes when using
//*- the vectoring. This assume that the IRQ management.
//*- The Interrupt Stack must be adjusted depending on the interrupt handlers.
//*- Fast Interrupt not requires stack If in your application it required you must
//*- be definehere.
//*- The System stack size is not defined and is limited by the free internal
//*- SRAM.
//*------------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
//*- Top of Stack Definition
//*-------------------------
//*- Interrupt and Supervisor Stack are located at the top of internal memory in
//*- order to speed the exception handling context saving and restoring.
//*- ARM_MODE_SVC (Application, C) Stack is located at the top of the external memory.
//*------------------------------------------------------------------------------*/
.EQU IRQ_STACK_SIZE, (3*8*4)
.EQU ARM_MODE_FIQ, 0x11
.EQU ARM_MODE_IRQ, 0x12
.EQU ARM_MODE_SVC, 0x13
.EQU I_BIT, 0x80
.EQU F_BIT, 0x40
/*------------------------------------------------------------------------------
//*- Setup the stack for each mode
//*-------------------------------*/
mov r0,r13
/*- Set up Fast Interrupt Mode and set FIQ Mode Stack*/
msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT
/*- Init the FIQ register*/
ldr r8, =AT91C_BASE_AIC
/*- Set up Interrupt Mode and set IRQ Mode Stack*/
msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT
mov r13, r0 /* Init stack IRQ */
sub r0, r0, #IRQ_Stack_Size
/*- Set up Supervisor Mode and set Supervisor Mode Stack*/
msr CPSR_c, #ARM_MODE_SVC
mov r13, r0 /* Init stack Sup */
/*- Enable interrupt & Set up Supervisor Mode and set Supervisor Mode Stack*/
# Relocate .data section (Copy from ROM to RAM)
LDR R1, =_etext
LDR R2, =_data
LDR R3, =_edata
LoopRel: CMP R2, R3
LDRLO R0, [R1], #4
STRLO R0, [R2], #4
BLO LoopRel
# Clear .bss section (Zero init)
MOV R0, #0
LDR R1, =__bss_start__
LDR R2, =__bss_end__
LoopZI: CMP R1, R2
STRLO R0, [R1], #4
BLO LoopZI
ldr lr,=exit
ldr r0,=main
bx r0
.size _startup, . - _startup
.endfunc
/* "exit" dummy added by mthomas to avoid sbrk write read etc. needed
by the newlib default "exit" */
.global exit
.func exit
exit:
b .
.size exit, . - exit
.endfunc
/*------------------------------------------------------------------------------
//*- Manage exception
//*---------------
//*- This module The exception must be ensure in ARM mode
//*------------------------------------------------------------------------------
//*------------------------------------------------------------------------------
//*- Function : IRQ_Handler_Entry
//*- Treatments : IRQ Controller Interrupt Handler.
//*- Called Functions : AIC_IVR[interrupt]
//*------------------------------------------------------------------------------*/
.global IRQ_Handler_Entry
.func IRQ_Handler_Entry
IRQ_Handler_Entry:
/*- Manage Exception Entry */
/*- Adjust and save LR_irq in IRQ stack */
sub lr, lr, #4
stmfd sp!, {lr}
/*- Save SPSR need to be saved for nested interrupt */
mrs r14, SPSR
stmfd sp!, {r14}
/*- Save and r0 in IRQ stack */
stmfd sp!, {r0}
/*- Write in the IVR to support Protect Mode */
/*- No effect in Normal Mode */
/*- De-assert the NIRQ and clear the source in Protect Mode */
ldr r14, =AT91C_BASE_AIC
ldr r0 , [r14, #AIC_IVR]
str r14, [r14, #AIC_IVR]
/*- Enable Interrupt and Switch in Supervisor Mode */
msr CPSR_c, #ARM_MODE_SVC
/*- Save scratch/used registers and LR in User Stack */
stmfd sp!, { r1-r3, r12, r14}
/*- Branch to the routine pointed by the AIC_IVR */
mov r14, pc
bx r0
/*- Restore scratch/used registers and LR from User Stack*/
ldmia sp!, { r1-r3, r12, r14}
/*- Disable Interrupt and switch back in IRQ mode */
msr CPSR_c, #I_BIT | ARM_MODE_IRQ
/*- Mark the End of Interrupt on the AIC */
ldr r14, =AT91C_BASE_AIC
str r14, [r14, #AIC_EOICR]
/*- Restore SPSR_irq and r0 from IRQ stack */
ldmia sp!, {r0}
/*- Restore SPSR_irq and r0 from IRQ stack */
ldmia sp!, {r14}
msr SPSR_cxsf, r14
/*- Restore adjusted LR_irq from IRQ stack directly in the PC */
ldmia sp!, {pc}^
.size IRQ_Handler_Entry, . - IRQ_Handler_Entry
.endfunc
/*---------------------------------------------------------------
//* ?EXEPTION_VECTOR
//* This module is only linked if needed for closing files.
//*---------------------------------------------------------------*/
.global AT91F_Default_FIQ_handler
.func AT91F_Default_FIQ_handler
AT91F_Default_FIQ_handler:
b AT91F_Default_FIQ_handler
.size AT91F_Default_FIQ_handler, . - AT91F_Default_FIQ_handler
.endfunc
.global AT91F_Default_IRQ_handler
.func AT91F_Default_IRQ_handler
AT91F_Default_IRQ_handler:
b AT91F_Default_IRQ_handler
.size AT91F_Default_IRQ_handler, . - AT91F_Default_IRQ_handler
.endfunc
.global AT91F_Spurious_handler
.func AT91F_Spurious_handler
AT91F_Spurious_handler:
b AT91F_Spurious_handler
.size AT91F_Spurious_handler, . - AT91F_Spurious_handler
.endfunc
.end

83
Cstartup_SAM7.c Normal file
View File

@@ -0,0 +1,83 @@
//*----------------------------------------------------------------------------
//* ATMEL Microcontroller Software Support - ROUSSET -
//*----------------------------------------------------------------------------
//* The software is delivered "AS IS" without warranty or condition of any
//* kind, either express, implied or statutory. This includes without
//* limitation any warranty or condition with respect to merchantability or
//* fitness for any particular purpose, or against the infringements of
//* intellectual property rights of others.
//*----------------------------------------------------------------------------
//* File Name : Cstartup_SAM7.c
//* Object : Low level initializations written in C for GCC Tools
//* Creation : 12/Jun/04
//* 1.2 28/Feb/05 JPP : LIB change AT91C_WDTC_WDDIS & PLL
//* 1.3 21/Mar/05 JPP : Change PLL Wait time
//*----------------------------------------------------------------------------
// Include the board file description
#include "AT91SAM7S256.h"
// The following functions must be write in ARM mode this function called directly
// by exception vector
extern void AT91F_Spurious_handler(void);
extern void AT91F_Default_IRQ_handler(void);
extern void AT91F_Default_FIQ_handler(void);
//*----------------------------------------------------------------------------
//* \fn AT91F_LowLevelInit
//* \brief This function performs very low level HW initialization
//* this function can be use a Stack, depending the compilation
//* optimization mode
//*----------------------------------------------------------------------------
void AT91F_LowLevelInit( void)
{
int i;
AT91PS_PMC pPMC = AT91C_BASE_PMC;
//* Set Flash Waite sate
// Single Cycle Access at Up to 30 MHz, or 40
// if MCK = 47923200 I have 50 Cycle for 1 usecond ( flied MC_FMR->FMCN
AT91C_BASE_MC->MC_FMR = ((AT91C_MC_FMCN)&(48 <<16)) | AT91C_MC_FWS_1FWS ;
//* Watchdog Disable
AT91C_BASE_WDTC->WDTC_WDMR= AT91C_WDTC_WDDIS;
//* Set MCK at 47 923 200
// 1 Enabling the Main Oscillator:
// SCK = 1/32768 = 30.51 uSecond
// Start up time = 8 * 6 / SCK = 56 * 30.51 = 1,46484375 ms
pPMC->PMC_MOR = ( (AT91C_CKGR_OSCOUNT) & (0x06 <<8)) | AT91C_CKGR_MOSCEN ;
// Wait the startup time
while(!(pPMC->PMC_SR & AT91C_PMC_MOSCS));
// 2 Checking the Main Oscillator Frequency (Optional)
// 3 Setting PLL and divider:
// - div by 5 Fin = 3,6864 =(18,432 / 5)
// - Mul 25+1: Fout = 95,8464 =(3,6864 *26)
// for 96 MHz the erroe is 0.16%
// Field out NOT USED = 0
// PLLCOUNT pll startup time estimate at : 0.844 ms
// PLLCOUNT 28 = 0.000844 /(1/32768)
pPMC->PMC_PLLR = ((AT91C_CKGR_DIV & 0x05) |
(AT91C_CKGR_PLLCOUNT & (28<<8)) |
(AT91C_CKGR_MUL & (25<<16)));
// Wait the startup time
while(!(pPMC->PMC_SR & AT91C_PMC_LOCK));
while(!(pPMC->PMC_SR & AT91C_PMC_MCKRDY));
// 4. Selection of Master Clock and Processor Clock
// select the PLL clock divided by 2
pPMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2 ;
while(!(pPMC->PMC_SR & AT91C_PMC_MCKRDY));
pPMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK ;
while(!(pPMC->PMC_SR & AT91C_PMC_MCKRDY));
// Set up the default interrupts handler vectors
AT91C_BASE_AIC->AIC_SVR[0] = (int) AT91F_Default_FIQ_handler ;
for (i=1;i < 31; i++)
{
AT91C_BASE_AIC->AIC_SVR[i] = (int) AT91F_Default_IRQ_handler ;
}
AT91C_BASE_AIC->AIC_SPU = (int) AT91F_Spurious_handler ;
}

87
Makefile Normal file
View File

@@ -0,0 +1,87 @@
BASE ?= /opt/arm-none-eabi/bin/arm-none-eabi
CC = $(BASE)-gcc
LD = $(BASE)-gcc
AS = $(BASE)-as
CP = $(BASE)-objcopy
DUMP = $(BASE)-objdump
TODAY = `date +"%m/%d/%y"`
PRJ = firmware
SRC = Cstartup_SAM7.c fat.c fdd.c firmware.c fpga.c hardware.c hdd.c main.c menu.c mmc.c osd.c syscalls.c user_io.c boot_print.c boot_logo.c rafile.c config.c tos.c
SRC += usb/max3421e.c usb/usb.c usb/hub.c usb/hid.c usb/timer.c
OBJ = $(SRC:.c=.o)
LINKMAP = AT91SAM7S256-ROM.ld
LIBDIR =
# Commandline options for each tool.
CFLAGS = -I. -Iusb -c -fno-common -O3 -DMIST -fsigned-char -DVDATE=\"`date +"%y%m%d"`\"
AFLAGS = -ahls -mapcs-32
LFLAGS = -nostartfiles -Wl,-Map,$(PRJ).map -T$(LINKMAP) $(LIBDIR)
CPFLAGS = --output-target=ihex
MKUPG = mkupg
# Libraries.
LIBS =
# Our target.
all: $(PRJ).hex $(PRJ).upg
clean:
rm -f *.o *.hex *.elf *.map *.lst core *~ */*.o $(MKUPG) *.bin *.upg
reset:
openocd -f interface/olimex-arm-usb-tiny-h.cfg -f target/at91sam7sx.cfg --command "adapter_khz 10000; init; reset init; resume; shutdown"
unprotect:
openocd -f interface/olimex-arm-usb-tiny-h.cfg -f target/at91sam7sx.cfg --command "adapter_khz 10000; init; reset init; flash protect 0 0 7 off; resume; shutdown"
$(MKUPG): $(MKUPG).c
gcc -o $@ $<
flash: $(PRJ).bin
openocd -f interface/olimex-arm-usb-tiny-h.cfg -f target/at91sam7sx.cfg --command "adapter_khz 10000; init; reset init; flash protect 0 0 7 off; sleep 1; arm7_9 fast_memory_access enable; flash write_bank 0 $(PRJ).bin 0x0; resume; shutdown"
flash_ul: $(PRJ).bin
openocd -f interface/ulink.cfg -f target/at91sam7sx.cfg --command "adapter_khz 10000; init; reset init; flash protect 0 0 7 off; sleep 1; arm7_9 fast_memory_access enable; flash write_bank 0 $(PRJ).bin 0x0; resume; shutdown"
flash_sam: $(PRJ).hex
Sam_I_Am -x flash_sam_i_am
# Convert ELF binary to bin file.
$(PRJ).bin: $(PRJ).elf
$(CP) -O binary $< $@
# Convert ELF binary to Intel HEX file.
$(PRJ).hex: $(PRJ).elf
$(CP) $(CPFLAGS) $< $@
# Link - this produces an ELF binary.
$(PRJ).elf: crt.o $(OBJ)
$(LD) $(LFLAGS) -o $@ $+ $(LIBS)
$(PRJ).upg: $(PRJ).bin $(MKUPG)
./$(MKUPG) $< $@ `date +"%y%m%d"`
# Compile the C runtime.
crt.o: Cstartup.S
$(AS) $(AFLAGS) -o $@ $< > crt.lst
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
sections: $(PRJ).elf
$(DUMP) --section-headers $<
release:
make clean
make $(PRJ).hex $(PRJ).bin $(PRJ).upg
rm ../../www/firmware*.zip
zip ../../www/firmware.zip $(PRJ).hex $(PRJ).bin $(PRJ).upg logo.raw
make clean
cd ..; zip -urq ../www/firmware_src.zip minimig -x '*/.svn/*' '*.old' '*.new'
cp ../../www/files.html files.tmp
sed -e "s|Firmware updated on [0-9/]*.|Firmware updated on $(TODAY).|g" files.tmp > ../../www/files.html
rm files.tmp

136
boot_logo.c Normal file
View File

@@ -0,0 +1,136 @@
/* boot_logo.c */
/* 2012, rok.krajnc@gmail.com */
#include "fpga.h"
#include "fat.h"
#include "boot_print.h"
static const unsigned int logo_width = 29;
static const unsigned int logo_height = 80;
static const char boot_logo[80][29] = {
{ 0x00, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xfc, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xfc, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x0f, 0xf0, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x0f, 0xf0, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x01, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x20, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x01, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x20, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x80, 0x03, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x80, 0x03, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xfe, 0x03, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0xff, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xfe, 0x03, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0xff, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xff, 0xf7, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xff, 0xf7, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xff, 0xf0, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xff, 0xf0, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xff, 0xf0, 0x03, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xff, 0xf0, 0x03, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xff, 0xe0, 0x00, 0x1f, 0x80, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xff, 0xe0, 0x00, 0x1f, 0x80, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xff, 0xc0, 0x00, 0x01, 0xc0, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xff, 0xc0, 0x00, 0x01, 0xc0, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xff, 0xc0, 0x00, 0x07, 0xff, 0x80, 0x0f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xff, 0xc0, 0x00, 0x07, 0xff, 0x80, 0x0f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xff, 0x80, 0x00, 0x1f, 0xff, 0xfc, 0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0x81, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00 },
{ 0xff, 0x80, 0x00, 0x1f, 0xff, 0xfc, 0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0x81, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00 },
{ 0x0f, 0x80, 0x00, 0x7f, 0xff, 0xfe, 0x1f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x01, 0xff, 0xff, 0x81, 0xff, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x80 },
{ 0x0f, 0x80, 0x00, 0x7f, 0xff, 0xfe, 0x1f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x01, 0xff, 0xff, 0x81, 0xff, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x80 },
{ 0x40, 0xe0, 0x01, 0xff, 0xff, 0xe0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x0f, 0xfc, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x7f, 0x00 },
{ 0x40, 0xe0, 0x01, 0xff, 0xff, 0xe0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x0f, 0xfc, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x7f, 0x00 },
{ 0x00, 0xfc, 0x07, 0xff, 0xfe, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x0f, 0xff, 0xe0, 0x00, 0x0f, 0xf8, 0x00, 0x07, 0xff, 0x00, 0x00, 0x0f, 0x00 },
{ 0x00, 0xfc, 0x07, 0xff, 0xfe, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x0f, 0xff, 0xe0, 0x00, 0x0f, 0xf8, 0x00, 0x07, 0xff, 0x00, 0x00, 0x0f, 0x00 },
{ 0x00, 0x3f, 0x8f, 0xff, 0xc0, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x1f, 0xf8, 0x00, 0x1f, 0xfc, 0x00, 0x00, 0x0f, 0x00 },
{ 0x00, 0x3f, 0x8f, 0xff, 0xc0, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x1f, 0xf8, 0x00, 0x1f, 0xfc, 0x00, 0x00, 0x0f, 0x00 },
{ 0x00, 0x00, 0xff, 0xf8, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcf, 0xf8, 0x00, 0x3e, 0xff, 0xc0, 0x00, 0x1f, 0xf8, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x0e, 0x00 },
{ 0x00, 0x00, 0xff, 0xf8, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcf, 0xf8, 0x00, 0x3e, 0xff, 0xc0, 0x00, 0x1f, 0xf8, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x0e, 0x00 },
{ 0x00, 0x00, 0x03, 0xc7, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcf, 0xf8, 0x00, 0x7c, 0xff, 0xc0, 0x00, 0x3f, 0xf0, 0x00, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x03, 0xc7, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcf, 0xf8, 0x00, 0x7c, 0xff, 0xc0, 0x00, 0x3f, 0xf0, 0x00, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc7, 0xf8, 0x00, 0xf9, 0xff, 0x80, 0x00, 0x3f, 0xf0, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc7, 0xf8, 0x00, 0xf9, 0xff, 0x80, 0x00, 0x3f, 0xf0, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x07, 0x87, 0xfc, 0x01, 0xf1, 0xff, 0x80, 0x00, 0x3f, 0xf0, 0x03, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x07, 0x87, 0xfc, 0x01, 0xf1, 0xff, 0x80, 0x00, 0x3f, 0xf0, 0x03, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x07, 0x87, 0xfc, 0x03, 0xe1, 0xff, 0x00, 0x00, 0x7f, 0xe0, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x07, 0x87, 0xfc, 0x03, 0xe1, 0xff, 0x00, 0x00, 0x7f, 0xe0, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x83, 0xfc, 0x07, 0x83, 0xff, 0x00, 0x00, 0x7f, 0xe0, 0x07, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x83, 0xfc, 0x07, 0x83, 0xff, 0x00, 0x00, 0x7f, 0xe0, 0x07, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x03, 0xfe, 0x0f, 0x03, 0xff, 0x00, 0x00, 0x7f, 0xc0, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x03, 0xfe, 0x0f, 0x03, 0xff, 0x00, 0x00, 0x7f, 0xc0, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x1f, 0x87, 0xc0, 0xfc, 0x0f, 0xe0, 0x7c, 0x3f, 0x01, 0xfc, 0x00, 0x0f, 0x03, 0xfe, 0x1e, 0x03, 0xfe, 0x00, 0x00, 0xff, 0xc0, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x1f, 0x87, 0xc0, 0xfc, 0x0f, 0xe0, 0x7c, 0x3f, 0x01, 0xfc, 0x00, 0x0f, 0x03, 0xfe, 0x1e, 0x03, 0xfe, 0x00, 0x00, 0xff, 0xc0, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x07, 0xbf, 0xe3, 0xfe, 0x01, 0xe0, 0x1c, 0xff, 0xc0, 0x3c, 0x00, 0x1f, 0x01, 0xff, 0x3c, 0x07, 0xfe, 0x00, 0x00, 0xff, 0xc0, 0x07, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xc0 },
{ 0x00, 0x07, 0xbf, 0xe3, 0xfe, 0x01, 0xe0, 0x1c, 0xff, 0xc0, 0x3c, 0x00, 0x1f, 0x01, 0xff, 0x3c, 0x07, 0xfe, 0x00, 0x00, 0xff, 0xc0, 0x07, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xc0 },
{ 0x00, 0x07, 0xe0, 0xfc, 0x0e, 0x03, 0xc0, 0x3f, 0x01, 0xc0, 0x38, 0x00, 0x1e, 0x01, 0xff, 0x78, 0x07, 0xfe, 0x00, 0x00, 0xff, 0x80, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xfc, 0x00 },
{ 0x00, 0x07, 0xe0, 0xfc, 0x0e, 0x03, 0xc0, 0x3f, 0x01, 0xc0, 0x38, 0x00, 0x1e, 0x01, 0xff, 0x78, 0x07, 0xfe, 0x00, 0x00, 0xff, 0x80, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xfc, 0x00 },
{ 0x00, 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, 0x3c, 0x01, 0xc0, 0x78, 0x00, 0x1e, 0x00, 0xff, 0xf0, 0x07, 0xfc, 0x00, 0x01, 0xff, 0x80, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xf8, 0x00 },
{ 0x00, 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, 0x3c, 0x01, 0xc0, 0x78, 0x00, 0x1e, 0x00, 0xff, 0xf0, 0x07, 0xfc, 0x00, 0x01, 0xff, 0x80, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xf8, 0x00 },
{ 0x00, 0x0f, 0x00, 0xe0, 0x1e, 0x03, 0xc0, 0x38, 0x03, 0xc0, 0x78, 0x00, 0x3c, 0x00, 0xff, 0xe0, 0x0f, 0xfc, 0x00, 0x01, 0xff, 0x80, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xf8, 0x00 },
{ 0x00, 0x0f, 0x00, 0xe0, 0x1e, 0x03, 0xc0, 0x38, 0x03, 0xc0, 0x78, 0x00, 0x3c, 0x00, 0xff, 0xe0, 0x0f, 0xfc, 0x00, 0x01, 0xff, 0x80, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xf8, 0x00 },
{ 0x00, 0x0e, 0x01, 0xe0, 0x1c, 0x07, 0x80, 0x78, 0x03, 0x80, 0xf0, 0x00, 0x3c, 0x00, 0x7f, 0xc0, 0x0f, 0xfc, 0x00, 0x01, 0xff, 0x00, 0x03, 0xff, 0x00, 0x00, 0x1f, 0xf8, 0x00 },
{ 0x00, 0x0e, 0x01, 0xe0, 0x1c, 0x07, 0x80, 0x78, 0x03, 0x80, 0xf0, 0x00, 0x3c, 0x00, 0x7f, 0xc0, 0x0f, 0xfc, 0x00, 0x01, 0xff, 0x00, 0x03, 0xff, 0x00, 0x00, 0x1f, 0xf8, 0x00 },
{ 0x00, 0x0e, 0x01, 0xe0, 0x3c, 0x07, 0x80, 0x78, 0x03, 0x80, 0xf0, 0x00, 0x3c, 0x00, 0x7f, 0x80, 0x0f, 0xf8, 0x00, 0x03, 0xff, 0x00, 0x03, 0xff, 0x00, 0x00, 0x3f, 0xf0, 0x00 },
{ 0x00, 0x0e, 0x01, 0xe0, 0x3c, 0x07, 0x80, 0x78, 0x03, 0x80, 0xf0, 0x00, 0x3c, 0x00, 0x7f, 0x80, 0x0f, 0xf8, 0x00, 0x03, 0xff, 0x00, 0x03, 0xff, 0x00, 0x00, 0x3f, 0xf0, 0x00 },
{ 0x00, 0x1e, 0x01, 0xc0, 0x3c, 0x07, 0x80, 0x70, 0x07, 0x80, 0xf0, 0x00, 0x78, 0x00, 0x7f, 0x00, 0x1f, 0xf8, 0x00, 0x03, 0xff, 0x00, 0x01, 0xff, 0x80, 0x00, 0x3f, 0xf0, 0x00 },
{ 0x00, 0x1e, 0x01, 0xc0, 0x3c, 0x07, 0x80, 0x70, 0x07, 0x80, 0xf0, 0x00, 0x78, 0x00, 0x7f, 0x00, 0x1f, 0xf8, 0x00, 0x03, 0xff, 0x00, 0x01, 0xff, 0x80, 0x00, 0x3f, 0xf0, 0x00 },
{ 0x00, 0x1e, 0x03, 0xc0, 0x38, 0x0f, 0x00, 0xf0, 0x07, 0x01, 0xe0, 0x00, 0x78, 0x00, 0x3e, 0x00, 0x1f, 0xf8, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x7f, 0xf0, 0x00 },
{ 0x00, 0x1e, 0x03, 0xc0, 0x38, 0x0f, 0x00, 0xf0, 0x07, 0x01, 0xe0, 0x00, 0x78, 0x00, 0x3e, 0x00, 0x1f, 0xf8, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x7f, 0xf0, 0x00 },
{ 0x00, 0x1c, 0x03, 0x80, 0x78, 0x0f, 0x00, 0xe0, 0x0f, 0x01, 0xe0, 0x07, 0xff, 0x00, 0x3c, 0x01, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xe0, 0x00 },
{ 0x00, 0x1c, 0x03, 0x80, 0x78, 0x0f, 0x00, 0xe0, 0x0f, 0x01, 0xe0, 0x07, 0xff, 0x00, 0x3c, 0x01, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xe0, 0x00 },
{ 0x00, 0x3c, 0x03, 0x80, 0x7f, 0x0f, 0xe0, 0xe0, 0x0f, 0xc1, 0xfc, 0x1f, 0xff, 0xc0, 0x38, 0x0f, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xff, 0xfc, 0x00, 0x00 },
{ 0x00, 0x3c, 0x03, 0x80, 0x7f, 0x0f, 0xe0, 0xe0, 0x0f, 0xc1, 0xfc, 0x1f, 0xff, 0xc0, 0x38, 0x0f, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xff, 0xfc, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};
void draw_boot_logo()
{
unsigned int line;
unsigned short int offset = 0;
char * p;
fileTYPE file;
// check if there's a logo file on disk
if(FileOpen(&file,"LOGO RAW")) {
if(file.size == logo_width * logo_height) {
char buffer[512+logo_width];
int fill = 0, cnt = logo_width * logo_height, i;
while(cnt) {
if(fill < logo_width) {
FileRead(&file, buffer+fill);
FileNextSector(&file);
fill += 512;
}
BootDraw(buffer, logo_width, offset);
offset += 640/8;
bcury+=640/8;
// remove line from buffer
for(i=0;i<512;i++)
buffer[i] = buffer[i+logo_width];
cnt -= logo_width;
fill -= logo_width;
}
return;
}
}
for (line=0; line<logo_height; line++) {
p = (char*)boot_logo[line];
BootDraw(p, logo_width, offset);
offset += 640/8;
bcury+=640/8;
}
}

11
boot_logo.h Normal file
View File

@@ -0,0 +1,11 @@
/* boot_logo.h */
/* 2012, rok.krajnc@gmail.com */
#ifndef __BOOT_LOGO_H__
#define __BOOT_LOGO_H__
void draw_boot_logo();
#endif // __BOOT_LOGO_H__

127
boot_print.c Normal file
View File

@@ -0,0 +1,127 @@
/* boot_print.c */
/* 2012, rok.krajnc@gmail.com */
#include "fpga.h"
#include "string.h"
unsigned short bcurx;
unsigned short bcury;
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} //
};
void BootPrintEx(char * str)
{
char buf[80];
unsigned char i,j;
unsigned char len;
len = strlen(str);
len = (len>80) ? 80 : len;
for(j=0; j<8; j++) {
for(i=0; i<len; i++) {
buf[i] = boot_font[str[i]-32][j];
}
BootDraw(buf, len, bcury+=640/8);
}
}

15
boot_print.h Normal file
View File

@@ -0,0 +1,15 @@
/* boot_print.h */
/* 2012, rok.krajnc@gmail.com */
#ifndef __BOOT_PRINT_H__
#define __BOOT_PRINT_H__
extern unsigned short bcurx;
extern unsigned short bcury;
void BootPrintEx(char * str);
#endif // __BOOT_PRINT_H__

290
charrom.h Normal file
View File

@@ -0,0 +1,290 @@
#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
*/
// *character font
unsigned char charfont[256][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,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 14 [0xe]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 15 [0xf]
{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
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 25 [0x19]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 26 [0x1a]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 27 [0x1b]
{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]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 128 [0x80]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 129 [0x81]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 130 [0x82]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 131 [0x83]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 132 [0x84]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 133 [0x85]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 134 [0x86]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 135 [0x87]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 136 [0x88]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 137 [0x89]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 138 [0x8a]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 139 [0x8b]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 140 [0x8c]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 141 [0x8d]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 142 [0x8e]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 143 [0x8f]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 144 [0x90]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 145 [0x91]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 146 [0x92]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 147 [0x93]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 148 [0x94]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 149 [0x95]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 150 [0x96]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 151 [0x97]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 152 [0x98]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 153 [0x99]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 154 [0x9a]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 155 [0x9b]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 156 [0x9c]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 157 [0x9d]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 158 [0x9e]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 159 [0x9f]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 160 [0xa0]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 161 [0xa1]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 162 [0xa2]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 163 [0xa3]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 164 [0xa4]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 165 [0xa5]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 166 [0xa6]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 167 [0xa7]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 168 [0xa8]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 169 [0xa9]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 170 [0xaa]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 171 [0xab]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 172 [0xac]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 173 [0xad]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 174 [0xae]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 175 [0xaf]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 176 [0xb0]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 177 [0xb1]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 178 [0xb2]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 179 [0xb3]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 180 [0xb4]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 181 [0xb5]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 182 [0xb6]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 183 [0xb7]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 184 [0xb8]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 185 [0xb9]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 186 [0xba]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 187 [0xbb]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 188 [0xbc]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 189 [0xbd]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 190 [0xbe]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 191 [0xbf]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 192 [0xc0]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 193 [0xc1]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 194 [0xc2]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 195 [0xc3]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 196 [0xc4]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 197 [0xc5]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 198 [0xc6]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 199 [0xc7]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 200 [0xc8]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 201 [0xc9]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 202 [0xca]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 203 [0xcb]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 204 [0xcc]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 205 [0xcd]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 206 [0xce]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 207 [0xcf]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 208 [0xd0]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 209 [0xd1]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 210 [0xd2]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 211 [0xd3]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 212 [0xd4]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 213 [0xd5]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 214 [0xd6]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 215 [0xd7]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 216 [0xd8]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 217 [0xd9]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 218 [0xda]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 219 [0xdb]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 220 [0xdc]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 221 [0xdd]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 222 [0xde]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 223 [0xdf]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 224 [0xe0]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 225 [0xe1]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 226 [0xe2]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 227 [0xe3]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 228 [0xe4]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 229 [0xe5]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 230 [0xe6]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 231 [0xe7]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 232 [0xe8]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 233 [0xe9]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 234 [0xea]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 235 [0xeb]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 236 [0xec]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 237 [0xed]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 238 [0xee]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 239 [0xef]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 240 [0xf0]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 241 [0xf1]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 242 [0xf2]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 243 [0xf3]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 244 [0xf4]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 245 [0xf5]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 246 [0xf6]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 247 [0xf7]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 248 [0xf8]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 249 [0xf9]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 250 [0xfa]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 251 [0xfb]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 252 [0xfc]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 253 [0xfd]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 254 [0xfe]
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // 255 [0xff]
};
#endif

420
config.c Normal file
View File

@@ -0,0 +1,420 @@
#include "errors.h"
#include "hardware.h"
#include "mmc.h"
#include "fat.h"
#include "osd.h"
#include "fpga.h"
#include "fdd.h"
#include "hdd.h"
#include "firmware.h"
#include "menu.h"
#include "config.h"
#include <stdio.h>
#include <string.h>
configTYPE config;
fileTYPE file;
extern char s[40];
char configfilename[12];
char DebugMode=0;
unsigned char romkey[3072];
RAFile romfile;
char UploadKickstart(char *name)
{
int keysize=0;
char filename[12];
strncpy(filename, name, 8); // copy base name
strcpy(&filename[8], "ROM"); // add extension
BootPrint("Checking for Amiga Forever key file:");
if(FileOpen(&file,"ROM KEY"))
{
keysize=file.size;
if(file.size<sizeof(romkey))
{
int c=0;
while(c<keysize)
{
FileRead(&file, &romkey[c]);
c+=512;
FileNextSector(&file);
}
BootPrint("Loaded Amiga Forever key file");
}
else
BootPrint("Amiga Forever keyfile is too large!");
}
BootPrint("Loading file: ");
BootPrint(filename);
if (RAOpen(&romfile, filename))
{
if (romfile.size == 0x80000)
{ // 512KB Kickstart ROM
BootPrint("Uploading 512 KB Kickstart...");
PrepareBootUpload(0xF8, 0x08);
SendFile(&romfile);
return(1);
}
if ((romfile.size == 0x8000b) && keysize)
{ // 512KB Kickstart ROM
BootPrint("Uploading 512 KB Kickstart (Probably Amiga Forever encrypted...)");
PrepareBootUpload(0xF8, 0x08);
SendFileEncrypted(&romfile,romkey,keysize);
return(1);
}
else if (romfile.size == 0x40000)
{ // 256KB Kickstart ROM
BootPrint("Uploading 256 KB Kickstart...");
PrepareBootUpload(0xF8, 0x04);
SendFile(&romfile);
return(1);
}
else if ((romfile.size == 0x4000b) && keysize)
{ // 256KB Kickstart ROM
BootPrint("Uploading 256 KB Kickstart (Probably Amiga Forever encrypted...");
PrepareBootUpload(0xF8, 0x04);
SendFileEncrypted(&romfile,romkey,keysize);
return(1);
}
else
{
BootPrint("Unsupported ROM file size!");
}
}
else
{
sprintf(s, "No \"%s\" file!", filename);
BootPrint(s);
}
return(0);
}
char UploadActionReplay()
{
if (RAOpen(&romfile, "AR3 ROM"))
{
if (romfile.file.size == 0x40000)
{ // 256 KB Action Replay 3 ROM
BootPrint("\nUploading Action Replay ROM...");
PrepareBootUpload(0x40, 0x04);
SendFile(&romfile);
ClearMemory(0x440000, 0x40000);
return(1);
}
else
{
BootPrint("\nUnsupported AR3.ROM file size!!!");
/* FatalError(6); */
return(0);
}
}
return(0);
}
void SetConfigurationFilename(int config)
{
if(config)
sprintf(configfilename,"MINIMIG%dCFG",config);
else
strcpy(configfilename,"MINIMIG CFG");
}
unsigned char ConfigurationExists(char *filename)
{
if(!filename)
filename=configfilename; // Use slot-based filename if none provided.
if (FileOpen(&file, filename))
{
return(1);
}
return(0);
}
unsigned char LoadConfiguration(char *filename)
{
static const char config_id[] = "MNMGCFG0";
char updatekickstart=0;
char result=0;
unsigned char key;
if(!filename)
filename=configfilename; // Use slot-based filename if none provided.
// load configuration data
if (FileOpen(&file, filename))
{
BootPrint("Opened configuration file\n");
printf("Configuration file size: %lu\r", file.size);
if (file.size == sizeof(config))
{
FileRead(&file, sector_buffer);
configTYPE *tmpconf=(configTYPE *)&sector_buffer;
// 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(strncmp(tmpconf->kickstart.name,config.kickstart.name,8)!=0)
updatekickstart=true;
memcpy((void*)&config, (void*)sector_buffer, 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("Wrong configuration file size: %lu (expected: %lu)\r", 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));
strncpy(config.kickstart.name, "KICK ", sizeof(config.kickstart.name));
config.kickstart.long_name[0] = 0;
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;
strncpy(config.hardfile[0].name, "HARDFILE", sizeof(config.hardfile[0].name));
config.hardfile[0].long_name[0]=0;
strncpy(config.hardfile[1].name, "HARDFILE", sizeof(config.hardfile[1].name));
config.hardfile[1].long_name[0]=0;
config.hardfile[1].enabled = 2; // Default is access to entire SD card
updatekickstart=true;
BootPrint("Defaults set\n");
}
key = OsdGetCtrl();
if (key == KEY_F1)
config.chipset |= CONFIG_NTSC; // force NTSC mode if F1 pressed
if (key == KEY_F2)
config.chipset &= ~CONFIG_NTSC; // force PAL mode if F2 pressed
ApplyConfiguration(updatekickstart);
return(result);
}
void ApplyConfiguration(char reloadkickstart)
{
ConfigCPU(config.cpu);
if(reloadkickstart)
{
ConfigChipset(config.chipset | CONFIG_TURBO); // set CPU in turbo mode
ConfigFloppy(1, CONFIG_FLOPPY2X); // set floppy speed
OsdReset(RESET_BOOTLOADER);
if (!UploadKickstart(config.kickstart.name))
{
strcpy(config.kickstart.name, "KICK ");
if (!UploadKickstart(config.kickstart.name))
FatalError(6);
}
if (!CheckButton() && !config.disable_ar3) // if menu button pressed don't load Action Replay
{
#ifndef ACTIONREPLAY_BROKEN
if(config.memory & 0x20)
BootPrint("More than 2MB of Fast RAM configured - disabling Action Replay!");
else
UploadActionReplay();
#endif
}
}
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 access
{
case (HDF_FILE | HDF_SYNTHRDB):
sprintf(s, "\nHardfile 1 (with fake RDB): %.8s.%.3s", hdf[1].file.name, &hdf[1].file.name[8]);
break;
case HDF_FILE:
sprintf(s, "\nHardfile 0: %.8s.%.3s", hdf[0].file.name, &hdf[0].file.name[8]);
break;
case HDF_CARD:
sprintf(s, "\nHardfile 0: using entire SD card");
break;
default:
sprintf(s, "\nHardfile 0: using SD card partition %d",hdf[0].type-HDF_CARD); // Number from 1
break;
}
BootPrint(s);
sprintf(s, "CHS: %u.%u.%u", hdf[0].cylinders, hdf[0].heads, hdf[0].sectors);
BootPrint(s);
sprintf(s, "Size: %lu MB", ((((unsigned long) hdf[0].cylinders) * hdf[0].heads * hdf[0].sectors) >> 11));
BootPrint(s);
sprintf(s, "Offset: %ld", hdf[0].offset);
BootPrint(s);
}
if(OpenHardfile(1))
{
switch(hdf[1].type)
{
case (HDF_FILE | HDF_SYNTHRDB):
sprintf(s, "\nHardfile 1 (with fake RDB): %.8s.%.3s", hdf[1].file.name, &hdf[1].file.name[8]);
break;
case HDF_FILE:
sprintf(s, "\nHardfile 1: %.8s.%.3s", hdf[1].file.name, &hdf[1].file.name[8]);
break;
case HDF_CARD:
sprintf(s, "\nHardfile 1: using entire SD card");
break;
default:
sprintf(s, "\nHardfile 1: using SD card partition %d",hdf[1].type-HDF_CARD); // Number from 1
break;
}
BootPrint(s);
sprintf(s, "CHS: %u.%u.%u", hdf[1].cylinders, hdf[1].heads, hdf[1].sectors);
BootPrint(s);
sprintf(s, "Size: %lu MB", ((((unsigned long) hdf[1].cylinders) * hdf[1].heads * hdf[1].sectors) >> 11));
BootPrint(s);
sprintf(s, "Offset: %ld", hdf[1].offset);
BootPrint(s);
}
ConfigIDE(config.enable_ide, config.hardfile[0].present && config.hardfile[0].enabled, config.hardfile[1].present && config.hardfile[1].enabled);
sprintf(s, "CPU clock : %s", config.chipset & 0x01 ? "turbo" : "normal");
BootPrint(s);
sprintf(s, "Chip RAM size : %s", config_memory_chip_msg[config.memory & 0x03]);
BootPrint(s);
sprintf(s, "Slow RAM size : %s", config_memory_slow_msg[config.memory >> 2 & 0x03]);
BootPrint(s);
sprintf(s, "Fast RAM size : %s", config_memory_fast_msg[config.memory >> 4 & 0x03]);
BootPrint(s);
sprintf(s, "Floppy drives : %u", config.floppy.drives + 1);
BootPrint(s);
sprintf(s, "Floppy speed : %s", config.floppy.speed ? "fast": "normal");
BootPrint(s);
BootPrint("");
sprintf(s, "\nA600 IDE HDC is %s.", config.enable_ide ? "enabled" : "disabled");
BootPrint(s);
sprintf(s, "Master HDD is %s.", config.hardfile[0].present ? config.hardfile[0].enabled ? "enabled" : "disabled" : "not present");
BootPrint(s);
sprintf(s, "Slave HDD is %s.", config.hardfile[1].present ? config.hardfile[1].enabled ? "enabled" : "disabled" : "not present");
BootPrint(s);
#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( "***************************************************");
}
printf("Bootloading is complete.\r");
#endif
BootPrint("\nExiting bootloader...");
ConfigMemory(config.memory);
ConfigCPU(config.cpu);
ConfigFilter(config.filter.lores, config.filter.hires);
ConfigScanlines(config.scanlines);
if(reloadkickstart)
{
WaitTimer(5000);
BootExit();
}
else
OsdReset(RESET_NORMAL);
ConfigChipset(config.chipset);
ConfigFloppy(config.floppy.drives, config.floppy.speed);
}
unsigned char SaveConfiguration(char *filename)
{
if(!filename)
filename=configfilename; // Use slot-based filename if none provided.
// save configuration data
if (FileOpen(&file, filename))
{
printf("Configuration file size: %lu\r", file.size);
if (file.size != sizeof(config))
{
file.size = sizeof(config);
if (!UpdateEntry(&file))
return(0);
}
memset((void*)&sector_buffer, 0, sizeof(sector_buffer));
memcpy((void*)&sector_buffer, (void*)&config, sizeof(config));
FileWrite(&file, sector_buffer);
return(1);
}
else
{
printf("Configuration file not found!\r");
printf("Trying to create a new one...\r");
strncpy(file.name, filename, 11);
file.attributes = 0;
file.size = sizeof(config);
if (FileCreate(0, &file))
{
printf("File created.\r");
printf("Trying to write new data...\r");
memset((void*)sector_buffer, 0, sizeof(sector_buffer));
memcpy((void*)sector_buffer, (void*)&config, sizeof(config));
if (FileWrite(&file, sector_buffer))
{
printf("File written successfully.\r");
return(1);
}
else
printf("File write failed!\r");
}
else
printf("File creation failed!\r");
}
return(0);
}

60
config.h Normal file
View File

@@ -0,0 +1,60 @@
#include "fat.h"
typedef struct
{
char name[8];
char long_name[16];
} kickstartTYPE;
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 name[8];
char long_name[16];
} hardfileTYPE;
typedef struct
{
char id[8];
unsigned long version;
kickstartTYPE kickstart;
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 pad2;
} configTYPE;
extern fileTYPE file; // Temporary file available for use by other modules, to avoid repeated memory usage.
// Shouldn't be considered persistent.
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);

9
errors.h Normal file
View 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);

1520
fat.c Normal file

File diff suppressed because it is too large Load Diff

128
fat.h Normal file
View File

@@ -0,0 +1,128 @@
#ifndef _FAT16_H_INCLUDED
#define _FAT16_H_INCLUDED
#include "hardware.h"
#define MAXDIRENTRIES 8
typedef struct
{
unsigned long sector;
unsigned long index;
} entryTYPE;
typedef struct
{
char name[11]; /* name of file */
unsigned char attributes; /* file attributes */
entryTYPE entry; /* file entry location */
unsigned long sector; /* sector index in file */
unsigned long size; /* file size */
unsigned long cluster; /* current cluster */
unsigned long start_cluster; /* first cluster of file */
char long_name[261];
} fileTYPE;
struct PartitionEntry
{
unsigned char geometry[8]; // ignored
unsigned long startlba;
unsigned long sectors;
} __attribute__ ((packed));
struct MasterBootRecord
{
unsigned char bootcode[446]; // ignored
struct PartitionEntry Partition[4]; // We copy these (and byteswap if need be)
unsigned short Signature; // This lets us detect an MBR (and the need for byteswapping).
} __attribute__ ((packed));
extern struct PartitionEntry partitions[4]; // FirstBlock and LastBlock will be byteswapped as necessary
extern int partitioncount;
typedef struct
{
unsigned char Name[8]; /* filename, blank filled */
#define SLOT_EMPTY 0x00 /* slot has never been used */
#define SLOT_E5 0x05 /* the real value is 0xe5 */
#define SLOT_DELETED 0xe5 /* file in this slot deleted */
unsigned char Extension[3]; /* extension, blank filled */
unsigned char Attributes; /* file attributes */
#define ATTR_NORMAL 0x00 /* normal file */
#define ATTR_READONLY 0x01 /* file is readonly */
#define ATTR_HIDDEN 0x02 /* file is hidden */
#define ATTR_SYSTEM 0x04 /* file is a system file */
#define ATTR_VOLUME 0x08 /* entry is a volume label */
#define ATTR_DIRECTORY 0x10 /* entry is a directory name */
#define ATTR_ARCHIVE 0x20 /* file is new or modified */
#define ATTR_LFN 0x0F /* long file name entry */
unsigned char LowerCase; /* NT VFAT lower case flags */
#define LCASE_BASE 0x08 /* filename base in lower case */
#define LCASE_EXT 0x10 /* filename extension in lower case */
unsigned char CreateHundredth; /* hundredth of seconds in CTime */
unsigned short CreateTime; /* create time */
unsigned short CreateDate; /* create date */
unsigned short AccessDate; /* access date */
unsigned short HighCluster; /* high bytes of cluster number */
unsigned short ModifyTime; /* last update time */
unsigned short ModifyDate; /* last update date */
unsigned short StartCluster; /* starting cluster of file */
unsigned long FileSize; /* size of file in bytes */
} DIRENTRY;
typedef union {
unsigned short fat16[256];
unsigned long fat32[128];
} FATBUFFER;
#define FILETIME(h,m,s) (((h<<11)&0xF800)|((m<<5)&0x7E0)|((s/2)&0x1F))
#define FILEDATE(y,m,d) ((((y-1980)<<9)&0xFE00)|((m<<5)&0x1E0)|(d&0x1F))
// global sector buffer, data for read/write actions is stored here.
// BEWARE, this buffer is also used and thus trashed by all other functions
extern unsigned char sector_buffer[1024]; // sector buffer - room for 2 sectors, to ease reading data not sector-aligned...
extern unsigned char cluster_size;
extern unsigned long cluster_mask;
extern unsigned char fat32;
// constants
#define DIRECTORY_ROOT 0
// file seeking
#define SEEK_SET 0
#define SEEK_CUR 1
// 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_INIT_FIRST 3 // search for an entry with given cluster number
#define SCAN_INIT_NEXT 4 // search for entries higher than the first one
// options flags
#define SCAN_DIR 1 // include subdirectories
#define SCAN_LFN 2 // include long file names
#define FIND_DIR 4 // find first directory beginning with given charater
#define FIND_FILE 8 // find first file entry beginning with given charater
// functions
unsigned char FindDrive(void);
unsigned long GetFATLink(unsigned long cluster);
unsigned char FileNextSector(fileTYPE *file) RAMFUNC;
unsigned char FileOpen(fileTYPE *file, const char *name);
unsigned char FileSeek(fileTYPE *file, unsigned long offset, unsigned long origin);
unsigned char FileRead(fileTYPE *file, unsigned char *pBuffer) RAMFUNC;
unsigned char FileWrite(fileTYPE *file, unsigned char *pBuffer);
unsigned char FileReadEx(fileTYPE *file, unsigned char *pBuffer, unsigned long nSize);
unsigned char FileCreate(unsigned long iDirectory, fileTYPE *file);
unsigned char UpdateEntry(fileTYPE *file);
char ScanDirectory(unsigned long mode, char *extension, unsigned char options);
void ChangeDirectory(unsigned long iStartCluster);
#endif

701
fdd.c Normal file
View File

@@ -0,0 +1,701 @@
/*
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
#ifdef __GNUC__
#include "AT91SAM7S256.h"
#include "stdio.h"
#include "string.h"
#else
#include <stdio.h>
#endif
#include "errors.h"
#include "hardware.h"
#include "fat.h"
#include "fdd.h"
#include "config.h"
#ifdef __GNUC__
#define SPIN
extern fileTYPE file;
#endif
unsigned char vDEBUG = 0;
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
#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)
// 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;
unsigned char *p;
// preamble
SPI(0xAA);
SPI(0xAA);
SPI(0xAA);
SPI(0xAA);
// synchronization
SPI(dsksynch);
SPI(dsksyncl);
SPI(dsksynch);
SPI(dsksyncl);
// odd bits of header
x = 0x55;
checksum[0] = x;
SPI(x);
x = track >> 1 & 0x55;
checksum[1] = x;
SPI(x);
x = sector >> 1 & 0x55;
checksum[2] = x;
SPI(x);
x = 11 - sector >> 1 & 0x55;
checksum[3] = x;
SPI(x);
// even bits of header
x = 0x55;
checksum[0] ^= x;
SPI(x);
x = track & 0x55;
checksum[1] ^= x;
SPI(x);
x = sector & 0x55;
checksum[2] ^= x;
SPI(x);
x = 11 - sector & 0x55;
checksum[3] ^= x;
SPI(x);
// sector label and reserved area (changes nothing to checksum)
i = 0x20;
while (i--)
SPI(0xAA);
// send header checksum
SPI(0xAA);
SPI(0xAA);
SPI(0xAA);
SPI(0xAA);
SPI(checksum[0] | 0xAA);
SPI(checksum[1] | 0xAA);
SPI(checksum[2] | 0xAA);
SPI(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(0xAA);
SPI(0xAA);
SPI(0xAA);
SPI(0xAA);
SPI(checksum[0] | 0xAA);
SPI(checksum[1] | 0xAA);
SPI(checksum[2] | 0xAA);
SPI(checksum[3] | 0xAA);
// odd bits of data field
i = DATA_SIZE / 2;
p = pData;
while (i--)
SPI(*p++ >> 1 | 0xAA);
// even bits of data field
i = DATA_SIZE / 2;
p = pData;
while (i--)
SPI(*p++ | 0xAA);
}
void SendGap(void)
{
unsigned short i = GAP_SIZE;
while (i--)
SPI(0xAA);
}
// 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;
//unsigned short n;
if (drive->track >= drive->tracks)
{
printf("Illegal track read: %d\r", drive->track);
ErrorMessage(" Illegal track read!", drive->track);
drive->track = drive->tracks - 1;
}
// display track number: cylinder & head
if (vDEBUG)
printf("*%u:", drive->track);
if (drive->track != drive->track_prev)
{ // track step or track 0, start at beginning of track
drive->track_prev = drive->track;
sector = 0;
file.cluster = drive->cache[drive->track];
file.sector = drive->track * SECTOR_COUNT;
drive->sector_offset = sector;
drive->cluster_offset = file.cluster;
}
else
{ // same track, start at next sector in track
sector = drive->sector_offset;
file.cluster = drive->cluster_offset;
file.sector = (drive->track * SECTOR_COUNT) + sector;
}
EnableFpga();
status = SPI(0); // read request signal
track = SPI(0); // track number (cylinder & head)
dsksync = (SPI(0)) << 8; // disk sync high byte
dsksync |= SPI(0); // disk sync low byte
dsklen = (SPI(0)) << 8 & 0x3F00; // msb of mfm words to transfer
dsklen |= SPI(0); // lsb of mfm words to transfer
DisableFpga();
if (track >= drive->tracks)
track = drive->tracks - 1;
if (vDEBUG)
printf("(%u)[%04X]:", status >> 6, dsksync);
while (1)
{
FileRead(&file, sector_buffer);
EnableFpga();
// check if FPGA is still asking for data
status = SPI(0); // read request signal
track = SPI(0); // track number (cylinder & head)
dsksync = (SPI(0)) << 8; // disk sync high byte
dsksync |= SPI(0); // disk sync low byte
dsklen = (SPI(0)) << 8 & 0x3F00; // msb of mfm words to transfer
dsklen |= SPI(0); // lsb of 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
if (vDEBUG)
printf("%X:%04X", sector, dsklen);
// 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)
{
FileNextSector(&file);
}
else // go to the start of current track
{
sector = 0;
file.cluster = drive->cache[drive->track];
file.sector = drive->track * SECTOR_COUNT;
}
// remember current sector and cluster
drive->sector_offset = sector;
drive->cluster_offset = file.cluster;
if (vDEBUG)
printf("->");
}
if (vDEBUG)
printf(":OK\r");
}
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;
while (1)
{
EnableFpga();
c1 = SPI(0); // write request signal
c2 = SPI(0); // track number (cylinder & head)
if (!(c1 & CMD_WRTRK))
break;
if (c2 != drive->track)
break;
SPI(0); // disk sync high byte
SPI(0); // disk sync low byte
c3 = (SPI(0)) & 0xBF; // msb of mfm words to transfer
c4 = SPI(0); // lsb of mfm words to transfer
if (c3 == 0 && c4 == 0)
break;
n = ((c3 & 0x3F) << 8) + c4;
while (n--)
{
c3 = SPI(0);
c4 = SPI(0);
if (c3 == 0x44 && c4 == 0x89)
{
DisableFpga();
if (vDEBUG)
printf("#SYNC:");
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];
Error = 0;
while (1)
{
EnableFpga();
c1 = SPI(0); // write request signal
c2 = SPI(0); // track number (cylinder & head)
if (!(c1 & CMD_WRTRK))
break;
SPI(0); // disk sync high byte
SPI(0); // disk sync low byte
c3 = SPI(0); // msb of mfm words to transfer
c4 = SPI(0); // lsb of mfm words to transfer
if ((c3 & 0x3F) != 0 || c4 > 24)// remaining header data is 25 mfm words
{
c1 = SPI(0); // second sync lsb
c2 = SPI(0); // second sync msb
if (c1 != 0x44 || c2 != 0x89)
{
Error = 21;
printf("\rSecond sync word missing...\r");
break;
}
SPIN;
c = SPI(0);
checksum[0] = c;
c1 = (c & 0x55) << 1;
SPIN;
c = SPI(0);
checksum[1] = c;
c2 = (c & 0x55) << 1;
SPIN;
c = SPI(0);
checksum[2] = c;
c3 = (c & 0x55) << 1;
SPIN;
c = SPI(0);
checksum[3] = c;
c4 = (c & 0x55) << 1;
SPIN;
c = SPI(0);
checksum[0] ^= c;
c1 |= c & 0x55;
SPIN;
c = SPI(0);
checksum[1] ^= c;
c2 |= c & 0x55;
SPIN;
c = SPI(0);
checksum[2] ^= c;
c3 |= c & 0x55;
SPIN;
c = SPI(0);
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)
{
printf("\rWrong header: %u.%u.%u.%u\r", c1, c2, c3, c4);
break;
}
if (vDEBUG)
printf("T%uS%u\r", c2, c3);
*pTrack = c2;
*pSector = c3;
for (i = 0; i < 8; i++)
{
SPIN;
checksum[0] ^= SPI(0);
checksum[1] ^= SPI(0);
SPIN;
checksum[2] ^= SPI(0);
checksum[3] ^= SPI(0);
}
checksum[0] &= 0x55;
checksum[1] &= 0x55;
checksum[2] &= 0x55;
checksum[3] &= 0x55;
SPIN;
c1 = ((SPI(0)) & 0x55) << 1;
c2 = ((SPI(0)) & 0x55) << 1;
SPIN;
c3 = ((SPI(0)) & 0x55) << 1;
c4 = ((SPI(0)) & 0x55) << 1;
SPIN;
c1 |= (SPI(0)) & 0x55;
c2 |= (SPI(0)) & 0x55;
SPIN;
c3 |= (SPI(0)) & 0x55;
c4 |= (SPI(0)) & 0x55;
if (c1 != checksum[0] || c2 != checksum[1] || c3 != checksum[2] || c4 != checksum[3])
{
Error = 26;
break;
}
DisableFpga();
return 1;
}
else if ((c3 & 0x80) == 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];
Error = 0;
while (1)
{
EnableFpga();
c1 = SPI(0); // write request signal
c2 = SPI(0); // track number (cylinder & head)
if (!(c1 & CMD_WRTRK))
break;
SPI(0); // disk sync high byte
SPI(0); // disk sync low byte
c3 = SPI(0); // msb of mfm words to transfer
c4 = SPI(0); // lsb of mfm words to transfer
n = ((c3 & 0x3F) << 8) + c4;
if (n >= 0x204)
{
SPIN;
c1 = ((SPI(0)) & 0x55) << 1;
c2 = ((SPI(0)) & 0x55) << 1;
SPIN;
c3 = ((SPI(0)) & 0x55) << 1;
c4 = ((SPI(0)) & 0x55) << 1;
SPIN;
c1 |= (SPI(0)) & 0x55;
c2 |= (SPI(0)) & 0x55;
SPIN;
c3 |= (SPI(0)) & 0x55;
c4 |= (SPI(0)) & 0x55;
checksum[0] = 0;
checksum[1] = 0;
checksum[2] = 0;
checksum[3] = 0;
// odd bits of data field
i = 128;
p = sector_buffer;
do
{
SPIN;
c = SPI(0);
checksum[0] ^= c;
*p++ = (c & 0x55) << 1;
c = SPI(0);
checksum[1] ^= c;
*p++ = (c & 0x55) << 1;
SPIN;
c = SPI(0);
checksum[2] ^= c;
*p++ = (c & 0x55) << 1;
c = SPI(0);
checksum[3] ^= c;
*p++ = (c & 0x55) << 1;
}
while (--i);
// even bits of data field
i = 128;
p = sector_buffer;
do
{
SPIN;
c = SPI(0);
checksum[0] ^= c;
*p++ |= c & 0x55;
c = SPI(0);
checksum[1] ^= c;
*p++ |= c & 0x55;
SPIN;
c = SPI(0);
checksum[2] ^= c;
*p++ |= c & 0x55;
c = SPI(0);
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 ((c3 & 0x80) == 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 sector;
unsigned char Track;
unsigned char Sector;
// setting file pointer to begining of current track
file.cluster = drive->cache[drive->track];
file.sector = drive->track * 11;
sector = 0;
drive->track_prev = drive->track + 1; // just to force next read from the start of current track
if (vDEBUG)
printf("*%u:\r", drive->track);
while (FindSync(drive))
{
if (GetHeader(&Track, &Sector))
{
if (Track == drive->track)
{
while (sector != Sector)
{
if (sector < Sector)
{
FileNextSector(&file);
sector++;
}
else
{
file.cluster = drive->cache[drive->track];
file.sector = drive->track * 11;
sector = 0;
}
}
if (GetData())
{
if (drive->status & DSK_WRITABLE)
FileWrite(&file, sector_buffer);
else
{
Error = 30;
printf("Write attempt to protected disk!\r");
}
}
}
else
Error = 27; //track number reported in sector header is not the same as current drive track
}
if (Error)
{
printf("WriteTrack: error %u\r", Error);
ErrorMessage(" WriteTrack", Error);
}
}
}
void UpdateDriveStatus(void)
{
EnableFpga();
SPI(0x10);
SPI(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;
}
}

38
fdd.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef FDD_H
#define FDD_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
{
unsigned char status; /*status of floppy*/
unsigned char tracks; /*number of tracks*/
unsigned long cache[MAX_TRACKS]; /*cluster cache*/
unsigned long cluster_offset; /*cluster offset to handle tricky loaders*/
unsigned char sector_offset; /*sector offset to handle tricky loaders*/
unsigned char track; /*current track*/
unsigned char track_prev; /*previous track*/
char name[22]; /*floppy name*/
} adfTYPE;
void SectorGapToFpga(void);
void SectorHeaderToFpga(unsigned char n, unsigned char dsksynch, unsigned char dsksyncl);
//unsigned short SectorToFpga(unsigned char sector, unsigned char track, unsigned char dsksynch, unsigned char dsksyncl);
void ReadTrack(adfTYPE *drive);
unsigned char FindSync(adfTYPE *drive);
unsigned char GetHeader(unsigned char *pTrack, unsigned char *pSector);
unsigned char GetData(void);
void WriteTrack(adfTYPE *drive);
void UpdateDriveStatus(void);
void HandleFDD(unsigned char c1, unsigned char c2);
#endif

224
firmware.c Normal file
View File

@@ -0,0 +1,224 @@
/*
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 "AT91SAM7S256.h"
#include "stdio.h"
#include "string.h"
#include "errors.h"
#include "hardware.h"
#include "fat.h"
#include "firmware.h"
#ifdef __GNUC__
#define __noinline
#endif
/* polynomial 0xEDB88320 */
const unsigned long crc32_table[256] =
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
// Initial CRC value is -1 (0xFFFFFFFF)
// Final CRC value is bitwise negation of the last calculated value
unsigned long CalculateCRC32(unsigned long crc, unsigned char *pBuffer, unsigned long nSize)
{
while (nSize--)
crc = crc32_table[(unsigned char)crc ^ *pBuffer++] ^ crc >> 8;
return crc;
}
unsigned char CheckFirmware(fileTYPE *file, char *name)
{
UPGRADE *pUpgrade = (UPGRADE*)sector_buffer;
unsigned long crc;
unsigned long size;
unsigned long rom_size;
unsigned long rom_crc;
unsigned long read_size;
Error = ERROR_FILE_NOT_FOUND;
if (FileOpen(file, name))
{
Error = ERROR_INVALID_DATA;
printf("Upgrade file size : %lu\r", file->size);
printf("Upgrade header size : %lu\r", (unsigned long)sizeof(UPGRADE));
if (file->size >= sizeof(UPGRADE))
{
FileRead(file, sector_buffer);
crc = ~CalculateCRC32(-1, sector_buffer, sizeof(UPGRADE) - 4);
printf("Upgrade ROM size : %lu\r", pUpgrade->rom.size);
printf("Upgrade header CRC : %08lX\r", pUpgrade->crc);
printf("Calculated header CRC : %08lX\r", crc);
if (pUpgrade->crc == crc)
{
if (strncmp((const char*)pUpgrade->id, "MNMGUPG", 7) == 0 && pUpgrade->id[7] == 0)
{
if (pUpgrade->rom.size == file->size - sizeof(UPGRADE))
{
rom_size = pUpgrade->rom.size;
rom_crc = pUpgrade->rom.crc;
crc = -1; // initial CRC32 value
size = rom_size;
while (size)
{
if (size > 512)
read_size = 512;
else
read_size = size;
FileNextSector(file);
FileRead(file, sector_buffer);
crc = CalculateCRC32(crc, sector_buffer, read_size);
size -= read_size;
}
printf("Calculated ROM CRC : %08lX\r", ~crc);
printf("ROM CRC from header : %08lX\r", rom_crc);
if (~crc == rom_crc)
{ // upgrade file CRC is OK so go back to the beginning of the file
FileSeek(file, 0, SEEK_SET);
Error = ERROR_NONE;
return 1;
}
else printf("ROM CRC mismatch! from header: %08lX, calculated: %08lX\r", rom_crc, ~crc);
}
else printf("ROM size mismatch! from header: %lu, from file: %lu\r", pUpgrade->rom.size, file->size-sizeof(UPGRADE));
}
else printf("Invalid upgrade file header!\r");
}
else printf("Header CRC mismatch! from header: %08lX, calculated: %08lX\r", pUpgrade->crc, crc);
}
else printf("Upgrade file size too small: %lu\r", file->size);
}
else printf("Cannot open firmware file!\r");
return 0;
}
char *GetFirmwareVersion(fileTYPE *file, char *name) {
static char v[16];
if ((!FileOpen(file, name) || file->size < sizeof(UPGRADE)))
return NULL;
FileRead(file, sector_buffer);
strncpy(v, ((UPGRADE*)sector_buffer)->version, 16);
v[15] = 0;
return v;
}
#pragma section_code_init
RAMFUNC __noinline unsigned long WriteFirmware(fileTYPE *file)
{
unsigned long read_size;
unsigned long i;
unsigned long k;
unsigned long page;
unsigned long *pSrc;
unsigned long *pDst;
unsigned long size;
size = file->size - sizeof(UPGRADE);
page = 0;
pDst = 0;
*AT91C_MC_FMR = 48 << 16 | FWS << 8; // MCLK cycles in 1us
for (i = 0; i < 16; i++)
if (*AT91C_MC_FSR & 1 << 16 + i)
{ // page is locked
while (!(*AT91C_MC_FSR & AT91C_MC_FRDY)); // wait for ready
*AT91C_MC_FCR = 0x5A << 24 | i << 6 + 8 | AT91C_MC_FCMD_UNLOCK; // unlock page
while (!(*AT91C_MC_FSR & AT91C_MC_FRDY)); // wait for ready
}
*AT91C_MC_FMR = 72 << 16 | FWS << 8; // MCLK cycles in 1.5us
while (size)
{
if (size > 512)
read_size = 512;
else
read_size = size;
FileNextSector(file);
FileRead(file, sector_buffer);
// fill the rest of buffer
for (i = read_size; i < 512; i++)
sector_buffer[i] = 0xFF;
// programming time: 13.2 ms per disk sector (512B)
pSrc = (unsigned long*)sector_buffer;
k = 2;
while (k--)
{
i = 256 / 4;
while (i--)
*pDst++ = *pSrc++;
DISKLED_ON;
while (!(*AT91C_MC_FSR & AT91C_MC_FRDY)); // wait for ready
*AT91C_MC_FCR = 0x5A << 24 | page << 8 | AT91C_MC_FCMD_START_PROG; // key: 0x5A
while (!(*AT91C_MC_FSR & AT91C_MC_FRDY)); // wait for ready
DISKLED_OFF;
page++;
}
size -= read_size;
}
*AT91C_RSTC_RCR = 0xA5 << 24 | AT91C_RSTC_PERRST | AT91C_RSTC_PROCRST; // restart
return 0;
}
#pragma section_no_code_init

24
firmware.h Normal file
View File

@@ -0,0 +1,24 @@
typedef struct
{
unsigned long flags;
unsigned long base;
unsigned long size;
unsigned long crc;
} romTYPE;
typedef struct
{
unsigned char id[8];
unsigned char version[16];
romTYPE rom;
unsigned long padding[117];
unsigned long crc;
} UPGRADE;
#define true -1
#define false 0
unsigned long CalculateCRC32(unsigned long crc, unsigned char *pBuffer, unsigned long nSize);
unsigned char CheckFirmware(fileTYPE *file, char *name);
unsigned long WriteFirmware(fileTYPE *file) RAMFUNC;
char *GetFirmwareVersion(fileTYPE *file, char *name);

16
flash_sam_i_am Normal file
View File

@@ -0,0 +1,16 @@
open /dev/ttyACM0
version
info flash
set
set ramwriteallow 0x200000 0x10000
set flashwriteallow 0x100000 0x40000
set ramwriteallow FFFFFF64 4
set
writew FFFFFF64 5A000004
shell sleep 0.1
writew FFFFFF64 5A004004
shell sleep 0.1
info flash
flash firmware.hex
go
exit

775
fpga.c Normal file
View File

@@ -0,0 +1,775 @@
/*
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-10-10 - any length (any multiple of 8 bytes) fpga core file support
// 2009-12-10 - changed command header id
// 2010-04-14 - changed command header id
#ifdef __GNUC__
#include "AT91SAM7S256.h"
#endif
#include "stdio.h"
#include "string.h"
#include "errors.h"
#include "hardware.h"
#include "fat.h"
#include "fdd.h"
#include "rafile.h"
#include "fpga.h"
#define CMD_HDRID 0xAACA
extern fileTYPE file;
extern char s[40];
char BootPrint(const char *text);
#ifdef XILINX_CCLK
// single byte serialization of FPGA configuration datastream
void ShiftFpga(unsigned char data)
{
AT91_REG *ppioa_codr = AT91C_PIOA_CODR;
AT91_REG *ppioa_sodr = AT91C_PIOA_SODR;
// bit 0
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
if (data & 0x80)
*ppioa_sodr = XILINX_DIN;
*ppioa_sodr = XILINX_CCLK;
// bit 1
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
if (data & 0x40)
*ppioa_sodr = XILINX_DIN;
*ppioa_sodr = XILINX_CCLK;
// bit 2
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
if (data & 0x20)
*ppioa_sodr = XILINX_DIN;
*ppioa_sodr = XILINX_CCLK;
// bit 3
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
if (data & 0x10)
*ppioa_sodr = XILINX_DIN;
*ppioa_sodr = XILINX_CCLK;
// bit 4
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
if (data & 0x08)
*ppioa_sodr = XILINX_DIN;
*ppioa_sodr = XILINX_CCLK;
// bit 5
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
if (data & 0x04)
*ppioa_sodr = XILINX_DIN;
*ppioa_sodr = XILINX_CCLK;
// bit 6
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
if (data & 0x02)
*ppioa_sodr = XILINX_DIN;
*ppioa_sodr = XILINX_CCLK;
// bit 7
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
if (data & 0x01)
*ppioa_sodr = XILINX_DIN;
*ppioa_sodr = XILINX_CCLK;
}
// Xilinx FPGA configuration
unsigned char ConfigureFpga(void)
{
unsigned long t;
unsigned long n;
unsigned char *ptr;
// set outputs
*AT91C_PIOA_SODR = XILINX_CCLK | XILINX_DIN | XILINX_PROG_B;
// enable outputs
*AT91C_PIOA_OER = XILINX_CCLK | XILINX_DIN | XILINX_PROG_B;
// reset FGPA configuration sequence
// specs: PROG_B pulse min 0.3 us
t = 15;
while (--t)
*AT91C_PIOA_CODR = XILINX_PROG_B;
*AT91C_PIOA_SODR = XILINX_PROG_B;
// now wait for INIT to go high
// specs: max 2ms
t = 100000;
while (!(*AT91C_PIOA_PDSR & XILINX_INIT_B))
{
if (--t == 0)
{
printf("FPGA init is NOT high!\r");
FatalError(3);
}
}
printf("FPGA init is high\r");
if (*AT91C_PIOA_PDSR & XILINX_DONE)
{
printf("FPGA done is high before configuration!\r");
FatalError(3);
}
// open bitstream file
if (FileOpen(&file, "MINIMIG1BIN") == 0)
{
printf("No FPGA configuration file found!\r");
FatalError(4);
}
printf("FPGA bitstream file opened\r");
printf("[");
// send all bytes to FPGA in loop
t = 0;
n = file.size >> 3;
ptr = sector_buffer;
do
{
// read sector if 512 (64*8) bytes done
if ((t & 0x3F) == 0)
{
if (t & (1<<10))
DISKLED_OFF
else
DISKLED_ON
if ((t & 0x1FF) == 0)
printf("*");
if (!FileRead(&file, sector_buffer))
return(0);
ptr = sector_buffer;
}
// send data in packets of 8 bytes
ShiftFpga(*ptr++);
ShiftFpga(*ptr++);
ShiftFpga(*ptr++);
ShiftFpga(*ptr++);
ShiftFpga(*ptr++);
ShiftFpga(*ptr++);
ShiftFpga(*ptr++);
ShiftFpga(*ptr++);
t++;
// read next sector if 512 (64*8) bytes done
if ((t & 0x3F) == 0)
FileNextSector(&file);
}
while (t < n);
// disable outputs
*AT91C_PIOA_ODR = XILINX_CCLK | XILINX_DIN | XILINX_PROG_B;
printf("]\r");
printf("FPGA bitstream loaded\r");
DISKLED_OFF;
// check if DONE is high
if (*AT91C_PIOA_PDSR & XILINX_DONE)
return(1);
printf("FPGA done is NOT high!\r");
FatalError(5);
return 0;
}
#endif
#ifdef ALTERA_DCLK
static inline void ShiftFpga(unsigned char data)
{
unsigned char i;
for ( i = 0; i < 8; i++ )
{
/* Dump to DATA0 and insert a positive edge pulse at the same time */
*AT91C_PIOA_CODR = ALTERA_DATA0 | ALTERA_DCLK;
if((data >> i) & 1) *AT91C_PIOA_SODR = ALTERA_DATA0;
*AT91C_PIOA_SODR = ALTERA_DCLK;
}
}
// Altera FPGA configuration
RAMFUNC unsigned char ConfigureFpga(void)
{
unsigned long i;
unsigned char *ptr;
// set outputs
*AT91C_PIOA_SODR = ALTERA_DCLK | ALTERA_DATA0 | ALTERA_NCONFIG;
// enable outputs
*AT91C_PIOA_OER = ALTERA_DCLK | ALTERA_DATA0 | ALTERA_NCONFIG;
// open bitstream file
if (FileOpen(&file, "CORE RBF") == 0)
{
printf("No FPGA configuration file found!\r");
FatalError(4);
}
printf("FPGA bitstream file opened, file size = %d\r", file.size);
printf("[");
// send all bytes to FPGA in loop
ptr = sector_buffer;
/* Drive a transition of 0 to 1 to NCONFIG to indicate start of configuration */
*AT91C_PIOA_CODR = ALTERA_NCONFIG;
*AT91C_PIOA_CODR = ALTERA_NCONFIG; // must be low for at least 500ns
*AT91C_PIOA_SODR = ALTERA_NCONFIG;
// now wait for NSTATUS to go high
// specs: max 800us
i = 100000;
while (!(*AT91C_PIOA_PDSR & ALTERA_NSTATUS))
{
if (--i == 0)
{
printf("FPGA NSTATUS is NOT high!\r");
FatalError(3);
}
}
DISKLED_ON;
int t = 0;
int n = file.size >> 3;
/* Loop through every single byte */
for ( i = 0; i < file.size; )
{
// read sector if 512 (64*8) bytes done
if ((i & 0x1FF) == 0)
{
if (i & (1<<13))
DISKLED_OFF
else
DISKLED_ON
if ((i & 0x3FFF) == 0)
printf("*");
if (!FileRead(&file, sector_buffer))
return(0);
ptr = sector_buffer;
}
int bytes2copy = (i < file.size - 8)?8:file.size-i;
i += bytes2copy;
while(bytes2copy) {
ShiftFpga(*ptr++);
bytes2copy--;
}
/* Check for error through NSTATUS for every 10KB programmed and the last byte */
if ( !(i % 10240) || (i == file.size - 1) ) {
if ( !*AT91C_PIOA_PDSR & ALTERA_NSTATUS ) {
printf("FPGA NSTATUS is NOT high!\r");
FatalError(5);
}
}
// read next sector if 512 (64*8) bytes done
if ((i & 0x1FF) == 0)
FileNextSector(&file);
}
printf("]\r");
printf("FPGA bitstream loaded\r");
DISKLED_OFF;
// check if DONE is high
if (!(*AT91C_PIOA_PDSR & ALTERA_DONE)) {
printf("FPGA Configuration done but contains error... CONF_DONE is LOW\r");
FatalError(5);
}
/* Start initialization */
/* Clock another extra DCLK cycles while initialization is in progress
through internal oscillator or driving clock cycles into CLKUSR pin */
/* These extra DCLK cycles do not initialize the device into USER MODE */
/* It is not required to drive extra DCLK cycles at the end of configuration */
/* The purpose of driving extra DCLK cycles here is to insert some delay
while waiting for the initialization of the device to complete before
checking the CONFDONE and NSTATUS signals at the end of whole
configuration cycle */
for ( i = 0; i < 50; i++ )
{
*AT91C_PIOA_CODR = ALTERA_DCLK;
*AT91C_PIOA_SODR = ALTERA_DCLK;
}
/* Initialization end */
if ( !(*AT91C_PIOA_PDSR & ALTERA_NSTATUS) ||
!(*AT91C_PIOA_PDSR & ALTERA_DONE)) {
printf("FPGA Initialization finish but contains error: NSTATUS is %s and CONF_DONE is %s.\r",
((*AT91C_PIOA_PDSR & ALTERA_NSTATUS)?"HIGH":"LOW"), ((*AT91C_PIOA_PDSR & ALTERA_DONE)?"HIGH":"LOW") );
FatalError(5);
}
return 1;
}
#endif
void SendFile(RAFile *file)
{
unsigned char c1, c2;
unsigned long j;
unsigned long n;
unsigned char *p;
printf("[");
n = (file->file.size + 511) >> 9; // sector count (rounded up)
while (n--)
{
// read data sector from memory card
RARead(file,sector_buffer,512);
do
{
// read FPGA status
EnableFpga();
c1 = SPI(0);
c2 = SPI(0);
SPI(0);
SPI(0);
SPI(0);
SPI(0);
DisableFpga();
}
while (!(c1 & CMD_RDTRK));
if ((n & 15) == 0)
printf("*");
// send data sector to FPGA
EnableFpga();
c1 = SPI(0);
c2 = SPI(0);
SPI(0);
SPI(0);
SPI(0);
SPI(0);
p = sector_buffer;
for (j = 0; j < 512; j++)
SPI(*p++);
DisableFpga();
}
printf("]\r");
}
void SendFileEncrypted(RAFile *file,unsigned char *key,int keysize)
{
unsigned char c1, c2;
unsigned char headersize;
unsigned int keyidx=0;
unsigned long j;
unsigned long n;
unsigned char *p;
int badbyte=0;
printf("[");
headersize=file->size&255; // ROM should be a round number of kilobytes; overspill will likely be the Amiga Forever header.
RARead(file,sector_buffer,headersize); // Read extra bytes
n = (file->size + (511-headersize)) >> 9; // sector count (rounded up)
while (n--)
{
RARead(file,sector_buffer,512);
for (j = 0; j < 512; j++)
{
sector_buffer[j]^=key[keyidx++];
if(keyidx>=keysize)
keyidx-=keysize;
}
do
{
// read FPGA status
EnableFpga();
c1 = SPI(0);
c2 = SPI(0);
SPI(0);
SPI(0);
SPI(0);
SPI(0);
DisableFpga();
}
while (!(c1 & CMD_RDTRK));
if ((n & 15) == 0)
printf("*");
// send data sector to FPGA
EnableFpga();
c1 = SPI(0);
c2 = SPI(0);
SPI(0);
SPI(0);
SPI(0);
SPI(0);
p = sector_buffer;
for (j = 0; j < 512; j++)
SPI(*p++);
DisableFpga();
}
printf("]\r");
}
// draw on screen
char BootDraw(char *data, unsigned short len, unsigned short offset)
{
DEBUG_FUNC_IN();
unsigned char c1, c2, c3, c4;
unsigned char cmd;
const char *p;
unsigned short n;
unsigned short i;
n = (len+3)&(~3);
i = 0;
cmd = 1;
while (1)
{
EnableFpga();
c1 = SPI(0x10); // track read command
c2 = SPI(0x01); // disk present
unsigned char x = SPI(0);
unsigned char y = SPI(0);
c3 = SPI(0);
c4 = SPI(0);
// printf("FPGA state: %d %d (%d %d) %d %d\n", c1, c2, x, y, c3, c4);
if (c1 & CMD_RDTRK)
{
if (cmd)
{ // command phase
if (c3 == 0x80 && c4 == 0x06) // command packet size must be 12 bytes
{
cmd = 0;
SPI(CMD_HDRID >> 8); // command header
SPI(CMD_HDRID & 0xFF);
SPI(0x00); // cmd: 0x0001 = print text
SPI(0x01);
// data packet size in bytes
SPI(0x00);
SPI(0x00);
SPI((n)>>8);
SPI((n)&0xff); // +2 because only even byte count is possible to send and we have to send termination zero byte
// offset
SPI(0x00);
SPI(0x00);
SPI(offset>>8);
SPI(offset&0xff);
}
else
break;
}
else
{ // data phase
if (c3 == 0x80 && c4 == ((n) >> 1))
{
p = data;
n = c4 << 1;
while (n--)
{
c4 = *p;
SPI((i>=len) ? 0 : c4);
p++;
i++;
}
DisableFpga();
return 1;
}
else
break;
}
}
DisableFpga();
}
DisableFpga();
return 0;
DEBUG_FUNC_OUT();
}
// print message on the boot screen
char BootPrint(const char *text)
{
unsigned char c1, c2, c3, c4;
unsigned char cmd;
const char *p;
unsigned char n;
return 0;
p = text;
n = 0;
while (*p++ != 0)
n++; // calculating string length
cmd = 1;
while (1)
{
EnableFpga();
c1 = SPI(0x10); // track read command
c2 = SPI(0x01); // disk present
SPI(0);
SPI(0);
c3 = SPI(0);
c4 = SPI(0);
if (c1 & CMD_RDTRK)
{
if (cmd)
{ // command phase
if (c3 == 0x80 && c4 == 0x06) // command packet size must be 12 bytes
{
cmd = 0;
SPI(CMD_HDRID >> 8); // command header
SPI(CMD_HDRID & 0xFF);
SPI(0x00); // cmd: 0x0001 = print text
SPI(0x01);
// data packet size in bytes
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(n+2); // +2 because only even byte count is possible to send and we have to send termination zero byte
// don't care
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
}
else
break;
}
else
{ // data phase
if (c3 == 0x80 && c4 == ((n + 2) >> 1))
{
p = text;
n = c4 << 1;
while (n--)
{
c4 = *p;
SPI(c4);
if (c4) // if current character is not zero go to next one
p++;
}
DisableFpga();
return 1;
}
else
break;
}
}
DisableFpga();
}
DisableFpga();
return 0;
}
char PrepareBootUpload(unsigned char base, unsigned char size)
// this function sends given file to Minimig's memory
// base - memory base address (bits 23..16)
// size - memory size (bits 23..16)
{
unsigned char c1, c2, c3, c4;
unsigned char cmd = 1;
while (1)
{
EnableFpga();
c1 = SPI(0x10); // track read command
c2 = SPI(0x01); // disk present
SPI(0);
SPI(0);
c3 = SPI(0);
c4 = SPI(0);
if (c1 & CMD_RDTRK)
{
if (cmd)
{ // command phase
if (c3 == 0x80 && c4 == 0x06) // command packet size 12 bytes
{
cmd = 0;
SPI(CMD_HDRID >> 8); // command header
SPI(CMD_HDRID & 0xFF);
SPI(0x00);
SPI(0x02); // cmd: 0x0002 = upload memory
// memory base address
SPI(0x00);
SPI(base);
SPI(0x00);
SPI(0x00);
// memory size
SPI(0x00);
SPI(size);
SPI(0x00);
SPI(0x00);
}
else
break;
}
else
{ // data phase
DisableFpga();
printf("Ready to upload ROM file...\r");
// send rom image to FPGA
// SendFile(file);
// printf("ROM file uploaded.\r");
return 0;
}
}
DisableFpga();
}
DisableFpga();
return -1;
}
void BootExit(void)
{
unsigned char c1, c2, c3, c4;
while (1)
{
EnableFpga();
c1 = SPI(0x10); // track read command
c2 = SPI(0x01); // disk present
SPI(0);
SPI(0);
c3 = SPI(0);
c4 = SPI(0);
if (c1 & CMD_RDTRK)
{
if (c3 == 0x80 && c4 == 0x06) // command packet size 12 bytes
{
SPI(CMD_HDRID >> 8); // command header
SPI(CMD_HDRID & 0xFF);
SPI(0x00); // cmd: 0x0003 = restart
SPI(0x03);
// don't care
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
// don't care
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
}
DisableFpga();
return;
}
DisableFpga();
}
}
void ClearMemory(unsigned long base, unsigned long size)
{
unsigned char c1, c2, c3, c4;
while (1)
{
EnableFpga();
c1 = SPI(0x10); // track read command
c2 = SPI(0x01); // disk present
SPI(0);
SPI(0);
c3 = SPI(0);
c4 = SPI(0);
if (c1 & CMD_RDTRK)
{
if (c3 == 0x80 && c4 == 0x06)// command packet size 12 bytes
{
SPI(CMD_HDRID >> 8); // command header
SPI(CMD_HDRID & 0xFF);
SPI(0x00); // cmd: 0x0004 = clear memory
SPI(0x04);
// memory base
SPI((unsigned char)(base >> 24));
SPI((unsigned char)(base >> 16));
SPI((unsigned char)(base >> 8));
SPI((unsigned char)base);
// memory size
SPI((unsigned char)(size >> 24));
SPI((unsigned char)(size >> 16));
SPI((unsigned char)(size >> 8));
SPI((unsigned char)size);
}
DisableFpga();
return;
}
DisableFpga();
}
}
unsigned char GetFPGAStatus(void)
{
unsigned char status;
EnableFpga();
status = SPI(0);
SPI(0);
SPI(0);
SPI(0);
SPI(0);
SPI(0);
DisableFpga();
return status;
}

17
fpga.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef FPGA_H
#define FPGA_H
#include "rafile.h"
unsigned char ConfigureFpga(void) RAMFUNC;
void SendFile(RAFile *file);
void SendFileEncrypted(RAFile *file,unsigned char *key,int keysize);
char BootDraw(char *data, unsigned short len, unsigned short offset);
char BootPrint(const char *text);
char PrepareBootUpload(unsigned char base, unsigned char size);
void BootExit(void);
void ClearMemory(unsigned long base, unsigned long size);
unsigned char GetFPGAStatus(void);
#endif

281
hardware.c Normal file
View File

@@ -0,0 +1,281 @@
/*
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 "AT91SAM7S256.h"
#include "stdio.h"
#include "hardware.h"
void __init_hardware(void)
{
*AT91C_WDTC_WDMR = AT91C_WDTC_WDDIS; // disable watchdog
*AT91C_RSTC_RMR = (0xA5 << 24) | AT91C_RSTC_URSTEN; // enable external user reset input
*AT91C_MC_FMR = FWS << 8; // Flash wait states
// configure clock generator
*AT91C_CKGR_MOR = AT91C_CKGR_MOSCEN | (40 << 8);
while (!(*AT91C_PMC_SR & AT91C_PMC_MOSCS));
*AT91C_CKGR_PLLR = AT91C_CKGR_OUT_0 | AT91C_CKGR_USBDIV_1 | (25 << 16) | (40 << 8) | 5; // DIV=5 MUL=26 USBDIV=1 (2) PLLCOUNT=40
while (!(*AT91C_PMC_SR & AT91C_PMC_LOCK));
*AT91C_PMC_MCKR = AT91C_PMC_PRES_CLK_2; // master clock register: clock source selection
while (!(*AT91C_PMC_SR & AT91C_PMC_MCKRDY));
*AT91C_PMC_MCKR = AT91C_PMC_CSS_PLL_CLK | AT91C_PMC_PRES_CLK_2; // master clock register: clock source selection
while (!(*AT91C_PMC_SR & AT91C_PMC_MCKRDY));
*AT91C_PIOA_PER = 0xFFFFFFFF; // enable pio on all pins
*AT91C_PIOA_SODR = DISKLED; // led off
#ifdef USB_PUP
// disable usb d+/d- pullups if present
*AT91C_PIOA_OER = USB_PUP;
*AT91C_PIOA_PPUDR = USB_PUP;
*AT91C_PIOA_SODR = USB_PUP;
#endif
// enable joystick ports
#ifdef JOY0
*AT91C_PIOA_PPUER = JOY0;
#endif
#ifdef JOY1
*AT91C_PIOA_PPUER = JOY1;
#endif
*AT91C_PIOA_SODR = MMC_SEL | FPGA0 | FPGA1 | FPGA2; // set output data register
// output enable register
*AT91C_PIOA_OER = DISKLED | MMC_SEL | FPGA0 | FPGA1 | FPGA2;
// pull-up disable register
*AT91C_PIOA_PPUDR = DISKLED | MMC_SEL | FPGA0 | FPGA1 | FPGA2;
#ifdef XILINX_CCLK
// xilinx interface
*AT91C_PIOA_SODR = XILINX_CCLK | XILINX_DIN | XILINX_PROG_B;
*AT91C_PIOA_OER = XILINX_CCLK | XILINX_DIN | XILINX_PROG_B;
*AT91C_PIOA_PPUDR = XILINX_CCLK | XILINX_DIN | XILINX_PROG_B |
XILINX_INIT_B | XILINX_DONE;
#endif
#ifdef ALTERA_DCLK
// altera interface
*AT91C_PIOA_SODR = ALTERA_DCLK | ALTERA_DATA0 | ALTERA_NCONFIG;
*AT91C_PIOA_OER = ALTERA_DCLK | ALTERA_DATA0 | ALTERA_NCONFIG;
*AT91C_PIOA_PPUDR = ALTERA_DCLK | ALTERA_DATA0 | ALTERA_NCONFIG |
ALTERA_NSTATUS | ALTERA_DONE;
#endif
#ifdef MMC_CLKEN
// MMC_CLKEN may be present
// (but is not used anymore, so it's only setup passive)
*AT91C_PIOA_SODR = MMC_CLKEN;
*AT91C_PIOA_PPUDR = MMC_CLKEN;
#endif
#ifdef USB_SEL
*AT91C_PIOA_SODR = USB_SEL;
*AT91C_PIOA_OER = USB_SEL;
*AT91C_PIOA_PPUDR = USB_SEL;
#endif
// Enable peripheral clock in the PMC
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOA;
}
void USART_Init(unsigned long baudrate)
{
// Configure PA5 and PA6 for USART0 use
AT91C_BASE_PIOA->PIO_PDR = AT91C_PA5_RXD0 | AT91C_PA6_TXD0;
// Enable the peripheral clock in the PMC
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_US0;
// Reset and disable receiver & transmitter
AT91C_BASE_US0->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RXDIS | AT91C_US_TXDIS;
// Configure USART0 mode
AT91C_BASE_US0->US_MR = AT91C_US_USMODE_NORMAL | AT91C_US_CLKS_CLOCK | AT91C_US_CHRL_8_BITS | AT91C_US_PAR_NONE | AT91C_US_NBSTOP_1_BIT | AT91C_US_CHMODE_NORMAL;
// Configure USART0 rate
AT91C_BASE_US0->US_BRGR = MCLK / 16 / baudrate;
// Enable receiver & transmitter
AT91C_BASE_US0->US_CR = AT91C_US_RXEN | AT91C_US_TXEN;
}
RAMFUNC void USART_Write(unsigned char c)
{
while (!(AT91C_BASE_US0->US_CSR & AT91C_US_TXEMPTY));
AT91C_BASE_US0->US_THR = c;
}
#ifndef __GNUC__
signed int fputc(signed int c, FILE *pStream)
{
if ((pStream == stdout) || (pStream == stderr))
{
USART_Write((unsigned char)c);
return c;
}
return EOF;
}
#endif
void SPI_Init()
{
// Enable the peripheral clock in the PMC
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_SPI;
// Enable SPI interface
*AT91C_SPI_CR = AT91C_SPI_SPIEN;
// SPI Mode Register
*AT91C_SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | (0x0E << 16);
// SPI CS register
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (48 << 8) | (0x00 << 16) | (0x01 << 24);
// Configure pins for SPI use
AT91C_BASE_PIOA->PIO_PDR = AT91C_PA14_SPCK | AT91C_PA13_MOSI | AT91C_PA12_MISO;
}
void EnableFpga()
{
*AT91C_PIOA_CODR = FPGA0; // clear output
}
void DisableFpga()
{
SPI_Wait4XferEnd();
*AT91C_PIOA_SODR = FPGA0; // set output
}
void EnableOsd()
{
*AT91C_PIOA_CODR = FPGA1; // clear output
}
void DisableOsd()
{
SPI_Wait4XferEnd();
*AT91C_PIOA_SODR = FPGA1; // set output
}
#ifdef FPGA3
void EnableIO() {
*AT91C_PIOA_CODR = FPGA3; // clear output
}
void DisableIO() {
SPI_Wait4XferEnd();
*AT91C_PIOA_SODR = FPGA3; // set output
}
#endif
unsigned long CheckButton(void)
{
#ifdef BUTTON
return((~*AT91C_PIOA_PDSR) & BUTTON);
#else
return 0;
#endif
}
void Timer_Init(void)
{
*AT91C_PITC_PIMR = AT91C_PITC_PITEN | ((MCLK / 16 / 1000 - 1) & AT91C_PITC_PIV); // counting period 1ms
}
unsigned long GetTimer(unsigned long offset)
{
unsigned long systimer = (*AT91C_PITC_PIIR & AT91C_PITC_PICNT);
systimer += offset << 20;
return (systimer); // valid bits [31:20]
}
unsigned long CheckTimer(unsigned long time)
{
unsigned long systimer = (*AT91C_PITC_PIIR & AT91C_PITC_PICNT);
time -= systimer;
return(time > (1UL << 31));
}
void WaitTimer(unsigned long time)
{
time = GetTimer(time);
while (!CheckTimer(time));
}
void SPI_slow() {
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (SPI_SLOW_CLK_VALUE << 8) | (2 << 24); // init clock 100-400 kHz
}
void SPI_fast() {
// set appropriate SPI speed for SD/SDHC card (max 25 Mhz)
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (SPI_SDC_CLK_VALUE << 8); // 24 MHz SPI clock
}
void SPI_fast_mmc() {
// set appropriate SPI speed for MMC card (max 20Mhz)
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (SPI_MMC_CLK_VALUE << 8); // 16 MHz SPI clock
}
void TIMER_wait(unsigned long ms) {
WaitTimer(ms);
}
void EnableDMode() {
*AT91C_PIOA_CODR = FPGA2; // enable FPGA2 output
}
void DisableDMode() {
*AT91C_PIOA_SODR = FPGA2; // disable FPGA2 output
}
void SPI_block(unsigned short num) {
unsigned short i;
unsigned long t;
for (i = 0; i < num; i++) {
while (!(*AT91C_SPI_SR & AT91C_SPI_TDRE)); // wait until transmiter buffer is empty
*AT91C_SPI_TDR = 0xFF; // write dummy spi data
}
while (!(*AT91C_SPI_SR & AT91C_SPI_TXEMPTY)); // wait for transfer end
t = *AT91C_SPI_RDR; // dummy read to empty receiver buffer for new data
}
RAMFUNC void SPI_block_read(char *addr) {
*AT91C_PIOA_SODR = AT91C_PA13_MOSI; // set GPIO output register
*AT91C_PIOA_OER = AT91C_PA13_MOSI; // GPIO pin as output
*AT91C_PIOA_PER = AT91C_PA13_MOSI; // enable GPIO function
// use SPI PDC (DMA transfer)
*AT91C_SPI_TPR = (unsigned long)addr;
*AT91C_SPI_TCR = 512;
*AT91C_SPI_TNCR = 0;
*AT91C_SPI_RPR = (unsigned long)addr;
*AT91C_SPI_RCR = 512;
*AT91C_SPI_RNCR = 0;
*AT91C_SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN; // start DMA transfer
// wait for tranfer end
while ((*AT91C_SPI_SR & (AT91C_SPI_ENDTX | AT91C_SPI_ENDRX)) != (AT91C_SPI_ENDTX | AT91C_SPI_ENDRX));
*AT91C_SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS; // disable transmitter and receiver
*AT91C_PIOA_PDR = AT91C_PA13_MOSI; // disable GPIO function
}

152
hardware.h Normal file
View File

@@ -0,0 +1,152 @@
#include "AT91SAM7S256.h"
#ifndef HARDWARE_H
#define HARDWARE_H
#define MCLK 48000000
#define FWS 1 // Flash wait states
#define RAMFUNC __attribute__ ((long_call, section (".ramsection")))
#if defined(MINIMIG_V1_0)
#define DISKLED AT91C_PIO_PA10
#define DISKLED_ON *AT91C_PIOA_SODR = DISKLED;
#define DISKLED_OFF *AT91C_PIOA_CODR = DISKLED;
#define MMC_CLKEN AT91C_PIO_PA24
#define MMC_SEL AT91C_PIO_PA27
#define BUTTON AT91C_PIO_PA28
// xilinx programming interface
#define XILINX_DIN AT91C_PIO_PA20
#define XILINX_CCLK AT91C_PIO_PA4
#define XILINX_PROG_B AT91C_PIO_PA9
#define XILINX_INIT_B AT91C_PIO_PA7
#define XILINX_DONE AT91C_PIO_PA8
#elif defined(SAM7_P256)
#define DISKLED AT91C_PIO_PA18
#define DISKLED_ON *AT91C_PIOA_CODR = DISKLED;
#define DISKLED_OFF *AT91C_PIOA_SODR = DISKLED;
#define MMC_SEL AT91C_PIO_PA11
#define BUTTON AT91C_PIO_PA19
#define USB_SEL AT91C_PIO_PA31
#define USB_PUP (AT91C_PIO_PA16 || AT91C_PIO_PA8)
// altera programming interface
#define ALTERA_DONE AT91C_PIO_PA2
#define ALTERA_DATA0 AT91C_PIO_PA3
#define ALTERA_NCONFIG AT91C_PIO_PA1
#define ALTERA_NSTATUS AT91C_PIO_PA0
#define ALTERA_DCLK AT91C_PIO_PA4
#elif defined(MIST)
#define DISKLED AT91C_PIO_PA29
#define DISKLED_ON *AT91C_PIOA_CODR = DISKLED;
#define DISKLED_OFF *AT91C_PIOA_SODR = DISKLED;
#define MMC_SEL AT91C_PIO_PA31
#define USB_SEL AT91C_PIO_PA11
#define USB_PUP AT91C_PIO_PA16
// altera programming interface
#define ALTERA_DONE AT91C_PIO_PA4
#define ALTERA_DATA0 AT91C_PIO_PA9
#define ALTERA_NCONFIG AT91C_PIO_PA8
#define ALTERA_NSTATUS AT91C_PIO_PA7
#define ALTERA_DCLK AT91C_PIO_PA15
// db9 joystick ports
#define JOY1_UP AT91C_PIO_PA28
#define JOY1_DOWN AT91C_PIO_PA27
#define JOY1_LEFT AT91C_PIO_PA26
#define JOY1_RIGHT AT91C_PIO_PA25
#define JOY1_BTN1 AT91C_PIO_PA24
#define JOY1_BTN2 AT91C_PIO_PA23
#define JOY1 (JOY1_UP|JOY1_DOWN|JOY1_LEFT|JOY1_RIGHT|JOY1_BTN1|JOY1_BTN2)
#define JOY0_UP AT91C_PIO_PA22
#define JOY0_DOWN AT91C_PIO_PA21
#define JOY0_LEFT AT91C_PIO_PA20
#define JOY0_RIGHT AT91C_PIO_PA19
#define JOY0_BTN1 AT91C_PIO_PA18
#define JOY0_BTN2 AT91C_PIO_PA17
#define JOY0 (JOY0_UP|JOY0_DOWN|JOY0_LEFT|JOY0_RIGHT|JOY0_BTN1|JOY0_BTN2)
// chip selects for FPGA communication
#define FPGA0 AT91C_PIO_PA10
#define FPGA1 AT91C_PIO_PA3
#define FPGA2 AT91C_PIO_PA2
#define FPGA3 AT91C_PIO_PA9 // same as ALTERA_DATA0
#else
#error "Undefined setup!"
#endif
#define VBL AT91C_PIO_PA7
void USART_Init(unsigned long baudrate);
void USART_Write(unsigned char c) RAMFUNC;
static inline unsigned char SPI(unsigned char outByte) {
while (!(*AT91C_SPI_SR & AT91C_SPI_TDRE));
*AT91C_SPI_TDR = outByte;
while (!(*AT91C_SPI_SR & AT91C_SPI_RDRF));
return((unsigned char)*AT91C_SPI_RDR);
}
#define SPI_SDC_CLK_VALUE 2 // 24 Mhz
#define SPI_MMC_CLK_VALUE 3 // 16 Mhz
#define SPI_SLOW_CLK_VALUE 120 // 400kHz
static inline void SPI_Wait4XferEnd() {
while (!(*AT91C_SPI_SR & AT91C_SPI_TXEMPTY));
/* Clear any data left in the receiver */
(void)*AT91C_SPI_RDR;
(void)*AT91C_SPI_RDR;
}
static inline void EnableCard() {
*AT91C_PIOA_CODR = MMC_SEL; // clear output (MMC chip select enabled)
}
static inline void DisableCard() {
SPI_Wait4XferEnd();
*AT91C_PIOA_SODR = MMC_SEL; // set output (MMC chip select disabled)
SPI(0xFF);
SPI_Wait4XferEnd();
}
void SPI_Init(void);
// unsigned char SPI(unsigned char outByte);
void EnableFpga(void);
void DisableFpga(void);
void EnableOsd(void);
void DisableOsd(void);
unsigned long CheckButton(void);
void Timer_Init(void);
unsigned long GetTimer(unsigned long offset);
unsigned long CheckTimer(unsigned long t);
void WaitTimer(unsigned long time);
void SPI_slow();
void SPI_fast();
void SPI_fast_mmc();
void TIMER_wait(unsigned long ms);
void EnableDMode();
void DisableDMode();
void SPI_block(unsigned short num);
#define SPI_BLOCK_READ
RAMFUNC void SPI_block_read(char *addr);
#ifdef FPGA3
// the MiST has the user inout on the arm controller
void EnableIO(void);
void DisableIO(void);
#endif
#define DEBUG_FUNC_IN()
#endif // HARDWARE_H

962
hdd.c Normal file
View File

@@ -0,0 +1,962 @@
/*
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
#ifdef __GNUC__
#include "AT91SAM7S256.h"
#include "stdio.h"
#include "string.h"
#else
#include <stdio.h>
#include <string.h>
#endif
#include "errors.h"
#include "hardware.h"
#include "fat.h"
#include "hdd.h"
#include "hdd_internal.h"
#include "mmc.h"
#include "menu.h"
#include "fpga.h"
#include "config.h"
// hardfile structure
hdfTYPE hdf[2];
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;
}
// 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
for(i=0;i<512;++i)
sector_buffer[i]=0;
// If we're asked for LBA 0 we create an RDSK block, and if LBA 1, a PART block.
switch(block)
{
case 0: // RDB
{
struct RigidDiskBlock *rdb=(struct RigidDiskBlock *)sector_buffer;
rdb->rdb_ID = 'R'<<24 | 'D' << 16 | 'S' << 8 | 'K';
rdb->rdb_Summedlongs=0x40;
rdb->rdb_HostID=0x07;
rdb->rdb_BlockBytes=0x200;
rdb->rdb_Flags=0x12; // (Disk ID valid, no LUNs after this one)
rdb->rdb_BadBlockList=0xffffffff; // We don't provide a bad block list
rdb->rdb_PartitionList=1;
rdb->rdb_FileSysHeaderList=0xffffffff;
rdb->rdb_DriveInit=0xffffffff;
rdb->rdb_Reserved1[0]=0xffffffff;
rdb->rdb_Reserved1[1]=0xffffffff;
rdb->rdb_Reserved1[2]=0xffffffff;
rdb->rdb_Reserved1[3]=0xffffffff;
rdb->rdb_Reserved1[4]=0xffffffff;
rdb->rdb_Reserved1[5]=0xffffffff;
rdb->rdb_Cylinders=hdf[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!");
RDBChecksum((unsigned long *)rdb);
}
break;
case 1: // Partition
{
struct PartitionBlock *pb=(struct PartitionBlock *)sector_buffer;
pb->pb_ID = 'P'<<24 | 'A' << 16 | 'R' << 8 | 'T';
pb->pb_Summedlongs=0x40;
pb->pb_HostID=0x07;
pb->pb_Next=0xffffffff;
pb->pb_Flags=0x1; // Bootable
pb->pb_DevFlags=0;
strcpy(pb->pb_DriveName," DH0");
pb->pb_DriveName[0]=3; // 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);
}
break;
break;
default:
break;
}
}
void IdentifyDevice(unsigned short *pBuffer, unsigned char unit)
{ // builds Identify Device struct
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], "1234567890ABCDEFGHIJ", 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;
if (config.hardfile[unit].long_name[0])
{
for (i = 0; (x = config.hardfile[unit].long_name[i]) && i < 16; i++) // copy file name as model name
p[i] = x;
}
else
{
memcpy(p, config.hardfile[unit].name, 8); // copy file name as model name
}
}
// SwapBytes((char*)&pBuffer[27], 40); //not for 68000
break;
case HDF_CARD:
case HDF_CARDPART0:
case HDF_CARDPART1:
case HDF_CARDPART2:
case HDF_CARDPART3:
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], "TC64MiniMigSD0 ", 20); // serial number - byte swapped
pBuffer[23]+=hdf[unit].type-HDF_CARD;
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.
memcpy(p, "YAQUBE ", 40); // model name - byte swapped
p += 8;
if(hdf[unit].type==HDF_CARD)
memcpy(p, "SD/MMC Card", 11); // copy file name as model name
else
{
memcpy(p, "Card Part 1", 11); // copy file name as model name
p[10]+=hdf[unit].partition;
}
// 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);
}
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;
}
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(CMD_IDE_REGS_WR); // write task file registers command
SPI(0x00);
SPI(0x00); // dummy
SPI(0x00);
SPI(0x00); // dummy
SPI(0x00);
SPI(0x00); // dummy
SPI(0x00);
SPI(0x00);
SPI(error); // error
SPI(0x00);
SPI(sector_count); // sector count
SPI(0x00);
SPI(sector_number); //sector number
SPI(0x00);
SPI(cylinder_low); // cylinder low
SPI(0x00);
SPI(cylinder_high); // cylinder high
SPI(0x00);
SPI(drive_head); // drive/head
DisableFpga();
}
void WriteStatus(unsigned char status)
{
EnableFpga();
SPI(CMD_IDE_STATUS_WR);
SPI(status);
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
DisableFpga();
}
void HandleHDD(unsigned char c1, unsigned char c2)
{
unsigned short id[256];
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(CMD_IDE_REGS_RD); // read task file registers
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
for (i = 0; i < 8; i++)
{
SPI(0);
tfr[i] = SPI(0);
}
DisableFpga();
unit = tfr[6] & 0x10 ? 1 : 0; // master/slave selection
if (0)
{
printf("IDE:");
for (i = 1; i < 7; i++)
printf("%02X.",tfr[i]);
printf("%02X\r", tfr[7]);
}
if ((tfr[7] & 0xF0) == ACMD_RECALIBRATE) // Recalibrate 0x10-0x1F (class 3 command: no data)
{
printf("Recalibrate\r");
WriteTaskFile(0, 0, 1, 0, 0, tfr[6] & 0xF0);
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
}
else if (tfr[7] == ACMD_IDENTIFY_DEVICE) // Identify Device
{
printf("Identify Device\r");
IdentifyDevice(id, 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(CMD_IDE_DATA_WR); // write data command
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
for (i = 0; i < 256; i++)
{
SPI((unsigned char)id[i]);
SPI((unsigned char)(id[i] >> 8));
}
DisableFpga();
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
}
else if (tfr[7] == ACMD_INITIALIZE_DEVICE_PARAMETERS) // Initiallize Device Parameters
{
printf("Initialize Device Parameters\r");
printf("IDE:");
for (i = 1; i < 7; i++)
printf("%02X.", tfr[i]);
printf("%02X\r", tfr[7]);
WriteTaskFile(0, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]);
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
}
else if (tfr[7] == ACMD_READ_SECTORS) // Read Sectors
{
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;
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++;
}
if((lba+hdf[unit].offset)<0)
{
FakeRDB(unit,lba);
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
EnableFpga();
SPI(CMD_IDE_DATA_WR); // write data command
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
for (i = 0; i < 512; i++)
{
SPI(sector_buffer[i]);
}
DisableFpga();
WriteStatus(sector_count==1 ? IDE_STATUS_IRQ|IDE_STATUS_END : IDE_STATUS_IRQ);
}
else
{
WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type
WriteTaskFile(0, tfr[2], sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
while (!(GetFPGAStatus() & CMD_IDECMD)); // wait for empty sector buffer
WriteStatus(IDE_STATUS_IRQ);
if (hdf[unit].file.size)
{
// FileRead(&hdf[unit].file, NULL);
FileRead(&hdf[unit].file, 0);
FileSeek(&hdf[unit].file, 1, SEEK_CUR);
}
}
lba++;
sector_count--; // decrease sector count
}
break;
case HDF_CARD:
case HDF_CARDPART0:
case HDF_CARDPART1:
case HDF_CARDPART2:
case HDF_CARDPART3:
{
WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type
lba=chs2lba(cylinder, head, sector, unit)+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);
while (!(GetFPGAStatus() & CMD_IDECMD)); // wait for empty sector buffer
WriteStatus(IDE_STATUS_IRQ);
MMC_Read(lba,0);
++lba;
--sector_count;
}
}
break;
}
}
else if (tfr[7] == ACMD_SET_MULTIPLE_MODE) // Set Multiple Mode
{
hdf[unit].sectors_per_block = tfr[2];
printf("Set Multiple Mode\r");
printf("IDE:");
for (i = 1; i < 7; i++)
printf("%02X.", tfr[i]);
printf("%02X\r", tfr[7]);
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
}
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;
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 (!(GetFPGAStatus() & 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);
if (hdf[unit].file.size)
// FileReadEx(&hdf[unit].file, NULL, block_count); // NULL enables direct transfer to the FPGA
FileReadEx(&hdf[unit].file, 0, block_count); // NULL enables direct transfer to the FPGA
while (block_count--)
{
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;
case HDF_CARD:
case HDF_CARDPART0:
case HDF_CARDPART1:
case HDF_CARDPART2:
case HDF_CARDPART3:
{
long lba=chs2lba(cylinder, head, sector, unit)+hdf[unit].offset;
while (sector_count)
{
while (!(GetFPGAStatus() & 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);
MMC_ReadMultiple(lba,0,block_count);
lba+=block_count;
while (block_count--)
{
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;
}
}
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 (!(GetFPGAStatus() & 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(CMD_IDE_DATA_RD); // read data command
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
for (i = 0; i < 512; i++)
sector_buffer[i] = SPI(0xFF);
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:
if (hdf[unit].file.size && (lba>-1)) // Don't attempt to write to fake RDB
{
FileWrite(&hdf[unit].file, sector_buffer);
FileSeek(&hdf[unit].file, 1, SEEK_CUR);
}
++lba;
break;
case HDF_CARD:
case HDF_CARDPART0:
case HDF_CARDPART1:
case HDF_CARDPART2:
case HDF_CARDPART3:
MMC_Write(lba,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 (!(GetFPGAStatus() & 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(CMD_IDE_DATA_RD); // read data command
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
for (i = 0; i < 512; i++)
sector_buffer[i] = SPI(0xFF);
DisableFpga();
switch(hdf[unit].type)
{
case HDF_FILE | HDF_SYNTHRDB:
case HDF_FILE:
if (hdf[unit].file.size && (lba>-1))
{
FileWrite(&hdf[unit].file, sector_buffer);
FileSeek(&hdf[unit].file, 1, SEEK_CUR);
}
++lba;
break;
case HDF_CARD:
case HDF_CARDPART0:
case HDF_CARDPART1:
case HDF_CARDPART2:
case HDF_CARDPART3:
MMC_Write(lba,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
{
printf("Unknown ATA command\r");
printf("IDE:");
for (i = 1; i < 7; i++)
printf("%02X.", tfr[i]);
printf("%02X\r", 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;
}
}
void GetHardfileGeometry(hdfTYPE *pHDF)
{ // this function comes from WinUAE, should return the same CHS as WinUAE
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;
case HDF_CARD:
total = MMC_GetCapacity(); // GetCapacity returns number of blocks, not bytes.
break;
case HDF_CARDPART0:
case HDF_CARDPART1:
case HDF_CARDPART2:
case HDF_CARDPART3:
total = partitions[pHDF->partition].sectors;
break;
default:
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;
}
void BuildHardfileIndex(hdfTYPE *pHDF)
{
// builds index to speed up hard file seek
fileTYPE *file = &pHDF->file;
unsigned long *index = pHDF->index;
unsigned long i;
unsigned long j;
pHDF->index_size = 16; // indexing size
j = 1 << pHDF->index_size;
i = pHDF->file.size >> 10; // divided by index table size (1024)
while (j < i) // find greater or equal power of two
{
j <<= 1;
pHDF->index_size++;
}
for (i = 0; i < file->size; i += j)
{
FileSeek(file, i >> 9, SEEK_SET); // FileSeek seeks in 512-byte sectors
*index++ = file->cluster;
}
}
unsigned char HardFileSeek(hdfTYPE *pHDF, unsigned long lba)
{
if ((pHDF->file.sector ^ lba) & cluster_mask)
{ // different clusters
if ((pHDF->file.sector > lba) || ((pHDF->file.sector ^ lba) & (cluster_mask << (fat32 ? 7 : 8)))) // 7: 128 FAT32 links per sector, 8: 256 FAT16 links per sector
{ // requested cluster lies before current pointer position or in different FAT sector
pHDF->file.cluster = pHDF->index[lba >> (pHDF->index_size - 9)];// minus 9 because lba is in 512-byte sectors
pHDF->file.sector = lba & (-1 << (pHDF->index_size - 9));
}
}
return FileSeek(&pHDF->file, lba, SEEK_SET);
}
unsigned char OpenHardfile(unsigned char unit)
{
unsigned long time;
char filename[12];
switch(config.hardfile[unit].enabled)
{
case HDF_FILE | HDF_SYNTHRDB:
case HDF_FILE:
hdf[unit].type=config.hardfile[unit].enabled;
strncpy(filename, config.hardfile[unit].name, 8);
strcpy(&filename[8], "HDF");
if (filename[0])
{
if (FileOpen(&hdf[unit].file, filename))
{
GetHardfileGeometry(&hdf[unit]);
printf("HARDFILE %d:\r", unit);
printf("file: \"%.8s.%.3s\"\r", hdf[unit].file.name, &hdf[unit].file.name[8]);
printf("size: %lu (%lu MB)\r", hdf[unit].file.size, hdf[unit].file.size >> 20);
printf("CHS: %u.%u.%u", hdf[unit].cylinders, hdf[unit].heads, hdf[unit].sectors);
printf(" (%lu MB)\r", ((((unsigned long) hdf[unit].cylinders) * hdf[unit].heads * hdf[unit].sectors) >> 11));
time = GetTimer(0);
BuildHardfileIndex(&hdf[unit]);
time = GetTimer(0) - time;
printf("Hardfile indexed in %lu ms\r", 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;
}
}
break;
case HDF_CARD:
hdf[unit].type=HDF_CARD;
config.hardfile[unit].present = 1;
hdf[unit].file.size=0;
hdf[unit].offset=0;
GetHardfileGeometry(&hdf[unit]);
return 1;
break;
case HDF_CARDPART0:
case HDF_CARDPART1:
case HDF_CARDPART2:
case HDF_CARDPART3:
hdf[unit].type=config.hardfile[unit].enabled;
hdf[unit].partition=hdf[unit].type-HDF_CARDPART0;
config.hardfile[unit].present = 1;
hdf[unit].file.size=0;
hdf[unit].offset=partitions[hdf[unit].partition].startlba;
GetHardfileGeometry(&hdf[unit]);
return 1;
break;
}
config.hardfile[unit].present = 0;
return 0;
}
fileTYPE rdbfile; // We scan for RDB without mounting the file as a unit, so need a file struct specifically for this task.
unsigned char GetHDFFileType(char *filename)
{
if(FileOpen(&rdbfile,filename))
{
int i;
for(i=0;i<16;++i)
{
FileRead(&rdbfile,sector_buffer);
FileSeek(&rdbfile,512,SEEK_CUR);
if(sector_buffer[0]=='R' && sector_buffer[1]=='D' && sector_buffer[2]=='S' && sector_buffer[3]=='K')
return(HDF_FILETYPE_RDB);
if(sector_buffer[0]=='D' && sector_buffer[1]=='O' && sector_buffer[2]=='S')
return(HDF_FILETYPE_DOS);
if(sector_buffer[0]=='P' && sector_buffer[1]=='F' && sector_buffer[2]=='S')
return(HDF_FILETYPE_DOS);
if(sector_buffer[0]=='S' && sector_buffer[1]=='F' && sector_buffer[2]=='S')
return(HDF_FILETYPE_DOS);
}
return(HDF_FILETYPE_UNKNOWN);
}
return(HDF_FILETYPE_NOTFOUND);
}

70
hdd.h Normal file
View File

@@ -0,0 +1,70 @@
#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_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_CARD 2
#define HDF_CARDPART0 3
#define HDF_CARDPART1 4
#define HDF_CARDPART2 5
#define HDF_CARDPART3 6
#define HDF_TYPEMASK 15
#define HDF_SYNTHRDB 128 // Flag to indicate whether we should auto-synthesize a RigidDiskBlock
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.
unsigned long index[1024];
unsigned long index_size;
} hdfTYPE;
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);
void BuildHardfileIndex(hdfTYPE *hdf);
unsigned char HardFileSeek(hdfTYPE *hdf, unsigned long lba);
unsigned char OpenHardfile(unsigned char unit);
#define HDF_FILETYPE_UNKNOWN 0
#define HDF_FILETYPE_NOTFOUND 1
#define HDF_FILETYPE_RDB 2
#define HDF_FILETYPE_DOS 3
unsigned char GetHDFFileType(char *filename);
extern char debugmsg[40];
extern char debugmsg2[40];
extern hdfTYPE hdf[2];

88
hdd_internal.h Normal file
View 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];
};
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;
};
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 */
};
#endif /* HDD_INTERNAL_H */

305
keycodes.h Normal file
View File

@@ -0,0 +1,305 @@
// 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.
// These keys are tagged with the "OSD_LOC" flag. The keycodes itself used are identical between OSD
// and OSD_LOC
#define OSD 0x0100 // to be used by OSD, not the core itself
#define OSD_LOC 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
// amiga unmapped:
// 0x0d |
// 0x5a KP-(
// 0x5b KP-)
// 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: ]
MISS, // 31: backslash
0x2b, // 32: Europe 1
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
0x69 | OSD, // 45: F12 (OSD)
0x6e | OSD, // 46: Print Screen (OSD)
0x69 | OSD, // 47: Scroll Lock (OSD)
MISS, // 48: Pause
MISS, // 49: Insert
MISS, // 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 +
MISS, // 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
MISS, // 65: App
MISS, // 66: Power
MISS, // 67: KP =
MISS, // 68: F13
MISS, // 69: F14
MISS, // 6a: F15
MISS, // 6b: F16
MISS, // 6c: F17
MISS, // 6d: F18
MISS, // 6e: F19
MISS // 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 | OSD_LOC, // 28: Return
0x01 | OSD_LOC, // 29: Escape
0x0e, // 2a: Backspace
0x0f, // 2b: Tab
0x39 | OSD_LOC, // 2c: Space
0x0c, // 2d: -
0x0d, // 2e: =
0x1a, // 2f: [
0x1b, // 30: ]
0x2b, // 31: backslash
MISS, // 32: Europe 1
0x27, // 33: ;
0x28, // 34: '
0x29, // 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_LOC, // 45: F12
MISS, // 46: Print Screen
MISS, // 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 | OSD_LOC, // 51: Down Arrow
0x48 | OSD_LOC, // 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
MISS, // 65: App
MISS, // 66: Power
MISS, // 67: KP =
MISS, // 68: F13
MISS, // 69: F14
MISS, // 6a: F15
MISS, // 6b: F16
MISS, // 6c: F17
MISS, // 6d: F18
MISS, // 6e: F19
MISS // 6f: F20
};
// OSD uses amiga keycodes. This table translates from usb to OSD/amiga
const unsigned char usb2osd[][2] = {
{ 0x45, KEY_MENU },
{ 0x52, KEY_UP },
{ 0x51, KEY_DOWN },
{ 0x28, KEY_ENTER },
{ 0x29, KEY_ESC },
{ 0x2c, KEY_SPACE },
{ 0,0 }
};
#if 0
// #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_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
#endif

80
logo.h Normal file
View File

@@ -0,0 +1,80 @@
#ifndef LOGO_H
#define LOGO_H
const unsigned char logodata[5][227] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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}
};
#endif

240
main.c Normal file
View File

@@ -0,0 +1,240 @@
/*
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/>.
*/
// 2008-10-04 - porting to ARM
// 2008-10-06 - support for 4 floppy drives
// 2008-10-30 - hdd write support
// 2009-05-01 - subdirectory support
// 2009-06-26 - SDHC and FAT32 support
// 2009-08-10 - hardfile selection
// 2009-09-11 - minor changes to hardware initialization routine
// 2009-10-10 - any length fpga core file support
// 2009-11-14 - adapted floppy gap size
// - changes to OSD labels
// 2009-12-24 - updated version number
// 2010-01-09 - changes to floppy handling
// 2010-07-28 - improved menu button handling
// - improved FPGA configuration routines
// - added support for OSD vsync
// 2010-08-15 - support for joystick emulation
// 2010-08-18 - clean-up
#include "AT91SAM7S256.h"
#include "stdio.h"
#include "string.h"
#include "errors.h"
#include "hardware.h"
#include "mmc.h"
#include "fat.h"
#include "osd.h"
#include "fpga.h"
#include "fdd.h"
#include "hdd.h"
#include "firmware.h"
#include "menu.h"
#include "config.h"
#include "user_io.h"
#include "boot_logo.h"
#ifdef MIST
#include "usb.h"
#endif
const char version[] = {"$VER:ATH" VDATE};
extern hdfTYPE hdf[2];
unsigned char Error;
extern adfTYPE df[4];
char s[40];
void FatalError(unsigned long error)
{
unsigned long i;
printf("Fatal error: %lu\r", error);
while (1)
{
for (i = 0; i < error; i++)
{
DISKLED_ON;
WaitTimer(250);
DISKLED_OFF;
WaitTimer(250);
}
WaitTimer(1000);
}
}
void HandleFpga(void)
{
unsigned char c1, c2;
EnableFpga();
c1 = SPI(0); // cmd request and drive number
c2 = SPI(0); // track number
SPI(0);
SPI(0);
SPI(0);
SPI(0);
DisableFpga();
HandleFDD(c1, c2);
HandleHDD(c1, c2);
UpdateDriveStatus();
}
extern void inserttestfloppy();
int main(void)
{
unsigned char rc;
unsigned char key;
unsigned long time;
unsigned short spiclk;
//unsigned char CSD[16];
#ifdef __GNUC__
__init_hardware();
// make sure printf works over rs232
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
#endif
DISKLED_ON;
Timer_Init();
USART_Init(115200);
printf("\rMinimig by Dennis van Weeren");
printf("\rARM Controller by Jakub Bednarski\r\r");
printf("Version %s\r\r", version+5);
SPI_Init();
if (!MMC_Init())
FatalError(1);
spiclk = MCLK / ((AT91C_SPI_CSR[0] & AT91C_SPI_SCBR) >> 8) / 1000000;
printf("spiclk: %u MHz\r", spiclk);
#ifdef USB_SEL
usb_init();
#endif
if (!FindDrive())
FatalError(2);
ChangeDirectory(DIRECTORY_ROOT);
time = GetTimer(0);
user_io_init();
#ifdef MIST
if(!user_io_button_pressed())
#endif
{
if (ConfigureFpga()) {
time = GetTimer(0) - time;
printf("FPGA configured in %lu ms\r", time >> 20);
} else {
printf("FPGA configuration failed\r");
FatalError(3);
}
WaitTimer(100); // let's wait some time till reset is inactive so we can get a valid keycode
}
user_io_detect_core_type();
if(user_io_core_type() == CORE_TYPE_MINIMIG) {
puts("Running minimig setup");
draw_boot_logo();
BootPrintEx("**** MINIMIG for MiST ****");
BootPrintEx("Minimig by Dennis van Weeren");
BootPrintEx("Updates by Jakub Bednarski, Tobias Gubener, Sascha Boing, A.M. Robinson");
BootPrintEx("DE1 port by Rok Krajnc (rok.krajnc@gmail.com)");
BootPrintEx("MiST port by Till Harbaum (till@harbaum.org)");
BootPrintEx(" ");
BootPrintEx("For support, see http://www.minimig.net");
BootPrint(" ");
ChangeDirectory(DIRECTORY_ROOT);
//eject all disk
df[0].status = 0;
df[1].status = 0;
df[2].status = 0;
df[3].status = 0;
BootPrint(" ");
BootPrintEx("Booting ...");
printf("Booting ...\r");
WaitTimer(6000);
config.kickstart.name[0]=0;
SetConfigurationFilename(0); // Use default config
LoadConfiguration(0); // Use slot-based config filename
} // end of minimig setup
if(user_io_core_type() == CORE_TYPE_MIST) {
puts("Running mist setup");
tos_upload();
// end of mist setup
}
int cnt = 0;
while (1) {
user_io_poll();
#ifdef USB_SEL
usb_poll();
#endif
// MIST (atari) core supports the same UI as Minimig
if(user_io_core_type() == CORE_TYPE_MIST) {
HandleUI();
}
// call original minimig handlers if minimig core is found
if(user_io_core_type() == CORE_TYPE_MINIMIG) {
HandleFpga();
HandleUI();
if(cnt < 20000) {
cnt++;
if(cnt == 20000)
inserttestfloppy();
}
}
}
return 0;
}

2319
menu.c Normal file

File diff suppressed because it is too large Load Diff

96
menu.h Normal file
View File

@@ -0,0 +1,96 @@
#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_MISC1,
MENU_MISC2,
MENU_ABOUT1,
MENU_ABOUT2,
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_MAIN2_1,
MENU_MAIN2_2,
MENU_LOADCONFIG_1,
MENU_LOADCONFIG_2,
MENU_SAVECONFIG_1,
MENU_SAVECONFIG_2,
MENU_FIRMWARE1,
MENU_FIRMWARE2,
MENU_FIRMWARE_UPDATE1,
MENU_FIRMWARE_UPDATE2,
MENU_FIRMWARE_UPDATE_ERROR1,
MENU_FIRMWARE_UPDATE_ERROR2,
MENU_FIRMWARE_UPDATING1,
MENU_FIRMWARE_UPDATING2,
MENU_FIRMWARE_OPTIONS1,
MENU_FIRMWARE_OPTIONS2,
MENU_FIRMWARE_OPTIONS_ENABLE1,
MENU_FIRMWARE_OPTIONS_ENABLE2,
MENU_FIRMWARE_OPTIONS_ENABLED1,
MENU_FIRMWARE_OPTIONS_ENABLED2,
MENU_ERROR,
MENU_INFO,
// Mist/atari specifig pages
MENU_MIST_MAIN1,
MENU_MIST_MAIN2,
MENU_MIST_FILE_SELECTED,
};
// 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[];
void InsertFloppy(adfTYPE *drive);
void HandleUI(void);
void PrintDirectory(void);
void ScrollLongName(void);
void ErrorMessage(const char *message, unsigned char code);
void InfoMessage(char *message);
void ShowSplash();
void HideSplash();
#endif

135
mkupg.c Normal file
View File

@@ -0,0 +1,135 @@
#include <stdio.h>
#include <string.h>
#include <malloc.h>
typedef struct
{
unsigned int flags;
unsigned int base;
unsigned int size;
unsigned int crc;
} __attribute__ ((packed)) romTYPE;
typedef struct
{
unsigned char id[8];
unsigned char version[16];
romTYPE rom;
unsigned int padding[117];
unsigned int crc;
} __attribute__ ((packed)) UPGRADE;
/* polynomial 0xEDB88320 */
const unsigned int crc32_table[256] =
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
// Initial CRC value is -1 (0xFFFFFFFF)
// Final CRC value is bitwise negation of the last calculated value
unsigned int CalculateCRC32(unsigned int crc, unsigned char *pBuffer, unsigned int nSize)
{
while (nSize--)
crc = crc32_table[(unsigned char)crc ^ *pBuffer++] ^ crc >> 8;
return crc;
}
int main(int argc, char **argv) {
UPGRADE upgrade;
printf("mkupg - minimig/mist upgrade file creator\n");
if(argc != 4) {
printf("Usage: mkupg <infile>.bin <outfile>.upg> <6-digit date code>\n");
return -1;
}
if(strlen(argv[3])!=6)
{
printf("Date code should be a 6-digit code in the form YYMMDD\n");
return -1;
}
FILE *inf, *outf;
int size;
inf = fopen(argv[1], "rb");
if(!inf) {
printf("Unable to open %s\n", argv[1]);
return -1;
}
// check file size
fseek(inf, 0, SEEK_END);
size = ftell(inf);
fseek(inf, 0, SEEK_SET);
unsigned char *bin = malloc(size);
if(fread(bin, 1, size, inf) != size) {
printf("Read error on %s\n", argv[1]);
return -1;
}
fclose(inf);
printf("Upgrade header size : %u\n", (unsigned int)sizeof(UPGRADE));
// create upgrade header
memset(&upgrade, 0, sizeof(upgrade));
strcpy(upgrade.version,"ATH");
strncpy(upgrade.version+3,argv[3],6);
strcpy(upgrade.id, "MNMGUPG");
upgrade.rom.size = size;
upgrade.rom.crc = ~CalculateCRC32(-1, bin, size);
upgrade.rom.size = size;
printf("ROM size : %d\n", size);
printf("ROM CRC : %08X\n", upgrade.rom.crc);
upgrade.crc = ~CalculateCRC32(-1, (unsigned char*)&upgrade, sizeof(UPGRADE) - 4);
printf("Header CRC : %08X\n", upgrade.crc);
printf("Version string : %s\n", upgrade.version);
outf = fopen(argv[2], "wb");
if(!outf) {
printf("Unable to open %s for writing\n", argv[2]);
return -1;
}
fwrite(&upgrade, 1, sizeof(UPGRADE), outf);
fwrite(bin, 1, size, outf);
fclose(outf);
return 0;
}

567
mmc.c Normal file
View File

@@ -0,0 +1,567 @@
/*
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/>.
*/
// --== based on the work by Dennis van Weeren and Jan Derogee ==--
// 2008-10-03 - adaptation for ARM controller
// 2009-07-23 - clean-up and some optimizations
// 2009-11-22 - multiple sector read implemented
// FIXME - get capacity from SD card
#include "stdio.h"
#include "string.h"
#include "hardware.h"
#include "mmc.h"
#include "fat.h"
// variables
unsigned char crc;
unsigned long timeout;
unsigned char response;
unsigned char CardType;
unsigned char CSDData[16];
// internal functions
static void MMC_CRC(unsigned char c) RAMFUNC;
static unsigned char MMC_Command(unsigned char cmd, unsigned long arg) RAMFUNC;
static unsigned char MMC_CMD12(void);
// init memory card
unsigned char MMC_Init(void)
{
unsigned char n;
unsigned char ocr[4];
SPI_slow(); // set slow clock
DisableCard(); // CS = 1
SPI(0xff); // DI = 1
TIMER_wait(20); // 20ms delay
for (n=0; n<10; n++) SPI(0xff); // 80 dummy clocks, DI = 1
TIMER_wait(20); // 20ms delay
EnableCard();
CardType = CARDTYPE_NONE;
for(n=0; n<16; n++) {
TIMER_wait(1);
if (MMC_Command(CMD0, 0) == 0x01) break; // try to send CMD0 multiple times
}
if (n<16) // got CMD0 IDLE response
{ // idle state
timeout = GetTimer(1000); // initialization timeout 1s, 4s doesn't work with the original arm timer
if (MMC_Command(CMD8, 0x1AA) == 0x01) // check if the card can operate with 2.7-3.6V power
{ // SDHC card
for (n = 0; n < 4; n++)
ocr[n] = SPI(0xFF); // get the rest of R7 response
if (ocr[2] == 0x01 && ocr[3] == 0xAA)
{ // the card can work at 2.7-3.6V
printf("SDHC card detected\r");
while (!CheckTimer(timeout))
{ // now we must wait until CMD41 returns 0 (or timeout elapses)
if (MMC_Command(CMD55, 0) == 0x01)
{ // CMD55 must precede any ACMD command
if (MMC_Command(CMD41, 1 << 30) == 0x00) // ACMD41 with HCS bit
{ // initialization completed
if (MMC_Command(CMD58, 0) == 0x00)
{ // check CCS (Card Capacity Status) bit in the OCR
for (n = 0; n < 4; n++)
ocr[n] = SPI(0xFF);
CardType = (ocr[0] & 0x40) ? CARDTYPE_SDHC : CARDTYPE_SD; // if CCS set then the card is SDHC compatible
}
else
printf("CMD58 (READ_OCR) failed!\r");
DisableCard();
// set appropriate SPI speed
#ifdef ARM_FW
if (GetSPIMode() == SPIMODE_FAST)
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (2 << 8); // 24 MHz SPI clock (max 25 MHz for SDHC card)
else
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (6 << 8); // 8 MHz SPI clock (no SPI mod)
#else
SPI_fast();
#endif
return(CardType);
}
}
else
{
printf("CMD55 (APP_CMD) failed!\r");
DisableCard();
return(CARDTYPE_NONE);
}
}
printf("SDHC card initialization timed out!\r");
DisableCard();
return(CARDTYPE_NONE);
}
}
// it's not an SDHC card
if (MMC_Command(CMD55, 0) == 0x01)
{ // CMD55 accepted so it's an SD card (or Kingston 128 MB MMC)
if (MMC_Command(CMD41, 0) <= 0x01)
{ // SD card detected - wait for the end of initialization
printf("SD card detected\r");
while (!CheckTimer(timeout))
{ // now we must wait until CMD41 returns 0 (or timeout elapses)
if (MMC_Command(CMD55, 0) == 0x01)
{ // CMD55 must precede any ACMD command
if (MMC_Command(CMD41, 0) == 0x00)
{ // initialization completed
if (MMC_Command(CMD16, 512) != 0x00) //set block length
printf("CMD16 (SET_BLOCKLEN) failed!\r");
DisableCard();
// set appropriate SPI speed
#ifdef ARM_FW
if (GetSPIMode() == SPIMODE_FAST)
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (2 << 8); // 24 MHz SPI clock (max 25 MHz for SD card)
else
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (6 << 8); // 8 MHz SPI clock (no SPI mod)
CardType = CARDTYPE_SD;
#else
SPI_fast();
CardType = CARDTYPE_SD;
#endif
return(CardType);
}
}
else
{
printf("CMD55 (APP_CMD) failed!\r");
DisableCard();
return(CARDTYPE_NONE);
}
}
printf("SD card initialization timed out!\r");
DisableCard();
return(CARDTYPE_NONE);
}
}
// it's not an SD card
printf("MMC card detected\r");
while (!CheckTimer(timeout))
{ // now we must wait until CMD1 returns 0 (or timeout elapses)
if (MMC_Command(CMD1, 0) == 0x00)
{ // initialization completed
if (MMC_Command(CMD16, 512) != 0x00) // set block length
printf("CMD16 (SET_BLOCKLEN) failed!\r");
DisableCard();
// set appropriate SPI speed
#ifdef ARM_FW
if (GetSPIMode() == SPIMODE_FAST)
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (3 << 8); // 16 MHz SPI clock (max 20 MHz for MMC card)
else
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (6 << 8); // 8 MHz SPI clock (no SPI mod)
#else
SPI_fast_mmc();
#endif
CardType = CARDTYPE_MMC;
return(CardType);
}
}
printf("MMC card initialization timed out!\r");
DisableCard();
return(CARDTYPE_NONE);
}
DisableCard();
printf("No memory card detected!\r");
return(CARDTYPE_NONE);
}
// Read single 512-byte block
RAMFUNC unsigned char MMC_Read(unsigned long lba, unsigned char *pReadBuffer)
{
// if pReadBuffer is NULL then use direct to the FPGA transfer mode (FPGA2 asserted)
unsigned long i;
unsigned char *p;
if (CardType != CARDTYPE_SDHC) // SDHC cards are addressed in sectors not bytes
lba = lba << 9; // otherwise convert sector adddress to byte address
EnableCard();
if (MMC_Command(CMD17, lba))
{
// printf("CMD17 (READ_BLOCK): invalid response 0x%02X (lba=%lu)\r", response, lba);
DisableCard();
return(0);
}
// now we are waiting for data token, it takes around 300us
timeout = 0;
while ((SPI(0xFF)) != 0xFE)
{
if (timeout++ >= 1000000) // we can't wait forever
{
// printf("CMD17 (READ_BLOCK): no data token! (lba=%lu)\r", lba);
DisableCard();
return(0);
}
}
if (pReadBuffer == 0)
{ // in this mode we do not receive data, instead the FPGA captures directly the data stream transmitted by the SD/MMC card
EnableDMode();
SPI_block(511);
SPI(0xff); // dummy write for 4096 clocks
SPI(0xff);
DisableDMode();
}
else
{
#ifdef SPI_BLOCK_READ
SPI_block_read(pReadBuffer);
#else
p=pReadBuffer;
for (i = 0; i < 128; i++)
{
*(p++) = SPI(0xFF);
*(p++) = SPI(0xFF);
*(p++) = SPI(0xFF);
*(p++) = SPI(0xFF);
}
#endif
}
SPI(0xFF); // read CRC lo byte
SPI(0xFF); // read CRC hi byte
DisableCard();
return(1);
}
// Read CSD register
unsigned char MMC_GetCSD()
{
int i;
EnableCard();
if (MMC_Command(CMD9,0))
{
printf("CMD9 (GET_CSD): invalid response 0x%02X \r", response);
DisableCard();
return(0);
}
// now we are waiting for data token, it takes around 300us
timeout = 0;
while ((SPI(0xFF)) != 0xFE)
{
if (timeout++ >= 1000000) // we can't wait forever
{
printf("CMD9 (READ_BLOCK): no data token!\r");
DisableCard();
return(0);
}
}
for (i = 0; i < 16; i++)
CSDData[i]=SPI(0xFF);
SPI(0xFF); // read CRC lo byte
SPI(0xFF); // read CRC hi byte
DisableCard();
return(1);
}
// MMC get capacity
unsigned long MMC_GetCapacity()
{
unsigned long result=0;
MMC_GetCSD();
// switch(CardType)
// {
// case CARDTYPE_SDHC:
// result=(CSDData[7]&0x3f)<<26;
// result|=CSDData[8]<<18;
// result|=CSDData[9]<<10;
// result+=1024;
// return(result);
// break;
// default:
// int blocksize=CSDData[5]&15; // READ_BL_LEN
// blocksize=1<<(blocksize-9); // Now a scalar: physical block size / 512.
// result=(CSDData[6]&3)<<10;
// result|=CSDData[7]<<2;
// result|=(CSDData[8]>>6)&3; // result now contains C_SIZE
// int cmult=(CSDData[9]&3)<<1;
// cmult|=(CSDData[10]>>7) & 1;
// ++result;
// result<<=cmult+2;
// return(result);
// break;
// }
if ((CSDData[0] & 0xC0)==0x40) //CSD Version 2.0 - SDHC
{
result=(CSDData[7]&0x3f)<<26;
result|=CSDData[8]<<18;
result|=CSDData[9]<<10;
result+=1024;
return(result);
}
else
{
int blocksize=CSDData[5]&15; // READ_BL_LEN
blocksize=1<<(blocksize-9); // Now a scalar: physical block size / 512.
result=(CSDData[6]&3)<<10;
result|=CSDData[7]<<2;
result|=(CSDData[8]>>6)&3; // result now contains C_SIZE
int cmult=(CSDData[9]&3)<<1;
cmult|=(CSDData[10]>>7) & 1;
++result;
result<<=cmult+2;
return(result);
}
}
// read multiple 512-byte blocks
unsigned char MMC_ReadMultiple(unsigned long lba, unsigned char *pReadBuffer, unsigned long nBlockCount)
{
// if pReadBuffer is NULL then use direct to the FPGA transfer mode (FPGA2 asserted)
unsigned long i;
unsigned char *p;
if (CardType != CARDTYPE_SDHC) // SDHC cards are addressed in sectors not bytes
lba = lba << 9; // otherwise convert sector adddress to byte address
EnableCard();
if (MMC_Command(CMD18, lba))
{
printf("CMD18 (READ_MULTIPLE_BLOCK): invalid response 0x%02X (lba=%u)\r", response, lba);
DisableCard();
return(0);
}
while (nBlockCount--)
{
// now we are waiting for data token, it takes around 300us
timeout = 0;
while ((SPI(0xFF)) != 0xFE)
{
if (timeout++ >= 1000000) // we can't wait forever
{
printf("CMD18 (READ_MULTIPLE_BLOCK): no data token! (lba=%u)\r", lba);
DisableCard();
return(0);
}
}
if (pReadBuffer == 0)
{ // in this mode we do not receive data, instead the FPGA captures directly the data stream transmitted by the SD/MMC card
EnableDMode();
SPI_block(511);
SPI(0xff); // dummy write for 4096 clocks
SPI(0xff);
DisableDMode();
}
else
{
#ifdef SPI_BLOCK_READ
SPI_block_read(pReadBuffer);
#else
p=pReadBuffer;
for (i = 0; i < 128; i++)
{
*(p++) = SPI(0xFF);
*(p++) = SPI(0xFF);
*(p++) = SPI(0xFF);
*(p++) = SPI(0xFF);
}
#endif
pReadBuffer += 512; // point to next sector
}
SPI(0xFF); // read CRC lo byte
SPI(0xFF); // read CRC hi byte
}
MMC_CMD12(); // stop multi block transmission
DisableCard();
return(1);
}
// write 512-byte block
unsigned char MMC_Write(unsigned long lba, unsigned char *pWriteBuffer)
{
unsigned long i;
if (CardType != CARDTYPE_SDHC) // SDHC cards are addressed in sectors not bytes
lba = lba << 9; // otherwise convert sector adddress to byte address
EnableCard();
if (MMC_Command(CMD24, lba))
{
printf("CMD24 (WRITE_BLOCK): invalid response 0x%02X (lba=%lu)\r", response, lba);
DisableCard();
return(0);
}
SPI(0xFF); // one byte gap
SPI(0xFE); // send Data Token
// send sector bytes
for (i = 0; i < 512; i++)
SPI(*(pWriteBuffer++));
SPI(0xFF); // send CRC lo byte
SPI(0xFF); // send CRC hi byte
response = SPI(0xFF); // read packet response
// Status codes
// 010 = Data accepted
// 101 = Data rejected due to CRC error
// 110 = Data rejected due to write error
response &= 0x1F;
if (response != 0x05)
{
printf("CMD24 (WRITE_BLOCK): invalid status 0x%02X (lba=%lu)\r", response, lba);
DisableCard();
return(0);
}
timeout = 0;
while ((SPI(0xFF)) == 0x00) // wait until the card is not busy
{
if (timeout++ >= 1000000)
{
printf("CMD24 (WRITE_BLOCK): busy wait timeout! (lba=%lu)\r", lba);
DisableCard();
return(0);
}
}
DisableCard();
return(1);
}
// MMC command
static RAMFUNC unsigned char MMC_Command(unsigned char cmd, unsigned long arg)
{
unsigned char c;
crc = 0;
SPI(0xFF); // flush SPI-bus
SPI(cmd);
MMC_CRC(cmd);
c = (unsigned char)(arg >> 24);
SPI(c);
MMC_CRC(c);
c = (unsigned char)(arg >> 16);
SPI(c);
MMC_CRC(c);
c = (unsigned char)(arg >> 8);
SPI(c);
MMC_CRC(c);
c = (unsigned char)(arg);
SPI(c);
MMC_CRC(c);
crc <<= 1;
crc++;
SPI(crc);
unsigned char Ncr = 100; // Ncr = 0..8 (SD) / 1..8 (MMC)
do
response = SPI(0xFF); // get response
while (response == 0xFF && Ncr--);
return response;
}
// stop multi block data transmission
static unsigned char MMC_CMD12(void)
{
SPI(CMD12); // command
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00); // dummy CRC7
SPI(0xFF); // skip stuff byte
unsigned char Ncr = 100; // Ncr = 0..8 (SD) / 1..8 (MMC)
do
{ response = SPI(0xFF); // get response
// RS232(response);
} while (response == 0xFF && Ncr--);
timeout = 0;
while ((SPI(0xFF)) == 0x00) // wait until the card is not busy
{ // RS232('+');
if (timeout++ >= 1000000)
{
printf("CMD12 (STOP_TRANSMISSION): busy wait timeout!\r");
DisableCard();
return(0);
}
}
return response;
}
// MMC CRC calc
static RAMFUNC void MMC_CRC(unsigned char c)
{
unsigned char i;
for (i = 0; i < 8; i++)
{
crc <<= 1;
if (c & 0x80)
crc ^= 0x09;
if (crc & 0x80)
crc ^= 0x09;
c <<= 1;
}
}

87
mmc.h Normal file
View File

@@ -0,0 +1,87 @@
#ifndef MMC_H
#define MMC_H
#include "hardware.h"
#define CARDTYPE_NONE 0
#define CARDTYPE_MMC 1
#define CARDTYPE_SD 2
#define CARDTYPE_SDHC 3
// MMC commandset
#define CMD0 0x40 /*Resets the multimedia card*/
#define CMD1 0x41 /*Activates the card's initialization process*/
#define CMD2 0x42 /*--*/
#define CMD3 0x43 /*--*/
#define CMD4 0x44 /*--*/
#define CMD5 0x45 /*reseved*/
#define CMD6 0x46 /*reserved*/
#define CMD7 0x47 /*--*/
#define CMD8 0x48 /*reserved*/
#define CMD9 0x49 /*CSD : Ask the selected card to send its card specific data*/
#define CMD10 0x4a /*CID : Ask the selected card to send its card identification*/
#define CMD11 0x4b /*--*/
#define CMD12 0x4c /*--*/
#define CMD13 0x4d /*Ask the selected card to send its status register*/
#define CMD14 0x4e /*--*/
#define CMD15 0x4f /*--*/
#define CMD16 0x50 /*Select a block length (in bytes) for all following block commands (Read:between 1-512 and Write:only 512)*/
#define CMD17 0x51 /*Reads a block of the size selected by the SET_BLOCKLEN command, the start address and block length must be set so that the data transferred will not cross a physical block boundry*/
#define CMD18 0x52 /*--*/
#define CMD19 0x53 /*reserved*/
#define CMD20 0x54 /*--*/
#define CMD21 0x55 /*reserved*/
#define CMD22 0x56 /*reserved*/
#define CMD23 0x57 /*reserved*/
#define CMD24 0x58 /*Writes a block of the size selected by CMD16, the start address must be alligned on a sector boundry, the block length is always 512 bytes*/
#define CMD25 0x59 /*--*/
#define CMD26 0x5a /*--*/
#define CMD27 0x5b /*Programming of the programmable bits of the CSD*/
#define CMD28 0x5c /*If the card has write protection features, this command sets the write protection bit of the addressed group. The porperties of the write protection are coded in the card specific data (WP_GRP_SIZE)*/
#define CMD29 0x5d /*If the card has write protection features, this command clears the write protection bit of the addressed group*/
#define CMD30 0x5e /*If the card has write protection features, this command asks the card to send the status of the write protection bits. 32 write protection bits (representing 32 write protect groups starting at the specific address) followed by 16 CRD bits are transferred in a payload format via the data line*/
#define CMD31 0x5f /*reserved*/
#define CMD32 0x60 /*sets the address of the first sector of the erase group*/
#define CMD33 0x61 /*Sets the address of the last sector in a cont. range within the selected erase group, or the address of a single sector to be selected for erase*/
#define CMD34 0x62 /*Removes on previously selected sector from the erase selection*/
#define CMD35 0x63 /*Sets the address of the first erase group within a range to be selected for erase*/
#define CMD36 0x64 /*Sets the address of the last erase group within a continuos range to be selected for erase*/
#define CMD37 0x65 /*Removes one previously selected erase group from the erase selection*/
#define CMD38 0x66 /*Erases all previously selected sectors*/
#define CMD39 0x67 /*--*/
#define CMD40 0x68 /*--*/
#define CMD41 0x69 /*reserved*/
#define CMD42 0x6a /*reserved*/
#define CMD43 0x6b /*reserved*/
#define CMD44 0x6c /*reserved*/
#define CMD45 0x6d /*reserved*/
#define CMD46 0x6e /*reserved*/
#define CMD47 0x6f /*reserved*/
#define CMD48 0x70 /*reserved*/
#define CMD49 0x71 /*reserved*/
#define CMD50 0x72 /*reserved*/
#define CMD51 0x73 /*reserved*/
#define CMD52 0x74 /*reserved*/
#define CMD53 0x75 /*reserved*/
#define CMD54 0x76 /*reserved*/
#define CMD55 0x77 /*reserved*/
#define CMD56 0x78 /*reserved*/
#define CMD57 0x79 /*reserved*/
#define CMD58 0x7a /*reserved*/
#define CMD59 0x7b /*Turns the CRC option ON or OFF. A '1' in the CRC option bit will turn the option ON, a '0' will turn it OFF*/
#define CMD60 0x7c /*--*/
#define CMD61 0x7d /*--*/
#define CMD62 0x7e /*--*/
#define CMD63 0x7f /*--*/
unsigned char MMC_Init(void);
unsigned char MMC_Read(unsigned long lba, unsigned char *pReadBuffer) RAMFUNC;
unsigned char MMC_Write(unsigned long lba, unsigned char *pWriteBuffer);
unsigned char MMC_ReadMultiple(unsigned long lba, unsigned char *pReadBuffer, unsigned long nBlockCount);
unsigned char MMC_GetCSD();
unsigned long MMC_GetCapacity(); // Returns the capacity in 512 byte blocks
extern unsigned char CSDData[16];
#endif

870
osd.c Normal file
View File

@@ -0,0 +1,870 @@
/*
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 "AT91SAM7S256.h"
#include "osd.h"
#include "hardware.h"
#include "stdio.h"
#include "charrom.h"
#include "logo.h"
#include "user_io.h"
#include <string.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
};
struct star
{
int x, y;
int dx, dy;
};
struct star stars[64];
char framebuffer[8][256];
void framebuffer_clear()
{
int i,j;
for(i=0;i<8;++i)
{
for(j=0;j<256;++j)
{
framebuffer[i][j]=0;
}
}
}
void framebuffer_plot(int x,int y)
{
framebuffer[y/8][x]|=(1<<(y & 7));
}
static int quickrand()
{
static int prev;
#ifndef MIST
int r=*(volatile unsigned long *)0x80000c;
#else
int r = (int)(AT91C_BASE_RTTC->RTTC_RTVR);
#endif
r^=(prev&0xc75a)<<4;
r^=(prev&0x5a7c)>>(prev&7);
prev=r;
return(r);
}
void StarsInit()
{
int i;
for(i=0;i<64;++i)
{
stars[i].x=(quickrand()%228)<<4; // X centre
stars[i].y=(quickrand()%56)<<4; // Y centre
stars[i].dx=-(quickrand()&7)-3;
stars[i].dy=0;
}
}
void StarsUpdate()
{
framebuffer_clear();
int i;
for(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=(quickrand()%56)<<4;
stars[i].dx=-(quickrand()&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 50
static unsigned long scroll_offset=0; // file/dir name scrolling position
static unsigned long scroll_timer=0; // file/dir name scrolling timer
extern char s[40];
static int arrow;
static unsigned char titlebuffer[64];
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;
}
}
void OsdSetTitle(char *s,int a)
{
// Compose the title, condensing character gaps
arrow=a;
char zeros=0;
char i=0,j=0;
char outp=0;
while(1)
{
int c=s[i++];
if(c && (outp<64))
{
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<64;++i)
{
titlebuffer[i]=0;
}
// Now centre it:
int c=(63-outp)/2;
for(i=(63-c);i>=0;--i)
{
titlebuffer[i+c]=titlebuffer[i];
}
for(i=0;i<c;++i)
titlebuffer[i]=0;
// Finally rotate it.
for(i=0;i<64;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);
}
// 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)
{
unsigned short i;
unsigned char b;
const unsigned char *p;
unsigned char stipplemask=0xff;
int linelimit=OSDLINELEN;
int arrowmask=arrow;
if(n==7 && (arrow & OSD_ARROW_RIGHT))
linelimit-=22;
if(stipple)
{
stipplemask=0x55;
stipple=0xff;
}
else
stipple=0;
// select OSD SPI device
EnableOsd();
// select buffer and line to write to
// if (invert)
// SPI(OSDCMDWRITE | 0x10 | n);
// else
SPI(OSDCMDWRITE | n);
if(invert)
invert=255;
i = 0;
// send all characters in string to OSD
while (1)
{
if(i==0) // Render sidestripe
{
p = &titlebuffer[(7-n)*8];
SPI(0xff);
SPI(0xff);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(0xff);
SPI(0xff);
SPI(0x00);
SPI(0x00);
i += 22;
}
else if(n==7 && (arrowmask & OSD_ARROW_LEFT)) // Draw initial arrow
{
SPI(0);
SPI(0);
SPI(0);
p = &charfont[0x10][0];
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
p = &charfont[0x14][0];
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
SPI(0);
SPI(0);
SPI(0);
SPI(invert);
SPI(invert);
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();
EnableOsd();
SPI(OSDCMDWRITE | n);
}
else if(i<(linelimit-8)) // normal character
{
p = &charfont[b][0];
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
i += 8;
}
}
}
for (; i < linelimit; i++) // clear end of line
SPI(invert);
if(n==7 && (arrowmask & OSD_ARROW_RIGHT)) // Draw final arrow if needed
{
SPI(0);
SPI(0);
SPI(0);
p = &charfont[0x15][0];
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
p = &charfont[0x11][0];
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
SPI(0);
SPI(0);
SPI(0);
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;
// select OSD SPI device
EnableOsd();
// select buffer and line to write to
SPI(OSDCMDWRITE | n);
const unsigned char *lp=logodata[row];
int bytes=sizeof(logodata[0]);
if(row>=(sizeof(logodata)/bytes))
lp=0;
i = 0;
// send all characters in string to OSD
if(superimpose)
{
char *bg=framebuffer[n];
while (bytes)
{
if(i==0) // Render sidestripe
{
p = &titlebuffer[(7-n)*8];
SPI(0xff);
SPI(0xff);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(0xff);
SPI(0xff);
SPI(0x00);
SPI(0x00);
i += 22;
}
if(i>=linelimit)
break;
if(lp)
SPI(*lp++ | *bg++);
else
SPI(*bg++);
--bytes;
++i;
}
for (; i < linelimit; i++) // clear end of line
SPI(*bg++);
}
else
{
while (bytes)
{
if(i==0) // Render sidestripe
{
p = &titlebuffer[(7-n)*8];
SPI(0xff);
SPI(0xff);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(0xff);
SPI(0xff);
SPI(0x00);
SPI(0x00);
i += 22;
}
if(i>=linelimit)
break;
if(lp)
SPI(*lp++);
else
SPI(0);
--bytes;
++i;
}
for (; i < linelimit; i++) // clear end of line
SPI(0);
}
// deselect OSD SPI device
DisableOsd();
}
void OsdWriteDoubleSize(unsigned char n, char *s, unsigned char pass)
{
unsigned short i;
unsigned char b;
const unsigned char *p;
int linelimit=OSDLINELEN;
// select OSD SPI device
EnableOsd();
// select buffer and line to write to
SPI(OSDCMDWRITE | n);
i = 0;
// send all characters in string to OSD
while (1)
{
if(i==0) // Render sidestripe
{
p = &titlebuffer[(7-n)*8];
SPI(0xff);
SPI(0xff);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(255^*p); SPI(255^*p++);
SPI(0xff);
SPI(0xff);
SPI(0x00);
SPI(0x00);
i += 22;
}
else
{
b = *s++;
if (b == 0) // end of string
break;
else if(i<(linelimit-16)) // normal character
{
int c;
p = &charfont[b][0];
if(pass) // Draw the bottom half..
{
int j;
for(j=0;j<8;++j)
{
c=*p++;
c=(c&0xf0)>>4;
c=(c&0x08)<<1 | c; // ....ABCD => ...AABCD
c=(c&0x1c)<<1 | (c & 0x07); // ...AABCD => ..AABBCD
c=(c&0x3e)<<1 | (c & 0x03); // ..AABBCD => .AABBCCD
c=c<<1 | (c&0x01); // .AABBCCD => AABBCCDD
SPI(c); SPI(c);
}
}
else // Draw the top half...
{
int j;
for(j=0;j<8;++j)
{
c=*p++;
c=c&0xf;
c=(c&0x08)<<1 | c; // ....ABCD => ...AABCD
c=(c&0x1c)<<1 | (c & 0x07); // ...AABCD => ..AABBCD
c=(c&0x3e)<<1 | (c & 0x03); // ..AABBCD => .AABBCCD
c=c<<1 | (c&0x01); // .AABBCCD => AABBCCDD
SPI(c); SPI(c);
}
}
i += 16;
}
}
}
for (; i < linelimit; i++) // clear end of line
SPI(0);
// 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 OSD SPI device
EnableOsd();
// select buffer and line to write to
// if (invert)
// SPI(OSDCMDWRITE | 0x10 | line);
// else
SPI(OSDCMDWRITE | line);
if(invert)
invert=0xff;
p = &titlebuffer[(7-line)*8];
if(start>2)
{
SPI(0xff); SPI(0xff); start-=2;
}
i=start>16 ? 16 : start;
for(j=0;j<(i/2);++j)
{
SPI(255^*p); SPI(255^*p++);
}
if(i&1)
SPI(255^*p);
start-=i;
if(start>2)
SPI(0xff), SPI(0xff), start-=2;
while (start--)
SPI(0x00);
if (offset)
{
width -= 8 - offset;
p = &charfont[*text++][offset];
for (; offset < 8; offset++)
SPI(*p++^invert);
}
while (width > 8)
{
p = &charfont[*text++][0];
SPI(*p++^invert);
SPI(*p++^invert);
SPI(*p++^invert);
SPI(*p++^invert);
SPI(*p++^invert);
SPI(*p++^invert);
SPI(*p++^invert);
SPI(*p++^invert);
width -= 8;
}
if (width)
{
p = &charfont[*text++][0];
while (width--)
SPI(*p++^invert);
}
DisableOsd();
}
// clear OSD frame buffer
void OsdClear(void)
{
unsigned short n;
// select OSD SPI device
EnableOsd();
// select buffer to write to
SPI(OSDCMDWRITE | 0x18);
// clear buffer
for (n = 0; n < (OSDLINELEN * OSDNLINE); n++)
SPI(0x00);
// deselect OSD SPI device
DisableOsd();
}
void OsdWaitVBL(void)
{
// unsigned long pioa_old = 0;
// unsigned long pioa = 0;
//
// while ((~pioa ^ pioa_old) & INIT_B)
// {
// pioa_old = pioa;
// pioa = *AT91C_PIOA_PDSR;
// }
}
// enable displaying of OSD
void OsdEnable(unsigned char mode)
{
user_io_osd_key_enable(mode & DISABLE_KEYBOARD);
EnableOsd();
SPI(OSDCMDENABLE | (mode & DISABLE_KEYBOARD));
DisableOsd();
}
// disable displaying of OSD
void OsdDisable(void)
{
user_io_osd_key_enable(0);
EnableOsd();
SPI(OSDCMDDISABLE);
DisableOsd();
}
void OsdReset(unsigned char boot)
{
EnableOsd();
SPI(OSDCMDRST | (boot & 0x01));
DisableOsd();
}
void ConfigFilter(unsigned char lores, unsigned char hires)
{
EnableOsd();
SPI(OSDCMDCFGFLT | ((hires & 0x03) << 2) | (lores & 0x03));
DisableOsd();
}
void ConfigMemory(unsigned char memory)
{
EnableOsd();
SPI(OSDCMDCFGMEM | (memory & 0x03)); //chip
DisableOsd();
EnableOsd();
SPI(OSDCMDCFGMEM | 0x04 | ((memory>>2) & 0x03)); //slow
DisableOsd();
EnableOsd();
SPI(OSDCMDCFGMEM | 0x08 | ((memory>>4) & 0x03)); //fast
DisableOsd();
EnableOsd();
// SPI(OSDCMDCFGCPU| 0x00); //68000 - Don't want to disable '020 here! AMR
// DisableOsd();
}
void ConfigCPU(unsigned char cpu)
{
EnableOsd();
SPI(OSDCMDCFGCPU | (cpu & 0x03)); //CPU
DisableOsd();
}
void ConfigChipset(unsigned char chipset)
{
EnableOsd();
SPI(OSDCMDCFGCHP | (chipset & 0x0F));
// SPI(OSDCMDCFGCHP | (chipset & 0x0E));
DisableOsd();
}
void ConfigFloppy(unsigned char drives, unsigned char speed)
{
EnableOsd();
SPI(OSDCMDCFGFLP | ((drives & 0x03) << 2) | (speed & 0x03));
DisableOsd();
}
void ConfigScanlines(unsigned char scanlines)
{
EnableOsd();
SPI(OSDCMDCFGSCL | (scanlines & 0x0F));
DisableOsd();
}
void ConfigIDE(unsigned char gayle, unsigned char master, unsigned char slave)
{
EnableOsd();
SPI(OSDCMDCFGIDE | (slave ? 4 : 0) | (master ? 2 : 0) | (gayle ? 1 : 0));
DisableOsd();
}
void ConfigAutofire(unsigned char autofire)
{
EnableOsd();
SPI(OSDCMDAUTOFIRE | (autofire & 0x03));
DisableOsd();
}
// 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;
// minimig OSD is controlled by key codes from core
if(user_io_core_type() == CORE_TYPE_MINIMIG) {
// send command and get current ctrl status
EnableOsd();
c1 = SPI(OSDCMDREAD);
DisableOsd();
}
// mist/atari core uses local queue
if(user_io_core_type() == CORE_TYPE_MIST)
c1 = OsdKeyGet();
// add front menu button
if (!CheckButton())
delay = GetTimer(BUTTONDELAY);
else if (CheckTimer(delay))
{
c1 = KEY_MENU;
delay = GetTimer(-1);
}
// generate normal "key-pressed" event
c = 0;
if (c1 != c2)
c = c1;
c2 = c1;
// generate repeat "key-pressed" events
if (c1 & KEY_UPSTROKE)
{
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 || GetASCIIKey(c1))
c = c1;
}
}
return(c);
}
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 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
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 (len > max_len) // scroll name if longer than display size
{
if (scroll_offset >= (len + BLANKSPACE) << 3) // reset scroll position if it exceeds predefined maximum
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) {
osd_key = c;
}
unsigned char OsdKeyGet() {
return osd_key;
}

111
osd.h Normal file
View File

@@ -0,0 +1,111 @@
#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
#define OSDCMDREAD 0x00 // OSD read controller/key status
#define OSDCMDWRITE 0x20 // OSD write video data command
#define OSDCMDENABLE 0x41 // OSD enable command
#define OSDCMDDISABLE 0x40 // OSD disable command
#define OSDCMDRST 0x80 // OSD reset command
#define OSDCMDRECONFIG 0x82 // OSD reset command
#define OSDCMDAUTOFIRE 0x84 // OSD autofire command
#define OSDCMDCFGSCL 0xA0 // OSD settings: scanlines effect
#define OSDCMDCFGIDE 0xB0 // OSD enable HDD command
#define OSDCMDCFGFLP 0xC0 // OSD settings: floppy config
#define OSDCMDCFGCHP 0xD0 // OSD settings: chipset config
#define OSDCMDCFGFLT 0xE0 // OSD settings: filter
#define OSDCMDCFGMEM 0xF0 // OSD settings: memory config
#define OSDCMDCFGCPU 0xFC // OSD settings: CPU config
#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_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_FLOPPY1X 0
#define CONFIG_FLOPPY2X 1
#define RESET_NORMAL 0
#define RESET_BOOTLOADER 1
#define OSD_ARROW_LEFT 1
#define OSD_ARROW_RIGHT 2
/*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); // 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 ConfigMemory(unsigned char memory);
void ConfigCPU(unsigned char cpu);
void ConfigChipset(unsigned char chipset);
void ConfigFloppy(unsigned char drives, unsigned char speed);
void ConfigScanlines(unsigned char scanlines);
void ConfigIDE(unsigned char gayle, unsigned char master, unsigned char slave);
void ConfigAutofire(unsigned char autofire);
unsigned char OsdGetCtrl(void);
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 len, int max_len,unsigned char invert);
void ScrollReset();
void StarsInit();
void StarsUpdate();
void OsdKeySet(unsigned char);
unsigned char OsdKeyGet();
#endif

81
rafile.c Normal file
View File

@@ -0,0 +1,81 @@
#include "rafile.h"
int RARead(RAFile *file,unsigned char *pBuffer, unsigned long bytes)
{
int result=1;
// Since we can only read from the SD card on 512-byte aligned boundaries,
// we need to copy in multiple pieces.
unsigned long blockoffset=file->ptr&511; // Offset within the current 512 block at which the previous read finished
// Bytes blockoffset to 512 will be drained first, before reading new data.
if(blockoffset) // If blockoffset is zero we'll just use aligned reads and don't need to drain the buffer.
{
int i;
int l=bytes;
if(l>512)
l=512;
for(i=blockoffset;i<l;++i)
{
*pBuffer++=file->buffer[i];
}
file->ptr+=l-blockoffset;
bytes-=l-blockoffset;
}
// We've now read any bytes left over from a previous read. If any data remains to be read we can read it
// in 512-byte aligned chunks, until the last block.
while(bytes>511)
{
result&=FileRead(&file->file,pBuffer); // Read direct to pBuffer
FileNextSector(&file->file);
bytes-=512;
file->ptr+=512;
pBuffer+=512;
}
if(bytes) // Do we have any bytes left to read?
{
int i;
result&=FileRead(&file->file,file->buffer); // Read to temporary buffer, allowing us to preserve any leftover for the next read.
FileNextSector(&file->file);
for(i=0;i<bytes;++i)
{
*pBuffer++=file->buffer[i];
}
file->ptr+=bytes;
}
return(result);
}
int RASeek(RAFile *file,unsigned long offset,unsigned long origin)
{
int result=1;
unsigned long blockoffset;
unsigned long blockaddress;
if(origin==SEEK_CUR)
offset+=file->ptr;
blockoffset=offset&511;
blockaddress=offset-blockoffset; // 512-byte-aligned...
result&=FileSeek(&file->file,blockaddress,SEEK_SET);
if(result && blockoffset) // If we're seeking into the middle of a block, we need to buffer it...
{
result&=FileRead(&file->file,file->buffer);
FileNextSector(&file->file);
}
file->ptr=offset;
return(result);
}
int RAOpen(RAFile *file,const char *filename)
{
int result=1;
if(!file)
return(0);
result=FileOpen(&file->file,filename);
file->size=file->file.size;
file->ptr=0;
return(result);
}

35
rafile.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef RAFILE_H
#define RAFILE_H
/* Utility functions to provide the Minimig OSD code with file access
at single-byte rather than 512-byte-block granularity.
Copyright (c) 2012 by Alastair M. Robinson
Contributed to the Minimig project, which 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 "fat.h"
typedef struct
{
fileTYPE file;
unsigned long size;
unsigned long ptr;
unsigned char buffer[512]; // Each RandomAccessFile has its own sector_buffer
} RAFile;
int RARead(RAFile *file,unsigned char *pBuffer, unsigned long bytes);
int RASeek(RAFile *file,unsigned long offset,unsigned long origin);
int RAOpen(RAFile *file,const char *filename);
#endif

56
swap.c Normal file
View File

@@ -0,0 +1,56 @@
////////////////////////////////////////////////////////////////////////////////
// swap.c //
// Endianness swap functions //
// //
// Copyright 2012- Christian Vogelgsang, A.M. Robinson, Rok Krajnc //
// //
// 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 2 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/>. //
// //
////////////////////////////////////////////////////////////////////////////////
// Changelog //
// //
// 2012-08-02 - rok.krajnc@gmail.com //
// Functions are now generic - removed assembler code. Added function-like //
// macros (gcc specific!). //
// //
////////////////////////////////////////////////////////////////////////////////
#include "swap.h"
#ifndef SWAP_MACROS
uint32_t SwapBBBB(uint32_t i)
{
return ((i&0x00ff0000)>>8) | ((i&0xff000000)>>24) | ((i&0x000000ff)<<24) | ((i&0x0000ff00)<<8);
}
uint16_t SwapBB(uint16_t i)
{
return ((i&0x00ff)<<8) | ((i&0xff00)>>8);
}
uint32_t SwapWW(uint32_t i)
{
//return ((i&0x0000ffff)<<16) | ((i&0xffff0000)>>16);
return ((i<<16) | (i>>16));
}
#endif // SWAP_MACROS

67
swap.h Normal file
View File

@@ -0,0 +1,67 @@
////////////////////////////////////////////////////////////////////////////////
// swap.h //
// Endianness swap functions //
// //
// Copyright 2012- Christian Vogelgsang, A.M. Robinson, Rok Krajnc //
// //
// 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 2 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/>. //
// //
////////////////////////////////////////////////////////////////////////////////
// Changelog //
// //
// 2012-08-02 - rok.krajnc@gmail.com //
// Functions are now generic - removed assembler code. Added function-like //
// macros (gcc specific!). //
// //
////////////////////////////////////////////////////////////////////////////////
#ifndef __SWAP_H__
#define __SWAP_H__
#include <inttypes.h>
//// config defines ////
// use macros / functions
#define SWAP_MACROS
#ifdef SWAP_MACROS
//// macros ////
#ifdef SWAP
#define SwapBBBB(x) ({ typeof(x) _x = (x); ((_x&0x00ff0000)>>8) | ((_x&0xff000000)>>24) | ((_x&0x000000ff)<<24) | ((_x&0x0000ff00)<<8); })
#define SwapBB(x) ({ typeof(x) _x = (x); ((_x&0x00ff)<<8) | ((_x&0xff00)>>8); })
#define SwapWW(x) ({ typeof(x) _x = (x); ((_x&0x0000ffff)<<16) | ((_x&0xffff0000)>>16); })
#else
#define SwapBBBB(x) (x)
#define SwapBB(x) (x)
#define SwapWW(x) (x)
#endif // SWAP
#else
//// function declarations ////
uint32_t SwapBBBB (uint32_t i);
uint16_t SwapBB (uint16_t i);
uint32_t SwapWW (uint32_t i);
#endif // SWAP_MACROS
#endif // __SWAP_H__

60
swi.h Normal file
View File

@@ -0,0 +1,60 @@
/* SWI numbers for RDP (Demon) monitor. */
#define SWI_WriteC 0x0
#define SWI_Write0 0x2
#define SWI_ReadC 0x4
#define SWI_CLI 0x5
#define SWI_GetEnv 0x10
#define SWI_Exit 0x11
#define SWI_EnterOS 0x16
#define SWI_GetErrno 0x60
#define SWI_Clock 0x61
#define SWI_Time 0x63
#define SWI_Remove 0x64
#define SWI_Rename 0x65
#define SWI_Open 0x66
#define SWI_Close 0x68
#define SWI_Write 0x69
#define SWI_Read 0x6a
#define SWI_Seek 0x6b
#define SWI_Flen 0x6c
#define SWI_IsTTY 0x6e
#define SWI_TmpNam 0x6f
#define SWI_InstallHandler 0x70
#define SWI_GenerateError 0x71
/* Now the SWI numbers and reason codes for RDI (Angel) monitors. */
#define AngelSWI_ARM 0x123456
#ifdef __thumb__
#define AngelSWI 0xAB
#else
#define AngelSWI AngelSWI_ARM
#endif
/* The reason codes: */
#define AngelSWI_Reason_Open 0x01
#define AngelSWI_Reason_Close 0x02
#define AngelSWI_Reason_WriteC 0x03
#define AngelSWI_Reason_Write0 0x04
#define AngelSWI_Reason_Write 0x05
#define AngelSWI_Reason_Read 0x06
#define AngelSWI_Reason_ReadC 0x07
#define AngelSWI_Reason_IsTTY 0x09
#define AngelSWI_Reason_Seek 0x0A
#define AngelSWI_Reason_FLen 0x0C
#define AngelSWI_Reason_TmpNam 0x0D
#define AngelSWI_Reason_Remove 0x0E
#define AngelSWI_Reason_Rename 0x0F
#define AngelSWI_Reason_Clock 0x10
#define AngelSWI_Reason_Time 0x11
#define AngelSWI_Reason_System 0x12
#define AngelSWI_Reason_Errno 0x13
#define AngelSWI_Reason_GetCmdLine 0x15
#define AngelSWI_Reason_HeapInfo 0x16
#define AngelSWI_Reason_EnterSVC 0x17
#define AngelSWI_Reason_ReportException 0x18
#define ADP_Stopped_ApplicationExit ((2 << 16) + 38)
#define ADP_Stopped_RunTimeError ((2 << 16) + 35)

646
syscalls.c Normal file
View File

@@ -0,0 +1,646 @@
/* Support files for GNU libc. Files in the system namespace go here.
Files in the C namespace (ie those that do not start with an
underscore) go in .c. */
// http://balau82.wordpress.com/2011/09/03/using-codesourcery-bare-metal-toolchain-for-cortex-m3/
#include <_ansi.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
#include <errno.h>
#include <reent.h>
#include <unistd.h>
#include "swi.h"
#include "AT91SAM7S256.h"
/* Forward prototypes. */
int _system _PARAMS ((const char *));
int _rename _PARAMS ((const char *, const char *));
/* Different versions of newlib name this differentely. */
int isatty _PARAMS ((int));
int _isatty _PARAMS ((int));
clock_t _times _PARAMS ((struct tms *));
int _gettimeofday _PARAMS ((struct timeval *, struct timezone *));
void _raise _PARAMS ((void));
int _unlink _PARAMS ((void));
int _link _PARAMS ((void));
int _stat _PARAMS ((const char *, struct stat *));
int _fstat _PARAMS ((int, struct stat *));
caddr_t _sbrk _PARAMS ((int));
int _getpid _PARAMS ((int));
int _kill _PARAMS ((int, int));
void _exit _PARAMS ((int));
int _close _PARAMS ((int));
int _swiclose _PARAMS ((int));
int _open _PARAMS ((const char *, int, ...));
int _swiopen _PARAMS ((const char *, int));
int _write _PARAMS ((int, char *, int));
int _swiwrite _PARAMS ((int, char *, int));
int _lseek _PARAMS ((int, int, int));
int _swilseek _PARAMS ((int, int, int));
int _read _PARAMS ((int, char *, int));
int _swiread _PARAMS ((int, char *, int));
void initialise_monitor_handles _PARAMS ((void));
static int wrap _PARAMS ((int));
static int error _PARAMS ((int));
static int get_errno _PARAMS ((void));
static int remap_handle _PARAMS ((int));
static int do_AngelSWI _PARAMS ((int, void *));
static int findslot _PARAMS ((int));
/* Register name faking - works in collusion with the linker. */
register char * stack_ptr asm ("sp");
/* following is copied from libc/stdio/local.h to check std streams */
extern void _EXFUN(__sinit,(struct _reent *));
#define CHECK_INIT(ptr) \
do \
{ \
if ((ptr) && !(ptr)->__sdidinit) \
__sinit (ptr); \
} \
while (0)
/* Adjust our internal handles to stay away from std* handles. */
#define FILE_HANDLE_OFFSET (0x20)
static int monitor_stdin;
static int monitor_stdout;
static int monitor_stderr;
/* Struct used to keep track of the file position, just so we
can implement fseek(fh,x,SEEK_CUR). */
typedef struct
{
int handle;
int pos;
}
poslog;
#define MAX_OPEN_FILES 20
static poslog openfiles [MAX_OPEN_FILES];
static int
findslot (int fh)
{
int i;
for (i = 0; i < MAX_OPEN_FILES; i ++)
if (openfiles[i].handle == fh)
break;
return i;
}
#ifdef ARM_RDI_MONITOR
static inline int
do_AngelSWI (int reason, void * arg)
{
int value;
asm volatile ("mov r0, %1; mov r1, %2; swi %a3; mov %0, r0"
: "=r" (value) /* Outputs */
: "r" (reason), "r" (arg), "i" (AngelSWI) /* Inputs */
: "r0", "r1", "r2", "r3", "ip", "lr", "memory", "cc"
/* Clobbers r0 and r1, and lr if in supervisor mode */);
/* Accordingly to page 13-77 of ARM DUI 0040D other registers
can also be clobbered. Some memory positions may also be
changed by a system call, so they should not be kept in
registers. Note: we are assuming the manual is right and
Angel is respecting the APCS. */
return value;
}
#endif /* ARM_RDI_MONITOR */
/* Function to convert std(in|out|err) handles to internal versions. */
static int
remap_handle (int fh)
{
CHECK_INIT(_REENT);
if (fh == STDIN_FILENO)
return monitor_stdin;
if (fh == STDOUT_FILENO)
return monitor_stdout;
if (fh == STDERR_FILENO)
return monitor_stderr;
return fh - FILE_HANDLE_OFFSET;
}
void
initialise_monitor_handles (void)
{
int i;
#ifdef ARM_RDI_MONITOR
int volatile block[3];
block[0] = (int) ":tt";
block[2] = 3; /* length of filename */
block[1] = 0; /* mode "r" */
monitor_stdin = do_AngelSWI (AngelSWI_Reason_Open, (void *) block);
block[0] = (int) ":tt";
block[2] = 3; /* length of filename */
block[1] = 4; /* mode "w" */
monitor_stdout = monitor_stderr = do_AngelSWI (AngelSWI_Reason_Open, (void *) block);
#else
int fh;
const char * name;
name = ":tt";
asm ("mov r0,%2; mov r1, #0; swi %a1; mov %0, r0"
: "=r"(fh)
: "i" (SWI_Open),"r"(name)
: "r0","r1");
monitor_stdin = fh;
name = ":tt";
asm ("mov r0,%2; mov r1, #4; swi %a1; mov %0, r0"
: "=r"(fh)
: "i" (SWI_Open),"r"(name)
: "r0","r1");
monitor_stdout = monitor_stderr = fh;
#endif
for (i = 0; i < MAX_OPEN_FILES; i ++)
openfiles[i].handle = -1;
openfiles[0].handle = monitor_stdin;
openfiles[0].pos = 0;
openfiles[1].handle = monitor_stdout;
openfiles[1].pos = 0;
}
static int
get_errno (void)
{
#ifdef ARM_RDI_MONITOR
return do_AngelSWI (AngelSWI_Reason_Errno, NULL);
#else
asm ("swi %a0" :: "i" (SWI_GetErrno));
#endif
}
static int
error (int result)
{
errno = get_errno ();
return result;
}
static int
wrap (int result)
{
if (result == -1)
return error (-1);
return result;
}
/* Returns # chars not! written. */
int
_swiread (int file,
char * ptr,
int len)
{
int fh = remap_handle (file);
#ifdef ARM_RDI_MONITOR
int block[3];
block[0] = fh;
block[1] = (int) ptr;
block[2] = len;
return do_AngelSWI (AngelSWI_Reason_Read, block);
#else
asm ("mov r0, %1; mov r1, %2;mov r2, %3; swi %a0"
: /* No outputs */
: "i"(SWI_Read), "r"(fh), "r"(ptr), "r"(len)
: "r0","r1","r2");
#endif
}
int
_read (int file,
char * ptr,
int len)
{
int slot = findslot (remap_handle (file));
int x = _swiread (file, ptr, len);
if (x < 0)
return error (-1);
if (slot != MAX_OPEN_FILES)
openfiles [slot].pos += len - x;
/* x == len is not an error, at least if we want feof() to work. */
return len - x;
}
int
_swilseek (int file,
int ptr,
int dir)
{
int res;
int fh = remap_handle (file);
int slot = findslot (fh);
#ifdef ARM_RDI_MONITOR
int block[2];
#endif
if (dir == SEEK_CUR)
{
if (slot == MAX_OPEN_FILES)
return -1;
ptr = openfiles[slot].pos + ptr;
dir = SEEK_SET;
}
#ifdef ARM_RDI_MONITOR
if (dir == SEEK_END)
{
block[0] = fh;
ptr += do_AngelSWI (AngelSWI_Reason_FLen, block);
}
/* This code only does absolute seeks. */
block[0] = remap_handle (file);
block[1] = ptr;
res = do_AngelSWI (AngelSWI_Reason_Seek, block);
#else
if (dir == SEEK_END)
{
asm ("mov r0, %2; swi %a1; mov %0, r0"
: "=r" (res)
: "i" (SWI_Flen), "r" (fh)
: "r0");
ptr += res;
}
/* This code only does absolute seeks. */
asm ("mov r0, %2; mov r1, %3; swi %a1; mov %0, r0"
: "=r" (res)
: "i" (SWI_Seek), "r" (fh), "r" (ptr)
: "r0", "r1");
#endif
if (slot != MAX_OPEN_FILES && res == 0)
openfiles[slot].pos = ptr;
/* This is expected to return the position in the file. */
return res == 0 ? ptr : -1;
}
int
_lseek (int file,
int ptr,
int dir)
{
return wrap (_swilseek (file, ptr, dir));
}
/* Returns #chars not! written. */
int
_swiwrite (
int file,
char * ptr,
int len)
{
int fh = remap_handle (file);
#ifdef ARM_RDI_MONITOR
int block[3];
block[0] = fh;
block[1] = (int) ptr;
block[2] = len;
return do_AngelSWI (AngelSWI_Reason_Write, block);
#else
asm ("mov r0, %1; mov r1, %2;mov r2, %3; swi %a0"
: /* No outputs */
: "i"(SWI_Write), "r"(fh), "r"(ptr), "r"(len)
: "r0","r1","r2");
#endif
}
int
_write (int file,
char * ptr,
int len) {
volatile AT91PS_USART pUart = AT91C_BASE_US0;
int l = len;
while(l--) {
if(*ptr == '\n') {
while(!(pUart->US_CSR & AT91C_US_TXRDY));
pUart->US_THR = '\r';
}
while(!(pUart->US_CSR & AT91C_US_TXRDY));
pUart->US_THR = *ptr;
if(*ptr == '\r') {
while(!(pUart->US_CSR & AT91C_US_TXRDY));
pUart->US_THR = '\n';
}
ptr++;
}
return len;
}
extern int strlen (const char *);
int
_swiopen (const char * path,
int flags)
{
int aflags = 0, fh;
#ifdef ARM_RDI_MONITOR
int block[3];
#endif
int i = findslot (-1);
if (i == MAX_OPEN_FILES)
return -1;
/* The flags are Unix-style, so we need to convert them. */
#ifdef O_BINARY
if (flags & O_BINARY)
aflags |= 1;
#endif
if (flags & O_RDWR)
aflags |= 2;
if (flags & O_CREAT)
aflags |= 4;
if (flags & O_TRUNC)
aflags |= 4;
if (flags & O_APPEND)
{
aflags &= ~4; /* Can't ask for w AND a; means just 'a'. */
aflags |= 8;
}
#ifdef ARM_RDI_MONITOR
block[0] = (int) path;
block[2] = strlen (path);
block[1] = aflags;
fh = do_AngelSWI (AngelSWI_Reason_Open, block);
#else
asm ("mov r0,%2; mov r1, %3; swi %a1; mov %0, r0"
: "=r"(fh)
: "i" (SWI_Open),"r"(path),"r"(aflags)
: "r0","r1");
#endif
if (fh >= 0)
{
openfiles[i].handle = fh;
openfiles[i].pos = 0;
}
return fh >= 0 ? fh + FILE_HANDLE_OFFSET : error (fh);
}
int
_open (const char * path,
int flags,
...)
{
return wrap (_swiopen (path, flags));
}
int
_swiclose (int file)
{
int myhan = remap_handle (file);
int slot = findslot (myhan);
if (slot != MAX_OPEN_FILES)
openfiles[slot].handle = -1;
#ifdef ARM_RDI_MONITOR
return do_AngelSWI (AngelSWI_Reason_Close, & myhan);
#else
asm ("mov r0, %1; swi %a0" :: "i" (SWI_Close),"r"(myhan):"r0");
#endif
}
int
_close (int file)
{
return wrap (_swiclose (file));
}
void
_exit (int n)
{
/* FIXME: return code is thrown away. */
#ifdef ARM_RDI_MONITOR
do_AngelSWI (AngelSWI_Reason_ReportException,
(void *) ADP_Stopped_ApplicationExit);
#else
asm ("swi %a0" :: "i" (SWI_Exit));
#endif
n = n;
while(1);
}
int
_kill (int n, int m)
{
#ifdef ARM_RDI_MONITOR
return do_AngelSWI (AngelSWI_Reason_ReportException,
(void *) ADP_Stopped_ApplicationExit);
#else
asm ("swi %a0" :: "i" (SWI_Exit));
#endif
n = n; m = m;
}
int
_getpid (int n)
{
return 1;
n = n;
}
caddr_t
_sbrk (int incr)
{
extern char end asm ("end"); /* Defined by the linker. */
static char * heap_end = NULL;
char * prev_heap_end;
if (heap_end == NULL)
heap_end = & end;
prev_heap_end = heap_end;
if (heap_end + incr > stack_ptr)
{
/* Some of the libstdc++-v3 tests rely upon detecting
out of memory errors, so do not abort here. */
#if 0
extern void abort (void);
_write (1, "_sbrk: Heap and stack collision\n", 32);
abort ();
#else
errno = ENOMEM;
return (caddr_t) -1;
#endif
}
heap_end += incr;
return (caddr_t) prev_heap_end;
}
extern void *memset (void *, int, size_t);
int
_fstat (int file, struct stat * st)
{
memset (st, 0, sizeof (* st));
st->st_mode = S_IFCHR;
st->st_blksize = 1024;
return 0;
file = file;
}
int _stat (const char *fname, struct stat *st)
{
int file;
/* The best we can do is try to open the file readonly. If it exists,
then we can guess a few things about it. */
if ((file = _open (fname, O_RDONLY)) < 0)
return -1;
memset (st, 0, sizeof (* st));
st->st_mode = S_IFREG | S_IREAD;
st->st_blksize = 1024;
_swiclose (file); /* Not interested in the error. */
return 0;
}
int
_link (void)
{
return -1;
}
int
_unlink (void)
{
return -1;
}
void
_raise (void)
{
return;
}
int
_gettimeofday (struct timeval * tp, struct timezone * tzp)
{
if (tp)
{
/* Ask the host for the seconds since the Unix epoch. */
#ifdef ARM_RDI_MONITOR
tp->tv_sec = do_AngelSWI (AngelSWI_Reason_Time,NULL);
#else
{
int value;
asm ("swi %a1; mov %0, r0" : "=r" (value): "i" (SWI_Time) : "r0");
tp->tv_sec = value;
}
#endif
tp->tv_usec = 0;
}
/* Return fixed data for the timezone. */
if (tzp)
{
tzp->tz_minuteswest = 0;
tzp->tz_dsttime = 0;
}
return 0;
}
/* Return a clock that ticks at 100Hz. */
clock_t
_times (struct tms * tp)
{
clock_t timeval;
#ifdef ARM_RDI_MONITOR
timeval = do_AngelSWI (AngelSWI_Reason_Clock,NULL);
#else
asm ("swi %a1; mov %0, r0" : "=r" (timeval): "i" (SWI_Clock) : "r0");
#endif
if (tp)
{
tp->tms_utime = timeval; /* user time */
tp->tms_stime = 0; /* system time */
tp->tms_cutime = 0; /* user time, children */
tp->tms_cstime = 0; /* system time, children */
}
return timeval;
};
int
isatty (int fd)
{
return 1;
fd = fd;
}
int
_isatty (int fd)
{
return 1;
fd = fd;
}
int
_system (const char *s)
{
if (s == NULL)
return 0;
errno = ENOSYS;
return -1;
}
int
_rename (const char * oldpath, const char * newpath)
{
errno = ENOSYS;
return -1;
}

547
tos.c Normal file
View File

@@ -0,0 +1,547 @@
#include "stdio.h"
#include "string.h"
#include "hardware.h"
#include "tos.h"
#include "fat.h"
#include "fpga.h"
#define TOS_BASE_ADDRESS_192k 0xfc0000
#define TOS_BASE_ADDRESS_256k 0xe00000
#define CART_BASE_ADDRESS 0xfa0000
#define VIDEO_BASE_ADDRESS 0x010000
unsigned long tos_system_ctrl = TOS_MEMCONFIG_4M;
static unsigned char font[2048]; // buffer for 8x16 atari font
static struct {
fileTYPE file;
unsigned char sides;
unsigned char spt;
} disk[2];
static unsigned char floppy_buffer[512];
static void mist_memory_set_address(unsigned long a) {
a >>= 1; // make word address
EnableFpga();
SPI(MIST_SET_ADDRESS);
SPI((a >> 24) & 0xff);
SPI((a >> 16) & 0xff);
SPI((a >> 8) & 0xff);
SPI((a >> 0) & 0xff);
DisableFpga();
}
static void mist_set_control(unsigned short ctrl) {
EnableFpga();
SPI(MIST_SET_CONTROL);
SPI((ctrl >> 8) & 0xff);
SPI((ctrl >> 0) & 0xff);
DisableFpga();
}
static void hexdump(void *data, unsigned long size, unsigned long offset) {
int i, b2c;
unsigned long n=0;
char *ptr = data;
if(!size) return;
while(size>0) {
iprintf("%08x: ", 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;
}
}
static void mist_memory_read(char *data, unsigned long words) {
EnableFpga();
SPI(MIST_READ_MEMORY);
// transmitted bytes must be multiple of 2 (-> words)
while(words--) {
*data++ = SPI(0);
*data++ = SPI(0);
}
DisableFpga();
}
static void mist_memory_write(char *data, unsigned long words) {
EnableFpga();
SPI(MIST_WRITE_MEMORY);
while(words--) {
SPI(*data++);
SPI(*data++);
}
DisableFpga();
}
void mist_memory_set(char data, unsigned long words) {
EnableFpga();
SPI(MIST_WRITE_MEMORY);
while(words--) {
SPI(data);
SPI(data);
}
DisableFpga();
}
static void mist_get_dmastate() {
static unsigned char buffer[10];
int i;
EnableFpga();
SPI(MIST_GET_DMASTATE);
for(i=0;i<10;i++)
buffer[i] = SPI(0);
DisableFpga();
// check if fdc is busy
if(buffer[8] & 1) {
// extract contents
unsigned int dma_address = 256 * 256 * buffer[0] + 256 * buffer[1] + buffer[2];
unsigned char scnt = buffer[3];
unsigned char fdc_cmd = buffer[4];
unsigned char fdc_track = buffer[5];
unsigned char fdc_sector = buffer[6];
unsigned char fdc_data = buffer[7];
unsigned char drv_sel = 3-((buffer[8]>>2)&3);
unsigned char drv_side = 1-((buffer[8]>>1)&1);
// check if a matching disk image has been inserted
if(drv_sel && disk[drv_sel-1].file.size) {
// if the fdc has been asked to write protect the disks, then
// write sector commands should never reach the oi controller
// read/write sector command
if((fdc_cmd & 0xc0) == 0x80) {
// convert track/sector/side into disk offset
unsigned int offset = drv_side;
offset += fdc_track * disk[drv_sel-1].sides;
offset *= disk[drv_sel-1].spt;
offset += fdc_sector-1;
while(scnt) {
DISKLED_ON;
FileSeek(&disk[drv_sel-1].file, offset, SEEK_SET);
mist_memory_set_address(dma_address);
if((fdc_cmd & 0xe0) == 0x80) {
// read from disk ...
FileRead(&disk[drv_sel-1].file, floppy_buffer);
// ... and copy to ram
mist_memory_write(floppy_buffer, 256);
} else {
// read from ram ...
mist_memory_read(floppy_buffer, 256);
// ... and write to disk
FileWrite(&(disk[drv_sel-1].file), floppy_buffer);
}
DISKLED_OFF;
scnt--;
dma_address += 512;
offset += 1;
}
EnableFpga();
SPI(MIST_ACK_DMA);
DisableFpga();
}
}
}
}
static void tos_clr() {
mist_memory_set_address(VIDEO_BASE_ADDRESS);
mist_memory_set(0, 16000);
}
// color test, used to test the shifter without CPU/TOS
#define COLORS 20
#define PLANES 4
static void tos_color_test() {
unsigned short buffer[COLORS][PLANES];
int y;
for(y=0;y<13;y++) {
int i, j;
for(i=0;i<COLORS;i++)
for(j=0;j<PLANES;j++)
buffer[i][j] = ((y+i) & (1<<j))?0xffff:0x0000;
for(i=0;i<16;i++) {
mist_memory_set_address(VIDEO_BASE_ADDRESS + (16*y+i)*160);
mist_memory_write((char*)buffer, COLORS*PLANES);
}
}
}
static void tos_write(char *str) {
static int y = 0;
int l;
int c = strlen(str);
{
char buffer[c];
// 16 pixel lines
for(l=0;l<16;l++) {
char *p = str, *f=buffer;
while(*p)
*f++ = font[16 * *p++ + l];
mist_memory_set_address(VIDEO_BASE_ADDRESS + 80*(y+l));
mist_memory_write(buffer, c/2);
}
}
y+=16;
}
static void tos_font_load() {
fileTYPE file;
if(FileOpen(&file,"SYSTEM FNT")) {
if(file.size == 4096) {
int i;
for(i=0;i<4;i++) {
FileRead(&file, font+i*512);
FileNextSector(&file);
}
tos_clr();
// tos_color_test();
tos_write("\016\017 MIST core \016\017 ");
} else
iprintf("SYSTEM.FNT has wrong size\n");
} else
iprintf("SYSTEM.FNT not found\n");
}
void tos_upload() {
// put cpu into reset
mist_set_control(tos_system_ctrl | TOS_CONTROL_CPU_RESET);
tos_font_load();
// do the MiST core handling
tos_write("Uploading TOS ... ");
iprintf("Uploading TOS ...\n");
DISKLED_ON;
// upload and verify tos image
fileTYPE file;
if(FileOpen(&file,"TOS IMG")) {
int i;
char buffer[512];
unsigned long time;
unsigned long tos_base = TOS_BASE_ADDRESS_192k;
iprintf("TOS.IMG:\n size = %d\n", file.size);
if(file.size == 256*1024)
tos_base = TOS_BASE_ADDRESS_256k;
else if(file.size != 192*1024)
iprintf("WARNING: Unexpected TOS size!\n");
int blocks = file.size / 512;
iprintf(" blocks = %d\n", blocks);
iprintf(" address = $%08x\n", tos_base);
// extract base address
FileRead(&file, buffer);
// clear first 16k
mist_memory_set_address(0);
mist_memory_set(0x00, 8192);
#if 0
iprintf("Erasing: ");
// clear memory to increase chances of catching write problems
mist_memory_set_address(tos_base);
mist_memory_set(0x00, file.size/2);
iprintf("done\n");
#endif
time = GetTimer(0);
iprintf("Uploading: [");
for(i=0;i<blocks;i++) {
FileRead(&file, buffer);
// copy first 8 bytes to address 0 as well
if(i == 0) {
mist_memory_set_address(0);
// write first 4 words
mist_memory_write(buffer, 4);
// set real tos base address
mist_memory_set_address(tos_base);
}
mist_memory_write(buffer, 256);
if(!(i & 7)) iprintf(".");
if(i != blocks-1)
FileNextSector(&file);
}
iprintf("]\n");
time = GetTimer(0) - time;
iprintf("TOS.IMG uploaded in %lu ms\r", time >> 20);
} else
iprintf("Unable to find tos.img\n");
#if 0
{
char rx[512], buffer[512];
int i,j;
int blocks = file.size / 512;
FileSeek(&file, 0, SEEK_SET);
mist_memory_set_address(TOS_BASE_ADDRESS);
iprintf("Verifying: [");
for(i=0;i<blocks;i++) {
FileRead(&file, buffer);
mist_memory_read(rx, 256);
if(!(i & 7)) iprintf("+");
for(j=0;j<512;j++) {
if(buffer[j] != rx[j]) {
iprintf("Verify error block %d, byte %x\n", i, j);
iprintf("should be:\n");
hexdump(buffer, 512, 0);
iprintf("is:\n");
hexdump(rx, 512, 0);
// try to re-read to check whether read or write failed
mist_memory_set_address(TOS_BASE_ADDRESS+i*512);
mist_memory_read(rx, 256);
iprintf("re-read: %s\n", (buffer[j] != rx[j])?"failed":"ok");
hexdump(rx, 512, 0);
while(1);
}
}
if(i != blocks-1)
FileNextSector(&file);
}
iprintf("]\n");
}
#endif
DISKLED_OFF;
// upload cartridge
if(FileOpen(&file,"CART IMG")) {
int i;
char buffer[512];
iprintf("CART.IMG:\n size = %d\n", file.size);
int blocks = file.size / 512;
iprintf(" blocks = %d\n", blocks);
iprintf("Uploading: [");
mist_memory_set_address(CART_BASE_ADDRESS);
DISKLED_ON;
for(i=0;i<blocks;i++) {
FileRead(&file, buffer);
mist_memory_write(buffer, 256);
if(!(i & 7)) iprintf(".");
if(i != blocks-1)
FileNextSector(&file);
}
DISKLED_OFF;
iprintf("]\n");
iprintf("CART.IMG uploaded\r");
} else {
iprintf("Unable to find cart.img\n");
// erase that ram area to remove any previously uploaded
// image
mist_memory_set_address(CART_BASE_ADDRESS);
mist_memory_set(0, 128*1024/2);
}
// try to open both floppies
int i;
for(i=0;i<2;i++) {
char name[] = "DISK_A ST ";
name[5] = 'A'+i;
fileTYPE file;
if(FileOpen(&file, name))
tos_insert_disk(i, &file);
}
tos_write("Booting ... ");
// let cpu run (release reset)
mist_set_control(tos_system_ctrl);
}
static unsigned long get_long(char *buffer, int offset) {
unsigned long retval = 0;
int i;
for(i=0;i<4;i++)
retval = (retval << 8) + *(unsigned char*)(buffer+offset+i);
return retval;
}
void tos_show_state() {
static unsigned long mtimer = 0;
mist_get_dmastate();
#if 0
if(CheckTimer(mtimer)) {
mtimer = GetTimer(2000);
int i;
char buffer[1024];
mist_memory_set_address(0);
mist_memory_read(buffer, 64);
hexdump(buffer, 128, 0);
// tos system varables are from $400
mist_memory_set_address(0x400);
mist_memory_read(buffer, 512);
iprintf("\n--- SYSTEM VARIABLES ---\n");
iprintf("memvalid: $%lx (should be $752019F3)\n", get_long(buffer,0x20));
iprintf("memcntrl: $%x (memory controller low nibble)\n", buffer[0x24]);
iprintf("phystop: $%lx (Physical RAM top)\n", get_long(buffer,0x2e));
iprintf("memval2: $%lx (should be $237698AA)\n", get_long(buffer,0x3a));
iprintf("sshiftmd: $%x (Shadow shiftmd, LMH/012)\n", buffer[0x4c]);
iprintf("_v_bas_ad: $%lx (Screen memory base)\n", get_long(buffer,0x4e));
iprintf("_vbclock: $%lx (vbl counter)\n", get_long(buffer,0x62));
iprintf("_dskbufp: $%lx (1k disk buffer)\n", get_long(buffer,0xc6));
iprintf("_frclock: $%lx (frame counter)\n", get_long(buffer,0x66));
iprintf("_hz_200: $%lx (Raw 200Hz timer)\n", get_long(buffer,0xba));
iprintf("_sysbase: $%lx (begin of tos)\n", get_long(buffer,0xf2));
}
#endif
}
void tos_update_sysctrl(unsigned long n) {
tos_system_ctrl = n;
mist_set_control(tos_system_ctrl);
}
char *tos_get_disk_name(char index) {
static char buffer[13]; // local buffer to assemble file name (8+3+2)
char *c;
if(!disk[index].file.size) {
strcpy(buffer, "* no disk *");
return buffer;
}
// copy and append nul
strncpy(buffer, disk[index].file.name, 8);
for(c=buffer+7;*c==' ';c--); c++;
*c++ = '.';
strncpy(c, disk[index].file.name+8, 3);
for(c+=2;*c==' ';c--); c++;
*c++='\0';
return buffer;
}
char tos_disk_is_inserted(char index) {
return (disk[index].file.size != 0);
}
void tos_insert_disk(char i, fileTYPE *file) {
iprintf("%c: eject\n", i+'A');
// toggle write protect bit to help tos detect a media change
int wp_bit = (!i)?TOS_CONTROL_FDC_WR_PROT_A:TOS_CONTROL_FDC_WR_PROT_B;
// any disk ejected is "write protected" (as nothing covers the write protect mechanism)
mist_set_control(tos_system_ctrl | wp_bit);
// first "eject" disk
disk[i].file.size = 0;
disk[i].sides = 1;
disk[i].spt = 0;
// no new disk given?
if(!file) return;
// open floppy
disk[i].file = *file;
iprintf("%c: insert %.11s\n", i+'A', disk[i].file.name);
// check image size and parameters
// check if image size suggests it's a two sided disk
if(disk[i].file.size > 80*9*512)
disk[i].sides = 2;
// try common sector/track values
int s, t;
for(s=9;s<=12;s++)
for(t=80;t<=85;t++)
if(512*s*t*disk[i].sides == disk[i].file.size)
disk[i].spt = s;
if(!disk[i].spt) {
iprintf("%c: image has unknown size\n", i+'A');
// todo: try to extract that info from the image itself
disk[i].file.size = 0;
} else {
// restore state of write protect bit
tos_update_sysctrl(tos_system_ctrl);
iprintf("%c: detected %d sides with %d sectors per track\n",
i+'A', disk[i].sides, disk[i].spt);
}
}

57
tos.h Normal file
View File

@@ -0,0 +1,57 @@
#ifndef TOS_H
#define TOS_H
#include "fat.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 // acknowledges 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
// 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 0x0001
#define TOS_CONTROL_FDC_WR_PROT_A 0x0040
#define TOS_CONTROL_FDC_WR_PROT_B 0x0080
#define TOS_CONTROL_VIDEO_COLOR 0x0100 // input to mfp
#define TOS_CONTROL_PAL50HZ 0x0200 // display pal at 50hz (56 hz otherwise)
extern unsigned long tos_system_ctrl;
void tos_upload();
void tos_show_state();
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, fileTYPE *file);
#endif

372
usb/hid.c Normal file
View File

@@ -0,0 +1,372 @@
#include <stdio.h>
#include "usb.h"
#include "max3421e.h"
#include "timer.h"
#include "../user_io.h"
static unsigned char kbd_led_state = 0; // default: all leds off
static void hexdump(void *data, int size) {
int i,n = 0, b2c;
char *ptr = data;
if(!size) return;
while(size>0) {
iprintf("%04x: ", n);
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;
}
}
//get HID report descriptor
static uint8_t hid_get_report_descr(usb_device_t *dev, uint8_t iface, uint16_t size) {
iprintf("%s(%x, if=%d, size=%d)\n", __FUNCTION__, dev->bAddress, iface, size);
uint8_t buf[size];
uint8_t rcode = usb_ctrl_req( dev, HID_REQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00,
HID_DESCRIPTOR_REPORT, iface, size, size, buf, NULL);
if(!rcode)
hexdump(buf, size);
return rcode;
}
static uint8_t hid_set_idle(usb_device_t *dev, uint8_t iface, uint8_t reportID, uint8_t duration ) {
iprintf("%s(%x, if=%d id=%d, dur=%d)\n", __FUNCTION__, dev->bAddress, iface, reportID, duration);
return( usb_ctrl_req( dev, HID_REQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID,
duration, iface, 0x0000, 0x0000, NULL, NULL ));
}
static uint8_t hid_set_protocol(usb_device_t *dev, uint8_t iface, uint8_t protocol) {
iprintf("%s(%x, if=%d proto=%d)\n", __FUNCTION__, dev->bAddress, iface, protocol);
return( usb_ctrl_req( dev, HID_REQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol,
0x00, iface, 0x0000, 0x0000, NULL, NULL ));
}
static uint8_t hid_set_report(usb_device_t *dev, uint8_t iface, uint8_t report_type, uint8_t report_id,
uint16_t nbytes, uint8_t* dataptr ) {
// iprintf("%s(%x, if=%d data=%x)\n", __FUNCTION__, dev->bAddress, iface, dataptr[0]);
return( usb_ctrl_req(dev, HID_REQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id,
report_type, iface, nbytes, nbytes, dataptr, NULL ));
}
/* todo: handle parsing in chunks */
static uint8_t usb_hid_parse_conf(usb_device_t *dev, uint8_t conf, uint16_t len) {
usb_hid_info_t *info = &(dev->hid_info);
uint8_t rcode;
bool isGoodInterface = false;
union buf_u {
usb_configuration_descriptor_t conf_desc;
usb_interface_descriptor_t iface_desc;
usb_endpoint_descriptor_t ep_desc;
usb_hid_descriptor_t hid_desc;
uint8_t raw[len];
} buf, *p;
// usb_interface_descriptor
if(rcode = usb_get_conf_descr(dev, len, conf, &buf.conf_desc))
return rcode;
/* scan through all descriptors */
p = &buf;
while(len > 0) {
switch(p->conf_desc.bDescriptorType) {
case USB_DESCRIPTOR_CONFIGURATION:
iprintf("conf descriptor size %d\n", p->conf_desc.bLength);
// we already had this, so we simply ignore it
break;
case USB_DESCRIPTOR_INTERFACE:
isGoodInterface = false;
iprintf("iface descriptor size %d\n", p->iface_desc.bLength);
/* check the interface descriptors for supported class */
// only HID interfaces are supported
if(p->iface_desc.bInterfaceClass == USB_CLASS_HID) {
puts("iface is HID");
if(info->bNumIfaces < MAX_IFACES) {
// ok, let's use this interface
isGoodInterface = true;
info->iface_info[info->bNumIfaces].iface_idx = p->iface_desc.bInterfaceNumber;
info->iface_info[info->bNumIfaces].has_boot_mode = false;
info->iface_info[info->bNumIfaces].device_type = HID_DEVICE_UNKNOWN;
if(p->iface_desc.bInterfaceSubClass == HID_BOOT_INTF_SUBCLASS) {
iprintf("Iface %d is Boot sub class\n", info->bNumIfaces);
info->iface_info[info->bNumIfaces].has_boot_mode = true;
// enable boot mode
hid_set_protocol(dev, info->iface_info[info->bNumIfaces].iface_idx, HID_BOOT_PROTOCOL);
}
switch(p->iface_desc.bInterfaceProtocol) {
case HID_PROTOCOL_NONE:
iprintf("HID protocol is NONE\n");
break;
case HID_PROTOCOL_KEYBOARD:
iprintf("HID protocol is KEYBOARD\n");
info->iface_info[info->bNumIfaces].device_type = HID_DEVICE_KEYBOARD;
// hid_set_report(dev, info->iface_info[info->bNumIfaces].iface_idx, 2, 0, 1, &kbd_led_state);
break;
case HID_PROTOCOL_MOUSE:
iprintf("HID protocol is MOUSE\n");
info->iface_info[info->bNumIfaces].device_type = HID_DEVICE_MOUSE;
break;
default:
iprintf("HID protocol is %d\n", p->iface_desc.bInterfaceProtocol);
break;
}
}
}
break;
case USB_DESCRIPTOR_ENDPOINT:
iprintf("endpoint descriptor size %d\n", p->ep_desc.bLength);
if(isGoodInterface) {
// only interrupt in endpoints are supported
if ((p->ep_desc.bmAttributes & 0x03) == 3 && (p->ep_desc.bEndpointAddress & 0x80) == 0x80) {
iprintf("endpint %d, interval = %dms\n",
p->ep_desc.bEndpointAddress & 0x0F, p->ep_desc.bInterval);
// Fill in the endpoint info structure
uint8_t epidx = info->bNumIfaces;
info->ep[epidx].epAddr = (p->ep_desc.bEndpointAddress & 0x0F);
info->ep[epidx].maxPktSize = p->ep_desc.wMaxPacketSize[0];
info->ep[epidx].epAttribs = 0;
info->ep[epidx].bmNakPower = USB_NAK_NOWAIT;
info->bNumIfaces++;
}
}
break;
case HID_DESCRIPTOR_HID:
iprintf("hid descriptor size %d\n", p->ep_desc.bLength);
if(isGoodInterface) {
// we need a report descriptor
if(p->hid_desc.bDescrType == HID_DESCRIPTOR_REPORT) {
uint16_t len = p->hid_desc.wDescriptorLength[0] +
256 * p->hid_desc.wDescriptorLength[1];
iprintf(" -> report descriptor size = %d\n", len);
info->iface_info[info->bNumIfaces].report_size = len;
}
}
break;
default:
iprintf("unsupported descriptor type %d size %d\n", p->raw[1], p->raw[0]);
}
// advance to next descriptor
len -= p->conf_desc.bLength;
p = (union buf_u*)(p->raw + p->conf_desc.bLength);
}
if(len != 0) {
iprintf("URGS, underrun: %d\n", len);
return USB_ERROR_CONFIGURAION_SIZE_MISMATCH;
}
iprintf("done\n");
return 0;
}
static uint8_t usb_hid_init(usb_device_t *dev) {
iprintf("%s()\n", __FUNCTION__);
iprintf("init with address %x\n", dev->bAddress);
uint8_t rcode;
uint8_t i;
usb_hid_info_t *info = &(dev->hid_info);
union {
usb_device_descriptor_t dev_desc;
usb_configuration_descriptor_t conf_desc;
} buf;
// reset status
info->qNextPollTime = 0;
info->bPollEnable = false;
info->bNumIfaces = 0;
for(i=0;i<MAX_IFACES;i++) {
info->ep[i].epAddr = i;
info->ep[i].maxPktSize = 8;
info->ep[i].epAttribs = 0;
info->ep[i].bmNakPower = USB_NAK_MAX_POWER;
}
// try to re-read full device descriptor from newly assigned address
if(rcode = usb_get_dev_descr( dev, sizeof(usb_device_descriptor_t), &buf.dev_desc )) {
puts("failed to get device descriptor");
return rcode;
}
uint8_t num_of_conf = buf.dev_desc.bNumConfigurations;
iprintf("number of configurations: %d\n", num_of_conf);
for(i=0; i<num_of_conf; i++) {
if(rcode = usb_get_conf_descr(dev, sizeof(usb_configuration_descriptor_t), i, &buf.conf_desc))
return rcode;
iprintf("conf descriptor %d has total size %d\n", i, buf.conf_desc.wTotalLength);
// extract number of interfaces
iprintf("number of interfaces: %d\n", buf.conf_desc.bNumInterfaces);
// parse directly if it already fitted completely into the buffer
usb_hid_parse_conf(dev, i, buf.conf_desc.wTotalLength);
}
// check if we found valid hid interfaces
if(!info->bNumIfaces) {
puts("no hid interfaces found");
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
}
// Set Configuration Value
iprintf("conf value = %d\n", buf.conf_desc.bConfigurationValue);
rcode = usb_set_conf(dev, buf.conf_desc.bConfigurationValue);
// process all supported interfaces
for(i=0; i<info->bNumIfaces; i++) {
rcode = hid_get_report_descr(dev,
info->iface_info[i].iface_idx, info->iface_info[i].report_size);
if (rcode)
return rcode;
rcode = hid_set_idle(dev, info->iface_info[i].iface_idx, 0, 0);
if (rcode && rcode != hrSTALL)
return rcode;
}
puts("HID configured");
// update leds
for(i=0;i<MAX_IFACES;i++)
if(dev->hid_info.iface_info[i].device_type == HID_DEVICE_KEYBOARD)
hid_set_report(dev, dev->hid_info.iface_info[i].iface_idx, 2, 0, 1, &kbd_led_state);
info->bPollEnable = true;
return 0;
}
static uint8_t usb_hid_release(usb_device_t *dev) {
puts(__FUNCTION__);
return 0;
}
static uint8_t usb_hid_poll(usb_device_t *dev) {
usb_hid_info_t *info = &(dev->hid_info);
if (!info->bPollEnable)
return 0;
if (info->qNextPollTime <= timer_get_msec()) {
int8_t i;
for(i=0;i<info->bNumIfaces;i++) {
// iprintf("poll %d...\n", info->ep[i].epAddr);
uint16_t read = info->ep[i].maxPktSize;
uint8_t buf[32];
uint8_t rcode =
usb_in_transfer(dev, &(info->ep[i]), &read, buf);
if (rcode) {
if (rcode != hrNAK)
iprintf("%s() error: %d %d\n", __FUNCTION__, rcode, timer_get_msec());
// else
// puts("nak");
} else {
// iprintf("interface %d: received %d bytes\n", i, read);
// successfully received some bytes
if(info->iface_info[i].has_boot_mode) {
if(info->iface_info[i].device_type == HID_DEVICE_MOUSE) {
// boot mouse needs at least three bytes
if(read >= 3) {
// forward all three bytes to the user_io layer
user_io_mouse(buf[0], buf[1], buf[2]);
}
}
if(info->iface_info[i].device_type == HID_DEVICE_KEYBOARD) {
// boot kbd needs at least eight bytes
if(read >= 8) {
user_io_kbd(buf[0], buf+2);
}
}
}
}
}
info->qNextPollTime = timer_get_msec() + 20; // poll 50 times a second
}
return 0;
}
void hid_set_kbd_led(unsigned char led, bool on) {
// check if led state has changed
if( (on && !(kbd_led_state&led)) || (!on && (kbd_led_state&led))) {
if(on) kbd_led_state |= led;
else kbd_led_state &= ~led;
// search for all keyboard interfaces on all hid devices
usb_device_t *dev = usb_get_devices();
int i;
for(i=0;i<USB_NUMDEVICES;i++) {
if(dev[i].bAddress && (dev[i].class == &usb_hid_class)) {
// search for keyboard interfaces
int j;
for(j=0;j<MAX_IFACES;j++)
if(dev[i].hid_info.iface_info[j].device_type == HID_DEVICE_KEYBOARD)
hid_set_report(dev+i, dev[i].hid_info.iface_info[j].iface_idx, 2, 0, 1, &kbd_led_state);
}
}
}
}
const usb_device_class_config_t usb_hid_class = {
usb_hid_init, usb_hid_release, usb_hid_poll };

79
usb/hid.h Normal file
View File

@@ -0,0 +1,79 @@
#ifndef HID_H
#define HID_H
#include <stdbool.h>
#include <inttypes.h>
#define HID_LED_NUM_LOCK 0x01
#define HID_LED_CAPS_LOCK 0x02
#define HID_LED_SCROLL_LOCK 0x04
/* HID constants. Not part of chapter 9 */
/* Class-Specific Requests */
#define HID_REQUEST_GET_REPORT 0x01
#define HID_REQUEST_GET_IDLE 0x02
#define HID_REQUEST_GET_PROTOCOL 0x03
#define HID_REQUEST_SET_REPORT 0x09
#define HID_REQUEST_SET_IDLE 0x0A
#define HID_REQUEST_SET_PROTOCOL 0x0B
#define HID_DESCRIPTOR_HID 0x21
#define HID_DESCRIPTOR_REPORT 0x22
#define HID_DESRIPTOR_PHY 0x23
/* Protocol Selection */
#define HID_BOOT_PROTOCOL 0x00
#define HID_RPT_PROTOCOL 0x01
/* HID Interface Class SubClass Codes */
#define HID_BOOT_INTF_SUBCLASS 0x01
#define HID_PROTOCOL_NONE 0x00
#define HID_PROTOCOL_KEYBOARD 0x01
#define HID_PROTOCOL_MOUSE 0x02
#define HID_REQ_HIDREPORT USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE
#define HID_REQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define MAX_IFACES 2 // max supported interfaces per device. 2 to support kbd/mouse combos
#define HID_DEVICE_UNKNOWN 0
#define HID_DEVICE_MOUSE 1
#define HID_DEVICE_KEYBOARD 2
typedef struct {
uint8_t iface_idx;
uint16_t report_size;
uint8_t device_type;
bool has_boot_mode; // device supports boot mode
} usb_hid_iface_info_t;
typedef struct {
ep_t ep[MAX_IFACES]; // interrupt endpoint info structure
uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag
uint8_t bNumIfaces;
usb_hid_iface_info_t iface_info[MAX_IFACES];
} usb_hid_info_t;
/* HID descriptor */
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdHID; // HID class specification release
uint8_t bCountryCode;
uint8_t bNumDescriptors; // Number of additional class specific descriptors
uint8_t bDescrType; // Type of class descriptor
uint8_t wDescriptorLength[2]; // Total size of the Report descriptor
} __attribute__((packed)) usb_hid_descriptor_t;
// interface to usb core
extern const usb_device_class_config_t usb_hid_class;
void hid_set_kbd_led(unsigned char led, bool on);
#endif // HID_H

283
usb/hub.c Normal file
View File

@@ -0,0 +1,283 @@
#include <stdio.h>
#include "usb.h"
#include "timer.h"
static uint8_t usb_hub_clear_hub_feature(usb_device_t *dev, uint8_t fid ) {
return( usb_ctrl_req( dev, USB_HUB_REQ_CLEAR_HUB_FEATURE,
USB_REQUEST_CLEAR_FEATURE, fid, 0, 0, 0, 0, NULL, NULL ));
}
// Clear Port Feature
static uint8_t usb_hub_clear_port_feature(usb_device_t *dev, uint8_t fid, uint8_t port, uint8_t sel ) {
return( usb_ctrl_req( dev , USB_HUB_REQ_CLEAR_PORT_FEATURE,
USB_REQUEST_CLEAR_FEATURE, fid, 0, ((0x0000|port)|(sel<<8)), 0, 0, NULL, NULL ));
}
// Get Hub Descriptor
static uint8_t usb_hub_get_hub_descriptor(usb_device_t *dev, uint8_t index,
uint16_t nbytes, usb_hub_descriptor_t *dataptr ) {
return( usb_ctrl_req( dev, USB_HUB_REQ_GET_HUB_DESCRIPTOR,
USB_REQUEST_GET_DESCRIPTOR, index, 0x29, 0, nbytes, nbytes,
(uint8_t*)dataptr, NULL ));
}
// Set Port Feature
static uint8_t usb_hub_set_port_feature(usb_device_t *dev, uint8_t fid, uint8_t port, uint8_t sel ) {
return( usb_ctrl_req( dev, USB_HUB_REQ_SET_PORT_FEATURE,
USB_REQUEST_SET_FEATURE, fid, 0, (((0x0000|sel)<<8)|port), 0, 0, NULL, NULL ));
}
// Get Port Status
static uint8_t usb_hub_get_port_status(usb_device_t *dev, uint8_t port, uint16_t nbytes, uint8_t* dataptr ) {
return( usb_ctrl_req( dev, USB_HUB_REQ_GET_PORT_STATUS,
USB_REQUEST_GET_STATUS, 0, 0, port, nbytes, nbytes, dataptr, NULL ));
}
static uint8_t usb_hub_init(usb_device_t *dev) {
iprintf("%s()\n", __FUNCTION__);
uint8_t rcode;
uint8_t i;
usb_hub_info_t *info = &(dev->hub_info);
union {
usb_device_descriptor_t dev_desc;
usb_configuration_descriptor_t conf_desc;
usb_hub_descriptor_t hub_desc;
} buf;
// reset status
info->bNbrPorts = 0;
info->qNextPollTime = 0;
info->bPollEnable = false;
info->ep.epAddr = 1;
info->ep.maxPktSize = 8; //kludge
info->ep.epAttribs = 0;
info->ep.bmNakPower = USB_NAK_NOWAIT;
rcode = usb_get_dev_descr( dev, 8, &buf.dev_desc );
if( rcode ) {
puts("failed to get device descriptor 1");
return rcode;
}
// Extract device class from device descriptor
// If device class is not a hub return
if (buf.dev_desc.bDeviceClass != USB_CLASS_HUB) {
puts("not a hub!");
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
}
// try to re-read full device descriptor from newly assigned address
if(rcode = usb_get_dev_descr( dev, sizeof(usb_device_descriptor_t), &buf.dev_desc )) {
puts("failed to get device descriptor 2");
return rcode;
}
// Get hub descriptor
rcode = usb_hub_get_hub_descriptor(dev, 0, 8, &buf.hub_desc);
if (rcode) {
puts("failed to get hub descriptor");
return rcode;
}
// Save number of ports for future use
info->bNbrPorts = buf.hub_desc.bNbrPorts;
// Read configuration Descriptor in Order To Obtain Proper Configuration Value
rcode = usb_get_conf_descr(dev, sizeof(usb_configuration_descriptor_t), 0, &buf.conf_desc);
if (rcode) {
puts("failed to read configuration descriptor");
return rcode;
}
// Set Configuration Value
rcode = usb_set_conf(dev, buf.conf_desc.bConfigurationValue);
if (rcode) {
iprintf("failed to set configuration to %d\n", buf.conf_desc.bConfigurationValue);
return rcode;
}
// Power on all ports
for (i=1; i<=info->bNbrPorts; i++)
usb_hub_set_port_feature(dev, HUB_FEATURE_PORT_POWER, i, 0); // HubPortPowerOn(i);
if(!dev->parent)
usb_SetHubPreMask();
info->bPollEnable = true;
return 0;
}
static uint8_t usb_hub_release(usb_device_t *dev) {
puts(__FUNCTION__);
// root hub unplugged
if(!dev->parent)
usb_ResetHubPreMask();
return 0;
}
static void usb_hub_show_port_status(uint8_t port, uint16_t status, uint16_t changed) {
iprintf("Status of port %d:\n", port);
if(status & USB_HUB_PORT_STATUS_PORT_CONNECTION) puts(" connected");
if(status & USB_HUB_PORT_STATUS_PORT_ENABLE) puts(" enabled");
if(status & USB_HUB_PORT_STATUS_PORT_SUSPEND) puts(" suspended");
if(status & USB_HUB_PORT_STATUS_PORT_OVER_CURRENT) puts(" over current");
if(status & USB_HUB_PORT_STATUS_PORT_RESET) puts(" reset");
if(status & USB_HUB_PORT_STATUS_PORT_POWER) puts(" powered");
if(status & USB_HUB_PORT_STATUS_PORT_LOW_SPEED) puts(" low speed");
if(status & USB_HUB_PORT_STATUS_PORT_HIGH_SPEED) puts(" high speed");
if(status & USB_HUB_PORT_STATUS_PORT_TEST) puts(" test");
if(status & USB_HUB_PORT_STATUS_PORT_INDICATOR) puts(" indicator");
iprintf("Changes on port %d:\n", port);
if(changed & USB_HUB_PORT_STATUS_PORT_CONNECTION) puts(" connected");
if(changed & USB_HUB_PORT_STATUS_PORT_ENABLE) puts(" enabled");
if(changed & USB_HUB_PORT_STATUS_PORT_SUSPEND) puts(" suspended");
if(changed & USB_HUB_PORT_STATUS_PORT_OVER_CURRENT) puts(" over current");
if(changed & USB_HUB_PORT_STATUS_PORT_RESET) puts(" reset");
}
static uint8_t usb_hub_port_status_change(usb_device_t *dev, uint8_t port, hub_event_t evt) {
usb_hub_info_t *info = &(dev->hub_info);
iprintf("status change on port %d, 0x%x\n", port, evt.bmEvent);
usb_hub_show_port_status(port, evt.bmStatus, evt.bmChange);
static bool bResetInitiated = false;
switch (evt.bmEvent) {
// Device connected event
case USB_HUB_PORT_EVENT_CONNECT:
case USB_HUB_PORT_EVENT_LS_CONNECT:
iprintf(" dev %x: port %d connect!\n", dev->bAddress, port);
if (bResetInitiated) {
iprintf("reset already in progress\n");
return 0;
}
// timer_delay_msec(100);
iprintf("resetting port %d\n", port);
usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_ENABLE, port, 0);
usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_CONNECTION, port, 0);
usb_hub_set_port_feature(dev, HUB_FEATURE_PORT_RESET, port, 0);
bResetInitiated = true;
return HUB_ERROR_PORT_HAS_BEEN_RESET;
// Device disconnected event
case USB_HUB_PORT_EVENT_DISCONNECT:
iprintf(" port %d disconnect!\n", port);
usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_ENABLE, port, 0);
usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_CONNECTION, port, 0);
bResetInitiated = false;
usb_release_device(dev->bAddress, port);
return 0;
// Reset complete event
case USB_HUB_PORT_EVENT_RESET_COMPLETE:
case USB_HUB_PORT_EVENT_LS_RESET_COMPLETE:
iprintf(" port %d reset complete!\n", port);
usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_RESET, port, 0);
usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_CONNECTION, port, 0);
usb_configure(dev->bAddress, port,
(evt.bmStatus & USB_HUB_PORT_STATUS_PORT_LOW_SPEED)!=0 );
bResetInitiated = false;
break;
}
return 0;
}
static uint8_t usb_hub_check_hub_status(usb_device_t *dev, uint8_t ports) {
usb_hub_info_t *info = &(dev->hub_info);
uint8_t rcode;
uint8_t buf[8];
uint16_t read = 1;
// iprintf("%s(addr=%x)\n", __FUNCTION__, addr);
rcode = usb_in_transfer(dev, &(info->ep), &read, buf);
if(rcode)
return rcode;
uint8_t port, mask;
for(port=1,mask=0x02; port<8; mask<<=1, port++) {
if (buf[0] & mask) {
hub_event_t evt;
evt.bmEvent = 0;
// TODO XXXX: try sizeof(evt.evtBuff)
rcode = usb_hub_get_port_status(dev, port, 4, evt.evtBuff);
if (rcode)
continue;
rcode = usb_hub_port_status_change(dev, port, evt);
if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
return 0;
if (rcode)
return rcode;
}
} // for
for (port=1; port<=ports; port++) {
hub_event_t evt;
evt.bmEvent = 0;
rcode = usb_hub_get_port_status(dev, port, 4, evt.evtBuff);
if (rcode)
continue;
if ((evt.bmStatus & USB_HUB_PORT_STATE_CHECK_DISABLED) != USB_HUB_PORT_STATE_DISABLED)
continue;
// Emulate connection event for the port
evt.bmChange |= USB_HUB_PORT_STATUS_PORT_CONNECTION;
rcode = usb_hub_port_status_change(dev, port, evt);
if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
return 0;
if (rcode)
return rcode;
}
return 0;
}
static uint8_t usb_hub_poll(usb_device_t *dev) {
usb_hub_info_t *info = &(dev->hub_info);
uint8_t rcode = 0;
if (!info->bPollEnable)
return 0;
if (info->qNextPollTime <= timer_get_msec()) {
rcode = usb_hub_check_hub_status(dev, info->bNbrPorts);
info->qNextPollTime = timer_get_msec() + 100; // poll 10 times a second
}
return rcode;
}
const usb_device_class_config_t usb_hub_class = {
usb_hub_init, usb_hub_release, usb_hub_poll };

109
usb/hub.h Normal file
View File

@@ -0,0 +1,109 @@
#ifndef HUB_H
#define HUB_H
#include <stdbool.h>
#include <inttypes.h>
typedef struct {
uint8_t bNbrPorts; // number of ports
uint32_t qNextPollTime; // next poll time
bool bPollEnable; // poll enable flag
ep_t ep; // interrupt endpoint info structure
} usb_hub_info_t;
// Hub Requests
#define USB_HUB_REQ_CLEAR_HUB_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define USB_HUB_REQ_CLEAR_PORT_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define USB_HUB_REQ_CLEAR_TT_BUFFER USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define USB_HUB_REQ_GET_HUB_DESCRIPTOR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define USB_HUB_REQ_GET_HUB_STATUS USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define USB_HUB_REQ_GET_PORT_STATUS USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define USB_HUB_REQ_RESET_TT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define USB_HUB_REQ_SET_HUB_DESCRIPTOR USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define USB_HUB_REQ_SET_HUB_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define USB_HUB_REQ_SET_PORT_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define USB_HUB_REQ_GET_TT_STATE USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
#define USB_HUB_REQ_STOP_TT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
// Hub Features
#define HUB_FEATURE_C_HUB_LOCAL_POWER 0
#define HUB_FEATURE_C_HUB_OVER_CURRENT 1
#define HUB_FEATURE_PORT_CONNECTION 0
#define HUB_FEATURE_PORT_ENABLE 1
#define HUB_FEATURE_PORT_SUSPEND 2
#define HUB_FEATURE_PORT_OVER_CURRENT 3
#define HUB_FEATURE_PORT_RESET 4
#define HUB_FEATURE_PORT_POWER 8
#define HUB_FEATURE_PORT_LOW_SPEED 9
#define HUB_FEATURE_C_PORT_CONNECTION 16
#define HUB_FEATURE_C_PORT_ENABLE 17
#define HUB_FEATURE_C_PORT_SUSPEND 18
#define HUB_FEATURE_C_PORT_OVER_CURRENT 19
#define HUB_FEATURE_C_PORT_RESET 20
#define HUB_FEATURE_PORT_TEST 21
#define HUB_FEATURE_PORT_INDICATOR 22
// Additional Error Codes
#define HUB_ERROR_PORT_HAS_BEEN_RESET 0xb1
// Hub Port Status Bitmasks
#define USB_HUB_PORT_STATUS_PORT_CONNECTION 0x0001
#define USB_HUB_PORT_STATUS_PORT_ENABLE 0x0002
#define USB_HUB_PORT_STATUS_PORT_SUSPEND 0x0004
#define USB_HUB_PORT_STATUS_PORT_OVER_CURRENT 0x0008
#define USB_HUB_PORT_STATUS_PORT_RESET 0x0010
#define USB_HUB_PORT_STATUS_PORT_POWER 0x0100
#define USB_HUB_PORT_STATUS_PORT_LOW_SPEED 0x0200
#define USB_HUB_PORT_STATUS_PORT_HIGH_SPEED 0x0400
#define USB_HUB_PORT_STATUS_PORT_TEST 0x0800
#define USB_HUB_PORT_STATUS_PORT_INDICATOR 0x1000
// Bit mask to check for DISABLED state in HubEvent::bmStatus field
#define USB_HUB_PORT_STATE_CHECK_DISABLED (USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_SUSPEND)
// Hub Port States
#define USB_HUB_PORT_STATE_DISABLED (USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_CONNECTION)
// Hub Port Events
#define USB_HUB_PORT_EVENT_CONNECT (((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION) << 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_CONNECTION)
#define USB_HUB_PORT_EVENT_DISCONNECT (((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION) << 16) | USB_HUB_PORT_STATUS_PORT_POWER)
#define USB_HUB_PORT_EVENT_RESET_COMPLETE (((0UL | USB_HUB_PORT_STATUS_PORT_RESET) << 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION)
#define USB_HUB_PORT_EVENT_LS_CONNECT (((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION) << 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_LOW_SPEED)
#define USB_HUB_PORT_EVENT_LS_RESET_COMPLETE (((0UL | USB_HUB_PORT_STATUS_PORT_RESET) << 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_LOW_SPEED)
#define USB_HUB_PORT_EVENT_LS_PORT_ENABLED (((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_ENABLE) << 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_LOW_SPEED)
typedef struct {
uint8_t bDescLength; // descriptor length
uint8_t bDescriptorType; // descriptor type
uint8_t bNbrPorts; // number of ports a hub equiped with
struct {
uint16_t LogPwrSwitchMode : 2;
uint16_t CompoundDevice : 1;
uint16_t OverCurrentProtectMode : 2;
uint16_t TTThinkTime : 2;
uint16_t PortIndicatorsSupported : 1;
uint16_t Reserved : 8;
} __attribute__((packed));
uint8_t bPwrOn2PwrGood;
uint8_t bHubContrCurrent;
} __attribute__((packed)) usb_hub_descriptor_t;
typedef struct {
union {
struct {
uint16_t bmStatus; // port status bits
uint16_t bmChange; // port status change bits
} __attribute__((packed));
uint32_t bmEvent;
uint8_t evtBuff[4];
} __attribute__((packed));
}__attribute__((packed)) hub_event_t;
// interface to usb core
extern const usb_device_class_config_t usb_hub_class;
#endif // HUB_H

219
usb/max3421e.c Normal file
View File

@@ -0,0 +1,219 @@
#include <stdio.h>
#include "max3421e.h"
#include "timer.h"
#include "spi.h"
static void hexdump(void *data, int size) {
int i,n = 0, b2c;
char *ptr = data;
if(!size) return;
while(size>0) {
iprintf("%04x: ", n);
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;
}
}
void max3421e_write_u08(uint8_t reg, uint8_t data) {
// iprintf("write %x %x\n", reg, data);
spi_start(0);
spi_xmit(reg | MAX3421E_WRITE);
spi_xmit(data);
spi_end();
}
uint8_t max3421e_read_u08(uint8_t reg) {
spi_start(0);
spi_xmit(reg);
uint8_t ret = spi_xmit(0);
spi_end();
return ret;
}
uint8_t *max3421e_write(uint8_t reg, uint8_t n, uint8_t* data) {
// hexdump(data, n);
spi_start(0);
spi_xmit(reg | MAX3421E_WRITE);
while(n--) spi_xmit(*data++);
spi_end();
return data;
}
uint8_t *max3421e_read(uint8_t reg, uint8_t n, uint8_t* data) {
spi_start(0);
spi_xmit(reg);
while(n--) *data++ = spi_xmit(0);
spi_end();
return data;
}
static uint8_t vbusState = MAX3421E_STATE_SE0;
uint16_t max3421e_reset() {
uint16_t i = 0;
/* reset chip */
max3421e_write_u08( MAX3421E_USBCTL, MAX3421E_CHIPRES );
max3421e_write_u08( MAX3421E_USBCTL, 0 );
/* wait for pll to synchronize */
while( ++i ) {
if(( max3421e_read_u08( MAX3421E_USBIRQ ) & MAX3421E_OSCOKIRQ )) {
return i;
}
}
return 0;
}
void max3421e_busprobe() {
iprintf("busprobe()\n");
uint8_t bus_sample = max3421e_read_u08( MAX3421E_HRSL ); // Get J,K status
bus_sample &= ( MAX3421E_JSTATUS | MAX3421E_KSTATUS ); // zero the rest of the byte
switch( bus_sample ) { // start full-speed or low-speed host
case MAX3421E_JSTATUS:
if( !(max3421e_read_u08( MAX3421E_MODE ) & MAX3421E_LOWSPEED) ) {
max3421e_write_u08( MAX3421E_MODE, MAX3421E_MODE_FS_HOST );
vbusState = MAX3421E_STATE_FSHOST;
} else {
max3421e_write_u08( MAX3421E_MODE, MAX3421E_MODE_LS_HOST);
vbusState = MAX3421E_STATE_LSHOST;
}
break;
case MAX3421E_KSTATUS:
if( !(max3421e_read_u08( MAX3421E_MODE ) & MAX3421E_LOWSPEED) ) {
max3421e_write_u08( MAX3421E_MODE, MAX3421E_MODE_LS_HOST );
vbusState = MAX3421E_STATE_LSHOST;
} else {
max3421e_write_u08( MAX3421E_MODE, MAX3421E_MODE_FS_HOST );
vbusState = MAX3421E_STATE_FSHOST;
}
break;
case MAX3421E_SE1: // illegal state
vbusState = MAX3421E_STATE_SE1;
break;
case MAX3421E_SE0: // disconnected state
max3421e_write_u08( MAX3421E_MODE, MAX3421E_DPPULLDN | MAX3421E_DMPULLDN | MAX3421E_HOST | MAX3421E_SEPIRQ);
vbusState = MAX3421E_STATE_SE0;
break;
}
}
void max3421e_init() {
iprintf("max3421e_init()\n");
timer_init();
spi_init();
// switch to full duplex mode
max3421e_write_u08(MAX3421E_PINCTL, MAX3421E_FDUPSPI | MAX3421E_INTLEVEL);
// read and output version
iprintf("Chip revision: %x\n", max3421e_read_u08(MAX3421E_REVISION));
if( max3421e_reset() == 0 ) {
iprintf("pll init failed\n");
return;
}
// enable pulldowns, set host mode
max3421e_write_u08( MAX3421E_MODE, MAX3421E_DPPULLDN | MAX3421E_DMPULLDN | MAX3421E_HOST );
// enable interrupts
// max3421e_write_u08( MAX3421E_HIEN, MAX3421E_CONDETIE| MAX3421E_FRAMEIE );
max3421e_write_u08( MAX3421E_HIEN, MAX3421E_CONDETIE );
/* check if device is connected */
// sample USB bus
max3421e_write_u08( MAX3421E_HCTL,MAX3421E_SAMPLEBUS );
// wait for sample operation to finish
while(!(max3421e_read_u08( MAX3421E_HCTL ) & MAX3421E_SAMPLEBUS ));
// check if anything is connected
max3421e_busprobe();
// clear connection detect interrupt
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_CONDETIRQ );
// enable interrupts
max3421e_write_u08( MAX3421E_CPUCTL, MAX3421E_IE );
return;
}
#include "timer.h"
uint8_t max3421e_poll() {
uint8_t hirq = max3421e_read_u08( MAX3421E_HIRQ );
#if 0
static msec_t next = 0;
if(timer_get_msec() > next) {
iprintf("irq src=%x, bus state %x\n", hirq, vbusState);
iprintf("host result %x\n", max3421e_read_u08( MAX3421E_HRSL));
next = timer_get_msec() + 10000;
}
#endif
if( hirq & MAX3421E_CONDETIRQ ) {
iprintf("=> CONDETIRQ\n");
max3421e_busprobe();
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_CONDETIRQ );
}
if( hirq & MAX3421E_BUSEVENTIRQ) {
iprintf("=> BUSEVENTIRQ\n");
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_BUSEVENTIRQ );
}
if( hirq & MAX3421E_SNDBAVIRQ) {
// iprintf("=> MAX3421E_SNDBAVIRQ\n");
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_SNDBAVIRQ);
}
if( hirq & MAX3421E_FRAMEIRQ) {
// iprintf("=> MAX3421E_FRAMEIRQ\n");
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_FRAMEIRQ);
}
#if 0
int i;
for(i=0;i<8;i++) {
if(hirq & 1<<i) {
iprintf("ack irq %d\n", 1<<i);
// max3421e_write_u08( MAX3421E_HIRQ, i );
}
}
#endif
return vbusState;
}

216
usb/max3421e.h Normal file
View File

@@ -0,0 +1,216 @@
#ifndef MAX3421E_H
#define MAX3421E_H
#include <inttypes.h>
#define MAX3421E_STATE_SE0 0
#define MAX3421E_STATE_SE1 1
#define MAX3421E_STATE_FSHOST 2
#define MAX3421E_STATE_LSHOST 3
#define MAX3421E_WRITE 0x02
/* MAX3421E command byte format: rrrrr0wa where 'r' is register number */
//
// MAX3421E Registers in HOST mode.
//
#define MAX3421E_RCVFIFO 0x08 //1<<3
#define MAX3421E_SNDFIFO 0x10 //2<<3
#define MAX3421E_SUDFIFO 0x20 //4<<3
#define MAX3421E_RCVBC 0x30 //6<<3
#define MAX3421E_SNDBC 0x38 //7<<3
#define MAX3421E_USBIRQ 0x68 //13<<3
/* USBIRQ Bits */
#define MAX3421E_VBUSIRQ 0x40 //b6
#define MAX3421E_NOVBUSIRQ 0x20 //b5
#define MAX3421E_OSCOKIRQ 0x01 //b0
#define MAX3421E_USBIEN 0x70 //14<<3
/* USBIEN Bits */
#define bmVBUSIE 0x40 //b6
#define bmNOVBUSIE 0x20 //b5
#define bmOSCOKIE 0x01 //b0
#define MAX3421E_USBCTL 0x78 //15<<3
/* USBCTL Bits */
#define MAX3421E_CHIPRES 0x20 //b5
#define MAX3421E_PWRDOWN 0x10 //b4
#define MAX3421E_CPUCTL 0x80 //16<<3
/* CPUCTL Bits */
#define MAX3421E_PUSLEWID1 0x80 //b7
#define MAX3421E_PULSEWID0 0x40 //b6
#define MAX3421E_IE 0x01 //b0
#define MAX3421E_PINCTL 0x88 //17<<3
/* PINCTL Bits */
#define MAX3421E_FDUPSPI 0x10 //b4
#define MAX3421E_INTLEVEL 0x08 //b3
#define MAX3421E_POSINT 0x04 //b2
#define MAX3421E_GPXB 0x02 //b1
#define MAX3421E_GPXA 0x01 //b0
// GPX pin selections
#define MAX3421E_GPX_OPERATE 0x00
#define MAX3421E_GPX_VBDET 0x01
#define MAX3421E_GPX_BUSACT 0x02
#define MAX3421E_GPX_SOF 0x03
#define MAX3421E_REVISION 0x90 //18<<3
#define MAX3421E_IOPINS1 0xa0 //20<<3
/* IOPINS1 Bits */
#define bmGPOUT0 0x01
#define bmGPOUT1 0x02
#define bmGPOUT2 0x04
#define bmGPOUT3 0x08
#define bmGPIN0 0x10
#define bmGPIN1 0x20
#define bmGPIN2 0x40
#define bmGPIN3 0x80
#define MAX3421E_IOPINS2 0xa8 //21<<3
/* IOPINS2 Bits */
#define bmGPOUT4 0x01
#define bmGPOUT5 0x02
#define bmGPOUT6 0x04
#define bmGPOUT7 0x08
#define bmGPIN4 0x10
#define bmGPIN5 0x20
#define bmGPIN6 0x40
#define bmGPIN7 0x80
#define MAX3421E_GPINIRQ 0xb0 //22<<3
/* GPINIRQ Bits */
#define bmGPINIRQ0 0x01
#define bmGPINIRQ1 0x02
#define bmGPINIRQ2 0x04
#define bmGPINIRQ3 0x08
#define bmGPINIRQ4 0x10
#define bmGPINIRQ5 0x20
#define bmGPINIRQ6 0x40
#define bmGPINIRQ7 0x80
#define MAX3421E_GPINIEN 0xb8 //23<<3
/* GPINIEN Bits */
#define bmGPINIEN0 0x01
#define bmGPINIEN1 0x02
#define bmGPINIEN2 0x04
#define bmGPINIEN3 0x08
#define bmGPINIEN4 0x10
#define bmGPINIEN5 0x20
#define bmGPINIEN6 0x40
#define bmGPINIEN7 0x80
#define MAX3421E_GPINPOL 0xc0 //24<<3
/* GPINPOL Bits */
#define bmGPINPOL0 0x01
#define bmGPINPOL1 0x02
#define bmGPINPOL2 0x04
#define bmGPINPOL3 0x08
#define bmGPINPOL4 0x10
#define bmGPINPOL5 0x20
#define bmGPINPOL6 0x40
#define bmGPINPOL7 0x80
#define MAX3421E_HIRQ 0xc8 //25<<3
/* HIRQ Bits */
#define MAX3421E_BUSEVENTIRQ 0x01 // indicates BUS reset Done or BUS resume
#define MAX3421E_RWUIRQ 0x02
#define MAX3421E_RCVDAVIRQ 0x04
#define MAX3421E_SNDBAVIRQ 0x08
#define MAX3421E_SUSDNIRQ 0x10
#define MAX3421E_CONDETIRQ 0x20
#define MAX3421E_FRAMEIRQ 0x40
#define MAX3421E_HXFRDNIRQ 0x80
#define MAX3421E_HIEN 0xd0 //26<<3
/* HIEN Bits */
#define MAX3421E_BUSEVENTIE 0x01
#define MAX3421E_RWUIE 0x02
#define MAX3421E_RCVDAVIE 0x04
#define MAX3421E_SNDBAVIE 0x08
#define MAX3421E_SUSDNIE 0x10
#define MAX3421E_CONDETIE 0x20
#define MAX3421E_FRAMEIE 0x40
#define MAX3421E_HXFRDNIE 0x80
#define MAX3421E_MODE 0xd8 //27<<3
/* MODE Bits */
#define MAX3421E_HOST 0x01
#define MAX3421E_LOWSPEED 0x02
#define MAX3421E_HUBPRE 0x04
#define MAX3421E_SOFKAENAB 0x08
#define MAX3421E_SEPIRQ 0x10
#define MAX3421E_DELAYISO 0x20
#define MAX3421E_DMPULLDN 0x40
#define MAX3421E_DPPULLDN 0x80
#define MAX3421E_PERADDR 0xe0 //28<<3
#define MAX3421E_HCTL 0xe8 //29<<3
/* HCTL Bits */
#define MAX3421E_BUSRST 0x01
#define MAX3421E_FRMRST 0x02
#define MAX3421E_SAMPLEBUS 0x04
#define MAX3421E_SIGRSM 0x08
#define MAX3421E_RCVTOG0 0x10
#define MAX3421E_RCVTOG1 0x20
#define MAX3421E_SNDTOG0 0x40
#define MAX3421E_SNDTOG1 0x80
#define MAX3421E_HXFR 0xf0 //30<<3
/* Host transfer token values for writing the HXFR MAX3421E_egister (R30) */
/* OR this bit field with the endpoint number in bits 3:0 */
#define tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1
#define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0
#define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0
#define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0
#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0
#define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0
#define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0
#define MAX3421E_HRSL 0xf8 //31<<3
/* HRSL Bits */
#define MAX3421E_RCVTOGRD 0x10
#define MAX3421E_SNDTOGRD 0x20
#define MAX3421E_KSTATUS 0x40
#define MAX3421E_JSTATUS 0x80
#define MAX3421E_SE0 0x00 //SE0 - disconnect state
#define MAX3421E_SE1 0xc0 //SE1 - illegal state
/* Host error MAX3421E_esult codes, the 4 LSB's in the HRSL register */
#define hrSUCCESS 0x00
#define hrBUSY 0x01
#define hrBADREQ 0x02
#define hrUNDEF 0x03
#define hrNAK 0x04
#define hrSTALL 0x05
#define hrTOGERR 0x06
#define hrWRONGPID 0x07
#define hrBADBC 0x08
#define hrPIDERR 0x09
#define hrPKTERR 0x0A
#define hrCRCERR 0x0B
#define hrKERR 0x0C
#define hrJERR 0x0D
#define hrTIMEOUT 0x0E
#define hrBABBLE 0x0F
#define MAX3421E_MODE_FS_HOST (MAX3421E_DPPULLDN|MAX3421E_DMPULLDN|MAX3421E_HOST|MAX3421E_SOFKAENAB)
#define MAX3421E_MODE_LS_HOST (MAX3421E_DPPULLDN|MAX3421E_DMPULLDN|MAX3421E_HOST|MAX3421E_LOWSPEED|MAX3421E_SOFKAENAB)
// interface used by usb.c
void max3421e_init();
uint8_t max3421e_poll();
void max3421e_write_u08(uint8_t reg, uint8_t data);
uint8_t max3421e_read_u08(uint8_t reg);
uint8_t *max3421e_write(uint8_t reg, uint8_t n, uint8_t* data);
uint8_t *max3421e_read(uint8_t reg, uint8_t n, uint8_t* data);
#endif //_max3421e_h_

14
usb/spi.h Normal file
View File

@@ -0,0 +1,14 @@
// interface between USB spi and minimig spi
#ifndef SPI_H
#define SPI_H
#include "AT91SAM7S256.h"
#include "hardware.h"
#define spi_init()
#define spi_start(a) { *AT91C_PIOA_CODR = USB_SEL; }
#define spi_end() { SPI_Wait4XferEnd(); *AT91C_PIOA_SODR = USB_SEL; }
#define spi_xmit(a) SPI(a)
#endif // SPI_H

17
usb/timer.c Normal file
View File

@@ -0,0 +1,17 @@
#include "timer.h"
#include "AT91SAM7S256.h"
void timer_init() {
// reprogram the realtime timer to run at 1Khz
AT91C_BASE_RTTC->RTTC_RTMR = 0x8000 / 1000;
}
msec_t timer_get_msec() {
return AT91C_BASE_RTTC->RTTC_RTVR;
}
void timer_delay_msec(msec_t t) {
msec_t now = AT91C_BASE_RTTC->RTTC_RTVR;
while(AT91C_BASE_RTTC->RTTC_RTVR - now < t);
}

13
usb/timer.h Normal file
View File

@@ -0,0 +1,13 @@
// interface between USB timer and minimig timer
#ifndef TIMER_H
#define TIMER_H
#include <inttypes.h>
typedef uint32_t msec_t;
void timer_init();
msec_t timer_get_msec();
void timer_delay_msec(msec_t t);
#endif // TIMER_H

590
usb/usb.c Normal file
View File

@@ -0,0 +1,590 @@
#include <stdio.h>
#include "timer.h"
#include "max3421e.h"
#include "usb.h"
static uint8_t usb_task_state;
static uint8_t bmHubPre;
static usb_device_t dev[USB_NUMDEVICES];
void usb_reset_state() {
puts(__FUNCTION__);
bmHubPre = 0;
}
usb_device_t *usb_get_devices() {
return dev;
}
void usb_init() {
puts(__FUNCTION__);
max3421e_init(); // init underlaying hardware layer
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
uint8_t i;
for(i=0;i<USB_NUMDEVICES;i++)
dev[i].bAddress = 0;
usb_reset_state();
}
uint8_t usb_set_address(usb_device_t *dev, ep_t *ep,
uint16_t *nak_limit) {
// iprintf(" %s(addr=%x, ep=%d)\n", __FUNCTION__, addr, ep);
*nak_limit = (1UL << ( ( ep->bmNakPower > USB_NAK_MAX_POWER ) ?
USB_NAK_MAX_POWER : ep->bmNakPower) ) - 1;
/*
iprintf("\nAddress: %x\n", addr);
iprintf(" EP: %d\n", ep);
iprintf(" NAK Power: %d\n",(*ppep)->bmNakPower);
iprintf(" NAK Limit: %d\n", nak_limit);
*/
max3421e_write_u08( MAX3421E_PERADDR, dev->bAddress); // set peripheral address
uint8_t mode = max3421e_read_u08( MAX3421E_MODE );
// Set bmLOWSPEED and bmHUBPRE in case of low-speed device,
// reset them otherwise
max3421e_write_u08( MAX3421E_MODE,
(dev->lowspeed) ? mode | MAX3421E_LOWSPEED | bmHubPre :
mode & ~(MAX3421E_HUBPRE | MAX3421E_LOWSPEED));
return 0;
}
/* dispatch usb packet. Assumes peripheral address is set and relevant */
/* buffer is loaded/empty */
/* If NAK, tries to re-send up to nak_limit times */
/* If nak_limit == 0, do not count NAKs, exit after timeout */
/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
/* return codes 0x00-0x0f are HRSLT (0x00 being success), 0xff means timeout */
uint8_t usb_dispatchPkt( uint8_t token, uint8_t ep, uint16_t nak_limit ) {
// iprintf(" %s(token=%x, ep=%d, nak_limit=%d)\n",
// __FUNCTION__, token, ep, nak_limit);
unsigned long timeout = timer_get_msec() + USB_XFER_TIMEOUT;
uint8_t tmpdata;
uint8_t rcode = 0x00;
uint8_t retry_count = 0;
uint16_t nak_count = 0;
while( timeout > timer_get_msec() ) {
max3421e_write_u08( MAX3421E_HXFR, ( token|ep )); //launch the transfer
rcode = USB_ERROR_TRANSFER_TIMEOUT;
// wait for transfer completion
while( timer_get_msec() < timeout ) {
tmpdata = max3421e_read_u08( MAX3421E_HIRQ );
if( tmpdata & MAX3421E_HXFRDNIRQ ) {
//clear the interrupt
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_HXFRDNIRQ );
rcode = 0x00;
break;
}
}
if( rcode != 0x00 ) //exit if timeout
return( rcode );
//analyze transfer result
rcode = ( max3421e_read_u08( MAX3421E_HRSL ) & 0x0f );
switch( rcode ) {
case hrNAK:
nak_count++;
if( nak_limit && ( nak_count == nak_limit ))
return( rcode );
break;
case hrTIMEOUT:
retry_count++;
if( retry_count == USB_RETRY_LIMIT )
return( rcode );
break;
default:
return( rcode );
}
}
return( rcode );
}
uint8_t usb_InTransfer(ep_t *pep, uint16_t nak_limit,
uint16_t *nbytesptr, uint8_t* data) {
uint8_t rcode = 0;
uint8_t pktsize;
uint16_t nbytes = *nbytesptr;
uint8_t maxpktsize = pep->maxPktSize;
*nbytesptr = 0;
// set toggle value
max3421e_write_u08( MAX3421E_HCTL,
(pep->bmRcvToggle) ? MAX3421E_RCVTOG1 : MAX3421E_RCVTOG0 );
// use a 'return' to exit this loop
while( 1 ) {
//IN packet to EP-'endpoint'. Function takes care of NAKS.
rcode = usb_dispatchPkt( tokIN, pep->epAddr, nak_limit );
//should be 0, indicating ACK. Else return error code.
if( rcode )
return( rcode );
/* check for RCVDAVIRQ and generate error if not present */
/* the only case when absense of RCVDAVIRQ makes sense is when */
/* toggle error occured. Need to add handling for that */
if(( max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_RCVDAVIRQ ) == 0 )
return ( 0xf0 ); //receive error
pktsize = max3421e_read_u08( MAX3421E_RCVBC ); // number of received bytes
//XXX assert(pktsize <= nbytes);
int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr);
if (mem_left < 0)
mem_left = 0;
// iprintf("rx %d of %d\n", pktsize, mem_left);
data = max3421e_read(MAX3421E_RCVFIFO,
((pktsize > mem_left) ? mem_left : pktsize), data );
// Clear the IRQ & free the buffer
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_RCVDAVIRQ );
*nbytesptr += pktsize;
// add this packet's byte count to total transfer length
/* The transfer is complete under two conditions: */
/* 1. The device sent a short packet (L.T. maxPacketSize) */
/* 2. 'nbytes' have been transferred. */
// have we transferred 'nbytes' bytes?
if (( pktsize < maxpktsize ) || (*nbytesptr >= nbytes )) {
// Save toggle value
pep->bmRcvToggle = (( max3421e_read_u08( MAX3421E_HRSL ) &
MAX3421E_RCVTOGRD )) ? 1 : 0;
return 0;
}
}
}
/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets */
/* if necessary. Transfers 'nbytes' bytes. Keep sending INs and writes data to memory area */
/* pointed by 'data' */
/* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error, */
/* fe USB xfer timeout */
uint8_t usb_in_transfer( usb_device_t *dev, ep_t *ep, uint16_t *nbytesptr, uint8_t* data) {
uint16_t nak_limit = 0;
uint8_t rcode = usb_set_address(dev, ep, &nak_limit);
if (rcode)
return rcode;
return usb_InTransfer(ep, nak_limit, nbytesptr, data);
}
uint8_t usb_OutTransfer(ep_t *pep, uint16_t nak_limit,
uint16_t nbytes, uint8_t *data) {
iprintf("%s(%d)\n", __FUNCTION__, nbytes);
uint8_t rcode = 0, retry_count;
uint16_t bytes_tosend, nak_count;
uint16_t bytes_left = nbytes;
uint8_t maxpktsize = pep->maxPktSize;
if (maxpktsize < 1 || maxpktsize > 64)
return USB_ERROR_INVALID_MAX_PKT_SIZE;
unsigned long timeout = timer_get_msec() + USB_XFER_TIMEOUT;
//set toggle value
max3421e_write_u08(MAX3421E_HCTL,
(pep->bmSndToggle) ? MAX3421E_SNDTOG1 : MAX3421E_SNDTOG0 );
while( bytes_left ) {
retry_count = 0;
nak_count = 0;
bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left;
//filling output FIFO
max3421e_write( MAX3421E_SNDFIFO, bytes_tosend, data );
//set number of bytes
max3421e_write_u08( MAX3421E_SNDBC, bytes_tosend );
// dispatch packet
max3421e_write_u08( MAX3421E_HXFR, ( tokOUT | pep->epAddr ));
//wait for the completion IRQ
while(!(max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_HXFRDNIRQ ));
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_HXFRDNIRQ ); //clear IRQ
rcode = max3421e_read_u08( MAX3421E_HRSL ) & 0x0f;
while( rcode && ( timeout > timer_get_msec())) {
switch( rcode ) {
case hrNAK:
nak_count ++;
if( nak_limit && ( nak_count == nak_limit ))
return( rcode );
break;
case hrTIMEOUT:
retry_count ++;
if( retry_count == USB_RETRY_LIMIT )
return( rcode );
break;
default:
return( rcode );
}
/* process NAK according to Host out NAK bug */
max3421e_write_u08( MAX3421E_SNDBC, 0 );
max3421e_write_u08( MAX3421E_SNDFIFO, *data );
max3421e_write_u08( MAX3421E_SNDBC, bytes_tosend );
// dispatch packet
max3421e_write_u08( MAX3421E_HXFR, ( tokOUT | pep->epAddr ));
// wait for the completion IRQ
while(!(max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_HXFRDNIRQ ));
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_HXFRDNIRQ ); // clear IRQ
rcode = ( max3421e_read_u08( MAX3421E_HRSL ) & 0x0f );
}//while( rcode && ....
bytes_left -= bytes_tosend;
data += bytes_tosend;
}//while( bytes_left...
//update toggle
pep->bmSndToggle = ( max3421e_read_u08( MAX3421E_HRSL ) & MAX3421E_SNDTOGRD ) ? 1 : 0;
return( rcode ); //should be 0 in all cases
}
/* Control transfer. Sets address, endpoint, fills control packet */
/* with necessary data, dispatches control packet, and initiates */
/* bulk IN transfer, depending on request. Actual requests are defined */
/* as inlines */
/* return codes: */
/* 00 = success */
/* 01-0f = non-zero HRSLT */
uint8_t usb_ctrl_req(usb_device_t *dev, uint8_t bmReqType,
uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
uint16_t wInd, uint16_t total, uint16_t nbytes,
uint8_t* dataptr, usb_parser_t *p) {
iprintf("%s(addr=%x, len=%d, ptr=%p)\n", __FUNCTION__,
dev->bAddress, nbytes, dataptr);
bool direction = false; //request direction, IN or OUT
uint8_t rcode;
setup_pkt_t setup_pkt;
uint16_t nak_limit;
rcode = usb_set_address(dev, &(dev->ep0), &nak_limit);
if (rcode)
return rcode;
direction = (( bmReqType & 0x80 ) > 0);
/* fill in setup packet */
setup_pkt.ReqType_u.bmRequestType = bmReqType;
setup_pkt.bRequest = bRequest;
setup_pkt.wVal_u.wValueLo = wValLo;
setup_pkt.wVal_u.wValueHi = wValHi;
setup_pkt.wIndex = wInd;
setup_pkt.wLength = total;
// transfer to setup packet FIFO
max3421e_write(MAX3421E_SUDFIFO, sizeof(setup_pkt_t), (uint8_t*)&setup_pkt );
rcode = usb_dispatchPkt( tokSETUP, 0, nak_limit ); //dispatch packet
if( rcode ) //return HRSLT if not zero
return( rcode );
// data stage, if present
if( dataptr != NULL ) {
if( direction ) { //IN transfer
uint16_t left = total;
dev->ep0.bmRcvToggle = 1; //bmRCVTOG1;
while (left) {
// Bytes read into buffer
uint16_t read = nbytes;
//uint16_t read = (left<nbytes) ? left : nbytes;
rcode = usb_InTransfer( &(dev->ep0), nak_limit, &read, dataptr );
if (rcode)
return rcode;
// Invoke callback function if inTransfer completed
// successfuly and callback function pointer is specified
if (!rcode && p)
(*p)(read, dataptr, total - left);
left -= read;
if (read < nbytes)
break;
}
} else {
//OUT transfer
dev->ep0.bmSndToggle = 1;
rcode = usb_OutTransfer( &(dev->ep0), nak_limit, nbytes, dataptr );
}
//return error
if( rcode )
return( rcode );
}
// Status stage
// GET if direction
return usb_dispatchPkt( (direction) ? tokOUTHS : tokINHS, 0, nak_limit );
}
// list of supported device classes
static const usb_device_class_config_t *class_list[] = {
&usb_hub_class,
&usb_hid_class,
NULL
};
uint8_t usb_configure(uint8_t parent, uint8_t port, bool lowspeed) {
uint8_t rcode = 0;
iprintf("%s(parent=%x port=%d lowspeed=%d)\n", __FUNCTION__, parent, port, lowspeed);
// find an empty device entry
uint8_t i;
for(i=0; i<USB_NUMDEVICES && dev[i].bAddress; i++);
if(i < USB_NUMDEVICES) {
iprintf("using free entry at %d\n", i);
usb_device_t *d = dev+i;
// setup generic info
d->bAddress = 0;
d->parent = parent;
d->lowspeed = lowspeed;
d->port = port;
d->class = NULL;
// setup endpoint 0
d->ep0.epAddr = 0;
d->ep0.maxPktSize = 8;
d->ep0.epAttribs = 0;
d->ep0.bmNakPower = USB_NAK_MAX_POWER;
// --- enumerate device ---
// Assign new address to the device
// (address is simply the number of the free slot + 1)
iprintf("Setting addr %x\n", i+1);
rcode = usb_set_addr(d, i+1);
if(rcode) {
puts("failed to assign address");
return rcode;
}
// try to connect device to one of the supported classes
uint8_t c;
for(c=0;class_list[c];c++) {
iprintf("trying to init class %d\n", c);
rcode = class_list[c]->init(d);
if (!rcode) {
d->class = class_list[c];
puts(" -> accepted :-)");
// ok, device accepted by class
return 0;
}
puts(" -> not accepted :-(");
}
} else
iprintf("no more free entries\n");
iprintf("unsupported device\n");
return 0;
}
void usb_poll() {
uint8_t rcode;
uint8_t tmpdata;
static msec_t delay = 0;
bool lowspeed = false;
// poll underlaying hardware layer
tmpdata = max3421e_poll();
/* modify USB task state if Vbus changed */
switch( tmpdata ) {
// illegal state
case MAX3421E_STATE_SE1:
usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
lowspeed = false;
break;
// disconnected
case MAX3421E_STATE_SE0:
if(( usb_task_state & USB_STATE_MASK ) != USB_STATE_DETACHED )
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
lowspeed = false;
break;
// attached
case MAX3421E_STATE_LSHOST:
lowspeed = true;
// intentional fall-through ...
case MAX3421E_STATE_FSHOST:
if(( usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED ) {
delay = timer_get_msec() + USB_SETTLE_DELAY;
usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
}
break;
}
// max poll 1ms
static msec_t poll=0;
if(timer_get_msec() > poll) {
poll = timer_get_msec()+1;
// poll all configured devices
uint8_t i;
for (i=0; i<USB_NUMDEVICES; i++)
if(dev[i].bAddress)
rcode = dev[i].class->poll(dev+i);
switch( usb_task_state ) {
case USB_DETACHED_SUBSTATE_INITIALIZE:
usb_reset_state();
// just remove everything ...
for (i=0; i<USB_NUMDEVICES; i++) {
if (dev[i].bAddress) {
rcode = dev[i].class->release(dev+i);
dev[i].bAddress = 0;
}
}
usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
break;
case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE:
case USB_DETACHED_SUBSTATE_ILLEGAL:
break;
case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device
if( delay < timer_get_msec() )
usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
break;
case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
max3421e_write_u08( MAX3421E_HCTL, MAX3421E_BUSRST ); // issue bus reset
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
break;
case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
if(( !max3421e_read_u08( MAX3421E_HCTL ) & MAX3421E_BUSRST ) ) {
tmpdata = max3421e_read_u08( MAX3421E_MODE ) | MAX3421E_SOFKAENAB; // start SOF generation
max3421e_write_u08( MAX3421E_MODE, tmpdata );
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
delay = timer_get_msec() + 20; //20ms wait after reset per USB spec
}
break;
case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
if( max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_FRAMEIRQ ) { //when first SOF received we can continue
if( delay < timer_get_msec() ) //20ms passed
usb_task_state = USB_STATE_CONFIGURING;
}
break;
case USB_STATE_CONFIGURING:
// configure root device
usb_configure(0, 0, lowspeed);
usb_task_state = USB_STATE_RUNNING;
break;
case USB_STATE_RUNNING:
break;
}
}
}
uint8_t usb_release_device(uint8_t parent, uint8_t port) {
iprintf("%s(parent=%x, port=%d\n", __FUNCTION__, parent, port);
uint8_t i;
for(i=0; i<USB_NUMDEVICES; i++) {
if(dev[i].bAddress && dev[i].parent == parent && dev[i].port == port) {
iprintf(" -> device with address %x\n", dev[i].bAddress);
// check if this is a hub (parent of some other device)
// and release its kids first
uint8_t j;
for(j=0; j<USB_NUMDEVICES; j++) {
if(dev[j].parent == dev[i].bAddress)
usb_release_device(dev[i].bAddress, dev[j].port);
}
uint8_t rcode = 0;
if(dev[i].class)
rcode = dev[i].class->release(dev+i);
dev[i].bAddress = 0;
return rcode;
}
}
// this should never happen ...
return 0;
}
uint8_t usb_get_dev_descr( usb_device_t *dev, uint16_t nbytes, usb_device_descriptor_t* p ) {
return( usb_ctrl_req( dev, USB_REQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR,
0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, nbytes, (uint8_t*)p, NULL ));
}
//get configuration descriptor
uint8_t usb_get_conf_descr( usb_device_t *dev, uint16_t nbytes,
uint8_t conf, usb_configuration_descriptor_t* p ) {
return( usb_ctrl_req( dev, USB_REQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR,
conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, (uint8_t*)p, NULL ));
}
uint8_t usb_set_addr( usb_device_t *dev, uint8_t newaddr ) {
iprintf("%s(new=%x)\n", __FUNCTION__, newaddr);
uint8_t rcode = usb_ctrl_req( dev, USB_REQ_SET, USB_REQUEST_SET_ADDRESS, newaddr,
0x00, 0x0000, 0x0000, 0x0000, NULL, NULL );
if(!rcode) dev->bAddress = newaddr;
return rcode;
}
//set configuration
uint8_t usb_set_conf( usb_device_t *dev, uint8_t conf_value ) {
return( usb_ctrl_req( dev, USB_REQ_SET, USB_REQUEST_SET_CONFIGURATION,
conf_value, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL ));
}
void usb_SetHubPreMask() {
bmHubPre |= MAX3421E_HUBPRE;
};
void usb_ResetHubPreMask() {
bmHubPre &= ~MAX3421E_HUBPRE;
};

250
usb/usb.h Normal file
View File

@@ -0,0 +1,250 @@
#ifndef USB_H
#define USB_H
#include <inttypes.h>
#include <stdbool.h>
/* NAK powers. To save space in endpoint data structure, amount of retries */
/* before giving up and returning 0x4 is stored in bmNakPower as a power of 2.*/
/* The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
#define USB_NAK_MAX_POWER 16 //NAK binary order maximum value
#define USB_NAK_DEFAULT 14 //default 16K-1 NAKs before giving up
#define USB_NAK_NOWAIT 1 //Single NAK stops transfer
#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
typedef struct {
uint8_t epAddr; // Endpoint address
uint8_t maxPktSize; // Maximum packet size
union {
uint8_t epAttribs;
struct {
// Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
uint8_t bmSndToggle: 1;
// Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
uint8_t bmRcvToggle: 1;
// Binary order for NAK_LIMIT value
uint8_t bmNakPower: 6;
};
};
} ep_t;
#define USB_NUMDEVICES 16 // number of supported USB devices
/* Common setup data constant combinations */
#define USB_REQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type
#define USB_REQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface'
#define USB_REQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type
#define USB_SETTLE_DELAY 200 // settle delay in milliseconds
#define USB_XFER_TIMEOUT 5000 // USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
#define USB_RETRY_LIMIT 3 // retry limit for a transfer
/* USB state machine states */
#define USB_STATE_MASK 0xf0
#define USB_STATE_DETACHED 0x10
#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11
#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x12
#define USB_DETACHED_SUBSTATE_ILLEGAL 0x13
#define USB_ATTACHED_SUBSTATE_SETTLE 0x20
#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30
#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x40
#define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x50
#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x60
#define USB_STATE_ADDRESSING 0x70
#define USB_STATE_CONFIGURING 0x80
#define USB_STATE_RUNNING 0x90
/* USB Setup Packet Structure */
typedef struct {
union { // offset description
uint8_t bmRequestType; // 0 Bit-map of request type
struct {
uint8_t recipient: 5; // Recipient of the request
uint8_t type: 2; // Type of request
uint8_t direction: 1; // Direction of data X-fer
} __attribute__((packed));
} __attribute__((packed)) ReqType_u;
uint8_t bRequest; // 1 Request
union {
uint16_t wValue; // 2/3 Depends on bRequest
struct {
uint8_t wValueLo;
uint8_t wValueHi;
} __attribute__((packed));
} __attribute__((packed)) wVal_u;
uint16_t wIndex; // 4 Depends on bRequest
uint16_t wLength; // 6 Depends on bRequest
} __attribute__((packed)) setup_pkt_t;
// Additional Error Codes
#define USB_ERROR_INVALID_MAX_PKT_SIZE 0xDA
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED 0xDB
#define USB_ERROR_CONFIGURAION_SIZE_MISMATCH 0xDC
#define USB_ERROR_TRANSFER_TIMEOUT 0xFF
struct usb_device_entry;
typedef struct {
uint8_t (*init)(struct usb_device_entry *);
uint8_t (*release)(struct usb_device_entry *);
uint8_t (*poll)(struct usb_device_entry *);
} usb_device_class_config_t;
#include "hub.h"
#include "hid.h"
// entry used for list of connected devices
typedef struct usb_device_entry {
const usb_device_class_config_t *class; // pointer to class hadlers
ep_t ep0; // information about endpoint 0
uint8_t bAddress; // device address
uint8_t parent; // parent device address
uint8_t port;
bool lowspeed;
union {
usb_hub_info_t hub_info;
usb_hid_info_t hid_info;
};
} usb_device_t;
#define USB_CLASS_USE_CLASS_INFO 0x00 // Use Class Info in the Interface Descriptors
#define USB_CLASS_AUDIO 0x01 // Audio
#define USB_CLASS_COM_AND_CDC_CTRL 0x02 // Communications and CDC Control
#define USB_CLASS_HID 0x03 // HID
#define USB_CLASS_PHYSICAL 0x05 // Physical
#define USB_CLASS_IMAGE 0x06 // Image
#define USB_CLASS_PRINTER 0x07 // Printer
#define USB_CLASS_MASS_STORAGE 0x08 // Mass Storage
#define USB_CLASS_HUB 0x09 // Hub
#define USB_CLASS_CDC_DATA 0x0a // CDC-Data
#define USB_CLASS_SMART_CARD 0x0b // Smart-Card
#define USB_CLASS_CONTENT_SECURITY 0x0d // Content Security
#define USB_CLASS_VIDEO 0x0e // Video
#define USB_CLASS_PERSONAL_HEALTH 0x0f // Personal Healthcare
#define USB_CLASS_DIAGNOSTIC_DEVICE 0xdc // Diagnostic Device
#define USB_CLASS_WIRELESS_CTRL 0xe0 // Wireless Controller
#define USB_CLASS_MISC 0xef // Miscellaneous
#define USB_CLASS_APP_SPECIFIC 0xfe // Application Specific
#define USB_CLASS_VENDOR_SPECIFIC 0xff // Vendor Specific
/*******************************************************************************/
/*** ***/
/*** USB chapter 9 structures ***/
/*** ***/
/*******************************************************************************/
/* Device descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
uint16_t bcdUSB; // USB Spec Release Number (BCD).
uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF).
uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0.
uint16_t idVendor; // Vendor ID (assigned by the USB-IF).
uint16_t idProduct; // Product ID (assigned by the manufacturer).
uint16_t bcdDevice; // Device release number (BCD).
uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer.
uint8_t iProduct; // Index of String Descriptor describing the product.
uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number.
uint8_t bNumConfigurations; // Number of possible configurations.
} __attribute__((packed)) usb_device_descriptor_t;
/* Configuration descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION).
uint16_t wTotalLength; // Total length of all descriptors for this configuration.
uint8_t bNumInterfaces; // Number of interfaces in this configuration.
uint8_t bConfigurationValue; // Value of this configuration (1 based).
uint8_t iConfiguration; // Index of String Descriptor describing the configuration.
uint8_t bmAttributes; // Configuration characteristics.
uint8_t bMaxPower; // Maximum power consumed by this configuration.
} __attribute__((packed)) usb_configuration_descriptor_t;
/* Interface descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE).
uint8_t bInterfaceNumber; // Number of this interface (0 based).
uint8_t bAlternateSetting; // Value of this alternate interface setting.
uint8_t bNumEndpoints; // Number of endpoints in this interface.
uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF).
uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
uint8_t iInterface; // Index of String Descriptor describing the interface.
} __attribute__((packed)) usb_interface_descriptor_t;
/* Endpoint descriptor structure */
typedef struct {
uint8_t bLength; // Length of this descriptor.
uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
uint8_t bmAttributes; // Endpoint transfer type.
uint8_t wMaxPacketSize[2]; // Maximum packet size.
uint8_t bInterval; // Polling interval in frames.
} __attribute__((packed)) usb_endpoint_descriptor_t;
/* Standard Device Requests */
#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS
#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE
#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE
#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS
#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR
#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR
#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION
#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION
#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE
#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE
#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME
#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up
#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode
/* Setup Data Constants */
#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer
#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer
#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard
#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class
#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor
#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device
#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface
#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint
#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other
/* USB descriptors */
#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor.
#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor.
#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor.
#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor.
#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor.
#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier.
#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration.
#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power.
typedef void(*usb_parser_t)(const uint16_t, const uint8_t *, const uint16_t);
void usb_init();
void usb_poll();
void usb_SetHubPreMask(void);
void usb_ResetHubPreMask(void);
uint8_t usb_set_addr( usb_device_t *, uint8_t );
uint8_t usb_ctrl_req( usb_device_t *, uint8_t bmReqType,
uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
uint16_t wInd, uint16_t total, uint16_t nbytes,
uint8_t* dataptr, usb_parser_t *p);
uint8_t usb_get_dev_descr( usb_device_t *, uint16_t nbytes, usb_device_descriptor_t* dataptr );
uint8_t usb_get_conf_descr( usb_device_t *, uint16_t nbytes, uint8_t conf, usb_configuration_descriptor_t* dataptr );
uint8_t usb_set_conf( usb_device_t *dev, uint8_t conf_value );
uint8_t usb_in_transfer( usb_device_t *, ep_t *ep, uint16_t *nbytesptr, uint8_t* data);
uint8_t usb_release_device(uint8_t parent, uint8_t port);
usb_device_t *usb_get_devices();
#endif // USB_H

732
user_io.c Normal file
View File

@@ -0,0 +1,732 @@
/*
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/Automation 8 X X
joystick interrogation mode ?
Absolute mouse mode Backlash/Automation 8
disable mouse ? X
disable joystick ? X
Joysticks also generate Goldrunner
mouse button events!
*/
#include "AT91SAM7S256.h"
#include "stdio.h"
#include "hardware.h"
#include "user_io.h"
#include "usb.h"
#include "keycodes.h"
typedef enum { EMU_NONE, EMU_MOUSE, EMU_JOY0, EMU_JOY1 } emu_mode_t;
static emu_mode_t emu_mode = EMU_NONE;
static unsigned char emu_state = 0;
static long emu_timer;
#define EMU_MOUSE_FREQ 5
static unsigned char core_type = CORE_TYPE_UNKNOWN;
AT91PS_ADC a_pADC = AT91C_BASE_ADC;
AT91PS_PMC a_pPMC = AT91C_BASE_PMC;
static char caps_lock_toggle = 0;
// 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_DEFAULT IKBD_STATE_JOYSTICK_EVENT_REPORTING
static unsigned char ikbd_cmd = 0;
static unsigned char ikbd_state = IKBD_DEFAULT;
static unsigned char ikbd_expect = 0;
static unsigned char ikbd_joystick_buttons = 0;
// #define IKBD_DEBUG
void ikbd_ok() {
// this only happens while we are reading
// from the spi. so stop reading
DisableIO();
// send reply
EnableIO();
SPI(UIO_IKBD_OUT);
SPI(0xf0);
DisableIO();
// continue reading
EnableIO();
SPI(UIO_IKBD_IN);
}
// process inout from atari core into ikbd
void ikbd_handle_input(unsigned char cmd) {
// expecting a second byte for command
if(ikbd_expect) {
ikbd_expect--;
// last byte of command received
if(!ikbd_expect) {
switch(ikbd_cmd) {
case 0x07: // set mouse button action
iprintf("mouse button action = %x\n", cmd);
// bit 2: Mouse buttons act like keys (LEFT=0x74 & RIGHT=0x75)
if(cmd & 0x04) ikbd_state |= IKBD_STATE_MOUSE_BUTTON_AS_KEY;
else ikbd_state &= ~IKBD_STATE_MOUSE_BUTTON_AS_KEY;
break;
case 0x80: // ibkd reset
// reply "everything is ok"
ikbd_ok();
break;
default:
break;
}
}
return;
}
ikbd_cmd = cmd;
switch(cmd) {
case 0x07:
puts("IKBD: Set mouse button action");
ikbd_expect = 1;
break;
case 0x08:
puts("IKBD: Set relative mouse positioning");
ikbd_state &= ~IKBD_STATE_MOUSE_DISABLED;
break;
case 0x0b:
puts("IKBD: Set Mouse threshold");
ikbd_expect = 2;
break;
case 0x0f:
puts("IKBD: Set Y at bottom");
ikbd_state |= IKBD_STATE_MOUSE_Y_BOTTOM;
break;
case 0x10:
puts("IKBD: Set Y at top");
ikbd_state &= ~IKBD_STATE_MOUSE_Y_BOTTOM;
break;
case 0x12:
puts("IKBD: Disable mouse");
ikbd_state |= IKBD_STATE_MOUSE_DISABLED;
break;
case 0x14:
puts("IKBD: Set Joystick event reporting");
ikbd_state |= IKBD_STATE_JOYSTICK_EVENT_REPORTING;
break;
case 0x15:
puts("IKBD: Set Joystick interrogation mode");
ikbd_state &= ~IKBD_STATE_JOYSTICK_EVENT_REPORTING;
break;
case 0x1a:
puts("IKBD: Disable joysticks");
ikbd_state &= ~IKBD_STATE_JOYSTICK_EVENT_REPORTING;
break;
case 0x1c:
puts("IKBD: Interrogate time of day");
// send some date
// stop reading from ikbd queue
DisableIO();
// send reply (the date this routine was written)
EnableIO();
SPI(UIO_IKBD_OUT);
SPI(0xfc);
SPI(0x13); // year bcd
SPI(0x03); // month bcd
SPI(0x07); // day bcd
SPI(0x20); // hour bcd
SPI(0x58); // minute bcd
SPI(0x00); // second bcd
DisableIO();
// continue reading
EnableIO();
SPI(UIO_IKBD_IN);
break;
case 0x80:
puts("IKBD: Reset");
ikbd_expect = 1;
ikbd_state = IKBD_DEFAULT;
break;
default:
iprintf("IKBD: unknown command: %x\n", cmd);
break;
}
}
static void InitADC(void) {
// Enable clock for interface
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_ADC;
// Reset
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;
AT91C_BASE_ADC->ADC_CR = 0x0;
// Set maximum startup time and hold time
AT91C_BASE_ADC->ADC_MR = 0x0F1F0F00 | AT91C_ADC_LOWRES_8_BIT;
}
static unsigned int GetAdc(unsigned char channel) {
// variable
unsigned int result;
// Enable desired chanel
AT91C_BASE_ADC->ADC_CHER = channel;
// Start conversion
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
// wait for end of convertion
while(!(AT91C_BASE_ADC->ADC_SR & channel));
switch (channel) {
case AT91C_ADC_CH4: result = AT91C_BASE_ADC->ADC_CDR4; break;
case AT91C_ADC_CH5: result = AT91C_BASE_ADC->ADC_CDR5; break;
case AT91C_ADC_CH6: result = AT91C_BASE_ADC->ADC_CDR6; break;
case AT91C_ADC_CH7: result = AT91C_BASE_ADC->ADC_CDR7; break;
}
return result;
}
void user_io_init() {
InitADC();
}
unsigned char user_io_core_type() {
return core_type;
}
void user_io_detect_core_type() {
EnableIO();
core_type = SPI(0xff);
DisableIO();
if((core_type != CORE_TYPE_DUMB) &&
(core_type != CORE_TYPE_MINIMIG) &&
(core_type != CORE_TYPE_PACE) &&
(core_type != CORE_TYPE_MIST))
core_type = CORE_TYPE_UNKNOWN;
switch(core_type) {
case CORE_TYPE_UNKNOWN:
puts("Unable to identify core!");
break;
case CORE_TYPE_DUMB:
puts("Identified core without user interface");
break;
case CORE_TYPE_MINIMIG:
puts("Identified Minimig core");
break;
case CORE_TYPE_PACE:
puts("Identified PACE core");
break;
case CORE_TYPE_MIST:
puts("Identified MiST core");
break;
}
}
// convert internal joystick format into atari ikbd format
unsigned char joystick_map2ikbd(unsigned 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 user_io_joystick(unsigned char joystick, unsigned char map) {
if(core_type == CORE_TYPE_MINIMIG) {
EnableIO();
SPI(UIO_JOYSTICK0 + joystick);
SPI(map);
DisableIO();
}
if(core_type == CORE_TYPE_MIST) {
// todo: suppress events for joystick 0 as long as mouse
// is enabled?
if(ikbd_state & IKBD_STATE_JOYSTICK_EVENT_REPORTING) {
#ifdef IKBD_DEBUG
iprintf("IKBD: joy %d %x\n", joystick, map);
#endif
EnableIO();
SPI(UIO_IKBD_OUT);
SPI(0xfe + joystick);
SPI(joystick_map2ikbd(map));
DisableIO();
// the fire button also generates a mouse event if
// mouse reporting is enabled
unsigned char button1 = (map & JOY_BTN1)?(1<<joystick):0;
if(button1 != (ikbd_joystick_buttons & (1<<joystick))) {
// update saved state of joystick buttons
ikbd_joystick_buttons = (ikbd_joystick_buttons & ~(1<<joystick)) | button1;
// generate mouse event (ikbd_joystick_buttons is evaluated inside
// user_io_mouse)
user_io_mouse(0, 0, 0);
}
}
#ifdef IKBD_DEBUG
else
iprintf("IKBD: no monitor, drop joy %d %x\n", joystick, map);
#endif
}
}
void user_io_poll() {
if((core_type != CORE_TYPE_MINIMIG) &&
(core_type != CORE_TYPE_PACE) &&
(core_type != CORE_TYPE_MIST)) {
return; // no user io for the installed core
}
if(core_type == CORE_TYPE_MIST) {
static mtimer = 0;
if(CheckTimer(mtimer)) {
mtimer = GetTimer(100);
// check for incoming ikbd data
EnableIO();
SPI(UIO_IKBD_IN);
while(SPI(0))
ikbd_handle_input(SPI(0));
DisableIO();
// check for incoming serial data
EnableIO();
SPI(UIO_SERIAL_IN);
while(SPI(0))
putchar(SPI(0));
DisableIO();
}
}
// poll db9 joysticks
static int joy0_state = JOY0;
if((*AT91C_PIOA_PDSR & JOY0) != joy0_state) {
joy0_state = *AT91C_PIOA_PDSR & JOY0;
unsigned char joy_map = 0;
if(!(joy0_state & JOY0_UP)) joy_map |= JOY_UP;
if(!(joy0_state & JOY0_DOWN)) joy_map |= JOY_DOWN;
if(!(joy0_state & JOY0_LEFT)) joy_map |= JOY_LEFT;
if(!(joy0_state & JOY0_RIGHT)) joy_map |= JOY_RIGHT;
if(!(joy0_state & JOY0_BTN1)) joy_map |= JOY_BTN1;
if(!(joy0_state & JOY0_BTN2)) joy_map |= JOY_BTN2;
user_io_joystick(0, joy_map);
}
static int joy1_state = JOY1;
if((*AT91C_PIOA_PDSR & JOY1) != joy1_state) {
joy1_state = *AT91C_PIOA_PDSR & JOY1;
unsigned char joy_map = 0;
if(!(joy1_state & JOY1_UP)) joy_map |= JOY_UP;
if(!(joy1_state & JOY1_DOWN)) joy_map |= JOY_DOWN;
if(!(joy1_state & JOY1_LEFT)) joy_map |= JOY_LEFT;
if(!(joy1_state & JOY1_RIGHT)) joy_map |= JOY_RIGHT;
if(!(joy1_state & JOY1_BTN1)) joy_map |= JOY_BTN1;
if(!(joy1_state & JOY1_BTN2)) joy_map |= JOY_BTN2;
user_io_joystick(1, joy_map);
}
static unsigned char key_map = 0;
unsigned char map = 0;
if(GetAdc(AT91C_ADC_CH4) < 128) map |= SWITCH2;
if(GetAdc(AT91C_ADC_CH5) < 128) map |= SWITCH1;
if(GetAdc(AT91C_ADC_CH6) < 128) map |= BUTTON1;
if(GetAdc(AT91C_ADC_CH7) < 128) map |= BUTTON2;
if(map != key_map) {
key_map = map;
EnableIO();
SPI(UIO_BUT_SW);
SPI(map);
DisableIO();
}
// mouse movement emulation is continous
if(emu_mode == EMU_MOUSE) {
if(CheckTimer(emu_timer)) {
emu_timer = GetTimer(EMU_MOUSE_FREQ);
if(emu_state & JOY_MOVE) {
unsigned char b = 0;
char x = 0, y = 0;
if((emu_state & (JOY_LEFT | JOY_RIGHT)) == JOY_LEFT) x = -1;
if((emu_state & (JOY_LEFT | JOY_RIGHT)) == JOY_RIGHT) x = +1;
if((emu_state & (JOY_UP | JOY_DOWN)) == JOY_UP) y = -1;
if((emu_state & (JOY_UP | JOY_DOWN)) == JOY_DOWN) y = +1;
if(emu_state & JOY_BTN1) b |= 1;
if(emu_state & JOY_BTN2) b |= 2;
user_io_mouse(b, x, y);
}
}
}
if(core_type == CORE_TYPE_MIST) {
// do some tos specific monitoring here
tos_show_state();
}
}
int user_io_button_pressed() {
return (GetAdc(AT91C_ADC_CH5) < 128);
}
static void send_keycode(unsigned short code) {
if(core_type == CORE_TYPE_MINIMIG) {
EnableIO();
if(code & OSD) SPI(UIO_KBD_OSD); // code for OSD
else SPI(UIO_KEYBOARD);
SPI(code & 0xff);
DisableIO();
}
if(core_type == CORE_TYPE_MIST) {
#ifdef IKBD_DEBUG
iprintf("IKBD: send keycode %x%s\n", code&0x7f, (code&0x80)?" BREAK":"");
#endif
EnableIO();
SPI(UIO_IKBD_OUT);
SPI(code & 0xff);
DisableIO();
}
}
void user_io_mouse(unsigned char b, char x, char y) {
// send mouse data as minimig expects it
if(core_type == CORE_TYPE_MINIMIG) {
EnableIO();
SPI(UIO_MOUSE);
SPI(x);
SPI(y);
SPI(b);
DisableIO();
}
// send mouse data as mist expects it
if(core_type == CORE_TYPE_MIST) {
if(ikbd_state & IKBD_STATE_MOUSE_DISABLED)
return;
// joystick and mouse buttons are wired together in
// atari st
b |= ikbd_joystick_buttons;
static unsigned char b_old = 0;
// monitor state of two mouse buttons
if(b != b_old) {
// check if mouse buttons are supposed to be treated like keys
if(ikbd_state & IKBD_STATE_MOUSE_BUTTON_AS_KEY) {
// Mouse buttons act like keys (LEFT=0x74 & RIGHT=0x75)
// handle left mouse button
if((b ^ b_old) & 1) send_keycode(0x74 | ((b&1)?0x00:0x80));
// handle right mouse button
if((b ^ b_old) & 2) send_keycode(0x75 | ((b&2)?0x00:0x80));
}
b_old = b;
}
#if 0
if(ikbd_state & IKBD_STATE_MOUSE_BUTTON_AS_KEY) {
b = 0;
// if mouse position is 0/0 quit here
if(!x && !y) return;
}
#endif
EnableIO();
SPI(UIO_IKBD_OUT);
// atari has mouse button bits swapped
SPI(0xf8|((b&1)?2:0)|((b&2)?1:0));
SPI(x);
SPI((ikbd_state & IKBD_STATE_MOUSE_Y_BOTTOM)?-y:y);
DisableIO();
}
}
// check if this is a key that's supposed to be suppressed
// when emulation is active
static unsigned char is_emu_key(unsigned char c) {
static const unsigned char m[] = { JOY_RIGHT, JOY_LEFT, JOY_DOWN, JOY_UP };
if(emu_mode == EMU_NONE)
return 0;
// direction keys R/L/D/U
if(c >= 0x4f && c <= 0x52)
return m[c-0x4f];
return 0;
}
#define EMU_BTN1 0 // left control
#define EMU_BTN2 4 // right control
unsigned short keycode(unsigned char in) {
if(core_type == CORE_TYPE_MINIMIG)
return usb2ami[in];
if(core_type == CORE_TYPE_MIST)
return usb2atari[in];
return MISS;
}
unsigned char modifier_keycode(unsigned char index) {
/* usb modifer bits:
0 1 2 3 4 5 6 7
LCTRL LSHIFT LALT LGUI RCTRL RSHIFT RALT RGUI
*/
if(core_type == CORE_TYPE_MINIMIG) {
static const unsigned char amiga_modifier[] =
{ 0x63, 0x60, 0x64, 0x66, 0x63, 0x61, 0x65, 0x67 };
return amiga_modifier[index];
}
if(core_type == CORE_TYPE_MIST) {
static const unsigned char atari_modifier[] =
{ 0x1d, 0x2a, 0x38, MISS, 0x1d, 0x36, 0x38, MISS };
return atari_modifier[index];
}
return MISS;
}
unsigned char osdcode(unsigned char c) {
int i = 0;
while(usb2osd[i][0] && usb2osd[i][0] != c)
i++;
if(!usb2osd[i][0])
iprintf("ERROR: Unsupported OSD code %x!\n", c);
return usb2osd[i][1];
}
// set by OSD code to suppress forwarding of those keys to the core which
// may be in use by an active OSD
static char osd_eats_keys = false;
void user_io_osd_key_enable(char on) {
osd_eats_keys = on;
}
static char key_used_by_osd(unsigned short s) {
if((s & OSD_LOC) && !(s & 0xff)) return true; // this key is only used in OSD and has no keycode
if(!osd_eats_keys) return false; // OSD currently doesn't use keyboard
return((s & OSD_LOC) != 0);
}
void user_io_kbd(unsigned char m, unsigned char *k) {
if((core_type == CORE_TYPE_MINIMIG) ||
(core_type == CORE_TYPE_MIST)) {
static unsigned char modifier = 0, pressed[6] = { 0,0,0,0,0,0 };
int i, j;
// modifier keys are used as buttons in emu mode
if(emu_mode != EMU_NONE) {
char last_btn = emu_state & (JOY_BTN1 | JOY_BTN2);
if(m & (1<<EMU_BTN1)) emu_state |= JOY_BTN1;
else emu_state &= ~JOY_BTN1;
if(m & (1<<EMU_BTN2)) emu_state |= JOY_BTN2;
else emu_state &= ~JOY_BTN2;
// check if state of mouse buttons has changed
if(last_btn != (emu_state & (JOY_BTN1 | JOY_BTN2))) {
if(emu_mode == EMU_MOUSE) {
unsigned char b;
if(emu_state & JOY_BTN1) b |= 1;
if(emu_state & JOY_BTN2) b |= 2;
user_io_mouse(b, 0, 0);
}
if(emu_mode == EMU_JOY0)
user_io_joystick(0, emu_state);
if(emu_mode == EMU_JOY1)
user_io_joystick(1, emu_state);
}
}
// handle modifier keys
if(m != modifier) {
for(i=0;i<8;i++) {
if((m & (1<<i)) && !(modifier & (1<<i)))
// shift keys are used for mouse joystick emulation in emu mode
if(((i != EMU_BTN1) && (i != EMU_BTN2)) || (emu_mode == EMU_NONE))
if(modifier_keycode(i) != MISS)
send_keycode(modifier_keycode(i));
if(!(m & (1<<i)) && (modifier & (1<<i)))
if(((i != EMU_BTN1) && (i != EMU_BTN2)) || (emu_mode == EMU_NONE))
if(modifier_keycode(i) != MISS)
send_keycode(0x80 | modifier_keycode(i));
}
modifier = m;
}
// check if there are keys in the pressed list which aren't
// reported anymore
for(i=0;i<6;i++) {
unsigned short code = keycode(pressed[i]);
if(pressed[i] && code != MISS) {
for(j=0;j<6 && pressed[i] != k[j];j++);
// don't send break for caps lock
if(j == 6) {
// special OSD key handled internally
if(code & OSD_LOC)
OsdKeySet(0x80 | osdcode(pressed[i]));
if(!key_used_by_osd(code)) {
if(is_emu_key(pressed[i])) {
emu_state &= ~is_emu_key(pressed[i]);
if(emu_mode == EMU_JOY0)
user_io_joystick(0, emu_state);
if(emu_mode == EMU_JOY1)
user_io_joystick(1, emu_state);
} else if(!(code & CAPS_LOCK_TOGGLE) &&
!(code & NUM_LOCK_TOGGLE))
send_keycode(0x80 | code);
}
}
}
}
for(i=0;i<6;i++) {
unsigned short code = keycode(k[i]);
if(k[i] && (k[i] <= KEYCODE_MAX) && code != MISS) {
// check if this key is already in the list of pressed keys
for(j=0;j<6 && k[i] != pressed[j];j++);
if(j == 6) {
// special OSD key handled internally
if(code & OSD_LOC)
OsdKeySet(osdcode(k[i]));
// no further processing of any key that is currently
// redirected to the OSD
if(!key_used_by_osd(code)) {
if (is_emu_key(k[i])) {
emu_state |= is_emu_key(k[i]);
if(emu_mode == EMU_JOY0)
user_io_joystick(0, emu_state);
if(emu_mode == EMU_JOY1)
user_io_joystick(1, emu_state);
} else if(!(code & CAPS_LOCK_TOGGLE)&&
!(code & NUM_LOCK_TOGGLE))
send_keycode(code);
else {
if(code & CAPS_LOCK_TOGGLE) {
// send alternating make and break codes for caps lock
send_keycode((code & 0xff) | (caps_lock_toggle?0x80:0));
caps_lock_toggle = !caps_lock_toggle;
hid_set_kbd_led(HID_LED_CAPS_LOCK, caps_lock_toggle);
}
if(code & NUM_LOCK_TOGGLE) {
// num lock has four states indicated by leds:
// all off: normal
// num lock on, scroll lock on: mouse emu
// num lock on, scroll lock off: joy0 emu
// num lock off, scroll lock on: joy1 emu
if(emu_mode == EMU_MOUSE)
emu_timer = GetTimer(EMU_MOUSE_FREQ);
emu_mode = (emu_mode+1)&3;
if(emu_mode == EMU_MOUSE || emu_mode == EMU_JOY0)
hid_set_kbd_led(HID_LED_NUM_LOCK, true);
else
hid_set_kbd_led(HID_LED_NUM_LOCK, false);
if(emu_mode == EMU_MOUSE || emu_mode == EMU_JOY1)
hid_set_kbd_led(HID_LED_SCROLL_LOCK, true);
else
hid_set_kbd_led(HID_LED_SCROLL_LOCK, false);
}
}
}
}
}
}
for(i=0;i<6;i++)
pressed[i] = k[i];
}
}

56
user_io.h Normal file
View File

@@ -0,0 +1,56 @@
/*
* user_io.h
*
*/
#ifndef USER_IO_H
#define USER_IO_H
#define UIO_STATUS 0x00
#define UIO_BUT_SW 0x01
// codes as used by minimig (amiga)
#define UIO_JOYSTICK0 0x02
#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)
#define UIO_IKBD_OUT 0x02
#define UIO_IKBD_IN 0x03
#define UIO_SERIAL_OUT 0x04
#define UIO_SERIAL_IN 0x05
#define JOY_RIGHT 0x01
#define JOY_LEFT 0x02
#define JOY_DOWN 0x04
#define JOY_UP 0x08
#define JOY_BTN1 0x10
#define JOY_BTN2 0x20
#define JOY_MOVE (JOY_RIGHT|JOY_LEFT|JOY_UP|JOY_DOWN)
#define BUTTON1 0x01
#define BUTTON2 0x02
#define SWITCH1 0x04
#define SWITCH2 0x08
// core type value should be unlikely to be returned by broken cores
#define CORE_TYPE_UNKNOWN 0x55
#define CORE_TYPE_DUMB 0xa0
#define CORE_TYPE_MINIMIG 0xa1
#define CORE_TYPE_PACE 0xa2
#define CORE_TYPE_MIST 0xa3
void user_io_init();
void user_io_detect_core_type();
unsigned char user_io_core_type();
void user_io_poll();
int user_io_button_pressed();
void user_io_osd_key_enable(char);
// hooks from the usb layer
void user_io_mouse(unsigned char b, char x, char y);
void user_io_kbd(unsigned char m, unsigned char *k);
#endif // USER_IO_H