Initial commit

This commit is contained in:
Gericom 2022-09-30 13:18:16 +02:00
commit 62c909ebf6
73 changed files with 29766 additions and 0 deletions

9
.clang-format Normal file
View File

@ -0,0 +1,9 @@
BasedOnStyle: Microsoft
AlignConsecutiveMacros: 'true'
AlignEscapedNewlines: Left
AlwaysBreakTemplateDeclarations: 'Yes'
BreakBeforeBraces: Allman
Cpp11BracedListStyle: 'false'
IndentCaseLabels: 'true'
PointerAlignment: Left
SortIncludes: 'false'

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
.vscode/
tmp/
nitrofiles/
*.nds
arm7/build/
arm9/build/
*.elf
FatInNitroFS.dldi
arm7/source/isdprint.c
Makefile_isnitro

56
Makefile Normal file
View File

@ -0,0 +1,56 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
export TARGET := $(shell basename $(CURDIR))
export TOPDIR := $(CURDIR)
# specify a directory which contains the nitro filesystem
# this is relative to the Makefile
NITRO_FILES := #nitrofiles
# These set the information text in the nds file
GAME_TITLE := FastVideoDS Player
GAME_SUBTITLE1 := By Gericom
GAME_ICON := icon.bmp
include $(DEVKITARM)/ds_rules
.PHONY: checkarm7 checkarm9 clean
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all: checkarm7 checkarm9 $(TARGET).nds
#---------------------------------------------------------------------------------
checkarm7:
$(MAKE) -C arm7
#---------------------------------------------------------------------------------
checkarm9:
$(MAKE) -C arm9
#---------------------------------------------------------------------------------
$(TARGET).nds : $(NITRO_FILES) arm7/$(TARGET).elf arm9/$(TARGET).elf
ndstool -c $(TARGET).nds -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf \
-b $(GAME_ICON) "$(GAME_TITLE);$(GAME_SUBTITLE1)" \
$(_ADDFILES)
#---------------------------------------------------------------------------------
arm7/$(TARGET).elf:
$(MAKE) -C arm7
#---------------------------------------------------------------------------------
arm9/$(TARGET).elf:
$(MAKE) -C arm9
#---------------------------------------------------------------------------------
clean:
$(MAKE) -C arm9 clean
$(MAKE) -C arm7 clean
rm -f $(TARGET).nds $(TARGET).arm7 $(TARGET).arm9

123
arm7/Makefile Normal file
View File

@ -0,0 +1,123 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
# DATA is a list of directories containing binary files
# all directories are relative to this makefile
#---------------------------------------------------------------------------------
BUILD := build
SOURCES := source source/fat ../common
INCLUDES := include build
DATA :=
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb-interwork -mcpu=arm7tdmi -mtune=arm7tdmi
CFLAGS := -g -Wall -O2 -fomit-frame-pointer -ffast-math -ffunction-sections -fdata-sections $(ARCH)
CFLAGS += $(INCLUDE) -DARM7
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -fno-rtti
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=../fv_ds_arm7.specs -g $(ARCH) -Wl,--nmagic -Wl,-Map,$(notdir $*).map
LIBS := -lnds7
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export ARM7ELF := $(CURDIR)/$(TARGET).elf
export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) *.elf
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(ARM7ELF) : $(OFILES)
@echo linking $(notdir $@)
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

233
arm7/fv_ds_arm7.ld Normal file
View File

@ -0,0 +1,233 @@
/*--------------------------------------------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/.
--------------------------------------------------------------------------------*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
PHDRS {
crt0 PT_LOAD FLAGS(7);
arm7 PT_LOAD FLAGS(7);
arm7i PT_LOAD FLAGS(0x100007);
}
MEMORY {
ewram : ORIGIN = 0x02380000, LENGTH = 12M - 512K
rom : ORIGIN = 0x08000000, LENGTH = 32M
/* iwram : ORIGIN = 0x037f8000, LENGTH = 96K */
iwram : ORIGIN = 0x037fc000, LENGTH = (96K - 16K)
twl_ewram : ORIGIN = 0x02e80000, LENGTH = 512K - 64K
twl_iwram : ORIGIN = 0x03000000, LENGTH = 256K
}
__iwram_start = ORIGIN(iwram);
__iwram_top = ORIGIN(iwram)+ LENGTH(iwram);
__sp_irq = __iwram_top - 0x100;
__sp_svc = __sp_irq - 0x100;
__sp_usr = __sp_svc - 0x100;
__irq_flags = 0x04000000 - 8;
__irq_flagsaux = 0x04000000 - 0x40;
__irq_vector = 0x04000000 - 4;
SECTIONS
{
.twl :
{
__arm7i_lma__ = LOADADDR(.twl);
__arm7i_start__ = .;
*(.twl)
*.twl*(.text .stub .text.* .gnu.linkonce.t.*)
*.twl*(.rodata)
*.twl*(.roda)
*.twl*(.rodata.*)
*.twl*(.data)
*.twl*(.data.*)
*.twl*(.gnu.linkonce.d*)
. = ALIGN(4);
__arm7i_end__ = .;
} >twl_iwram AT>twl_ewram :arm7i
.twl_bss ALIGN(4) (NOLOAD) :
{
__twl_bss_start__ = .;
*(.twl_bss)
*.twl.*(.dynbss)
*.twl.*(.gnu.linkonce.b*)
*.twl.*(.bss*)
*.twl.*(COMMON)
. = ALIGN(4);
__twl_bss_end__ = .;
} >twl_iwram :NONE
.crt0 :
{
KEEP (*(.crt0))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ewram :crt0
.text :
{
__arm7_lma__ = LOADADDR(.text);
__arm7_start__ = .;
KEEP (*(SORT_NONE(.init)))
*(.plt)
*(.text .stub .text.* .gnu.linkonce.t.*)
KEEP (*(.text.*personality*))
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >iwram AT>ewram :arm7
.fini :
{
KEEP (*(.fini))
} >iwram AT>ewram
.rodata :
{
*(.rodata)
*all.rodata*(*)
*(.roda)
*(.rodata.*)
*(.gnu.linkonce.r*)
SORT(CONSTRUCTORS)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >iwram AT>ewram
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >iwram AT>ewram
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
__exidx_end = .;
} >iwram AT>ewram
/* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but
the linker would then create the section even if it turns out to
be empty, which isn't pretty. */
.preinit_array : {
. = ALIGN(32 / 8);
PROVIDE (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE (__preinit_array_end = .);
} >iwram AT>ewram
.init_array : {
PROVIDE (__init_array_start = .);
KEEP (*(.init_array))
PROVIDE (__init_array_end = .);
} >iwram AT>ewram
.fini_array : {
PROVIDE (__fini_array_start = .);
KEEP (*(.fini_array))
PROVIDE (__fini_array_end = .);
} >iwram AT>ewram
.ctors :
{
/* gcc uses crtbegin.o to find the start of the constructors, so
we make sure it is first. Because this is a wildcard, it
doesn't matter if the user does not actually link against
crtbegin.o; the linker won't look for a file to match a
wildcard. The wildcard also means that it doesn't matter which
directory crtbegin.o is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >iwram AT>ewram
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >iwram AT>ewram
.eh_frame :
{
KEEP (*(.eh_frame))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >iwram AT>ewram
.gcc_except_table :
{
*(.gcc_except_table)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >iwram AT>ewram
.jcr : { KEEP (*(.jcr)) } >iwram AT>ewram
.got : { *(.got.plt) *(.got) } >iwram AT>ewram
.data ALIGN(4) : {
__data_start = ABSOLUTE(.);
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
CONSTRUCTORS
. = ALIGN(4);
__data_end = ABSOLUTE(.) ;
} >iwram AT>ewram
.bss ALIGN(4) (NOLOAD) :
{
__arm7_end__ = .;
__bss_start = ABSOLUTE(.);
__bss_start__ = ABSOLUTE(.);
*(.dynbss)
*(.gnu.linkonce.b*)
*(.bss*)
*(COMMON)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
__bss_end__ = ABSOLUTE(.);
__end__ = ABSOLUTE(.);
} >iwram
/* 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) }
.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) }
/* These must appear regardless of . */
}

8
arm7/fv_ds_arm7.specs Normal file
View File

@ -0,0 +1,8 @@
%rename link old_link
*link:
%(old_link) -T ../fv_ds_arm7.ld%s --gc-sections
*startfile:
ds_arm7_crt0%O%s crti%O%s crtbegin%O%s

3
arm7/source/adpcm.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
extern void adpcm_decompress(const void* src, u32 len, s16* dst);

63
arm7/source/adpcm.s Normal file
View File

@ -0,0 +1,63 @@
.text
.arm
indexTable:
@ .byte 0, -1, 0, -1, 0, -1, 0, -1, 0, 2, 0, 4, 0, 6, 0, 8
.byte 0, -3, 0, -3, 0, -2, 0, -1, 0, 2, 0, 4, 0, 6, 0, 8
stepTable:
.word 7, 8, 9, 10, 11, 12, 13, 14
.word 16, 17, 19, 21, 23, 25, 28
.word 31, 34, 37, 41, 45, 50, 55
.word 60, 66, 73, 80, 88, 97, 107
.word 118, 130, 143, 157, 173, 190, 209
.word 230, 253, 279, 307, 337, 371, 408
.word 449, 494, 544, 598, 658, 724, 796
.word 876, 963, 1060, 1166, 1282, 1411, 1552
.word 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026
.word 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630
.word 9493, 10442, 11487, 12635, 13899, 15289, 16818
.word 18500, 20350, 22385, 24623, 27086, 29794, 32767
//r0: src
//r1: length
//r2: dst
.global adpcm_decompress
adpcm_decompress:
stmfd sp!, {r4-r11,lr}
add r12, r0, r1
ldr r11,= indexTable
ldr r10,= stepTable
mov r9, #1
ldr r8,= 0x7FFF
ldrsh r3, [r0], #2 //last
ldrh r4, [r0], #2 //index
1:
ldr r5, [r0], #4
.set offs, 0
.rept 8
ldr r6, [r10, r4, lsl #2]
movs r7, r5, lsl #(29 - offs)
orr r7, r9, r7, lsr #28
ldrsb lr, [r11, r7]
mul r6, r7, r6
addcc r3, r3, r6, lsr #3
subcs r3, r3, r6, lsr #3
@ mov r6, r3, asr #15
@ teq r6, r3, asr #31
@ eorne r3, r8, r3, asr #31
cmp r3, r8
movgt r3, r8
cmn r3, r8
rsblt r3, r8, #0
strh r3, [r2], #2
adds r4, r4, lr
movmi r4, #0
cmp r4, #88
movgt r4, #88
.set offs, offs + 4
.endr
cmp r0, r12
blo 1b
ldmfd sp!, {r4-r11,lr}
bx lr

16
arm7/source/dldi.s Normal file
View File

@ -0,0 +1,16 @@
.global _dldi_start
.equ _dldi_start, 0x037F8000
.global _io_dldi
.equ _io_dldi, (_dldi_start + 0x60)
.global _DLDI_startup_ptr
.equ _DLDI_startup_ptr, (_io_dldi + 0x8)
.global _DLDI_isInserted_ptr
.equ _DLDI_isInserted_ptr, (_io_dldi + 0xC)
.global _DLDI_readSectors_ptr
.equ _DLDI_readSectors_ptr, (_io_dldi + 0x10)
.global _DLDI_writeSectors_ptr
.equ _DLDI_writeSectors_ptr, (_io_dldi + 0x14)
.global _DLDI_clearStatus_ptr
.equ _DLDI_clearStatus_ptr, (_io_dldi + 0x18)
.global _DLDI_shutdown_ptr
.equ _DLDI_shutdown_ptr, (_io_dldi + 0x1C)

19
arm7/source/fat.c Normal file
View File

@ -0,0 +1,19 @@
#include <nds.h>
#include <string.h>
#include "fat/ff.h"
#include "fat.h"
FATFS gFatFs;
void fat_init(void)
{
memset(&gFatFs, 0, sizeof(gFatFs));
if (isDSiMode())
f_mount(&gFatFs, "sd:", 1); //mount dsi sd card
}
void fat_mountDldi(void)
{
f_mount(&gFatFs, "fat:", 1);
}

7
arm7/source/fat.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include "fat/ff.h"
extern FATFS gFatFs;
void fat_init(void);
void fat_mountDldi(void);

149
arm7/source/fat/diskio.c Normal file
View File

@ -0,0 +1,149 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include <nds.h>
#include <nds/disc_io.h>
#include "ff.h" /* Obtains integer types */
#include "diskio.h" /* Declarations of disk functions */
/* Definitions of physical drive number for each drive */
#define DEV_FAT 0 //dldi
#define DEV_SD 1 //dsi sd
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
return 0;
}
extern FN_MEDIUM_STARTUP _DLDI_startup_ptr;
extern FN_MEDIUM_READSECTORS _DLDI_readSectors_ptr;
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
if (pdrv == DEV_FAT)
{
_DLDI_startup_ptr();
return 0;
}
else if (isDSiMode() && pdrv == DEV_SD)
{
sdmmc_sd_startup();
return 0;
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */
)
{
if (pdrv == DEV_FAT)
{
_DLDI_readSectors_ptr(sector, count, buff);
return RES_OK;
}
else if (isDSiMode() && pdrv == DEV_SD)
{
sdmmc_sdcard_readsectors(sector, count, buff);
return RES_OK;
}
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if FF_FS_READONLY == 0
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */
)
{
DRESULT res;
int result;
/*switch (pdrv) {
case DEV_RAM :
// translate the arguments here
result = RAM_disk_write(buff, sector, count);
// translate the reslut code here
return res;
case DEV_MMC :
// translate the arguments here
result = MMC_disk_write(buff, sector, count);
// translate the reslut code here
return res;
case DEV_USB :
// translate the arguments here
result = USB_disk_write(buff, sector, count);
// translate the reslut code here
return res;
}*/
write_sd_sectors_safe(sector, count, buff);
return RES_OK;
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
return RES_OK;
}

77
arm7/source/fat/diskio.h Normal file
View File

@ -0,0 +1,77 @@
/*-----------------------------------------------------------------------/
/ Low level disk interface modlue include file (C)ChaN, 2014 /
/-----------------------------------------------------------------------*/
#ifndef _DISKIO_DEFINED
#define _DISKIO_DEFINED
#ifdef __cplusplus
extern "C" {
#endif
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
/* Command code for disk_ioctrl fucntion */
/* Generic command (Used by FatFs) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
/* Generic command (Not used by FatFs) */
#define CTRL_POWER 5 /* Get/Set power status */
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
#define CTRL_EJECT 7 /* Eject media */
#define CTRL_FORMAT 8 /* Create physical format on the media */
/* MMC/SDC specific ioctl command */
#define MMC_GET_TYPE 10 /* Get card type */
#define MMC_GET_CSD 11 /* Get CSD */
#define MMC_GET_CID 12 /* Get CID */
#define MMC_GET_OCR 13 /* Get OCR */
#define MMC_GET_SDSTAT 14 /* Get SD status */
#define ISDIO_READ 55 /* Read data form SD iSDIO register */
#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
/* ATA/CF specific ioctl command */
#define ATA_GET_REV 20 /* Get F/W revision */
#define ATA_GET_MODEL 21 /* Get model name */
#define ATA_GET_SN 22 /* Get serial number */
#ifdef __cplusplus
}
#endif
#endif

6590
arm7/source/fat/ff.c Normal file

File diff suppressed because it is too large Load Diff

409
arm7/source/fat/ff.h Normal file
View File

@ -0,0 +1,409 @@
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.13c /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 2018, ChaN, all right reserved.
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
/ that the following condition is met:
/ 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer.
/
/ This software is provided by the copyright holder and contributors "AS IS"
/ and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software.
/
/----------------------------------------------------------------------------*/
#ifndef FF_DEFINED
#define FF_DEFINED 86604 /* Revision ID */
#ifdef __cplusplus
extern "C" {
#endif
#include "ffconf.h" /* FatFs configuration options */
#if FF_DEFINED != FFCONF_DEF
#error Wrong configuration file (ffconf.h).
#endif
/* Integer types used for FatFs API */
#if defined(_WIN32) /* Main development platform */
#define FF_INTDEF 2
#include <windows.h>
typedef unsigned __int64 QWORD;
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */
#define FF_INTDEF 2
#include <stdint.h>
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
typedef unsigned char BYTE; /* char must be 8-bit */
typedef uint16_t WORD; /* 16-bit unsigned integer */
typedef uint16_t WCHAR; /* 16-bit unsigned integer */
typedef uint32_t DWORD; /* 32-bit unsigned integer */
typedef uint64_t QWORD; /* 64-bit unsigned integer */
#else /* Earlier than C99 */
#define FF_INTDEF 1
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
typedef unsigned char BYTE; /* char must be 8-bit */
typedef unsigned short WORD; /* 16-bit unsigned integer */
typedef unsigned short WCHAR; /* 16-bit unsigned integer */
typedef unsigned long DWORD; /* 32-bit unsigned integer */
#endif
#include "math.h"
/* Definitions of volume management */
#if FF_MULTI_PARTITION /* Multiple partition configuration */
typedef struct {
BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
#endif
#if FF_STR_VOLUME_ID
#ifndef FF_VOLUME_STRS
extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
#endif
#endif
/* Type of path name strings on FatFs API */
#ifndef _INC_TCHAR
#define _INC_TCHAR
#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */
typedef WCHAR TCHAR;
#define _T(x) L ## x
#define _TEXT(x) L ## x
#elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */
typedef char TCHAR;
#define _T(x) u8 ## x
#define _TEXT(x) u8 ## x
#elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */
typedef DWORD TCHAR;
#define _T(x) U ## x
#define _TEXT(x) U ## x
#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3)
#error Wrong FF_LFN_UNICODE setting
#else /* ANSI/OEM code in SBCS/DBCS */
typedef char TCHAR;
#define _T(x) x
#define _TEXT(x) x
#endif
#endif
/* Type of file size variables */
#if FF_FS_EXFAT
#if FF_INTDEF != 2
#error exFAT feature wants C99 or later
#endif
typedef QWORD FSIZE_t;
#else
typedef DWORD FSIZE_t;
#endif
/* Filesystem object structure (FATFS) */
typedef struct {
BYTE fs_type; /* Filesystem type (0:not mounted) */
BYTE pdrv; /* Associated physical drive */
BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
WORD id; /* Volume mount ID */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
WORD csize; /* Cluster size [sectors] */
#if FF_MAX_SS != FF_MIN_SS
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
#endif
#if FF_USE_LFN
WCHAR* lfnbuf; /* LFN working buffer */
#endif
#if FF_FS_EXFAT
BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
#endif
#if FF_FS_REENTRANT
FF_SYNC_t sobj; /* Identifier of sync object */
#endif
#if !FF_FS_READONLY
DWORD last_clst; /* Last allocated cluster */
DWORD free_clst; /* Number of free clusters */
#endif
#if FF_FS_RPATH
DWORD cdir; /* Current directory start cluster (0:root) */
#if FF_FS_EXFAT
DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
#endif
#endif
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
DWORD fsize; /* Size of an FAT [sectors] */
DWORD volbase; /* Volume base sector */
DWORD fatbase; /* FAT base sector */
DWORD dirbase; /* Root directory base sector/cluster */
DWORD database; /* Data base sector */
#if FF_FS_EXFAT
DWORD bitbase; /* Allocation bitmap base sector */
#endif
DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[FF_MAX_SS] __attribute__((aligned(32))); /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS;
/* Object ID and allocation information (FFOBJID) */
typedef struct {
FATFS* fs; /* Pointer to the hosting volume of this object */
WORD id; /* Hosting volume mount ID */
BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
#if FF_FS_EXFAT
DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */
DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */
#endif
#if FF_FS_LOCK
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
#endif
} FFOBJID;
/* File object structure (FIL) */
typedef struct {
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
BYTE flag; /* File status flags */
BYTE err; /* Abort flag (error code) */
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
#if !FF_FS_READONLY
DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
#endif
#if FF_USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
#endif
#if !FF_FS_TINY
BYTE buf[FF_MAX_SS] __attribute__((aligned(32))); /* File private data read/write window */
#endif
} FIL;
/* Directory object structure (DIR) */
typedef struct {
FFOBJID obj; /* Object identifier */
DWORD dptr; /* Current read/write offset */
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector (0:Read operation has terminated) */
BYTE* dir; /* Pointer to the directory item in the win[] */
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
#if FF_USE_LFN
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
#endif
#if FF_USE_FIND
const TCHAR* pat; /* Pointer to the name matching pattern */
#endif
} DIR;
/* File information structure (FILINFO) */
typedef struct {
FSIZE_t fsize; /* File size */
WORD fdate; /* Modified date */
WORD ftime; /* Modified time */
BYTE fattrib; /* File attribute */
#if FF_USE_LFN
TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */
TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
#else
TCHAR fname[12 + 1]; /* File name */
#endif
} FILINFO;
/* File function return code (FRESULT) */
typedef enum {
FR_OK = 0, /* (0) Succeeded */
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
FR_INT_ERR, /* (2) Assertion failed */
FR_NOT_READY, /* (3) The physical drive cannot work */
FR_NO_FILE, /* (4) Could not find the file */
FR_NO_PATH, /* (5) Could not find the path */
FR_INVALID_NAME, /* (6) The path name format is invalid */
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
FR_EXIST, /* (8) Access denied due to prohibited access */
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FR_NOT_ENABLED, /* (12) The volume has no work area */
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
} FRESULT;
/*--------------------------------------------------------------*/
/* FatFs module application interface */
DWORD f_clst2sect(FATFS* fs, DWORD clst);
DWORD f_getFat(FIL* fp, DWORD clst);
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
FRESULT f_close (FIL* fp); /* Close an open file object */
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
FRESULT f_truncate (FIL* fp); /* Truncate the file */
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
FRESULT f_closedir (DIR* dp); /* Close an open directory */
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
FRESULT f_setcp (WORD cp); /* Set current code page */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
#define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr)
#define f_size(fp) ((fp)->obj.objsize)
#define f_rewind(fp) f_lseek((fp), 0)
#define f_rewinddir(dp) f_readdir((dp), 0)
#define f_rmdir(path) f_unlink(path)
#define f_unmount(path) f_mount(0, path, 0)
#ifndef EOF
#define EOF (-1)
#endif
/*--------------------------------------------------------------*/
/* Additional user defined functions */
/* RTC function */
#if !FF_FS_READONLY && !FF_FS_NORTC
DWORD get_fattime (void);
#endif
/* LFN support functions */
#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
#endif
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
void* ff_memalloc (UINT msize); /* Allocate memory block */
void ff_memfree (void* mblock); /* Free memory block */
#endif
/* Sync functions */
#if FF_FS_REENTRANT
int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */
int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */
void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */
int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */
#endif
/*--------------------------------------------------------------*/
/* Flags and offset address */
/* File access mode and open method flags (3rd argument of f_open) */
#define FA_READ 0x01
#define FA_WRITE 0x02
#define FA_OPEN_EXISTING 0x00
#define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
#define FA_OPEN_APPEND 0x30
/* Fast seek controls (2nd argument of f_lseek) */
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
/* Format options (2nd argument of f_mkfs) */
#define FM_FAT 0x01
#define FM_FAT32 0x02
#define FM_EXFAT 0x04
#define FM_ANY 0x07
#define FM_SFD 0x08
/* Filesystem type (FATFS.fs_type) */
#define FS_FAT12 1
#define FS_FAT16 2
#define FS_FAT32 3
#define FS_EXFAT 4
/* File attribute bits for directory entry (FILINFO.fattrib) */
#define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
#ifdef __cplusplus
}
#endif
#endif /* FF_DEFINED */

288
arm7/source/fat/ffconf.h Normal file
View File

@ -0,0 +1,288 @@
/*---------------------------------------------------------------------------/
/ FatFs Functional Configurations
/---------------------------------------------------------------------------*/
#define FFCONF_DEF 86604 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
/---------------------------------------------------------------------------*/
#define FF_FS_READONLY 1
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/ and optional writing functions as well. */
#define FF_FS_MINIMIZE 0
/* This option defines minimization level to remove some basic API functions.
/
/ 0: Basic functions are fully enabled.
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
/ are removed.
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/ 3: f_lseek() function is removed in addition to 2. */
#define FF_USE_STRFUNC 1
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
/
/ 0: Disable string functions.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */
#define FF_USE_FIND 0
/* This option switches filtered directory read functions, f_findfirst() and
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
#define FF_USE_MKFS 0
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define FF_USE_FASTSEEK 0
/* This option switches fast seek function. (0:Disable or 1:Enable) */
#define FF_USE_EXPAND 0
/* This option switches f_expand function. (0:Disable or 1:Enable) */
#define FF_USE_CHMOD 0
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
#define FF_USE_LABEL 0
/* This option switches volume label functions, f_getlabel() and f_setlabel().
/ (0:Disable or 1:Enable) */
#define FF_USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
#define FF_CODE_PAGE 437 //932
/* This option specifies the OEM code page to be used on the target system.
/ Incorrect code page setting can cause a file open failure.
/
/ 437 - U.S.
/ 720 - Arabic
/ 737 - Greek
/ 771 - KBL
/ 775 - Baltic
/ 850 - Latin 1
/ 852 - Latin 2
/ 855 - Cyrillic
/ 857 - Turkish
/ 860 - Portuguese
/ 861 - Icelandic
/ 862 - Hebrew
/ 863 - Canadian French
/ 864 - Arabic
/ 865 - Nordic
/ 866 - Russian
/ 869 - Greek 2
/ 932 - Japanese (DBCS)
/ 936 - Simplified Chinese (DBCS)
/ 949 - Korean (DBCS)
/ 950 - Traditional Chinese (DBCS)
/ 0 - Include all code pages above and configured by f_setcp()
*/
#define FF_USE_LFN 1
#define FF_MAX_LFN 255
/* The FF_USE_LFN switches the support for LFN (long file name).
/
/ 0: Disable LFN. FF_MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
/ be in range of 12 to 255. It is recommended to be set 255 to fully support LFN
/ specification.
/ When use stack for the working buffer, take care on stack overflow. When use heap
/ memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree() in ffsystem.c, need to be added to the project. */
#define FF_LFN_UNICODE 0
/* This option switches the character encoding on the API when LFN is enabled.
/
/ 0: ANSI/OEM in current CP (TCHAR = char)
/ 1: Unicode in UTF-16 (TCHAR = WCHAR)
/ 2: Unicode in UTF-8 (TCHAR = char)
/ 3: Unicode in UTF-32 (TCHAR = DWORD)
/
/ Also behavior of string I/O functions will be affected by this option.
/ When LFN is not enabled, this option has no effect. */
#define FF_LFN_BUF 255
#define FF_SFN_BUF 12
/* This set of options defines size of file name members in the FILINFO structure
/ which is used to read out directory items. These values should be suffcient for
/ the file names to read. The maximum possible length of the read file name depends
/ on character encoding. When LFN is not enabled, these options have no effect. */
#define FF_STRF_ENCODE 3
/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),
/ f_putc(), f_puts and f_printf() convert the character encoding in it.
/ This option selects assumption of character encoding ON THE FILE to be
/ read/written via those functions.
/
/ 0: ANSI/OEM in current CP
/ 1: Unicode in UTF-16LE
/ 2: Unicode in UTF-16BE
/ 3: Unicode in UTF-8
*/
#define FF_FS_RPATH 1
/* This option configures support for relative path.
/
/ 0: Disable relative path and remove related functions.
/ 1: Enable relative path. f_chdir() and f_chdrive() are available.
/ 2: f_getcwd() function is available in addition to 1.
*/
/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/
#define FF_VOLUMES 2
/* Number of volumes (logical drives) to be used. (1-10) */
#define FF_STR_VOLUME_ID 1
#define FF_VOLUME_STRS "fat","sd"//"RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
/ logical drives. Number of items must not be less than FF_VOLUMES. Valid
/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
/ not defined, a user defined volume string table needs to be defined as:
/
/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
*/
#define FF_MULTI_PARTITION 0
/* This option switches support for multiple volumes on the physical drive.
/ By default (0), each logical drive number is bound to the same physical drive
/ number and only an FAT volume found on the physical drive will be mounted.
/ When this function is enabled (1), each logical drive number can be bound to
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/ funciton will be available. */
#define FF_MIN_SS 512
#define FF_MAX_SS 512
/* This set of options configures the range of sector size to be supported. (512,
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
/ harddisk. But a larger value may be required for on-board flash memory and some
/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
/ for variable sector size mode and disk_ioctl() function needs to implement
/ GET_SECTOR_SIZE command. */
#define FF_USE_TRIM 0
/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
/ disk_ioctl() function. */
#define FF_FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/
/ bit0=0: Use free cluster count in the FSINFO if available.
/ bit0=1: Do not trust free cluster count in the FSINFO.
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
*/
/*---------------------------------------------------------------------------/
/ System Configurations
/---------------------------------------------------------------------------*/
#define FF_FS_TINY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.
/ Instead of private sector buffer eliminated from the file object, common sector
/ buffer in the filesystem object (FATFS) is used for the file data transfer. */
#define FF_FS_EXFAT 0
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
#define FF_FS_NORTC 1
#define FF_NORTC_MON 1
#define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2018
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
/ added to the project to read current time form real-time clock. FF_NORTC_MON,
/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
/ These options have no effect at read-only configuration (FF_FS_READONLY = 1). */
#define FF_FS_LOCK 0
/* The option FF_FS_LOCK switches file lock function to control duplicated file open
/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY
/ is 1.
/
/ 0: Disable file lock function. To avoid volume corruption, application program
/ should avoid illegal open, remove and rename to the open objects.
/ >0: Enable file lock function. The value defines how many files/sub-directories
/ can be opened simultaneously under file lock control. Note that the file
/ lock control is independent of re-entrancy. */
/* #include <somertos.h> // O/S definitions */
#define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000
#define FF_SYNC_t HANDLE
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this function.
/
/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect.
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
/ function, must be added to the project. Samples are available in
/ option/syscall.c.
/
/ The FF_FS_TIMEOUT defines timeout period in unit of time tick.
/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.h. */
/*--- End of configuration options ---*/

170
arm7/source/fat/ffsystem.c Normal file
View File

@ -0,0 +1,170 @@
/*------------------------------------------------------------------------*/
/* Sample Code of OS Dependent Functions for FatFs */
/* (C)ChaN, 2018 */
/*------------------------------------------------------------------------*/
#include "ff.h"
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
/*------------------------------------------------------------------------*/
/* Allocate a memory block */
/*------------------------------------------------------------------------*/
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
UINT msize /* Number of bytes to allocate */
)
{
return malloc(msize); /* Allocate a new memory block with POSIX API */
}
/*------------------------------------------------------------------------*/
/* Free a memory block */
/*------------------------------------------------------------------------*/
void ff_memfree (
void* mblock /* Pointer to the memory block to free (nothing to do if null) */
)
{
free(mblock); /* Free the memory block with POSIX API */
}
#endif
#if FF_FS_REENTRANT /* Mutal exclusion */
/*------------------------------------------------------------------------*/
/* Create a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to create a new
/ synchronization object for the volume, such as semaphore and mutex.
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
*/
//const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */
int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */
BYTE vol, /* Corresponding volume (logical drive number) */
FF_SYNC_t* sobj /* Pointer to return the created sync object */
)
{
/* Win32 */
*sobj = CreateMutex(NULL, FALSE, NULL);
return (int)(*sobj != INVALID_HANDLE_VALUE);
/* uITRON */
// T_CSEM csem = {TA_TPRI,1,1};
// *sobj = acre_sem(&csem);
// return (int)(*sobj > 0);
/* uC/OS-II */
// OS_ERR err;
// *sobj = OSMutexCreate(0, &err);
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */
// *sobj = xSemaphoreCreateMutex();
// return (int)(*sobj != NULL);
/* CMSIS-RTOS */
// *sobj = osMutexCreate(&Mutex[vol]);
// return (int)(*sobj != NULL);
}
/*------------------------------------------------------------------------*/
/* Delete a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to delete a synchronization
/ object that created with ff_cre_syncobj() function. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */
FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
)
{
/* Win32 */
return (int)CloseHandle(sobj);
/* uITRON */
// return (int)(del_sem(sobj) == E_OK);
/* uC/OS-II */
// OS_ERR err;
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err);
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */
// vSemaphoreDelete(sobj);
// return 1;
/* CMSIS-RTOS */
// return (int)(osMutexDelete(sobj) == osOK);
}
/*------------------------------------------------------------------------*/
/* Request Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on entering file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
FF_SYNC_t sobj /* Sync object to wait */
)
{
/* Win32 */
return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0);
/* uITRON */
// return (int)(wai_sem(sobj) == E_OK);
/* uC/OS-II */
// OS_ERR err;
// OSMutexPend(sobj, FF_FS_TIMEOUT, &err));
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */
// return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE);
/* CMSIS-RTOS */
// return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK);
}
/*------------------------------------------------------------------------*/
/* Release Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leaving file functions to unlock the volume.
*/
void ff_rel_grant (
FF_SYNC_t sobj /* Sync object to be signaled */
)
{
/* Win32 */
ReleaseMutex(sobj);
/* uITRON */
// sig_sem(sobj);
/* uC/OS-II */
// OSMutexPost(sobj);
/* FreeRTOS */
// xSemaphoreGive(sobj);
/* CMSIS-RTOS */
// osMutexRelease(sobj);
}
#endif

15597
arm7/source/fat/ffunicode.c Normal file

File diff suppressed because it is too large Load Diff

141
arm7/source/fpsAdjust.c Normal file
View File

@ -0,0 +1,141 @@
#include <nds.h>
#include <string.h>
#include <math.h>
#include "fpsAdjust.h"
#include "isdprint.h"
static fpsa_t* sActiveFpsa = NULL;
static void vcountIrqLower()
{
while (1)
{
if (sActiveFpsa->initial)
{
sActiveFpsa->initial = FALSE;
break;
}
if (!sActiveFpsa->backJump)
sActiveFpsa->cycleDelta += sActiveFpsa->targetCycles - ((u64)FPSA_CYCLES_PER_FRAME << 24);
u32 linesToAdd = 0;
while (sActiveFpsa->cycleDelta >= (s64)((u64)FPSA_CYCLES_PER_LINE << 23))
{
sActiveFpsa->cycleDelta -= (u64)FPSA_CYCLES_PER_LINE << 24;
if (++linesToAdd == 5)
break;
}
if (linesToAdd == 0)
{
sActiveFpsa->backJump = FALSE;
break;
}
if (linesToAdd > 1)
{
sActiveFpsa->backJump = TRUE;
}
else
{
// don't set the backJump flag because the irq is not retriggered if the new vcount
// is the same as the previous line
sActiveFpsa->backJump = FALSE;
}
// ensure we won't accidentally run out of line time
while (REG_DISPSTAT & DISP_IN_HBLANK)
;
int curVCount = REG_VCOUNT;
REG_VCOUNT = curVCount - (linesToAdd - 1);
if (linesToAdd == 1)
break;
while (REG_VCOUNT >= curVCount)//FPSA_ADJUST_MAX_VCOUNT - 5)
;
while (REG_VCOUNT < curVCount)//FPSA_ADJUST_MAX_VCOUNT - 5)
;
}
REG_IF = IRQ_VCOUNT;
}
static void vcountIrqHigher()
{
if (sActiveFpsa->initial)
{
sActiveFpsa->initial = FALSE;
return;
}
sActiveFpsa->cycleDelta += ((u64)FPSA_CYCLES_PER_FRAME << 24) - sActiveFpsa->targetCycles;
u32 linesToSkip = 0;
while (sActiveFpsa->cycleDelta >= (s64)((u64)FPSA_CYCLES_PER_LINE << 23))
{
sActiveFpsa->cycleDelta -= (u64)FPSA_CYCLES_PER_LINE << 24;
if (++linesToSkip == 5)
break;
}
if (linesToSkip == 0)
return;
// ensure we won't accidentally run out of line time
while (REG_DISPSTAT & DISP_IN_HBLANK)
;
REG_VCOUNT = REG_VCOUNT + (linesToSkip + 1);
}
void fpsa_init(fpsa_t* fpsa)
{
memset(fpsa, 0, sizeof(fpsa_t));
fpsa->isStarted = FALSE;
fpsa_setTargetFrameCycles(fpsa, (u64)FPSA_CYCLES_PER_FRAME << 24); // default to no adjustment
}
void fpsa_start(fpsa_t* fpsa)
{
int irq = enterCriticalSection();
do
{
if (fpsa->isStarted || sActiveFpsa)
break;
if (fpsa->targetCycles == ((u64)FPSA_CYCLES_PER_FRAME << 24))
break;
irqDisable(IRQ_VCOUNT);
sActiveFpsa = fpsa;
fpsa->backJump = FALSE;
fpsa->cycleDelta = 0;
fpsa->initial = TRUE;
fpsa->isFpsLower = fpsa->targetCycles >= ((u64)FPSA_CYCLES_PER_FRAME << 24);
// prevent the irq from immediately happening
while (REG_VCOUNT != FPSA_ADJUST_MAX_VCOUNT + 2)
;
fpsa->isStarted = TRUE;
if (fpsa->isFpsLower)
{
SetYtrigger(FPSA_ADJUST_MAX_VCOUNT - 5);
irqSet(IRQ_VCOUNT, vcountIrqLower);
}
else
{
SetYtrigger(FPSA_ADJUST_MIN_VCOUNT);
irqSet(IRQ_VCOUNT, vcountIrqHigher);
}
irqEnable(IRQ_VCOUNT);
} while (0);
leaveCriticalSection(irq);
}
void fpsa_stop(fpsa_t* fpsa)
{
if (!fpsa->isStarted)
return;
sActiveFpsa = NULL;
fpsa->isStarted = FALSE;
irqDisable(IRQ_VCOUNT);
}
void fpsa_setTargetFrameCycles(fpsa_t* fpsa, u64 cycles)
{
fpsa->targetCycles = cycles;
}
void fpsa_setTargetFpsFraction(fpsa_t* fpsa, u32 num, u32 den)
{
u64 cycles = (((double)FPSA_SYS_CLOCK * den * (1 << 24)) / num) + 0.5;
fpsa_setTargetFrameCycles(fpsa, cycles);//((((u64)FPSA_SYS_CLOCK * (u64)den) << 24) + ((num + 1) >> 1)) / num);
}

45
arm7/source/fpsAdjust.h Normal file
View File

@ -0,0 +1,45 @@
#pragma once
#define FPSA_SYS_CLOCK 33513982
#define FPSA_CYCLES_PER_PIXEL 6
#define FPSA_LCD_WIDTH 256
#define FPSA_LCD_HBLANK 99
#define FPSA_LCD_COLUMNS (FPSA_LCD_WIDTH + FPSA_LCD_HBLANK)
#define FPSA_LCD_HEIGHT 192
#define FPSA_LCD_VBLANK 71
#define FPSA_LCD_LINES (FPSA_LCD_HEIGHT + FPSA_LCD_VBLANK)
#define FPSA_CYCLES_PER_LINE (FPSA_LCD_COLUMNS * FPSA_CYCLES_PER_PIXEL)
#define FPSA_CYCLES_PER_FRAME (FPSA_LCD_COLUMNS * FPSA_LCD_LINES * FPSA_CYCLES_PER_PIXEL)
#define FPSA_ADJUST_MIN_VCOUNT 202
#define FPSA_ADJUST_MAX_VCOUNT 212
typedef struct
{
u32 isStarted;
u32 isFpsLower; //TRUE if vblank needs to be extended, FALSE if it needs to be shortened
u32 backJump;
u32 initial;
u64 targetCycles; //target cycles in 0.40.24 format
s64 cycleDelta;
} fpsa_t;
void fpsa_init(fpsa_t* fpsa);
void fpsa_start(fpsa_t* fpsa);
void fpsa_stop(fpsa_t* fpsa);
//Sets the target frame rate as clock cycles per frame in 0.40.24 format
void fpsa_setTargetFrameCycles(fpsa_t* fpsa, u64 cycles);
//Sets the target frame rate as a frames per second fraction
void fpsa_setTargetFpsFraction(fpsa_t* fpsa, u32 num, u32 den);
//Sets the target frame rate in integer frames per second
static inline void fpsa_setTargetFps(fpsa_t* fpsa, u32 fps)
{
fpsa_setTargetFpsFraction(fpsa, fps, 1);
}

341
arm7/source/fvPlayer7.c Normal file
View File

@ -0,0 +1,341 @@
#include <nds.h>
#include <string.h>
#include "isdprint.h"
#include "../../common/ipc.h"
#include "fat.h"
#include "adpcm.h"
#include "irqWait.h"
#include "fvPlayer7.h"
#define FV_AUDIO_START_OFFSET 12
#define FV_AUDIO_CH_LEFT 1
#define FV_AUDIO_CH_RIGHT 3
static fv_player7_t sPlayer;
void fv_init(void)
{
memset(&sPlayer, 0, sizeof(sPlayer));
}
static inline int getAudioTimerValue(int rate)
{
return (16756991 + ((rate + 1) >> 1)) / rate;
}
static void audioFrameIrq(void)
{
}
static void decodeAudioFrame(void)
{
adpcm_decompress(sPlayer.audioQueueL[sPlayer.queueReadPtr], FV_AUDIO_FRAME_SIZE,
sPlayer.audioRingL[sPlayer.ringPos]);
adpcm_decompress(sPlayer.audioQueueR[sPlayer.queueReadPtr], FV_AUDIO_FRAME_SIZE,
sPlayer.audioRingR[sPlayer.ringPos]);
// sPlayer.ringVideoFrameIds[sPlayer.ringPos] = sPlayer.queueVideoFrameIds[sPlayer.queueReadPtr];
if (++sPlayer.ringPos == FV_AUDIO_RING_FRAMES)
sPlayer.ringPos = 0;
if (++sPlayer.queueReadPtr == FV_AUDIO_QUEUE_FRAMES)
sPlayer.queueReadPtr = 0;
sPlayer.queueFrameCount--;
sPlayer.audioFramesNeeded--;
sPlayer.audioFramesProvided++;
}
static void startAudio(void)
{
if (sPlayer.audioStarted)
return;
sPlayer.ringPos = 0;
sPlayer.audioFramesNeeded = 0;
sPlayer.audioFramesProvided = 0;
for (int i = 0; i < FV_AUDIO_START_OFFSET; i++)
{
if (sPlayer.queueFrameCount == 0)
break;
decodeAudioFrame();
}
sPlayer.audioFramesProvided -= FV_AUDIO_START_OFFSET;
int tmr = getAudioTimerValue(FV_AUDIO_RATE);
SCHANNEL_SOURCE(FV_AUDIO_CH_LEFT) = (u32)sPlayer.audioRingL;
SCHANNEL_REPEAT_POINT(FV_AUDIO_CH_LEFT) = 0;
SCHANNEL_LENGTH(FV_AUDIO_CH_LEFT) = sizeof(sPlayer.audioRingL) >> 2;
SCHANNEL_TIMER(FV_AUDIO_CH_LEFT) = -tmr;
SCHANNEL_SOURCE(FV_AUDIO_CH_RIGHT) = (u32)sPlayer.audioRingR;
SCHANNEL_REPEAT_POINT(FV_AUDIO_CH_RIGHT) = 0;
SCHANNEL_LENGTH(FV_AUDIO_CH_RIGHT) = sizeof(sPlayer.audioRingR) >> 2;
SCHANNEL_TIMER(FV_AUDIO_CH_RIGHT) = -tmr;
TIMER_CR(0) = 0;
TIMER_CR(1) = 0;
TIMER_CR(2) = 0;
TIMER_CR(3) = 0;
TIMER_DATA(0) = -2; // 1/2 clock divider
TIMER_DATA(1) = -tmr; // sample rate
TIMER_DATA(2) = -256; // length of audio frame
TIMER_DATA(3) = 0; // audio block counter
TIMER_CR(3) = TIMER_CASCADE | TIMER_ENABLE;
TIMER_CR(2) = TIMER_CASCADE | TIMER_ENABLE | TIMER_IRQ_REQ;
TIMER_CR(1) = TIMER_CASCADE | TIMER_ENABLE;
irqSet(IRQ_TIMER2, audioFrameIrq);
irqEnable(IRQ_TIMER2);
SCHANNEL_CR(FV_AUDIO_CH_LEFT) =
SCHANNEL_ENABLE | SOUND_VOL(0x7F) | SOUND_PAN(0) | SOUND_FORMAT_16BIT | SOUND_REPEAT;
SCHANNEL_CR(FV_AUDIO_CH_RIGHT) =
SCHANNEL_ENABLE | SOUND_VOL(0x7F) | SOUND_PAN(0x7F) | SOUND_FORMAT_16BIT | SOUND_REPEAT;
TIMER_CR(0) = TIMER_ENABLE;
sPlayer.audioStarted = true;
}
static void stopAudio(void)
{
if (!sPlayer.audioStarted)
return;
sPlayer.audioStarted = false;
TIMER_CR(0) = 0;
irqDisable(IRQ_TIMER2);
SCHANNEL_CR(FV_AUDIO_CH_LEFT) = 0;
SCHANNEL_CR(FV_AUDIO_CH_RIGHT) = 0;
TIMER_CR(1) = 0;
TIMER_CR(2) = 0;
TIMER_CR(3) = 0;
sPlayer.ringPos = 0;
memset(&sPlayer.audioRingL[0][0], 0, sizeof(sPlayer.audioRingL));
memset(&sPlayer.audioRingR[0][0], 0, sizeof(sPlayer.audioRingR));
}
static void updateAudio(void)
{
if (!sPlayer.audioStarted)
return;
int audioBlocks = TIMER_DATA(3);
int needed = audioBlocks - (sPlayer.audioFramesProvided & 0xFFFF);
if (needed < 0)
needed += 65536;
while (needed > 0 && sPlayer.queueFrameCount > 0)
{
decodeAudioFrame();
needed--;
}
}
static void gotoKeyFrameDirect(const fv_keyframe_t* keyFrameData)
{
f_lseek(&sPlayer.file, keyFrameData->offset);
// reset player state
stopAudio();
sPlayer.ringPos = 0;
sPlayer.queueReadPtr = 0;
sPlayer.queueWritePtr = 0;
sPlayer.queueFrameCount = 0;
sPlayer.audioFramesNeeded = 0;
sPlayer.audioFramesProvided = 0;
memset(&sPlayer.audioQueueL[0][0], 0, sizeof(sPlayer.audioQueueL));
memset(&sPlayer.audioQueueR[0][0], 0, sizeof(sPlayer.audioQueueR));
}
static u32 gotoKeyFrame(u32 keyFrame)
{
UINT br;
fv_keyframe_t keyFrameData;
f_lseek(&sPlayer.file, sizeof(fv_header_t) + sizeof(fv_keyframe_t) * keyFrame);
f_read(&sPlayer.file, &keyFrameData, sizeof(fv_keyframe_t), &br);
gotoKeyFrameDirect(&keyFrameData);
return keyFrameData.frame;
}
static u32 gotoNearestKeyFrame(u32 frame, u32* resultFrame)
{
UINT br;
fv_keyframe_t keyFrameData = { 0 };
fv_keyframe_t newKeyFrameData;
u32 keyFrameId = -1;
f_lseek(&sPlayer.file, sizeof(fv_header_t));
for (int i = 0; i < sPlayer.nrKeyFrames; i++)
{
f_read(&sPlayer.file, &newKeyFrameData, sizeof(fv_keyframe_t), &br);
if (newKeyFrameData.frame <= frame)
{
keyFrameData = newKeyFrameData;
keyFrameId = i;
}
if (newKeyFrameData.frame >= frame)
break;
}
gotoKeyFrameDirect(&keyFrameData);
if (resultFrame)
*resultFrame = keyFrameData.frame;
return keyFrameId;
}
static void handleFifo(u32 value)
{
UINT br;
switch (value >> IPC_CMD_CMD_SHIFT)
{
case IPC_CMD_READ_FRAME:
{
u32 len;
if (f_read(&sPlayer.file, &len, 4, &br) != FR_OK || br != 4)
{
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_READ_FRAME, 0));
break;
}
f_read(&sPlayer.file, (void*)(value & IPC_CMD_ARG_MASK), len & 0x1FFFF, &br);
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_READ_FRAME, len & 0x1FFFF));
// read audio frames
u32 audioFrames = len >> 17;
for (int i = 0; i < audioFrames; i++)
{
f_read(&sPlayer.file, sPlayer.audioQueueL[sPlayer.queueWritePtr], FV_AUDIO_FRAME_SIZE, &br);
f_read(&sPlayer.file, sPlayer.audioQueueR[sPlayer.queueWritePtr], FV_AUDIO_FRAME_SIZE, &br);
// sPlayer.queueVideoFrameIds[sPlayer.queueWritePtr] = sPlayer.curVideoFrame;
if (++sPlayer.queueWritePtr == FV_AUDIO_QUEUE_FRAMES)
sPlayer.queueWritePtr = 0;
sPlayer.queueFrameCount++;
}
// sPlayer.curVideoFrame++;
break;
}
case IPC_CMD_OPEN_FILE:
{
FRESULT result = f_open(&sPlayer.file, (const char*)(value & IPC_CMD_ARG_MASK), FA_OPEN_EXISTING | FA_READ);
if (result != FR_OK)
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_OPEN_FILE, 0));
else
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_OPEN_FILE, 1));
break;
}
case IPC_CMD_READ_HEADER:
{
fv_header_t* header = (fv_header_t*)(value & IPC_CMD_ARG_MASK);
f_read(&sPlayer.file, header, sizeof(fv_header_t), &br);
sPlayer.nrKeyFrames = header->nrKeyFrames;
gotoKeyFrame(0);
u32 num = header->fpsNum;
u32 den = header->fpsDen;
int vblankCount = 1;
while (num * (vblankCount + 1) / den < 62)
vblankCount++;
// safety
if (num * vblankCount / den < 62)
{
fpsa_init(&sPlayer.fpsa);
fpsa_setTargetFpsFraction(&sPlayer.fpsa, num * vblankCount, den);
sPlayer.fpsa.targetCycles =
(double)sPlayer.fpsa.targetCycles * getAudioTimerValue(FV_AUDIO_RATE) * FV_AUDIO_RATE / 16756991.0;
fpsa_start(&sPlayer.fpsa);
}
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_READ_HEADER, vblankCount));
break;
}
case IPC_CMD_GOTO_KEYFRAME:
{
u32 frame = gotoKeyFrame(value & IPC_CMD_ARG_MASK);
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_GOTO_KEYFRAME, frame));
break;
}
case IPC_CMD_GOTO_NEAREST_KEYFRAME:
{
u32 frame = value & IPC_CMD_ARG_MASK;
u32 resultFrame;
u32 keyFrame = gotoNearestKeyFrame(frame, &resultFrame);
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_GOTO_NEAREST_KEYFRAME, keyFrame));
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_GOTO_KEYFRAME, resultFrame));
break;
}
case IPC_CMD_CONTROL_AUDIO:
{
if ((value & IPC_CMD_ARG_MASK) == IPC_ARG_CONTROL_AUDIO_START)
startAudio();
else if ((value & IPC_CMD_ARG_MASK) == IPC_ARG_CONTROL_AUDIO_STOP)
stopAudio();
else if ((value & IPC_CMD_ARG_MASK) == IPC_ARG_CONTROL_AUDIO_STOP_CLEAR)
{
stopAudio();
sPlayer.ringPos = 0;
sPlayer.queueReadPtr = 0;
sPlayer.queueWritePtr = 0;
sPlayer.queueFrameCount = 0;
sPlayer.audioFramesNeeded = 0;
sPlayer.audioFramesProvided = 0;
memset(&sPlayer.audioQueueL[0][0], 0, sizeof(sPlayer.audioQueueL));
memset(&sPlayer.audioQueueR[0][0], 0, sizeof(sPlayer.audioQueueR));
}
break;
}
case IPC_CMD_SETUP_DLDI:
{
if (!isDSiMode())
{
memcpy((void*)0x037F8000, (void*)(value & IPC_CMD_ARG_MASK), 16 * 1024);
fat_mountDldi();
}
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_SETUP_DLDI, 0));
break;
}
case IPC_CMD_HANDSHAKE:
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_HANDSHAKE, 0));
break;
}
}
void fv_main(void)
{
if (!fifoCheckValue32(FIFO_USER_01))
irq_wait(false, IRQ_TIMER2 | IRQ_FIFO_NOT_EMPTY);
updateAudio();
if (fifoCheckValue32(FIFO_USER_01))
handleFifo(fifoGetValue32(FIFO_USER_01));
}

32
arm7/source/fvPlayer7.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#include "../../common/fastVideo.h"
#include "fat/ff.h"
#include "fpsAdjust.h"
#define FV_AUDIO_QUEUE_FRAMES 64
#define FV_AUDIO_RING_FRAMES 24
typedef struct
{
bool audioStarted;
FIL file;
fpsa_t fpsa;
u32 nrKeyFrames;
// u32 curVideoFrame;
int queueReadPtr;
int queueWritePtr;
int queueFrameCount;
int audioFramesNeeded;
int audioFramesProvided;
int ringPos;
// u32 queueVideoFrameIds[FV_AUDIO_QUEUE_FRAMES];
// u32 ringVideoFrameIds[FV_AUDIO_RING_FRAMES];
u8 audioQueueL[FV_AUDIO_QUEUE_FRAMES][FV_AUDIO_FRAME_SIZE] ALIGN(4);
u8 audioQueueR[FV_AUDIO_QUEUE_FRAMES][FV_AUDIO_FRAME_SIZE] ALIGN(4);
s16 audioRingL[FV_AUDIO_RING_FRAMES][FV_AUDIO_FRAME_SAMPLES] ALIGN(4);
s16 audioRingR[FV_AUDIO_RING_FRAMES][FV_AUDIO_FRAME_SAMPLES] ALIGN(4);
} fv_player7_t;
void fv_init(void);
void fv_main(void);

3
arm7/source/irqWait.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
extern void irq_wait(bool clearFlags, u32 mask);

53
arm7/source/irqWait.s Normal file
View File

@ -0,0 +1,53 @@
.arm
.cpu arm7tdmi
.text
.global irq_wait
irq_wait:
push {lr}
mrs r12, cpsr
orr r2, r12, #0x80 //cpsr disable irq
msr cpsr_c, r2
and r12, r12, #0x80
mov r2, #0x04000000
ldr r3, [r2, #0x208] //old ime state
mov lr, #1
str lr, [r2, #0x208] //enable ime
cmp r0, #1
bne 1f
ldr lr, [r2, #-8] //check flags
bic lr, lr, r1
str lr, [r2, #-8]
1:
ldr lr, [r2, #-8] //check flags
tst lr, r1
bne 2f
swi (6 << 16) //halt
mrs lr, cpsr
bic lr, lr, #0x80 //cpsr enable irq
msr cpsr_c, lr
//here the interrupt handler will be called
mrs lr, cpsr
orr lr, lr, #0x80 //cpsr disable irq
msr cpsr_c, lr
b 1b
2:
bic lr, lr, r1
str lr, [r2, #-8]
str r3, [r2, #0x208] //restore ime
mrs lr, cpsr
bic lr, lr, #0x80
orr lr, lr, r12
msr cpsr_c, lr
pop {r3}
bx r3

9
arm7/source/isdprint.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
// #define PRINT_DEBUG
#ifdef PRINT_DEBUG
void isnd_printchar(char c);
void isnd_initPrint();
void isnd_printf(const char *fmt, ...);
#endif

161
arm7/source/main.c Normal file
View File

@ -0,0 +1,161 @@
#include <nds.h>
#include <nds/fifomessages.h>
#include <string.h>
#include "../../common/ipc.h"
#include "fat/ff.h"
#include "isdprint.h"
#include "fat.h"
#include "fvPlayer7.h"
#include "../../common/twlwram.h"
volatile bool exitflag = false;
static u16 sVBlankTime;
static u16 sLastVBlankTime;
static int sSleepCounter = 0;
enum
{
KEYXY_TOUCH = (1 << 6),
KEYXY_LID = (1 << 7)
};
// fixes issue with missing touch inputs
static void inputGetAndSendNew(void)
{
touchPosition tempPos = { 0 };
FifoMessage msg = { 0 };
u16 keys = REG_KEYXY;
if (!touchPenDown())
keys |= KEYXY_TOUCH;
else
keys &= ~KEYXY_TOUCH;
msg.SystemInput.keys = keys;
if (!(keys & KEYXY_TOUCH))
{
msg.SystemInput.keys |= KEYXY_TOUCH;
touchReadXY(&tempPos);
if (tempPos.rawx && tempPos.rawy)
{
msg.SystemInput.keys &= ~KEYXY_TOUCH;
msg.SystemInput.touch = tempPos;
}
}
if (keys & KEYXY_LID)
sSleepCounter++;
else
sSleepCounter = 0;
// sleep if lid has been closed for 20 frames
if (sSleepCounter >= 20)
{
systemSleep();
sSleepCounter = 0;
}
msg.type = SYS_INPUT_MESSAGE;
fifoSendDatamsg(FIFO_SYSTEM, sizeof(msg), (u8*)&msg);
}
void VblankHandler(void)
{
inputGetAndSendNew();
if (0 == (REG_KEYINPUT & (KEY_SELECT | KEY_START | KEY_L | KEY_R)))
exitflag = true;
int time = sVBlankTime - sLastVBlankTime;
if (time < 0)
time += 65536;
// isnd_printf("%d\n", time);
sLastVBlankTime = sVBlankTime;
// if(sTimingStarted)
// {
// sVblankCount++;
// u64 time = (((u64)TIMER_DATA(0) | ((u64)TIMER_DATA(1) << 16) | ((u64)TIMER_DATA(2) << 32)) + (sVblankCount + 1
// >> 1)) / sVblankCount; isnd_printf("%d\n", (u32)((33513982LL * 10000) / time));
// }
// else if (sStartTiming)
// {
// TIMER_CR(0) = 0;
// TIMER_CR(1) = 0;
// TIMER_CR(2) = 0;
// TIMER_DATA(0) = 0;
// TIMER_DATA(1) = 0;
// TIMER_DATA(2) = 0;
// TIMER_CR(2) = TIMER_CASCADE | TIMER_ENABLE;
// TIMER_CR(1) = TIMER_CASCADE | TIMER_ENABLE;
// TIMER_CR(0) = TIMER_ENABLE;
// sStartTiming = FALSE;
// sTimingStarted = TRUE;
// }
}
void powerButtonCB()
{
exitflag = true;
}
extern void enableSound(void);
int main(void)
{
// clear sound registers
dmaFillWords(0, (void*)0x04000400, 0x100);
if (isDSiMode())
{
twr_setBlockMapping(TWR_WRAM_BLOCK_B, 0x03100000, 0x40000, TWR_WRAM_BLOCK_IMAGE_SIZE_256K);
twr_setBlockMapping(TWR_WRAM_BLOCK_C, 0x03140000, 0x40000, TWR_WRAM_BLOCK_IMAGE_SIZE_256K);
// switch to 47kHz output
REG_SNDEXTCNT = 0;
REG_SNDEXTCNT = SNDEXTCNT_FREQ_47KHZ | SNDEXTCNT_RATIO(8);
cdcWriteReg(CDC_CONTROL, 6, 15);
cdcWriteReg(CDC_CONTROL, 11, 0x85);
cdcWriteReg(CDC_CONTROL, 18, 0x85);
REG_SNDEXTCNT |= SNDEXTCNT_ENABLE;
}
enableSound();
readUserSettings();
ledBlink(0);
irqInit();
initClockIRQ();
fifoInit();
touchInit();
installSystemFIFO();
irqSet(IRQ_VBLANK, VblankHandler);
irqEnable(IRQ_VBLANK | IRQ_NETWORK);
setPowerButtonCB(powerButtonCB);
#ifdef PRINT_DEBUG
isnd_initPrint();
#endif
fat_init();
fv_init();
swiWaitForVBlank();
while (!exitflag)
{
fv_main();
}
return 0;
}

146
arm9/Makefile Normal file
View File

@ -0,0 +1,146 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
# DATA is a list of directories containing binary files
# all directories are relative to this makefile
#---------------------------------------------------------------------------------
BUILD := build
SOURCES := source source/FastVideo ../common source/gui source/gui/core
INCLUDES := include
DATA := data
GRAPHICS := gfx
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -marm -mthumb-interwork
CFLAGS := -g -Wall -O3\
-ffunction-sections -fdata-sections \
-march=armv5te -mtune=arm946e-s -fomit-frame-pointer\
-ffast-math \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM9
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s $(INCLUDE)
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lnds9
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export ARM9ELF := $(CURDIR)/$(TARGET).elf
export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))\
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir))
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(PNGFILES:.png=.o)\
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) *.elf *.nds* *.bin
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(ARM9ELF) : $(OFILES)
@echo linking $(notdir $@)
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
%.ntft.o : %.ntft
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
# This rule creates assembly source files using grit
# grit takes an image file and a .grit describing how the file is to be processed
# add additional rules like this for each image extension
# you use in the graphics folders
#---------------------------------------------------------------------------------
%.s %.h: %.png %.grit
#---------------------------------------------------------------------------------
grit $< -fts -o$*
-include $(DEPSDIR)/*.d
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

Binary file not shown.

Binary file not shown.

7
arm9/gfx/circle0.grit Normal file
View File

@ -0,0 +1,7 @@
# tile format
-gt
# graphics bit depth is 4 (16 color)
-gB4
-p!

BIN
arm9/gfx/circle0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

7
arm9/gfx/circle1.grit Normal file
View File

@ -0,0 +1,7 @@
# tile format
-gt
# graphics bit depth is 4 (16 color)
-gB4
-p!

BIN
arm9/gfx/circle1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

7
arm9/gfx/iconPause.grit Normal file
View File

@ -0,0 +1,7 @@
# tile format
-gt
# graphics bit depth is 4 (16 color)
-gB4
-p!

BIN
arm9/gfx/iconPause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

7
arm9/gfx/iconPlay.grit Normal file
View File

@ -0,0 +1,7 @@
# tile format
-gt
# graphics bit depth is 4 (16 color)
-gB4
-p!

BIN
arm9/gfx/iconPlay.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

17
arm9/gfx/playBg.grit Normal file
View File

@ -0,0 +1,17 @@
# tile format
-gt
# tile reduction by tiles, palette and hflip/vflip
-mRtpf
# graphics bit depth is 4 (16 color)
-gB4
-p
-pn16
# map layout standard bg format
-mLs
-gzl
-mzl

BIN
arm9/gfx/playBg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

View File

@ -0,0 +1,38 @@
#include <nds.h>
#include "fvConst.h"
DTCM_DATA u8 fv_gClampTable[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F
};
u32 fv_gDCTQTab2x2[] =
{
0x00000000, 0x00000008, 0x00000010, 0x00000018,
0x00000020, 0x00000028, 0x00000030, 0x00000038,
0x00000040, 0x00000048, 0x00000050, 0x00000058,
0x00000060, 0x00000068, 0x00000070, 0x00000078,
0x00000002, 0x0000000A, 0x00000012, 0x0000001A,
0x00000022, 0x0000002A, 0x00000032, 0x0000003A,
0x00000042, 0x0000004A, 0x00000052, 0x0000005A,
0x00000062, 0x0000006A, 0x00000072, 0x0000007A,
0x00000004, 0x0000000C, 0x00000014, 0x0000001C,
0x00000024, 0x0000002C, 0x00000034, 0x0000003C,
0x00000044, 0x0000004C, 0x00000054, 0x0000005C,
0x00000064, 0x0000006C, 0x00000074, 0x0000007C,
0x00000006, 0x0000000E, 0x00000016, 0x0000001E,
0x00000026, 0x0000002E, 0x00000036, 0x0000003E,
0x00000046, 0x0000004E, 0x00000056, 0x0000005E,
0x00000066, 0x0000006E, 0x00000076, 0x0000007E
};

View File

@ -0,0 +1,9 @@
#pragma once
extern u8 fv_gDequantCoefs4[];
extern u8 fv_gDeZigZagTable4x4[];
extern u32 fv_gDCTQTab2x2[];
extern u8 fv_gClampTable[];
extern u8 fv_gVlcIdxTab[];
extern u8 fv_gVlcBitTab2[];
extern u32 fv_gVlcPackTab[];

View File

@ -0,0 +1,688 @@
.section .dtcm
.global fv_gVlcValueExTab
fv_gVlcValueExTab:
.byte 0x1B, 0xFB, 0x2A, 0xD6, 0x29, 0xD7, 0x28, 0xD8, 0x02, 0xFE, 0x03, 0xFD, 0x03, 0xFD, 0x06, 0xFA
.byte 0x0E, 0xF2, 0x05, 0x27, 0xD5, 0xF1, 0x02, 0xFE, 0x02, 0x1E, 0x05, 0xFB, 0x05, 0xFB, 0x05, 0xFB
.byte 0x07, 0xF9, 0x08, 0xF8, 0x10, 0xF0, 0x0F, 0x2B, 0xD4, 0xD9, 0xDA, 0xDE, 0x0C, 0xF4, 0x21, 0xDF
.byte 0x06, 0xFA, 0x20, 0xE0, 0x1F, 0xE1, 0x1C, 0xE4, 0x1D, 0xE3, 0x0B, 0xF5, 0x22, 0x26, 0xDD, 0xFB
.byte 0x25, 0xDB, 0x04, 0xFC, 0x04, 0xFC, 0x07, 0xF9, 0x0D, 0xF3, 0x24, 0xDC, 0x04, 0xFC, 0x04, 0xFC
.byte 0x05, 0x23, 0x2C, 0xFE, 0x2D, 0x2E, 0xD2, 0x32, 0xCE, 0x33, 0xCD, 0x12, 0xD1, 0xEE, 0xFC, 0xD3
.byte 0x34, 0xCC, 0x35, 0xCB, 0x36, 0x04, 0xCA, 0x2F, 0x11, 0x31, 0xCF, 0x30, 0xD0, 0x02, 0xFE, 0x06
.byte 0xEF, 0xFA, 0xFC, 0x06, 0xFA, 0x08, 0xF8, 0x09, 0xF7, 0x04, 0x13, 0xE2, 0x06, 0xFA, 0x06, 0xF6
.byte 0xFE, 0xEC, 0x0A, 0x02, 0xED, 0xFA, 0x14, 0xFE, 0x02, 0xFE, 0x02, 0xFE, 0x05, 0xFB, 0x0C, 0x02
.byte 0xFE, 0xF4, 0xFC, 0x04, 0x03, 0xFD, 0x0D, 0xF3, 0x0F, 0xF1, 0x0E, 0xF2, 0x02, 0xFE, 0xF7, 0x09
.byte 0x02, 0xFE, 0x04, 0xFC, 0x06, 0xFA, 0xF6, 0x02, 0x0A, 0xFE, 0x02, 0xFC, 0xFE, 0xFE, 0x02, 0x02
.byte 0xFE, 0x04, 0xF5, 0xFD, 0x03, 0xFE, 0x02, 0xFE, 0x02, 0x0B, 0xFE, 0xFC, 0x10, 0xFE, 0x02, 0x02
.byte 0xFC, 0x04, 0xFD, 0x04, 0x03, 0x04, 0xFD, 0x03, 0xFD, 0x03, 0xF0, 0xFC, 0x02, 0, 0, 0
.global fv_gVlcBitTab
fv_gVlcBitTab:
.byte 0x01, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09
.byte 0x09, 0x09, 0x0A, 0x09, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x05, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A
.byte 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x09, 0x09, 0x07, 0x07, 0x07, 0x07, 0x07
.byte 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x07, 0x09, 0x07, 0x07
.byte 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07
.byte 0x07, 0x07, 0x0B, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0B, 0x0C, 0x0C, 0x0B
.byte 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0B, 0x0B, 0x0B
.byte 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0D, 0x05, 0x0D, 0x0D, 0x0D, 0x0D
.byte 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0D
.byte 0x0D, 0x0A, 0x07, 0x07, 0x07, 0x07, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0A, 0x0A, 0x05, 0x05
.byte 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B, 0x07, 0x0A, 0x07, 0x0D, 0x0D, 0x0C, 0x0C, 0x09, 0x09, 0x0C
.byte 0x0C, 0x0C, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D
.byte 0x0D, 0x0D, 0x08, 0x0C, 0x08, 0x0D, 0x08, 0x08, 0x08, 0x08, 0x0D, 0x0D, 0x0C, 0, 0, 0
.global fv_gVlcValueTab
fv_gVlcValueTab:
.byte 0x00, 0xFE, 0x0F, 0xF1, 0x0E, 0xF2, 0x0D, 0xF3, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x02, 0xFE
.byte 0x04, 0xFC, 0x02, 0x0C, 0xF0, 0xFB, 0x01, 0xFF, 0x01, 0x03, 0x02, 0xFE, 0x02, 0xFE, 0x02, 0xFE
.byte 0x03, 0xFD, 0x03, 0xFD, 0x06, 0xFA, 0x05, 0x10, 0xEF, 0xF4, 0xF5, 0xF9, 0x02, 0xFE, 0x06, 0xFA
.byte 0x01, 0xFF, 0x05, 0xFB, 0x04, 0xFC, 0x01, 0xFF, 0x02, 0xFE, 0x01, 0xFF, 0x07, 0x0B, 0xF8, 0xFF
.byte 0x0A, 0xF6, 0x01, 0xFF, 0x01, 0xFF, 0x02, 0xFE, 0x03, 0xFD, 0x09, 0xF7, 0x01, 0xFF, 0x01, 0xFF
.byte 0x01, 0x08, 0x11, 0xFF, 0x12, 0x13, 0xED, 0x17, 0xE9, 0x18, 0xE8, 0x08, 0xEC, 0xF8, 0xFE, 0xEE
.byte 0x19, 0xE7, 0x1A, 0xE6, 0x1B, 0x02, 0xE5, 0x14, 0x07, 0x16, 0xEA, 0x15, 0xEB, 0x01, 0xFF, 0x03
.byte 0xF9, 0xFD, 0xFE, 0x03, 0xFD, 0x04, 0xFC, 0x04, 0xFC, 0x02, 0x09, 0xFD, 0x03, 0xFD, 0x03, 0xFB
.byte 0xFF, 0xF6, 0x05, 0x01, 0xF7, 0xFD, 0x0A, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x02, 0xFE, 0x04, 0x01
.byte 0xFF, 0xFC, 0xFF, 0x01, 0x01, 0xFF, 0x05, 0xFB, 0x07, 0xF9, 0x06, 0xFA, 0x01, 0xFF, 0xFF, 0x01
.byte 0x01, 0xFF, 0x02, 0xFE, 0x03, 0xFD, 0xFE, 0x01, 0x02, 0xFF, 0x01, 0xFE, 0xFF, 0xFF, 0x01, 0x01
.byte 0xFF, 0x02, 0xFD, 0xFF, 0x01, 0xFF, 0x01, 0xFF, 0x01, 0x03, 0xFF, 0xFE, 0x08, 0xFF, 0x01, 0x01
.byte 0xFE, 0x02, 0xFF, 0x02, 0x01, 0x02, 0xFF, 0x01, 0xFF, 0x01, 0xF8, 0xFE, 0x01, 0, 0, 0
.global fv_gVlcSkipTab
fv_gVlcSkipTab:
.byte 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0B, 0x0B, 0x0A, 0x0A, 0x09, 0x09, 0x04, 0x04
.byte 0x02, 0x02, 0x05, 0x01, 0x01, 0x02, 0x0D, 0x0D, 0x0C, 0x01, 0x08, 0x08, 0x07, 0x07, 0x06, 0x06
.byte 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01
.byte 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x01, 0x04
.byte 0x01, 0x01, 0x07, 0x07, 0x08, 0x08, 0x03, 0x03, 0x02, 0x02, 0x01, 0x01, 0x06, 0x06, 0x05, 0x05
.byte 0x04, 0x01, 0x01, 0x0C, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x0A, 0x01
.byte 0x01, 0x01, 0x01, 0x01, 0x01, 0x0A, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x0E, 0x0E, 0x06
.byte 0x02, 0x06, 0x09, 0x05, 0x05, 0x04, 0x04, 0x03, 0x03, 0x09, 0x02, 0x01, 0x07, 0x08, 0x08, 0x03
.byte 0x0F, 0x02, 0x03, 0x0F, 0x02, 0x07, 0x02, 0x0D, 0x0C, 0x0C, 0x0B, 0x0B, 0x02, 0x02, 0x01, 0x15
.byte 0x15, 0x01, 0x02, 0x02, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0F, 0x0F, 0x01, 0x01
.byte 0x0E, 0x0E, 0x03, 0x03, 0x02, 0x02, 0x01, 0x0D, 0x01, 0x12, 0x14, 0x05, 0x10, 0x0A, 0x0A, 0x11
.byte 0x11, 0x05, 0x01, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x01, 0x14, 0x04, 0x01, 0x13, 0x13, 0x12
.byte 0x07, 0x07, 0x06, 0x04, 0x06, 0x06, 0x04, 0x04, 0x05, 0x05, 0x01, 0x06, 0x10, 0, 0, 0
.global fv_gVlcSkipExTab
fv_gVlcSkipExTab:
.byte 0x02, 0x0F, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x1A, 0x1A, 0x19, 0x19, 0x18, 0x18, 0x0E, 0x0E
.byte 0x06, 0x06, 0x0F, 0x02, 0x02, 0x05, 0x1C, 0x1C, 0x1B, 0x09, 0x12, 0x12, 0x11, 0x11, 0x10, 0x10
.byte 0x0C, 0x0C, 0x0B, 0x0B, 0x04, 0x04, 0x05, 0x02, 0x02, 0x02, 0x02, 0x03, 0x0C, 0x0C, 0x03, 0x03
.byte 0x12, 0x12, 0x04, 0x04, 0x05, 0x05, 0x10, 0x10, 0x0B, 0x0B, 0x11, 0x11, 0x03, 0x02, 0x03, 0x13
.byte 0x03, 0x03, 0x16, 0x16, 0x17, 0x17, 0x0D, 0x0D, 0x0A, 0x0A, 0x03, 0x03, 0x15, 0x15, 0x14, 0x14
.byte 0x13, 0x03, 0x02, 0x1B, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x04, 0x14, 0x02
.byte 0x02, 0x02, 0x02, 0x02, 0x02, 0x14, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, 0x02, 0x1D, 0x1D, 0x0E
.byte 0x04, 0x0E, 0x13, 0x0D, 0x0D, 0x08, 0x08, 0x07, 0x07, 0x13, 0x04, 0x09, 0x0F, 0x10, 0x10, 0x06
.byte 0x1E, 0x04, 0x06, 0x1E, 0x04, 0x0F, 0x04, 0x22, 0x21, 0x21, 0x20, 0x20, 0x09, 0x09, 0x02, 0x2A
.byte 0x2A, 0x02, 0x17, 0x17, 0x18, 0x18, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x24, 0x24, 0x16, 0x16
.byte 0x23, 0x23, 0x0A, 0x0A, 0x04, 0x04, 0x08, 0x22, 0x08, 0x27, 0x29, 0x0C, 0x25, 0x1F, 0x1F, 0x26
.byte 0x26, 0x0C, 0x03, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x03, 0x29, 0x0B, 0x02, 0x28, 0x28, 0x27
.byte 0x0E, 0x0E, 0x1B, 0x0B, 0x1B, 0x0D, 0x19, 0x19, 0x1A, 0x1A, 0x02, 0x0D, 0x25, 0, 0, 0
.global fv_gVlcIdxTab
fv_gVlcIdxTab:
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
.byte 0x98, 0x98, 0x99, 0x99, 0x9A, 0x9A, 0x9B, 0x9B, 0x69, 0x69, 0x6A, 0x6A, 0x6B, 0x6B, 0x6C, 0x6C
.byte 0xA2, 0xA2, 0xA2, 0xA2, 0xA3, 0xA3, 0xA3, 0xA3, 0xA4, 0xA4, 0xA4, 0xA4, 0xA5, 0xA5, 0xA5, 0xA5
.byte 0x96, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x97, 0x6D, 0x6D, 0x6D, 0x6D, 0x6E, 0x6E, 0x6E, 0x6E
.byte 0x6F, 0x6F, 0x6F, 0x6F, 0x71, 0x71, 0x71, 0x71, 0x79, 0x79, 0x79, 0x79, 0x72, 0x72, 0x72, 0x72
.byte 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, 0x76, 0x76, 0x76, 0x76
.byte 0x77, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x78, 0x68, 0x68, 0x68, 0x68, 0x70, 0x70, 0x70, 0x70
.byte 0x67, 0x67, 0x67, 0x67, 0x5C, 0x5C, 0x5C, 0x5C, 0x55, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, 0x56
.byte 0x57, 0x57, 0x58, 0x58, 0x59, 0x59, 0x5A, 0x5A, 0x5B, 0x5B, 0x5D, 0x5D, 0x65, 0x65, 0x5E, 0x5E
.byte 0xC3, 0xC3, 0xBB, 0xBB, 0xB1, 0xB1, 0xAB, 0xAB, 0xCC, 0xCC, 0xAC, 0xAC, 0xAF, 0xAF, 0xB0, 0xB0
.byte 0x60, 0x61, 0x62, 0x63, 0x64, 0x66, 0x7A, 0x84, 0x7C, 0x85, 0x86, 0x81, 0x82, 0x7F, 0x7E, 0x7D
.byte 0x83, 0x80, 0xBC, 0xCA, 0xC5, 0xCB, 0xC1, 0xC0, 0xBF, 0xA9, 0xBE, 0xBD, 0xAA, 0xBA, 0x8F, 0x90
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
.byte 0x54, 0x54, 0x54, 0x54, 0x5F, 0x5F, 0x5F, 0x5F, 0x52, 0x52, 0x52, 0x52, 0x28, 0x28, 0x28, 0x28
.byte 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D
.byte 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1
.byte 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87
.byte 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89
.byte 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B
.byte 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D
.byte 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91
.byte 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17
.byte 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53
.byte 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B
.byte 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D
.byte 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F
.byte 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21
.byte 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23
.byte 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25
.byte 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15
.byte 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14
.byte 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
.byte 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
.byte 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05
.byte 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
.byte 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8
.byte 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7
.byte 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6
.byte 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5
.byte 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4
.byte 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3
.byte 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9
.byte 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2
.byte 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
.byte 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09
.byte 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A
.byte 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B
.byte 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C
.byte 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D
.byte 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE
.byte 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD
.byte 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E
.byte 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F
.byte 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
.byte 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
.byte 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13
.byte 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29
.byte 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D
.byte 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A
.byte 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
.byte 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41
.byte 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9
.byte 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9
.byte 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8
.byte 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8
.byte 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7
.byte 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7
.byte 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6
.byte 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6
.byte 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42
.byte 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42
.byte 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43
.byte 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43
.byte 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4
.byte 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4
.byte 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2
.byte 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2
.byte 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44
.byte 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44
.byte 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45
.byte 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45
.byte 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46
.byte 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46
.byte 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47
.byte 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47
.byte 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48
.byte 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48
.byte 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49
.byte 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49
.byte 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A
.byte 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A
.byte 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B
.byte 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B
.byte 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8
.byte 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8
.byte 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8
.byte 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8
.byte 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6
.byte 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6
.byte 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6
.byte 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6
.byte 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C
.byte 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C
.byte 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C
.byte 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C
.byte 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D
.byte 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D
.byte 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D
.byte 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D
.byte 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94
.byte 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94
.byte 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94
.byte 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94
.byte 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95
.byte 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95
.byte 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95
.byte 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95
.byte 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93
.byte 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93
.byte 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93
.byte 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93
.byte 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92
.byte 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92
.byte 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92
.byte 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92
.byte 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E
.byte 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E
.byte 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E
.byte 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4E
.byte 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F
.byte 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F
.byte 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F
.byte 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F
.byte 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50
.byte 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50
.byte 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50
.byte 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50
.byte 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
.byte 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
.byte 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
.byte 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
.byte 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51
.byte 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51
.byte 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51
.byte 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51
.byte 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E
.byte 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E
.byte 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E
.byte 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E
.byte 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C
.byte 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C
.byte 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C
.byte 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C
.byte 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B
.byte 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B
.byte 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B
.byte 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B
.byte 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C
.byte 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C
.byte 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C
.byte 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C
.byte 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D
.byte 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D
.byte 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D
.byte 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D
.byte 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E
.byte 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E
.byte 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E
.byte 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E
.byte 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F
.byte 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F
.byte 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F
.byte 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F
.byte 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
.byte 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
.byte 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
.byte 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
.byte 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
.byte 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
.byte 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
.byte 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
.byte 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
.byte 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
.byte 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
.byte 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
.byte 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
.byte 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
.byte 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
.byte 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
.byte 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32
.byte 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32
.byte 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32
.byte 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32
.byte 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32
.byte 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32
.byte 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32
.byte 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32
.byte 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33
.byte 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33
.byte 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33
.byte 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33
.byte 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33
.byte 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33
.byte 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33
.byte 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33
.byte 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34
.byte 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34
.byte 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34
.byte 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34
.byte 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34
.byte 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34
.byte 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34
.byte 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34
.byte 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35
.byte 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35
.byte 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35
.byte 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35
.byte 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35
.byte 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35
.byte 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35
.byte 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.byte 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B
.global fv_gVlcBitTab2
fv_gVlcBitTab2:
.byte 0x01, 0x0C, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0D, 0x0D, 0x01, 0x01, 0x01, 0x01
.byte 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A
.byte 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09
.byte 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09
.byte 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
.byte 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
.byte 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
.byte 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
.byte 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
.byte 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
.byte 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
.byte 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06
.byte 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06
.byte 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06
.byte 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05
.byte 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05
.byte 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
.byte 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
.byte 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
.byte 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
.byte 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
.byte 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
.byte 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
.byte 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
.byte 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04
.byte 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04
.byte 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04
.byte 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04
.byte 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05
.byte 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05
.byte 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05
.byte 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05
.global fv_gVlcPackTab
fv_gVlcPackTab:
.word 0x04000000, 0x1400FFFE, 0x0400000F, 0x0400FFF1
.word 0x0400000E, 0x0400FFF2, 0x0400000D, 0x0400FFF3
.word 0x2C000001, 0x2C00FFFF, 0x28000001, 0x2800FFFF
.word 0x24000001, 0x2400FFFF, 0x10000002, 0x1000FFFE
.word 0x08000004, 0x0800FFFC, 0x14000002, 0x0400000C
.word 0x0400FFF0, 0x0800FFFB, 0x34000001, 0x3400FFFF
.word 0x30000001, 0x04000003, 0x20000002, 0x2000FFFE
.word 0x1C000002, 0x1C00FFFE, 0x18000002, 0x1800FFFE
.word 0x10000003, 0x1000FFFD, 0x0C000003, 0x0C00FFFD
.word 0x08000006, 0x0800FFFA, 0x08000005, 0x04000010
.word 0x0400FFEF, 0x0400FFF4, 0x0400FFF5, 0x0400FFF9
.word 0x08000002, 0x0800FFFE, 0x04000006, 0x0400FFFA
.word 0x0C000001, 0x0C00FFFF, 0x04000005, 0x0400FFFB
.word 0x04000004, 0x0400FFFC, 0x04000001, 0x0400FFFF
.word 0x04000002, 0x0400FFFE, 0x08000001, 0x0800FFFF
.word 0x04000007, 0x0400000B, 0x0400FFF8, 0x1000FFFF
.word 0x0400000A, 0x0400FFF6, 0x1C000001, 0x1C00FFFF
.word 0x20000001, 0x2000FFFF, 0x0C000002, 0x0C00FFFE
.word 0x08000003, 0x0800FFFD, 0x04000009, 0x0400FFF7
.word 0x18000001, 0x1800FFFF, 0x14000001, 0x1400FFFF
.word 0x10000001, 0x04000008, 0x04000011, 0x3000FFFF
.word 0x04000012, 0x04000013, 0x0400FFED, 0x04000017
.word 0x0400FFE9, 0x04000018, 0x0400FFE8, 0x08000008
.word 0x0400FFEC, 0x0800FFF8, 0x2800FFFE, 0x0400FFEE
.word 0x04000019, 0x0400FFE7, 0x0400001A, 0x0400FFE6
.word 0x0400001B, 0x28000002, 0x0400FFE5, 0x04000014
.word 0x08000007, 0x04000016, 0x0400FFEA, 0x04000015
.word 0x0400FFEB, 0x38000001, 0x3800FFFF, 0x18000003
.word 0x0800FFF9, 0x1800FFFD, 0x2400FFFE, 0x14000003
.word 0x1400FFFD, 0x10000004, 0x1000FFFC, 0x0C000004
.word 0x0C00FFFC, 0x24000002, 0x08000009, 0x0400FFFD
.word 0x1C000003, 0x2000FFFD, 0x20000003, 0x0C00FFFB
.word 0x3C00FFFF, 0x0800FFF6, 0x0C000005, 0x3C000001
.word 0x0800FFF7, 0x1C00FFFD, 0x0800000A, 0x3401FFFF
.word 0x30010001, 0x3001FFFF, 0x2C010001, 0x2C01FFFF
.word 0x08010002, 0x0801FFFE, 0x04010004, 0x54010001
.word 0x5401FFFF, 0x0401FFFC, 0x0801FFFF, 0x08010001
.word 0x0C010001, 0x0C01FFFF, 0x04010005, 0x0401FFFB
.word 0x04010007, 0x0401FFF9, 0x04010006, 0x0401FFFA
.word 0x3C010001, 0x3C01FFFF, 0x0401FFFF, 0x04010001
.word 0x38010001, 0x3801FFFF, 0x0C010002, 0x0C01FFFE
.word 0x08010003, 0x0801FFFD, 0x0401FFFE, 0x34010001
.word 0x04010002, 0x4801FFFF, 0x50010001, 0x1401FFFE
.word 0x4001FFFF, 0x2801FFFF, 0x28010001, 0x44010001
.word 0x4401FFFF, 0x14010002, 0x0401FFFD, 0x1C01FFFF
.word 0x1C010001, 0x2001FFFF, 0x20010001, 0x2401FFFF
.word 0x24010001, 0x04010003, 0x5001FFFF, 0x1001FFFE
.word 0x04010008, 0x4C01FFFF, 0x4C010001, 0x48010001
.word 0x1C01FFFE, 0x1C010002, 0x1801FFFF, 0x10010002
.word 0x18010001, 0x18010002, 0x1001FFFF, 0x10010001
.word 0x1401FFFF, 0x14010001, 0x0401FFF8, 0x1801FFFE
.word 0x40010001
.align 4

View File

@ -0,0 +1,22 @@
#include <nds.h>
#include "fvConst.h"
#include "fvDecoder.h"
void fv_initDecoderAsm(fv_decoder_asm_t* dec)
{
dec->q = 0xFF;
for(int i = 0; i < 64; i++)
dec->qTab[i] = fv_gDCTQTab2x2[i];
dec->clampTable = &fv_gClampTable[32];
dec->vlcIdxTab = fv_gVlcIdxTab;
dec->vlcBitTab2 = fv_gVlcBitTab2;
dec->vlcPackTab = fv_gVlcPackTab;
dec->dequant0 = 32 | (23 << 16);
dec->dequant1 = 23 | (64 << 16);
dec->dequantP0 = 32 | (23 << 16);
dec->dequantP1 = 23 | (64 << 16);
// dec->dequantP0 = 32 | (36 << 16);
// dec->dequantP1 = 36 | (48 << 16);
// dec->dequant0 = 64 | (46 << 16);
// dec->dequant1 = 46 | (128 << 16);
}

View File

@ -0,0 +1,39 @@
#pragma once
#include "../../common/fastVideo.h"
typedef struct
{
u16 qTab[16];
u8 q;
} fv_decoder_t;
typedef struct
{
u32 qTab[64];
const u8* clampTable;
const u8* vlcIdxTab;
const u8* vlcBitTab2;
const u32* vlcPackTab;
u32 dequant0;
u32 dequant1;
u32 dequantP0;
u32 dequantP1;
u32 q;
u32 yBlocks;
u32 texYOffset;
const u32* dlB;
u32 pFrameIsIBlock[24];
} fv_decoder_asm_t;
void fv_initDecoder(fv_decoder_t* dec);
void fv_initDecoderAsm(fv_decoder_asm_t* dec);
void fv_decodeFrame(fv_decoder_t* dec, const u16* src, u8* dst);
extern void fv_decodeFrame_asm(fv_decoder_asm_t* dec, const u16* src, u8* dst);
extern const u16* fv_decodePFrameVectors(fv_decoder_asm_t* dec, const u16* src);
extern void fv_decodePFrameDcts(fv_decoder_asm_t* dec, const u16* src, u8* residual);
extern void fv_finishPBlock(fv_decoder_asm_t* dec, const u8* residual, const u16* prediction);
static inline int fv_frameIsP(const u16* src)
{
return *src >> 15;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
#pragma once
extern u32 fv_gMcGxCmdBuf[];
extern u32 fv_gMcGxCmdBufA[];

View File

@ -0,0 +1,73 @@
.section .data
#define GX_CMD_PACK(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
#define GX_CMD_NOP 0x00
#define GX_CMD_TRANSLATE 0x20
#define GX_CMD_COLOR 0x20
#define GX_CMD_NORMAL 0x21
#define GX_CMD_TEXCOORD 0x22
#define GX_CMD_VTX_16 0x23
#define GX_CMD_VTX_10 0x24
#define GX_CMD_VTX_XY 0x25
#define GX_CMD_VTX_XZ 0x26
#define GX_CMD_VTX_YZ 0x27
#define GX_CMD_VTX_DIFF 0x28
#define GX_CMD_POLY_ATTR 0x29
#define GX_CMD_TEX_PARAM 0x2A
#define GX_CMD_BEGIN 0x40
#define GX_CMD_END 0x41
#define GX_CMD_SWAPBUFFERS 0x50
#define GX_BEGIN_TRIANGLE 0x00
#define GX_BEGIN_QUAD 0x01
#define GX_BEGIN_TRI_STRIP 0x02
#define GX_BEGIN_QUAD_STRIP 0x03
#define BLOCK_VTX_PACK(x,y,z) (((x) & 0x3FF) | ((((y) >> 3) & 0x3FF) << 10) | ((z) << 20))
#define VTX_PACK(a,b) (((a) & 0xFFFF) | (((b) & 0xFFFF) << 16))
#define HEIGHT 192 //144
.balign 32 //cache alignment
.global fv_gMcGxCmdBuf
fv_gMcGxCmdBuf:
.word GX_CMD_PACK(GX_CMD_POLY_ATTR, GX_CMD_BEGIN, GX_CMD_COLOR, 0x71)
.word 0x1F00C0
.word GX_BEGIN_TRI_STRIP
.word 0
.word 0
.word 40 << 6
.rept 11
.word GX_CMD_PACK(GX_CMD_VTX_XY, GX_CMD_VTX_XY, GX_CMD_VTX_XY, GX_CMD_VTX_XY)
.word VTX_PACK(0 << 6, -256 << 3)
.word VTX_PACK(0 << 6, 2 << 3)
.word VTX_PACK(256 << 6, 2 << 3)
.word VTX_PACK(0 << 6, -256 << 3)
.word GX_CMD_PACK(GX_CMD_VTX_XY, GX_CMD_VTX_XY, GX_CMD_VTX_XY, GX_CMD_VTX_XY)
.word VTX_PACK(0 << 6, 2 << 3)
.word VTX_PACK(256 << 6, 2 << 3)
.word VTX_PACK(0 << 6, -256 << 3)
.word VTX_PACK(0 << 6, 2 << 3)
.word GX_CMD_PACK(GX_CMD_VTX_XY, GX_CMD_VTX_XY, GX_CMD_VTX_XY, GX_CMD_VTX_XY)
.word VTX_PACK(256 << 6, 2 << 3)
.word VTX_PACK(0 << 6, -256 << 3)
.word VTX_PACK(0 << 6, 2 << 3)
.word VTX_PACK(256 << 6, 2 << 3)
.endr
.word GX_CMD_END
.word GX_CMD_PACK(GX_CMD_POLY_ATTR, GX_CMD_TEX_PARAM, GX_CMD_COLOR, GX_CMD_BEGIN)
.word 0x1F0080
.word (0xDED00000)// + ((24 * 256 * 2) >> 3))
.word 0x7FFF //color
.word GX_BEGIN_TRIANGLE
.global fv_gMcGxCmdBufA
fv_gMcGxCmdBufA:
.space 30768
.balign 32 //cache alignment
.end

View File

@ -0,0 +1,520 @@
#include <nds.h>
#include <stdio.h>
#include "../../common/ipc.h"
#include "../../common/twlwram.h"
#include "fvMcData.h"
#include "fvPlayer.h"
static ITCM_CODE void requestDataBuffer(fv_player_t* player)
{
int irq = enterCriticalSection();
do
{
if (player->isRequesting)
break;
player->isRequesting = TRUE;
if (isDSiMode())
{
// map wram block to arm7
int slot = (player->dataBufferWriteIdx * 2) & 7;
if (player->dataBufferWriteIdx < 4)
{
twr_mapWramBSlot(slot, TWR_WRAM_B_SLOT_MASTER_ARM7, slot, true);
twr_mapWramBSlot(slot + 1, TWR_WRAM_B_SLOT_MASTER_ARM7, slot + 1, true);
}
else
{
twr_mapWramCSlot(slot, TWR_WRAM_C_SLOT_MASTER_ARM7, slot, true);
twr_mapWramCSlot(slot + 1, TWR_WRAM_C_SLOT_MASTER_ARM7, slot + 1, true);
}
}
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_READ_FRAME,
(u32)fv_getPlayerDataBuffer(player, player->dataBufferWriteIdx)));
} while (0);
leaveCriticalSection(irq);
}
static ITCM_CODE void fifoHandler(u32 value, void* arg)
{
fv_player_t* player = (fv_player_t*)arg;
u32 cmd = value >> IPC_CMD_CMD_SHIFT;
if (cmd == IPC_CMD_READ_FRAME)
{
if (isDSiMode())
{
// map wram block to arm9
int slot = (player->dataBufferWriteIdx * 2) & 7;
if (player->dataBufferWriteIdx < 4)
{
twr_mapWramBSlot(slot, TWR_WRAM_B_SLOT_MASTER_ARM9, slot, true);
twr_mapWramBSlot(slot + 1, TWR_WRAM_B_SLOT_MASTER_ARM9, slot + 1, true);
}
else
{
twr_mapWramCSlot(slot, TWR_WRAM_C_SLOT_MASTER_ARM9, slot, true);
twr_mapWramCSlot(slot + 1, TWR_WRAM_C_SLOT_MASTER_ARM9, slot + 1, true);
}
}
player->isRequesting = FALSE;
u32 length = value & IPC_CMD_ARG_MASK;
if (length == 0)
{
// todo: this means the video has ended
return;
}
player->frameDataSizes[player->dataBufferWriteIdx] = length;
player->frameHasAudio[player->dataBufferWriteIdx] = true;
if (++player->dataBufferWriteIdx == FV_PLAYER_DATA_BUFFER_COUNT)
player->dataBufferWriteIdx = 0;
player->validDataBufferCount++;
if (--player->freeDataBufferCount != 0 && player->isPlaying)
requestDataBuffer(player);
}
else if (cmd == IPC_CMD_GOTO_KEYFRAME)
{
player->curFrame = value & IPC_CMD_ARG_MASK;
player->seekComplete = true;
}
else if (cmd == IPC_CMD_GOTO_NEAREST_KEYFRAME)
{
player->lastKeyFrame = value & IPC_CMD_ARG_MASK;
}
// else if ((value >> IPC_CMD_CMD_SHIFT) == 0xE)
// {
// // iprintf("%d\n", value & 0xFFFF);
// }
}
static volatile DTCM_BSS int sVBlankCount;
static ITCM_CODE void vblankHandler()
{
sVBlankCount++;
}
static void setupProjectionMtx()
{
glMatrixMode(GL_PROJECTION);
MATRIX_LOAD4x3 = divf32(inttof32(2), (256 << 6) - 0);
MATRIX_LOAD4x3 = 0;
MATRIX_LOAD4x3 = 0;
MATRIX_LOAD4x3 = 0;
MATRIX_LOAD4x3 = -21845;
MATRIX_LOAD4x3 = 0;
MATRIX_LOAD4x3 = 0;
MATRIX_LOAD4x3 = 0;
MATRIX_LOAD4x3 = 4096 >> 5;
MATRIX_LOAD4x3 = -divf32((256 << 6), (256 << 6));
MATRIX_LOAD4x3 = -divf32((192 << 6), -(192 << 6));
MATRIX_LOAD4x3 = 0;
}
static void setupTextureMtx()
{
glMatrixMode(GL_TEXTURE);
MATRIX_LOAD4x3 = 4096 * 64 * 16;
MATRIX_LOAD4x3 = 0;
MATRIX_LOAD4x3 = 0;
MATRIX_LOAD4x3 = 0;
MATRIX_LOAD4x3 = 4096 * 64 * 8 * 16;
MATRIX_LOAD4x3 = 0;
MATRIX_LOAD4x3 = 0;
MATRIX_LOAD4x3 = 0;
MATRIX_LOAD4x3 = 0;
MATRIX_LOAD4x3 = 0;
MATRIX_LOAD4x3 = 0;
MATRIX_LOAD4x3 = 0;
}
static void setup3DEngine()
{
powerOn(POWER_3D_CORE | POWER_MATRIX);
while (GFX_BUSY)
;
GFX_STATUS |= 1 << 29; // clear fifo
glResetMatrixStack();
glFlush(1);
GFX_CONTROL = 0x9;
glClearColor(0, 0, 0, 31);
glClearPolyID(63);
glClearDepth(0x7FFF);
glFlush(0);
setupProjectionMtx();
setupTextureMtx();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0, 0, 255, 191);
}
static ITCM_CODE void executeDisplayList(const fv_player_t* player)
{
DMA3_SRC = (u32)fv_gMcGxCmdBuf;
DMA3_DEST = (u32)&GFX_FIFO;
DMA3_CR = DMA_FIFO | (player->dlLength >> 2);
}
static ITCM_CODE void startCapture(int dst)
{
REG_DISPCAPCNT = DCAP_ENABLE | DCAP_MODE(DCAP_MODE_A) | DCAP_BANK(dst) | DCAP_SIZE(DCAP_SIZE_256x192) |
DCAP_SRC_A(DCAP_SRC_A_3DONLY);
}
#define BLOCK_VTX_PACK(x, y, z) (((x)&0x3FF) | ((((y) >> 3) & 0x3FF) << 10) | ((z) << 20))
static u32* makeMbRenderDl(u32* displayList, int height, u32 texParam)
{
int y = 0;
for (; y < height / 8 / 2; y++)
{
for (int x = 0; x < 256 / 8; x++)
{
*displayList++ = FIFO_COMMAND_PACK(FIFO_TEX_COORD, FIFO_VERTEX10, FIFO_VERTEX10, FIFO_VERTEX10);
*displayList++ = 0; // texcoord placeholder
*displayList++ = BLOCK_VTX_PACK(x * 8, y * 8 - 8, 33 - x);
*displayList++ = BLOCK_VTX_PACK(x * 8, y * 8 + 8, 32 - x);
*displayList++ = BLOCK_VTX_PACK(x * 8 + 16, y * 8 + 8, 32 - x);
}
}
*displayList++ = FIFO_COMMAND_PACK(FIFO_END, FIFO_TEX_FORMAT, FIFO_BEGIN, FIFO_NOP);
*displayList++ = texParam;
*displayList++ = GL_TRIANGLES;
for (; y < height / 8; y++)
{
for (int x = 0; x < 256 / 8; x++)
{
*displayList++ = FIFO_COMMAND_PACK(FIFO_TEX_COORD, FIFO_VERTEX10, FIFO_VERTEX10, FIFO_VERTEX10);
*displayList++ = 0; // texcoord placeholder
*displayList++ = BLOCK_VTX_PACK(x * 8, y * 8 - 8, 33 - x);
*displayList++ = BLOCK_VTX_PACK(x * 8, y * 8 + 8, 32 - x);
*displayList++ = BLOCK_VTX_PACK(x * 8 + 16, y * 8 + 8, 32 - x);
}
}
return displayList;
}
bool fv_initPlayer(fv_player_t* player, const char* filePath)
{
memset(player, 0, sizeof(fv_player_t));
if (isDSiMode())
player->dataBuffer = (u8*)twr_getBlockAddress(TWR_WRAM_BLOCK_B);
else
player->dataBuffer = memalign(32, FV_PLAYER_DATA_BUFFER_SIZE * FV_PLAYER_DATA_BUFFER_COUNT);
player->fvHeader = memalign(32, sizeof(fv_header_t));
player->dataBufferReadIdx = 0;
player->dataBufferWriteIdx = 0;
player->validDataBufferCount = 0;
player->stage1Buffer = -1;
player->stage2Buffer = -1;
fv_initDecoderAsm(&player->decoder);
vramSetBankA(VRAM_A_LCD);
vramSetBankB(VRAM_B_LCD);
vramSetBankC(VRAM_C_LCD);
// open file
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_OPEN_FILE, filePath));
fifoWaitValue32(FIFO_USER_01);
if ((fifoGetValue32(FIFO_USER_01) & IPC_CMD_ARG_MASK) == 0)
return false;
// open file and read header
DC_InvalidateRange(player->fvHeader, sizeof(fv_header_t));
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_READ_HEADER, (u32)player->fvHeader));
fifoWaitValue32(FIFO_USER_01);
player->vblankPerFrame = fifoGetValue32(FIFO_USER_01) & IPC_CMD_ARG_MASK;
if (player->fvHeader->signature != FV_SIGNATURE)
return false;
if (player->vblankPerFrame == 0)
return false;
int height = player->fvHeader->height;
player->decoder.yBlocks = height / 8;
player->decoder.texYOffset = (256 - height) << 1;
u32 texParam = 0xDED00000 + (((-(256 - height) * 256 * 2) >> 3) & 0xFFFF);
// make display list
u32* displayList = (u32*)fv_gMcGxCmdBufA;
displayList = makeMbRenderDl(displayList, height, texParam);
*displayList++ = FIFO_COMMAND_PACK(FIFO_END, FIFO_POLY_FORMAT, FIFO_TEX_FORMAT, FIFO_BEGIN);
*displayList++ = 0x0F4080;
*displayList++ = 0xDED00000;
*displayList++ = GL_TRIANGLES;
player->decoder.dlB = displayList + 1;
displayList = makeMbRenderDl(displayList, height, texParam);
*displayList++ = FIFO_COMMAND_PACK(FIFO_END, FIFO_FLUSH, FIFO_NOP, FIFO_NOP);
*displayList++ = 0;
player->dlLength = (u32)displayList - (u32)fv_gMcGxCmdBuf;
DC_FlushRange(fv_gMcGxCmdBuf, player->dlLength);
// int irq = enterCriticalSection();
// iprintf("fps %d/%d\n", player->fvHeader->fpsNum, player->fvHeader->fpsDen);
// iprintf("lcd %d/%d\n", player->fvHeader->fpsNum * player->vblankPerFrame, player->fvHeader->fpsDen);
// leaveCriticalSection(irq);
fifoSetValue32Handler(FIFO_USER_01, fifoHandler, player);
setup3DEngine();
player->lastKeyFrame = 0;
player->curFrame = 0;
return true;
}
void fv_destroyPlayer(fv_player_t* player)
{
fifoSetValue32Handler(FIFO_USER_01, NULL, NULL);
if (!isDSiMode())
free(player->dataBuffer);
}
ITCM_CODE void fv_startPlayer(fv_player_t* player)
{
if (VRAM_A_CR == 0x81)
{
player->nextVramBlock = 1;
VRAM_B_CR = 0x80;
VRAM_C_CR = 0x80;
}
else if (VRAM_B_CR == 0x81)
{
player->nextVramBlock = 2;
VRAM_A_CR = 0x80;
VRAM_C_CR = 0x80;
}
else
{
player->nextVramBlock = 0;
VRAM_A_CR = 0x80;
VRAM_B_CR = 0x80;
}
player->stage3VramBlock = -1;
player->stage2Buffer = -1;
player->stage1Buffer = -1;
player->freeDataBufferCount = FV_PLAYER_DATA_BUFFER_COUNT;
player->validDataBufferCount = 0;
player->dataBufferReadIdx = 0;
player->dataBufferWriteIdx = 0;
player->isPlaying = true;
// start by loading the first blocks of data
requestDataBuffer(player);
while (player->validDataBufferCount < 3)
;
swiWaitForVBlank();
sVBlankCount = 0;
irqSet(IRQ_VBLANK, vblankHandler);
player->lateCount = 0;
player->audioStarted = false;
player->firstKeyFrame = true;
REG_DISPCNT = MODE_5_2D | DISPLAY_BG2_ACTIVE;
REG_BG2CNT = (u16)BgSize_B16_256x256;
REG_BG2PA = 256;
REG_BG2PB = 0;
REG_BG2PC = 0;
REG_BG2PD = 256;
REG_BG2X = 0;
REG_BG2Y = -((192 - player->fvHeader->height) >> 1) << 8;
}
static void startAudio(void)
{
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_CONTROL_AUDIO, IPC_ARG_CONTROL_AUDIO_START));
}
static void stopAudio(void)
{
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_CONTROL_AUDIO, IPC_ARG_CONTROL_AUDIO_STOP));
}
static void stopAudioClearQueue(void)
{
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_CONTROL_AUDIO, IPC_ARG_CONTROL_AUDIO_STOP_CLEAR));
}
ITCM_CODE void fv_updatePlayer(fv_player_t* player)
{
if (player->validDataBufferCount > 0)
{
player->stage1Buffer = player->dataBufferReadIdx;
if (++player->dataBufferReadIdx == FV_PLAYER_DATA_BUFFER_COUNT)
player->dataBufferReadIdx = 0;
int irq = enterCriticalSection();
{
player->validDataBufferCount--;
}
leaveCriticalSection(irq);
}
const u16* nextStage2DataPtr = NULL;
int nextStage2IsPFrame = FALSE;
int doStartCapture = FALSE;
int stage1VramBlock = -1;
if (player->stage1Buffer != -1)
{
stage1VramBlock = player->nextVramBlock;
if (++player->nextVramBlock == 3)
player->nextVramBlock = 0;
const u16* dataBuf = fv_getPlayerDataBuffer(player, player->stage1Buffer);
DC_FlushAll();
// DC_InvalidateRange(dataBuf, player->frameDataSizes[player->stage1Buffer]);
int isPFrame = fv_frameIsP(dataBuf);
if (isPFrame)
{
dataBuf = fv_decodePFrameVectors(&player->decoder, dataBuf);
executeDisplayList(player);
doStartCapture = TRUE;
}
nextStage2DataPtr = dataBuf;
nextStage2IsPFrame = isPFrame;
}
bool nextStage3HasAudio = false;
if (player->stage2Buffer != -1)
{
if (player->stage2IsPFrame)
{
fv_decodePFrameDcts(&player->decoder, player->stage2DataPtr, (u8*)VRAM_D);
// DC_InvalidateRange((u16*)((u32)VRAM_A + 0x20000 * player->stage2VramBlock), 256 *
// player->fvHeader->height * 2);
DC_FlushAll();
while (sVBlankCount == 0 && REG_VCOUNT >= 192)
;
fv_finishPBlock(&player->decoder, (u8*)VRAM_D, (u16*)((u32)VRAM_A + 0x20000 * player->stage2VramBlock));
}
else
{
fv_decodeFrame_asm(&player->decoder, player->stage2DataPtr,
(u8*)((u32)VRAM_A + 0x20000 * player->stage2VramBlock));
}
nextStage3HasAudio = player->frameHasAudio[player->stage2Buffer];
int irq = enterCriticalSection();
{
player->freeDataBufferCount++;
}
leaveCriticalSection(irq);
if (player->isPlaying)
requestDataBuffer(player);
DC_FlushAll();
// DC_FlushRange((u16*)((u32)VRAM_A + 0x20000 * player->stage2VramBlock), 256 * player->fvHeader->height * 2);
}
if ((sVBlankCount == player->vblankPerFrame && (REG_VCOUNT >= 245 || REG_VCOUNT < 192)) ||
sVBlankCount > player->vblankPerFrame)
{
player->lateCount++;
int irq = enterCriticalSection();
iprintf("late %d, %d, %d\n", player->lateCount, player->stage2IsPFrame, REG_VCOUNT);
leaveCriticalSection(irq);
swiWaitForVBlank();
}
else
{
while (sVBlankCount < player->vblankPerFrame)
{
// halt to save energy, if a vblank irq already happened this will return immediately
swiIntrWait(0, IRQ_VBLANK);
}
}
sVBlankCount = 0;
// iprintf("\n%d", GFX_RDLINES_COUNT);
if (player->stage1Buffer != -1)
{
*(vu8*)(0x04000240 + stage1VramBlock) = 0x80; // map to lcdc
}
if (player->stage3VramBlock != -1)
{
*(vu8*)(0x04000240 + player->stage3VramBlock) = 0x81; // map to bg
player->stage3VramBlock = -1;
if (!player->audioStarted && player->stage3HasAudio)
{
player->audioStarted = true;
startAudio();
}
if (player->firstKeyFrame)
player->firstKeyFrame = false;
else
{
player->curFrame++;
if (!player->stage3IsPFrame)
player->lastKeyFrame++;
}
}
if (player->stage2Buffer != -1)
{
*(vu8*)(0x04000240 + player->stage2VramBlock) = 0x83; // map to tex
player->stage3VramBlock = player->stage2VramBlock;
player->stage2VramBlock = -1;
player->stage3IsPFrame = player->stage2IsPFrame;
player->stage3HasAudio = nextStage3HasAudio;
}
player->stage2Buffer = player->stage1Buffer;
player->stage1Buffer = -1;
player->stage2DataPtr = nextStage2DataPtr;
player->stage2IsPFrame = nextStage2IsPFrame;
player->stage2VramBlock = stage1VramBlock;
if (doStartCapture)
startCapture(stage1VramBlock);
}
void fv_pausePlayer(fv_player_t* player)
{
player->isPlaying = false;
while (player->isRequesting)
;
stopAudioClearQueue();
player->audioStarted = false;
for (int i = 0; i < FV_PLAYER_DATA_BUFFER_COUNT; i++)
player->frameHasAudio[i] = false;
player->stage3HasAudio = false;
}
void fv_resumePlayer(fv_player_t* player)
{
sVBlankCount = 0;
player->isPlaying = true;
}
void fv_gotoKeyFrame(fv_player_t* player, u32 keyFrame)
{
if (keyFrame >= player->fvHeader->nrKeyFrames)
keyFrame = player->fvHeader->nrKeyFrames - 1;
player->isPlaying = false;
player->seekComplete = false;
while (player->isRequesting)
;
stopAudio();
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_GOTO_KEYFRAME, keyFrame));
while (!player->seekComplete)
;
while (REG_DISPCAPCNT & DCAP_ENABLE)
;
player->lastKeyFrame = keyFrame;
}
void fv_gotoNearestKeyFrame(fv_player_t* player, u32 frame)
{
if (frame >= player->fvHeader->nrFrames)
frame = player->fvHeader->nrFrames - 1;
player->isPlaying = false;
player->seekComplete = false;
while (player->isRequesting)
;
stopAudio();
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_GOTO_NEAREST_KEYFRAME, frame));
while (!player->seekComplete)
;
while (REG_DISPCAPCNT & DCAP_ENABLE)
;
}

View File

@ -0,0 +1,84 @@
#pragma once
#include "fvDecoder.h"
//the player has 4 stages
//0 - fetching video data -> done by arm7
//1 - decoding vectors of P frames and sending DL to GE
//2 - decoding full I frames or dcts of P frames
//3 - finishing P frames
#define FV_PLAYER_DATA_BUFFER_SIZE (64 * 1024)
#define FV_PLAYER_DATA_BUFFER_COUNT 6
typedef struct
{
u8* dataBuffer; //cache-aligned buffer containing encoded frame data
int frameDataSizes[FV_PLAYER_DATA_BUFFER_COUNT]; //size of the encoded data in the buffers
bool frameHasAudio[FV_PLAYER_DATA_BUFFER_COUNT];
int dataBufferReadIdx;
int dataBufferWriteIdx;
volatile int validDataBufferCount;
volatile int freeDataBufferCount;
fv_decoder_asm_t decoder;
int stage1Buffer;
int stage2Buffer;
const u16* stage2DataPtr;
int stage2IsPFrame;
int stage3IsPFrame;
int stage2VramBlock;
int stage3VramBlock;
bool stage3HasAudio;
int nextVramBlock;
volatile int isRequesting;
fv_header_t* fvHeader;
int vblankPerFrame;
u32 dlLength;
int lateCount;
bool audioStarted;
bool firstKeyFrame;
int curFrame;
int lastKeyFrame;
volatile bool seekComplete;
volatile bool isPlaying;
} fv_player_t;
#ifdef __cplusplus
extern "C" {
#endif
bool fv_initPlayer(fv_player_t* player, const char* filePath);
void fv_destroyPlayer(fv_player_t* player);
void fv_startPlayer(fv_player_t* player);
void fv_updatePlayer(fv_player_t* player);
void fv_pausePlayer(fv_player_t* player);
void fv_resumePlayer(fv_player_t* player);
void fv_gotoKeyFrame(fv_player_t* player, u32 keyFrame);
void fv_gotoNearestKeyFrame(fv_player_t* player, u32 frame);
static inline u32 fv_gotoNextKeyFrame(fv_player_t* player)
{
int frame = player->lastKeyFrame + 1;
if ((u32)frame >= player->fvHeader->nrKeyFrames)
frame = player->fvHeader->nrKeyFrames - 1;
fv_gotoKeyFrame(player, frame);
return frame;
}
static inline u32 fv_gotoPreviousKeyFrame(fv_player_t* player)
{
int frame = player->lastKeyFrame - 1;
if (frame < 0)
frame = 0;
fv_gotoKeyFrame(player, frame);
return frame;
}
static inline u16* fv_getPlayerDataBuffer(const fv_player_t* player, int index)
{
return (u16*)&player->dataBuffer[FV_PLAYER_DATA_BUFFER_SIZE * index];
}
#ifdef __cplusplus
}
#endif

100
arm9/source/dldi_stub.s Normal file
View File

@ -0,0 +1,100 @@
/*---------------------------------------------------------------------------------
Copyright (C) 2006 - 2016
Michael Chisholm (Chishm)
Dave Murphy (WinterMute)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
---------------------------------------------------------------------------------*/
#include <nds/arm9/dldi_asm.h>
.align 4
.arm
.global gDldiStub
@---------------------------------------------------------------------------------
.equ DLDI_ALLOCATED_SPACE, 16384
gDldiStub:
dldi_start:
@---------------------------------------------------------------------------------
@ Driver patch file standard header -- 16 bytes
.word 0xBF8DA5ED @ Magic number to identify this region
.asciz " Chishm" @ Identifying Magic string (8 bytes with null terminator)
.byte 0x01 @ Version number
.byte DLDI_SIZE_16KB @16KiB @ Log [base-2] of the size of this driver in bytes.
.byte 0x00 @ Sections to fix
.byte DLDI_SIZE_16KB @16KiB @ Log [base-2] of the allocated space in bytes.
@---------------------------------------------------------------------------------
@ Text identifier - can be anything up to 47 chars + terminating null -- 16 bytes
.align 4
.asciz "Default (No interface)"
@---------------------------------------------------------------------------------
@ Offsets to important sections within the data -- 32 bytes
.align 6
.word 0x037F8000 //dldi_start @ data start
.word 0x037FC000 //dldi_end @ data end
.word 0x00000000 @ Interworking glue start -- Needs address fixing
.word 0x00000000 @ Interworking glue end
.word 0x00000000 @ GOT start -- Needs address fixing
.word 0x00000000 @ GOT end
.word 0x00000000 @ bss start -- Needs setting to zero
.word 0x00000000 @ bss end
@---------------------------------------------------------------------------------
@ DISC_INTERFACE data -- 32 bytes
.ascii "DLDI" @ ioType
.word 0x00000000 @ Features
.word _DLDI_startup @
.word _DLDI_isInserted @
.word _DLDI_readSectors @ Function pointers to standard device driver functions
.word _DLDI_writeSectors @
.word _DLDI_clearStatus @
.word _DLDI_shutdown @
@---------------------------------------------------------------------------------
_DLDI_startup:
_DLDI_isInserted:
_DLDI_readSectors:
_DLDI_writeSectors:
_DLDI_clearStatus:
_DLDI_shutdown:
mov r0, #0x00 @ Return false for every function
bx lr
@---------------------------------------------------------------------------------
.align
.pool
dldi_data_end:
@ Pad to end of allocated space
.space DLDI_ALLOCATED_SPACE - (dldi_data_end - dldi_start)
dldi_end:
.end
@---------------------------------------------------------------------------------

View File

@ -0,0 +1,227 @@
#include <nds.h>
#include "PlayerController.h"
#define DIM_WAIT_SEC 5
#define DIM_FADE_SEC 3
PlayerController::PlayerController(fv_player_t* player)
: _subScreenState(SUB_SCREEN_STATE_ACTIVE), _subScreenStateCounter(0), _subBacklightOff(false), _player(player),
_playing(true), _lastTime(-1), _seekPenDown(false), _playPausePenDown(false), _seekLastFrame(-1),
_inputRepeater(KEY_LEFT | KEY_RIGHT, 12, 3)
{
}
void PlayerController::Initialize()
{
_view.Initialize();
_dimWaitFrames = DIM_WAIT_SEC * _player->fvHeader->fpsNum / _player->fvHeader->fpsDen;
_dimFadeFrames = DIM_FADE_SEC * _player->fvHeader->fpsNum / _player->fvHeader->fpsDen;
_invDimFadeFrames = 0x800000 / _dimFadeFrames;
u32 totalSeconds = ((u64)_player->fvHeader->nrFrames * _player->fvHeader->fpsDen) / _player->fvHeader->fpsNum;
_view.SetTotalTime(totalSeconds);
_view.SetCurrentTime(0);
}
void PlayerController::TogglePlayPause()
{
if (_playing)
{
fv_pausePlayer(_player);
_playing = false;
}
else
{
fv_resumePlayer(_player);
_playing = true;
}
}
void PlayerController::UpdateTouch()
{
if (_subScreenState != SUB_SCREEN_STATE_ACTIVE)
return;
touchPosition touch;
touchRead(&touch);
if (_inputProvider.Triggered(KEY_TOUCH))
{
if (touch.px >= 16 && touch.px < 240 && touch.py >= /*117*/ 113 && touch.py < /*121*/ 125)
{
_seekPenDown = true;
_seekLastFrame = -1;
}
else if (touch.px >= 110 && touch.px < 110 + 36 && touch.py >= 140 && touch.py < 140 + 36)
{
_playPausePenDown = true;
}
}
if (_inputProvider.Released(KEY_TOUCH))
{
_seekPenDown = false;
if (_playPausePenDown)
{
TogglePlayPause();
_playPausePenDown = false;
}
}
if (_inputProvider.Current(KEY_TOUCH) && _playPausePenDown)
{
if (!(touch.px >= 110 && touch.px < 110 + 36 && touch.py >= 140 && touch.py < 140 + 36))
{
_playPausePenDown = false;
}
}
if (_inputProvider.Current(KEY_TOUCH) && _seekPenDown)
{
int frame = ((int)touch.px - 16) * (int)_player->fvHeader->nrFrames / 224;
if (frame < 0)
frame = 0;
else if ((u32)frame >= _player->fvHeader->nrFrames)
frame = _player->fvHeader->nrFrames - 1;
if (frame != _seekLastFrame)
{
_seekLastFrame = frame;
fv_gotoNearestKeyFrame(_player, frame);
fv_startPlayer(_player);
_playing = true;
}
}
}
void PlayerController::UpdateKeys()
{
if (_inputProvider.Current(KEY_LID))
{
// pause when lid is closed
if (_playing)
{
fv_pausePlayer(_player);
_playing = false;
}
}
else if (_inputProvider.Triggered(KEY_A))
{
TogglePlayPause();
}
else if (_inputProvider.Triggered(KEY_LEFT))
{
_seekKeyFrame = fv_gotoPreviousKeyFrame(_player);
fv_startPlayer(_player);
_playing = true;
}
else if (_inputRepeater.Triggered(KEY_LEFT))
{
if (_seekKeyFrame > 0)
_seekKeyFrame--;
fv_gotoKeyFrame(_player, _seekKeyFrame);
fv_startPlayer(_player);
_playing = true;
}
else if (_inputProvider.Triggered(KEY_RIGHT))
{
_seekKeyFrame = fv_gotoNextKeyFrame(_player);
fv_startPlayer(_player);
_playing = true;
}
else if (_inputRepeater.Triggered(KEY_RIGHT))
{
fv_gotoKeyFrame(_player, ++_seekKeyFrame);
fv_startPlayer(_player);
_playing = true;
}
}
void PlayerController::UpdateDim()
{
if (!_playing || (_inputProvider.GetCurrentKeys() & ~KEY_LID) || (_inputProvider.GetReleasedKeys() & KEY_LID))
{
_subScreenState = SUB_SCREEN_STATE_ACTIVE;
_subScreenStateCounter = 0;
}
if (_subBacklightOff && _subScreenState != SUB_SCREEN_STATE_OFF)
{
powerOn(PM_BACKLIGHT_BOTTOM);
_subBacklightOff = false;
}
else if (!_subBacklightOff && _subScreenState == SUB_SCREEN_STATE_OFF)
{
powerOff(PM_BACKLIGHT_BOTTOM);
_subBacklightOff = true;
}
switch (_subScreenState)
{
case SUB_SCREEN_STATE_ACTIVE:
REG_MASTER_BRIGHT_SUB = 0;
if (++_subScreenStateCounter >= _dimWaitFrames)
{
_subScreenStateCounter = 0;
_subScreenState = SUB_SCREEN_STATE_DIMMING;
}
break;
case SUB_SCREEN_STATE_DIMMING:
{
int dimFrame = (_subScreenStateCounter * 16 * _invDimFadeFrames + 0x400000) >> 23;
if (dimFrame < 0)
dimFrame = 0;
else if (dimFrame > 16)
dimFrame = 16;
REG_MASTER_BRIGHT_SUB = dimFrame | (2 << 14);
if (dimFrame < 16)
_subScreenStateCounter++;
else
_subScreenState = SUB_SCREEN_STATE_OFF;
break;
}
case SUB_SCREEN_STATE_OFF:
break;
}
}
void PlayerController::Update()
{
_view.SetPlaying(_playing);
if (_playing)
{
REG_DIVCNT = DIV_64_32;
REG_DIV_NUMER = (u64)_player->curFrame * (u64)_player->fvHeader->fpsDen;
REG_DIV_DENOM_L = _player->fvHeader->fpsNum;
fv_updatePlayer(_player);
while (REG_DIVCNT & DIV_BUSY)
;
u32 time = REG_DIV_RESULT_L;
if (time != _lastTime)
{
_lastTime = time;
_view.SetCurrentTime(time);
_view.Update();
_view.VBlank();
}
}
else
{
_view.Update();
swiWaitForVBlank();
_view.VBlank();
_lastTime = -1;
}
_inputProvider.Sample(); // todo: sample more frequently
_inputProvider.Update();
_inputRepeater.Update(&_inputProvider);
UpdateTouch();
UpdateKeys();
UpdateDim();
}

View File

@ -0,0 +1,50 @@
#pragma once
#include "core/PadInputProvider.h"
#include "core/InputRepeater.h"
#include "../FastVideo/fvPlayer.h"
#include "PlayerView.h"
class PlayerController
{
enum SubScreenState
{
SUB_SCREEN_STATE_ACTIVE,
SUB_SCREEN_STATE_DIMMING,
SUB_SCREEN_STATE_OFF
};
SubScreenState _subScreenState;
int _subScreenStateCounter;
bool _subBacklightOff;
int _dimWaitFrames;
int _dimFadeFrames;
u32 _invDimFadeFrames;
fv_player_t* _player;
bool _playing;
u32 _seekKeyFrame;
u32 _lastTime;
bool _seekPenDown;
bool _playPausePenDown;
int _seekLastFrame;
PadInputProvider _inputProvider;
InputRepeater _inputRepeater;
PlayerView _view;
void TogglePlayPause();
void UpdateTouch();
void UpdateKeys();
void UpdateDim();
public:
PlayerController(fv_player_t* player);
void Initialize();
void Update();
};

View File

@ -0,0 +1,260 @@
#include <nds.h>
#include <stdio.h>
#include "RobotoRegular10_ntft.h"
#include "playBg.h"
#include "iconPlay.h"
#include "iconPause.h"
#include "circle0.h"
#include "circle1.h"
#include "core/uiUtil.h"
#include "PlayerView.h"
PlayerView::PlayerView() : _robotoRegular10(RobotoRegular10_ntft)
{
}
void PlayerView::Initialize()
{
decompress(playBgTiles, BG_GFX_SUB, LZ77Vram);
decompress(playBgMap, (u8*)BG_GFX_SUB + 0x800, LZ77Vram);
dmaCopyWords(3, playBgPal, BG_PALETTE_SUB, playBgPalLen);
_subOam.Apply(OAM_SUB);
REG_DISPCNT_SUB = DISPLAY_BG0_ACTIVE | DISPLAY_BG1_ACTIVE | DISPLAY_BG2_ACTIVE | DISPLAY_SPR_ACTIVE |
DISPLAY_SPR_1D | DISPLAY_SPR_1D_SIZE_32 | MODE_0_2D | DISPLAY_WIN0_ON;
REG_BG2CNT_SUB &= ~BG_PRIORITY_3;
REG_BG0CNT_SUB = BG_32x32 | BG_PRIORITY_2 | BG_COLOR_16 | BG_MAP_BASE(1) | BG_TILE_BASE(0);
REG_BG0HOFS_SUB = 0;
REG_BG0VOFS_SUB = 0;
REG_BG1CNT_SUB = BG_32x32 | BG_PRIORITY_1 | BG_COLOR_16 | BG_MAP_BASE(1) | BG_TILE_BASE(0);
REG_BG1HOFS_SUB = 0;
REG_BG1VOFS_SUB = -176;
SUB_WIN0_X0 = 16;
SUB_WIN0_X1 = 128;
SUB_WIN0_Y0 = 117;
SUB_WIN0_Y1 = 117 + 4;
SUB_WIN_IN = 0x16;
SUB_WIN_OUT = 0x15;
for (int i = 0; i < 16; i++)
{
int rnew = 4 + ((31 - 4) * i) / 15;
int gnew = 6 + ((31 - 6) * i) / 15;
int bnew = 8 + ((31 - 8) * i) / 15;
SPRITE_PALETTE_SUB[16 + i] = RGB5(rnew, gnew, bnew);
}
for (int i = 0; i < 16; i++)
{
int rnew = 6 + ((31 - 6) * i) / 15;
int gnew = 8 + ((31 - 8) * i) / 15;
int bnew = 11 + ((31 - 11) * i) / 15;
SPRITE_PALETTE_SUB[32 + i] = RGB5(rnew, gnew, bnew);
}
for (int i = 0; i < 16; i++)
{
int rnew = 4 + ((6 - 4) * i) / 15;
int gnew = 6 + ((8 - 6) * i) / 15;
int bnew = 8 + ((11 - 8) * i) / 15;
SPRITE_PALETTE_SUB[48 + i] = RGB5(rnew, gnew, bnew);
}
_twoDigitObjAddr = _subObj.Alloc(/*100*/ 60 * 2 * 32) >> 5;
char twoDigitStr[3];
for (int i = 0; i < /*100*/ 60; i++)
{
memset(_textTmpBuf, 0, sizeof(_textTmpBuf));
twoDigitStr[0] = '0' + ((u32)i / 10);
twoDigitStr[1] = '0' + ((u32)i % 10);
twoDigitStr[2] = 0;
int w, h;
_robotoRegular10.MeasureString(twoDigitStr, w, h);
const ntft_cinfo_char_t* charInfo = _robotoRegular10.GetCharInfo(twoDigitStr[0]);
_twoDigitOffset[i] = charInfo->characterBeginOffset < 0 ? charInfo->characterBeginOffset : 0;
charInfo = _robotoRegular10.GetCharInfo(twoDigitStr[1]);
_twoDigitWidth[i] = w;
_twoDigitEndOffset[i] = charInfo->characterEndOffset;
_robotoRegular10.CreateStringData(twoDigitStr, _textTmpBuf, 16);
uiutil_convertToObj(_textTmpBuf + 2 * 16, 16, 8, 16, &SPRITE_GFX_SUB[(_twoDigitObjAddr + 2 * i) << 4]);
}
_oneDigitObjAddr = _subObj.Alloc(10 * 32) >> 5;
for (int i = 0; i < 10; i++)
{
memset(_textTmpBuf, 0, sizeof(_textTmpBuf));
twoDigitStr[0] = '0' + i;
twoDigitStr[1] = 0;
int w, h;
_robotoRegular10.MeasureString(twoDigitStr, w, h);
const ntft_cinfo_char_t* charInfo = _robotoRegular10.GetCharInfo(twoDigitStr[0]);
_oneDigitOffset[i] = charInfo->characterBeginOffset < 0 ? charInfo->characterBeginOffset : 0;
_oneDigitWidth[i] = w;
_oneDigitEndOffset[i] = charInfo->characterEndOffset;
_robotoRegular10.CreateStringData(twoDigitStr, _textTmpBuf, 8);
uiutil_convertToObj(_textTmpBuf + 2 * 8, 8, 8, 8, &SPRITE_GFX_SUB[(_oneDigitObjAddr + i) << 4]);
}
_colonObjAddr = _subObj.Alloc(32) >> 5;
memset(_textTmpBuf, 0, sizeof(_textTmpBuf));
twoDigitStr[0] = ':';
twoDigitStr[1] = 0;
int w, h;
_robotoRegular10.MeasureString(twoDigitStr, w, h);
const ntft_cinfo_char_t* charInfo = _robotoRegular10.GetCharInfo(twoDigitStr[0]);
_colonOffset = charInfo->characterBeginOffset < 0 ? charInfo->characterBeginOffset : 0;
_colonWidth = w + charInfo->characterEndOffset;
_robotoRegular10.CreateStringData(twoDigitStr, _textTmpBuf, 8);
uiutil_convertToObj(_textTmpBuf + 2 * 8, 8, 8, 8, &SPRITE_GFX_SUB[_colonObjAddr << 4]);
SetCurrentTime(0 * 60 * 60 + 16 * 60 + 27);
SetTotalTime(3 * 60 * 60 + 48 * 60 + 59);
_circleObjAddr = _subObj.Alloc(32 * 20) >> 5;
dmaCopyWords(3, circle0Tiles, &SPRITE_GFX_SUB[_circleObjAddr << 4], circle0TilesLen);
dmaCopyWords(3, circle1Tiles, &SPRITE_GFX_SUB[(_circleObjAddr + 16) << 4], circle1TilesLen);
_playIconObjAddr = _subObj.Alloc(32 * 4) >> 5;
dmaCopyWords(3, iconPlayTiles, &SPRITE_GFX_SUB[_playIconObjAddr << 4], iconPlayTilesLen);
_pauseIconObjAddr = _subObj.Alloc(32 * 4) >> 5;
dmaCopyWords(3, iconPauseTiles, &SPRITE_GFX_SUB[_pauseIconObjAddr << 4], iconPauseTilesLen);
_playing = false;
}
int PlayerView::RenderColon(SpriteEntry* oam, int x, int y)
{
x += _colonOffset;
oam[0].attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_SQUARE | y; // OBJ_Y(y);
oam[0].attribute[1] = ATTR1_SIZE_8 | x; // OBJ_X(x);
oam[0].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(1) | _colonObjAddr;
return x + _colonWidth;
}
int PlayerView::RenderSingleDigit(SpriteEntry* oam, int digit, int x, int y)
{
x += _oneDigitOffset[digit];
oam[0].attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_SQUARE | y; // OBJ_Y(y);
oam[0].attribute[1] = ATTR1_SIZE_8 | x; // OBJ_X(x);
oam[0].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(1) | (_oneDigitObjAddr + digit);
return x + _oneDigitWidth[digit] + _oneDigitEndOffset[digit];
}
int PlayerView::RenderDoubleDigit(SpriteEntry* oam, int digits, int x, int y)
{
x += _twoDigitOffset[digits];
oam[0].attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_WIDE | y; // OBJ_Y(y);
oam[0].attribute[1] = ATTR1_SIZE_8 | x; // OBJ_X(x);
oam[0].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(1) | (_twoDigitObjAddr + digits * 2);
return x + _twoDigitWidth[digits] + _twoDigitEndOffset[digits];
}
void PlayerView::Update()
{
_subOam.Clear();
SpriteEntry* oams = _subOam.AllocOams(14);
memcpy(&oams[0], _curTimeOams, sizeof(_curTimeOams));
memcpy(&oams[5], _totalTimeOams, sizeof(_totalTimeOams));
// circle
oams[11].attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_SQUARE | 140;
oams[11].attribute[1] = ATTR1_SIZE_32 | 110;
oams[11].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(3) | _circleObjAddr;
oams[12].attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_TALL | 140;
oams[12].attribute[1] = ATTR1_SIZE_16 | (110 + 32);
oams[12].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(3) | (_circleObjAddr + 16);
oams[13].attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_WIDE | (140 + 32 - 4);
oams[13].attribute[1] = ATTR1_SIZE_16 | ATTR1_FLIP_Y | 110;
oams[13].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(3) | _circleObjAddr;
// play/pause
oams[10].attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_SQUARE | (146 + 4);
oams[10].attribute[1] = ATTR1_SIZE_16 | (116 + 4);
oams[10].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(2) | (_playing ? _pauseIconObjAddr : _playIconObjAddr);
}
void PlayerView::VBlank()
{
_subOam.Apply(OAM_SUB);
SUB_WIN0_X0 = 16;
u32 width;
if (_curTime >= _totalTime)
width = 224;
else
width = (_curTime * 224 * _invTotalTime + 0x400000) >> 23;
SUB_WIN0_X1 = 16 + width;
SUB_WIN0_Y0 = 117;
SUB_WIN0_Y1 = 117 + 4;
}
void PlayerView::SetTotalTime(u32 totalTime)
{
_totalTime = totalTime;
_invTotalTime = 0x800000 / _totalTime;
u32 totalH = _totalTime / 3600;
u32 totalM = _totalTime / 60 % 60;
u32 totalS = _totalTime % 60;
int x = 240;
x -= _twoDigitWidth[totalS];
x -= _twoDigitOffset[totalS];
x -= _colonWidth;
x -= _colonOffset;
x -= _twoDigitEndOffset[totalM];
x -= _twoDigitWidth[totalM];
x -= _twoDigitOffset[totalM];
if (totalH != 0)
{
x -= _colonWidth;
x -= _colonOffset;
x -= _oneDigitEndOffset[totalH];
x -= _oneDigitWidth[totalH];
x -= _oneDigitOffset[totalH];
x = RenderSingleDigit(&_totalTimeOams[0], totalH, x, 101);
x = RenderColon(&_totalTimeOams[1], x, 101);
}
else
{
_totalTimeOams[0].attribute[0] = 0x200;
_totalTimeOams[1].attribute[0] = 0x200;
}
x = RenderDoubleDigit(&_totalTimeOams[2], totalM, x, 101);
x = RenderColon(&_totalTimeOams[3], x, 101);
x = RenderDoubleDigit(&_totalTimeOams[4], totalS, x, 101);
}
void PlayerView::SetCurrentTime(u32 currentTime)
{
_curTime = currentTime;
int x = 16;
if (_totalTime >= 3600)
{
x = RenderSingleDigit(&_curTimeOams[0], _curTime / 3600, x, 101);
x = RenderColon(&_curTimeOams[1], x, 101);
}
else
{
_curTimeOams[0].attribute[0] = 0x200;
_curTimeOams[1].attribute[0] = 0x200;
}
x = RenderDoubleDigit(&_curTimeOams[2], _curTime / 60 % 60, x, 101);
x = RenderColon(&_curTimeOams[3], x, 101);
x = RenderDoubleDigit(&_curTimeOams[4], _curTime % 60, x, 101);
}

View File

@ -0,0 +1,63 @@
#pragma once
#include "core/VramManager.h"
#include "core/OamManager.h"
#include "core/NtftFont.h"
class PlayerView
{
VramManager _subObj;
OamManager _subOam;
NtftFont _robotoRegular10;
u8 _textTmpBuf[16 * 10];
u16 _oneDigitObjAddr;
s8 _oneDigitOffset[10];
u8 _oneDigitWidth[10];
s8 _oneDigitEndOffset[10];
u16 _twoDigitObjAddr;
s8 _twoDigitOffset[/*100*/60];
u8 _twoDigitWidth[/*100*/60];
s8 _twoDigitEndOffset[/*100*/60];
u16 _colonObjAddr;
s8 _colonOffset;
u8 _colonWidth;
u32 _curTime;
SpriteEntry _curTimeOams[5];
u32 _totalTime;
u32 _invTotalTime;
SpriteEntry _totalTimeOams[5];
u16 _circleObjAddr;
u16 _playIconObjAddr;
u16 _pauseIconObjAddr;
bool _playing;
int RenderColon(SpriteEntry* oam, int x, int y);
int RenderSingleDigit(SpriteEntry* oam, int digit, int x, int y);
int RenderDoubleDigit(SpriteEntry* oam, int digits, int x, int y);
public:
PlayerView();
void Initialize();
void Update();
void VBlank();
void SetTotalTime(u32 totalTime);
void SetCurrentTime(u32 currentTime);
void SetPlaying(bool playing)
{
_playing = playing;
}
};

View File

@ -0,0 +1,96 @@
#pragma once
class InputProvider
{
u16 _currentKeys;
u16 _triggeredKeys;
u16 _releasedKeys;
u16 _inputBuffer[4];
u8 _inputBufferRPtr;
u8 _inputBufferWPtr;
protected:
InputProvider() : _currentKeys(0), _triggeredKeys(0), _releasedKeys(0), _inputBufferRPtr(0), _inputBufferWPtr(0)
{
}
virtual u16 SampleIntern() = 0;
public:
virtual ~InputProvider()
{
}
void Update()
{
u16 cur = _currentKeys;
u16 trig = 0;
u16 rel = 0;
while (_inputBufferRPtr != _inputBufferWPtr)
{
u16 keyMask = _inputBuffer[_inputBufferRPtr];
trig |= (keyMask ^ cur) & keyMask;
rel |= (keyMask ^ cur) & cur;
cur = keyMask;
_inputBufferRPtr = (_inputBufferRPtr + 1) & 3;
}
_triggeredKeys = trig;
_releasedKeys = rel;
_currentKeys = cur;
}
/**
* \brief Returns a bitmask of the keys currently being held
*/
u16 GetCurrentKeys() const
{
return _currentKeys;
}
bool Current(u16 mask) const
{
return _currentKeys & mask;
}
/**
* \brief Returns a bitmask of the keys that went from unpressed to pressed in the latest update
*/
u16 GetTriggeredKeys() const
{
return _triggeredKeys;
}
bool Triggered(u16 mask) const
{
return _triggeredKeys & mask;
}
/**
* \brief Returns a bitmask of the keys that went from pressed to unpressed in the latest update
*/
u16 GetReleasedKeys() const
{
return _releasedKeys;
}
bool Released(u16 mask) const
{
return _releasedKeys & mask;
}
void Sample()
{
_inputBuffer[_inputBufferWPtr] = SampleIntern();
_inputBufferWPtr = (_inputBufferWPtr + 1) & 3;
}
void Reset()
{
_currentKeys = 0;
_inputBufferRPtr = 0;
_inputBufferWPtr = 0;
}
};

View File

@ -0,0 +1,47 @@
#include <nds.h>
#include "InputRepeater.h"
void InputRepeater::Update(const InputProvider* inputProvider)
{
_trigKeys = inputProvider->GetTriggeredKeys();
u16 curKeys = inputProvider->GetCurrentKeys();
_repKeys = 0;
if (_state != STATE_IDLE)
{
if (_state == STATE_FIRST)
{
if (curKeys & _mask)
{
_frameCounter++;
if (_frameCounter >= _firstFrame)
{
_state = STATE_NEXT;
_frameCounter = 0;
_repKeys = curKeys & _mask;
}
}
else
_state = STATE_IDLE;
}
else if (_state == STATE_NEXT)
{
if (curKeys & _mask)
{
_frameCounter++;
if (_frameCounter >= _nextFrame)
{
_frameCounter = 0;
_repKeys = curKeys & _mask;
}
}
else
_state = STATE_IDLE;
}
}
else if (curKeys & _mask)
{
_state = STATE_FIRST;
_frameCounter = 0;
_repKeys = curKeys & _mask;
}
}

View File

@ -0,0 +1,34 @@
#pragma once
#include "InputProvider.h"
class InputRepeater
{
enum State
{
STATE_IDLE,
STATE_FIRST,
STATE_NEXT
};
u16 _trigKeys;
u16 _repKeys;
State _state;
u16 _frameCounter;
u16 _mask;
u16 _firstFrame;
u16 _nextFrame;
public:
InputRepeater(u16 mask, u16 firstFrame, u16 nextFrame)
: _trigKeys(0), _repKeys(0), _state(STATE_IDLE), _frameCounter(0), _mask(mask), _firstFrame(firstFrame), _nextFrame(nextFrame)
{ }
void Update(const InputProvider* inputProvider);
u16 GetTriggeredKeys() const { return _trigKeys | _repKeys; }
bool Triggered(u16 mask) const
{
return (_trigKeys | _repKeys) & mask;
}
};

View File

@ -0,0 +1,93 @@
#include <nds.h>
#include "NtftFont.h"
NtftFont::NtftFont(const void* data)
{
const ntft_header_t* font = (const ntft_header_t*)data;
_font.header = font;
_font.characterInfo = (const ntft_cinfo_t*)((u32)font + font->charInfoOffset);
_font.glyphData = (const ntft_gdata_t*)((u32)font + font->glyphDataOffset);
}
void NtftFont::MeasureString(const char* text, int& width, int& height) const
{
width = 0;
height = _font.characterInfo->characterHeight;
int tmpwidth = 0;
unsigned char c = *text++;
while (c != 0)
{
int end = 0;
if (c == '\n')
{
if (width < tmpwidth)
width = tmpwidth;
tmpwidth = 0;
height += _font.characterInfo->characterHeight + 1;
}
else
{
if ((tmpwidth + _font.characterInfo->characters[c].characterBeginOffset) >= 0)
tmpwidth += _font.characterInfo->characters[c].characterBeginOffset;
tmpwidth += _font.characterInfo->characters[c].characterWidth;
end = _font.characterInfo->characters[c].characterEndOffset;
}
c = *text++;
if (c != 0)
tmpwidth += end;
}
if (width < tmpwidth)
width = tmpwidth;
}
void NtftFont::CreateStringData(const char* text, u8* dst, int stride) const
{
// todo: maybe support alignment
// int width;
// int height;
// GetStringSize(text, width, height);
int xpos = 0;
int ypos = 0;
bool nodraw = false;
unsigned char c = *text++;
while (c != 0)
{
if (c == '\n')
{
xpos = 0;
ypos += _font.characterInfo->characterHeight + 1;
nodraw = false;
}
else
{
if ((xpos + _font.characterInfo->characters[c].characterBeginOffset) >= 0)
xpos += _font.characterInfo->characters[c].characterBeginOffset;
if (xpos + (int)_font.characterInfo->characters[c].characterWidth > stride)
nodraw = true;
if (!nodraw)
{
u8* glyph = (uint8_t*)&_font.glyphData->glyphData[_font.characterInfo->characters[c].glyphDataOffset];
u8* dst_ptr = dst + ypos * stride + xpos;
int w = _font.characterInfo->characters[c].characterWidth;
int h = _font.characterInfo->characterHeight;
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
u8 data = *glyph++;
int oldval = *dst_ptr;
int newval = oldval + data;
if (newval > 255)
newval = 255;
*dst_ptr++ = newval;
}
dst_ptr -= _font.characterInfo->characters[c].characterWidth;
dst_ptr += stride;
}
xpos += _font.characterInfo->characters[c].characterWidth;
xpos += _font.characterInfo->characters[c].characterEndOffset;
}
}
c = *text++;
}
}

View File

@ -0,0 +1,64 @@
#pragma once
#define NTFT_SIGNATURE_HEADER MKTAG('N', 'T', 'F', 'T')
#define NTFT_SIGNATURE_CHARACTER_INFO MKTAG('C', 'I', 'N', 'F')
#define NTFT_SIGNATURE_GLYPH_DATA MKTAG('G', 'L', 'P', 'D')
struct ntft_header_t
{
u32 signature;
u32 fileSize;
u32 charInfoOffset;
u32 glyphDataOffset;
};
struct ntft_cinfo_char_t
{
u32 glyphDataOffset;
s32 characterBeginOffset;
u32 characterWidth;
s32 characterEndOffset;
};
struct ntft_cinfo_t
{
u32 signature;
u32 blockSize;
u32 characterHeight;
ntft_cinfo_char_t characters[256];
};
struct ntft_gdata_t
{
uint32_t signature;
uint32_t blockSize;
uint32_t glyphDataSize;
uint8_t glyphData[0];
};
struct ntft_t
{
const ntft_header_t* header;
const ntft_cinfo_t* characterInfo;
const ntft_gdata_t* glyphData;
};
class NtftFont
{
ntft_t _font;
public:
explicit NtftFont(const void* data);
void MeasureString(const char* text, int& width, int& height) const;
void CreateStringData(const char* text, u8* dst, int stride) const;
int GetFontHeight() const
{
return _font.characterInfo->characterHeight;
}
const ntft_cinfo_char_t* GetCharInfo(unsigned char c) const
{
return &_font.characterInfo->characters[c];
}
};

View File

@ -0,0 +1,42 @@
#pragma once
#include <string.h>
class OamManager
{
SpriteEntry* _oamPtr;
int _mtxIdx;
OAMTable _oamTable ALIGN(4);
public:
OamManager()
{
Clear();
}
SpriteEntry* AllocOams(int count)
{
_oamPtr -= count;
return _oamPtr;
}
SpriteRotation* AllocMatrices(int count, int& mtxId)
{
mtxId = _mtxIdx;
SpriteRotation* result = &_oamTable.matrixBuffer[_mtxIdx];
_mtxIdx += count;
return result;
}
void Apply(u16* dst)
{
DC_FlushRange(&_oamTable, sizeof(OAMTable));
dmaCopyWords(3, &_oamTable, dst, sizeof(OAMTable));
}
void Clear()
{
memset(&_oamTable, 0x2, sizeof(OAMTable));
_oamPtr = &_oamTable.oamBuffer[128];
_mtxIdx = 0;
}
};

View File

@ -0,0 +1,11 @@
#pragma once
#include "InputProvider.h"
class PadInputProvider : public InputProvider
{
public:
u16 SampleIntern()
{
return keysCurrent();
}
};

View File

@ -0,0 +1,23 @@
#pragma once
class VramManager
{
u16 _offset;
public:
VramManager()
: _offset(0)
{
}
u16 Alloc(u16 length)
{
u16 result = _offset;
_offset += length;
return result;
}
u16 GetState() const { return _offset; }
void SetState(u16 state) { _offset = state; }
};

View File

@ -0,0 +1,31 @@
#include <nds.H>
#include "uiUtil.h"
void uiutil_convertToObj(u8* src, int width, int height, int stride, u16* dst)
{
for (int y = 0; y < height / 8; y++)
{
for (int x = 0; x < width / 8; x++)
{
for (int y2 = 0; y2 < 8; y2++)
{
//write in 32 bit units for vram compatibility
*((uint32_t*)dst) =
((src[0] * 15 + 128) >> 8) |
(((src[1] * 15 + 128) >> 8) << 4) |
(((src[2] * 15 + 128) >> 8) << 8) |
(((src[3] * 15 + 128) >> 8) << 12) |
(((src[4] * 15 + 128) >> 8) << 16) |
(((src[5] * 15 + 128) >> 8) << 20) |
(((src[6] * 15 + 128) >> 8) << 24) |
(((src[7] * 15 + 128) >> 8) << 28);
dst += 2;
src += stride;
}
src -= 8 * stride;
src += 8;
}
src -= width;
src += 8 * stride;
}
}

View File

@ -0,0 +1,16 @@
#pragma once
union XBGR1555
{
uint16_t color;
struct
{
uint16_t r : 5;
uint16_t g : 5;
uint16_t b : 5;
uint16_t x : 1;
};
};
void uiutil_convertToObj(u8* src, int width, int height, int stride, u16* dst);

88
arm9/source/main.cpp Normal file
View File

@ -0,0 +1,88 @@
#include <nds.h>
#include <stdio.h>
#include "../../common/ipc.h"
#include "FastVideo/fvDecoder.h"
#include "FastVideo/fvMcData.h"
#include "FastVideo/fvPlayer.h"
#include "mpu.h"
#include "gui/PlayerController.h"
#include "../../common/twlwram.h"
static DTCM_BSS fv_player_t sPlayer;
static PlayerController* sPlayerController;
extern u8 gDldiStub[];
int main(int argc, char** argv)
{
DC_FlushAll();
mpu_enableVramCache();
if (isDSiMode())
{
twr_setBlockMapping(TWR_WRAM_BLOCK_A, 0x03000000, 0x40000, TWR_WRAM_BLOCK_IMAGE_SIZE_256K);
twr_setBlockMapping(TWR_WRAM_BLOCK_B, 0x03100000, 0x40000, TWR_WRAM_BLOCK_IMAGE_SIZE_256K);
twr_setBlockMapping(TWR_WRAM_BLOCK_C, 0x03140000, 0x40000, TWR_WRAM_BLOCK_IMAGE_SIZE_256K);
mpu_enableTwlWramCache();
}
fifoSetValue32Handler(FIFO_USER_01, NULL, NULL);
// handshake
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_HANDSHAKE, 0));
fifoWaitValue32(FIFO_USER_01);
fifoGetValue32(FIFO_USER_01);
if (!isDSiMode())
{
// setup dldi on arm7 if not on dsi
DC_FlushRange(gDldiStub, 16 * 1024);
fifoSendValue32(FIFO_USER_01, IPC_CMD_PACK(IPC_CMD_SETUP_DLDI, (u32)gDldiStub));
fifoWaitValue32(FIFO_USER_01);
fifoGetValue32(FIFO_USER_01);
}
videoSetModeSub(MODE_0_2D);
vramSetBankH(VRAM_H_SUB_BG);
vramSetBankI(VRAM_I_SUB_SPRITE);
consoleInit(NULL, 2, BgType_Text4bpp, BgSize_T_256x256, /*0, 1*/ 2, 1, false, true);
// iprintf("FastVideoDS Player by Gericom\n\n");
vramSetBankA(VRAM_A_LCD);
vramSetBankB(VRAM_B_LCD);
vramSetBankC(VRAM_C_LCD);
vramSetBankD(VRAM_D_LCD);
vramSetBankE(VRAM_E_LCD);
for (int i = 0; i < 3 * 128 * 1024; i += 4)
*(vu32*)((u32)VRAM_A + i) = 0x80008000;
const char* filePath;
if (isDSiMode())
filePath = "sd:/testVideo.fv";
else
filePath = "fat:/testVideo.fv";
if (argc >= 2)
filePath = argv[1];
// iprintf("Playing %s\n", filePath);
if (fv_initPlayer(&sPlayer, filePath))
{
sPlayerController = new PlayerController(&sPlayer);
sPlayerController->Initialize();
fv_startPlayer(&sPlayer);
while (1)
sPlayerController->Update();
}
fv_destroyPlayer(&sPlayer);
while (1)
swiWaitForVBlank();
return 0;
}

12
arm9/source/mpu.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
extern void mpu_enableVramCache(void);
extern void mpu_enableTwlWramCache(void);
#ifdef __cplusplus
}
#endif

33
arm9/source/mpu.s Normal file
View File

@ -0,0 +1,33 @@
.section .itcm
.arm
#define PAGE_1M (0b10011 << 1)
.global mpu_enableVramCache
mpu_enableVramCache:
//setup region 2 for vram
ldr r0,= (PAGE_1M | 0x06800000 | 1)
mcr p15, 0, r0, c6, c2, 0
//write buffer
mrc p15, 0, r0, c3, c0, 0
orr r0, #(1 << 2)
mcr p15, 0, r0, c3, c0, 0
//dcache
mrc p15, 0, r0, c2, c0, 0
orr r0, #(1 << 2)
mcr p15, 0, r0, c2, c0, 0
bx lr
.global mpu_enableTwlWramCache
mpu_enableTwlWramCache:
//write buffer
mrc p15, 0, r0, c3, c0, 0
orr r0, #(1 << 3)
mcr p15, 0, r0, c3, c0, 0
//dcache
mrc p15, 0, r0, c2, c0, 0
orr r0, #(1 << 3)
mcr p15, 0, r0, c2, c0, 0
bx lr

26
common/fastVideo.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#define FV_AUDIO_RATE 47605
#define FV_AUDIO_FRAME_SAMPLES 256
#define FV_AUDIO_FRAME_SIZE (4 + FV_AUDIO_FRAME_SAMPLES / 2)
#define FV_SIGNATURE 0x53445646 // FVDS
typedef struct
{
u32 frame;
u32 offset;
} fv_keyframe_t;
typedef struct
{
u32 signature;
u16 width;
u16 height;
u32 fpsNum;
u32 fpsDen;
u16 audioRate;
u16 audioChannels;
u32 nrFrames;
u32 nrKeyFrames;
} fv_header_t;

19
common/ipc.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#define IPC_CMD_READ_FRAME 1
#define IPC_CMD_OPEN_FILE 2
#define IPC_CMD_CONTROL_AUDIO 3
#define IPC_CMD_READ_HEADER 4
#define IPC_CMD_GOTO_KEYFRAME 5
#define IPC_CMD_GOTO_NEAREST_KEYFRAME 6
#define IPC_CMD_SETUP_DLDI 13
#define IPC_CMD_HANDSHAKE 15
#define IPC_CMD_ARG_MASK 0x0FFFFFFF
#define IPC_CMD_CMD_SHIFT 28
#define IPC_CMD_CMD_MASK 0xF0000000
#define IPC_CMD_PACK(cmd, arg) ((((u32)(cmd) << IPC_CMD_CMD_SHIFT) & IPC_CMD_CMD_MASK) | ((u32)(arg)&IPC_CMD_ARG_MASK))
#define IPC_ARG_CONTROL_AUDIO_STOP 0
#define IPC_ARG_CONTROL_AUDIO_START 1
#define IPC_ARG_CONTROL_AUDIO_STOP_CLEAR 2

98
common/twlwram.h Normal file
View File

@ -0,0 +1,98 @@
#pragma once
typedef enum
{
TWR_WRAM_BLOCK_A = 0,
TWR_WRAM_BLOCK_B = 1,
TWR_WRAM_BLOCK_C = 2
} TWRWramBlock;
typedef enum
{
TWR_WRAM_BLOCK_IMAGE_SIZE_32K = 0,
TWR_WRAM_BLOCK_IMAGE_SIZE_64K,
TWR_WRAM_BLOCK_IMAGE_SIZE_128K,
TWR_WRAM_BLOCK_IMAGE_SIZE_256K,
} TWRWramBlockImageSize;
#define TWR_WRAM_BASE 0x03000000
//WRAM A
#define TWR_WRAM_A_SLOT_SIZE 0x10000
#define TWR_WRAM_A_SLOT_SHIFT 16
#define TWR_WRAM_A_SLOT_COUNT 4
#define TWR_WRAM_A_ADDRESS_MAX 0x03FF0000
#define TWR_WRAM_A_SLOT_OFFSET(i) ((i) << 2)
#define TWR_WRAM_A_SLOT_ENABLE 0x80
typedef enum
{
TWR_WRAM_A_SLOT_MASTER_ARM9 = 0,
TWR_WRAM_A_SLOT_MASTER_ARM7 = 1
} TWRWramASlotMaster;
#define TWR_MBK6_START_ADDR_MASK 0x00000FF0
#define TWR_MBK6_START_ADDR_SHIFT 4
#define TWR_MBK6_IMAGE_SIZE_SHIFT 12
#define TWR_MBK6_END_ADDR_SHIFT 20
//WRAM B
#define TWR_WRAM_BC_SLOT_SIZE 0x8000
#define TWR_WRAM_BC_SLOT_SHIFT 15
#define TWR_WRAM_BC_SLOT_COUNT 8
#define TWR_WRAM_BC_ADDRESS_MAX 0x03FF8000
#define TWR_WRAM_BC_SLOT_OFFSET(i) ((i) << 2)
#define TWR_WRAM_BC_SLOT_ENABLE 0x80
typedef enum
{
TWR_WRAM_B_SLOT_MASTER_ARM9 = 0,
TWR_WRAM_B_SLOT_MASTER_ARM7 = 1,
TWR_WRAM_B_SLOT_MASTER_DSP_CODE = 2
} TWRWramBSlotMaster;
typedef enum
{
TWR_WRAM_C_SLOT_MASTER_ARM9 = 0,
TWR_WRAM_C_SLOT_MASTER_ARM7 = 1,
TWR_WRAM_C_SLOT_MASTER_DSP_DATA = 2
} TWRWramCSlotMaster;
#define TWR_MBK7_START_ADDR_MASK 0x00000FF8
#define TWR_MBK7_START_ADDR_SHIFT 3
#define TWR_MBK7_IMAGE_SIZE_SHIFT 12
#define TWR_MBK7_END_ADDR_SHIFT 19
#define TWR_MBK8_START_ADDR_MASK 0x00000FF8
#define TWR_MBK8_START_ADDR_SHIFT 3
#define TWR_MBK8_IMAGE_SIZE_SHIFT 12
#define TWR_MBK8_END_ADDR_SHIFT 19
#ifdef __cplusplus
extern "C" {
#endif
u32 twr_getBlockAddress(TWRWramBlock block);
void twr_setBlockMapping(TWRWramBlock block, u32 start, u32 length, TWRWramBlockImageSize imageSize);
#ifdef ARM9
void twr_mapWramASlot(int slot, TWRWramASlotMaster master, int offset, bool enable);
void twr_mapWramBSlot(int slot, TWRWramBSlotMaster master, int offset, bool enable);
void twr_mapWramCSlot(int slot, TWRWramCSlotMaster master, int offset, bool enable);
#endif
#ifdef __cplusplus
}
#endif

68
common/twlwram.twl.c Normal file
View File

@ -0,0 +1,68 @@
#include <nds.h>
#include "twlwram.h"
u32 twr_getBlockAddress(TWRWramBlock block)
{
switch(block)
{
case TWR_WRAM_BLOCK_A:
return TWR_WRAM_BASE + (((REG_MBK6 & TWR_MBK6_START_ADDR_MASK) >> TWR_MBK6_START_ADDR_SHIFT) << TWR_WRAM_A_SLOT_SHIFT);
case TWR_WRAM_BLOCK_B:
return TWR_WRAM_BASE + (((REG_MBK7 & TWR_MBK7_START_ADDR_MASK) >> TWR_MBK7_START_ADDR_SHIFT) << TWR_WRAM_BC_SLOT_SHIFT);
case TWR_WRAM_BLOCK_C:
return TWR_WRAM_BASE + (((REG_MBK8 & TWR_MBK8_START_ADDR_MASK) >> TWR_MBK8_START_ADDR_SHIFT) << TWR_WRAM_BC_SLOT_SHIFT);
}
return 0;
}
void twr_setBlockMapping(TWRWramBlock block, u32 start, u32 length, TWRWramBlockImageSize imageSize)
{
start -= TWR_WRAM_BASE;
u32 end;
switch(block)
{
case TWR_WRAM_BLOCK_A:
start >>= TWR_WRAM_A_SLOT_SHIFT;
length >>= TWR_WRAM_A_SLOT_SHIFT;
end = start + length;
REG_MBK6 = (start << TWR_MBK6_START_ADDR_SHIFT) | (imageSize << TWR_MBK6_IMAGE_SIZE_SHIFT) | (end << TWR_MBK6_END_ADDR_SHIFT);
break;
case TWR_WRAM_BLOCK_B:
start >>= TWR_WRAM_BC_SLOT_SHIFT;
length >>= TWR_WRAM_BC_SLOT_SHIFT;
end = start + length;
REG_MBK7 = (start << TWR_MBK7_START_ADDR_SHIFT) | (imageSize << TWR_MBK7_IMAGE_SIZE_SHIFT) | (end << TWR_MBK7_END_ADDR_SHIFT);
break;
case TWR_WRAM_BLOCK_C:
start >>= TWR_WRAM_BC_SLOT_SHIFT;
length >>= TWR_WRAM_BC_SLOT_SHIFT;
end = start + length;
REG_MBK8 = (start << TWR_MBK8_START_ADDR_SHIFT) | (imageSize << TWR_MBK8_IMAGE_SIZE_SHIFT) | (end << TWR_MBK8_END_ADDR_SHIFT);
break;
}
}
#ifdef ARM9
void twr_mapWramASlot(int slot, TWRWramASlotMaster master, int offset, bool enable)
{
if(slot < 0 || slot > 3 || offset < 0 || offset > 3)
return;
REG_MBK1[slot] = enable ? (TWR_WRAM_A_SLOT_ENABLE | master | TWR_WRAM_A_SLOT_OFFSET(offset)) : 0;
}
void twr_mapWramBSlot(int slot, TWRWramBSlotMaster master, int offset, bool enable)
{
if(slot < 0 || slot > 7 || offset < 0 || offset > 7)
return;
REG_MBK2[slot] = enable ? (TWR_WRAM_BC_SLOT_ENABLE | master | TWR_WRAM_BC_SLOT_OFFSET(offset)) : 0;
}
void twr_mapWramCSlot(int slot, TWRWramCSlotMaster master, int offset, bool enable)
{
if(slot < 0 || slot > 7 || offset < 0 || offset > 7)
return;
REG_MBK4[slot] = enable ? (TWR_WRAM_BC_SLOT_ENABLE | master | TWR_WRAM_BC_SLOT_OFFSET(offset)) : 0;
}
#endif

BIN
icon.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

25
readme.md Normal file
View File

@ -0,0 +1,25 @@
FastVideoDS Player
===================
Player for the FastVideoDS format. Opens the video file supplied by argv, or otherwise `testVideo.fv` on the root of your sd card.
## Features
- Supports long videos
- Smooth playback by adjusting the lcd refresh rate to an integer multiple of the frame rate
- Supports up to 60 fps on dsi (~30 fps on ds)
- Uses the 3d engine for motion compensation
- Loads data from the sd card and decodes audio on the arm7 while the arm9 is fully available for decoding video
- Argv support (for use with TWiLight Menu++ for example)
- Video controls: play/pause and keyframe seeking
- Disables the backlight of the bottom screen while playing to save energy
## Controls
### Buttons
- A - Play/pause
- Dpad left - Jump to previous keyframe (hold to keep going)
- Dpad right - Jump to next keyframe (hold to keep going)
### Touch
The touch screen can be used to play/pause the video and to seek by tapping/dragging the seek bar.
## Libraries Used
- [FatFS](http://elm-chan.org/fsw/ff/00index_e.html)