initial commit

This commit is contained in:
olebeck 2022-05-28 14:27:06 +02:00
commit 2eaa9449a2
19 changed files with 1115 additions and 0 deletions

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
/*.bin
out_*.bin
__pycache__
/player/*.o
/player/badapple
/player/badapple.bin
/player/badapple.mcs
/player/data/icon.bin
/player/data/title.txt
/tools/ascii2sjis
/tools/bin2mcs
/tools/bmp2ps1b
/tools/mcpad

13
README.md Normal file
View File

@ -0,0 +1,13 @@
to build run:
`make clean all target=pocketstation`
extra options:
- target=[pocketstation]
specify to build for pocketstation else it builds for linux (default="")
- frameskip=[everynthframe]
only display every nth frame (default=4)
- loop=[1|0]
if it should loop forever (default=1)

BIN
encoder/badapple_input.bin Normal file

Binary file not shown.

20
encoder/common.py Normal file
View File

@ -0,0 +1,20 @@
import sys
from typing import List
def diff(last: List[List[bool]], current: List[List[bool]]) -> List[List[bool]]:
out = []
for i, row in enumerate(current):
out.append([])
for j, pixel in enumerate(row):
out[i].append(pixel != last[i][j])
return out
def print_frame(pixels: List[List[bool]]):
p = "\033[H\033[J"
for y in range(res[1]):
for x in range(res[0]):
p += "##" if pixels[y][x] else " "
p += "\n"
sys.stdout.write(p)
res = (32, 32)

110
encoder/encode.py Normal file
View File

@ -0,0 +1,110 @@
import sys
from typing import List, Tuple
def flatten(l):
for i in l:
if isinstance(i, list):
yield from flatten(i)
else:
yield i
from common import *
def encode_RLE(data: List[bool]) -> bytes:
out = b""
" values is a list of tuples where the first element is the count and the second is the value "
" the count can only go upto 7 bit "
values: List[Tuple[int,bool]] = []
for i in range(len(data)):
if i == 0:
values.append((1, data[i]))
elif data[i] != data[i-1]:
values.append((1, data[i]))
else:
last = values[-1][0]
if last < 127:
values[-1] = (last+1, data[i])
else:
values.append((1, data[i]))
for v in values:
# high bit is set if value is true
v = v[0] << 1 | int(v[1])
out += v.to_bytes(1, "little")
return out
stats = {
"avg_frame_size": 0,
"min_frame_size": float("inf"),
"max_frame_size": 0,
"total_size": 0,
}
def diff_encode(frames: List[List[List[bool]]]) -> bytes:
out = b""
for i, frame in enumerate(frames):
if i > 0:
last_frame = frames[i-1]
frame = diff(last_frame, frame)
o = encode_RLE(list(flatten(frame)))
out += o
sz_b = len(o)
#print(f"Frame {i} size: {sz_b}")
stats["min_frame_size"] = min(stats["min_frame_size"], sz_b)
stats["max_frame_size"] = max(stats["max_frame_size"], sz_b)
return out
def rle_encode(frames: List[List[List[bool]]]) -> bytes:
out = b""
for frame in frames:
o = encode_RLE(list(flatten(frame)))
out += o
stats["min_frame_size"] = min(stats["min_frame_size"], len(o))
stats["max_frame_size"] = max(stats["max_frame_size"], len(o))
return out
def get_frame(f):
pixels = []
for y in range(res[1]):
b = f.read(4)
if len(b) < 4:
return None
row = [ int(a) == 1 for a in bin(int.from_bytes(b, "little"))[2:].zfill(32)]
pixels.append(row)
return pixels
def encode():
f = open("badapple_input.bin", "rb")
frames = []
i = 0
while True:
i += 1
pixels = get_frame(f)
if not pixels:
break
if i % frameskip == 0:
frames.append(pixels)
stats["frame_count"] = len(frames)
with open("out_diff.bin", "wb") as fo:
o = diff_encode(frames)
stats["avg_frame_size"] = len(o) / len(frames)
stats["total_size"] = len(o)
fo.write(o)
print("diff", stats)
with open("out_rle.bin", "wb") as fo:
o = rle_encode(frames)
stats["avg_frame_size"] = len(o) / len(frames)
stats["total_size"] = len(o)
fo.write(o)
print("rle", stats)
if __name__ == "__main__":
frameskip = int(sys.argv[1])
encode()

37
encoder/play.py Normal file
View File

@ -0,0 +1,37 @@
import time
from typing import IO
from common import *
def decode_frame(f: IO[bytes], last_frame: list[list[bool]]) -> list[list[bool]]:
pixels = []
while len(pixels) < res[0]*res[1]:
count = int.from_bytes(f.read(1), "little")
# high bit stores value
val = bool(count & 1)
cnt = count >> 1
for _ in range(cnt):
pixels.append(val)
# reshape to res
pixels = [pixels[i:i+res[0]] for i in range(0, len(pixels), res[0])]
# apply diff
if last_frame:
pixels = diff(last_frame, pixels)
return pixels
def run_encoded():
f = open("out_diff.bin", "rb")
last_frame = None
while True:
t1 = time.time()
pixels = decode_frame(f, last_frame)
if len(pixels) == 0:
break
last_frame = pixels
print_frame(pixels)
t2 = time.time()
time.sleep(1/24 - (t2-t1))
if __name__ == "__main__":
run_encoded()

BIN
icon.BMP Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

100
player/Makefile Normal file
View File

@ -0,0 +1,100 @@
frameskip := 4
loop := 1
RLE := 1
name = badapple
DEFINES += -DFRAMESKIP=$(frameskip)
ifneq ($(loop),1)
else
DEFINES += -DLOOP=$(loop)
endif
ifneq ($(RLE),1)
input_type = diff
else
DEFINES += -DRLE
input_type = rle
endif
LDFLAGS =
CFLAGS = -Wl,--gc-sections -nostartfiles -s -static -nostdlib -Os -ffunction-sections -fdata-sections
# if pocketstation
ifeq ($(target),pocketstation)
POCKETSTATION = 1
CC = arm-none-eabi-gcc
LD = arm-none-eabi-ld
OBJCOPY = arm-none-eabi-objcopy
AS = arm-none-eabi-as
LDFLAGS += -Tldscript
CFLAGS += -march=armv4 -mtune=arm7tdmi
COPYFLAGS = -I binary -O elf32-littlearm
DEFINES += -D__POCKETSTATION__
extra_objects = head.o
else ifeq ($(target),)
CC = gcc
LD = gcc
OBJCOPY = objcopy
AS = as
COPYFLAGS = -B i386 -I binary -O elf64-x86-64
DEFINES += -D__LINUX__
else
$(error "unknown target")
endif
all: $(name)
ifdef POCKETSTATION
all: $(name).mcs
$(name).mcs: $(name).bin tools
../tools/bin2mcs BESCEDP-00000BADAPPLE0 $< $@
$(name).bin: $(name) tools
$(OBJCOPY) -O binary $< $@
../tools/mcpad $@
head.o: head.s data/title.txt data/icon.bin
endif
$(name): player.o badapple_$(input_type).o $(extra_objects)
$(LD) $(LDFLAGS) $^ -o $@
player.o: player.c
$(CC) -c $(CFLAGS) $(DEFINES) player.c -o player.o
badapple_$(input_type).o: out_$(input_type).bin
cp $< badapple_$(input_type).bin
$(OBJCOPY) $(COPYFLAGS) badapple_$(input_type).bin $@
rm badapple_$(input_type).bin
out_$(input_type).bin:
cd ../encoder && python3 encode.py $(frameskip)
cp ../encoder/out_$(input_type).bin .
tools:
cd ../tools && make
data/title.txt: tools
../tools/ascii2sjis $(name) $@
data/icon.bin: ../icon.BMP tools
../tools/bmp_to_1bit.py $< icon1bit.bmp
../tools/bmp2ps1b b icon1bit.bmp
rm icon1bit.bmp
mv icon1bit.bin $@
clean:
rm -f *.o $(name) $(name).bin $(name).mcs out_*.bin data/icon.bin data/title.txt
cd ../tools && make clean

BIN
player/data/psicon.bin Normal file

Binary file not shown.

78
player/head.s Normal file
View File

@ -0,0 +1,78 @@
.text
.code 32
.globl _start
_start:
.ascii "SC"
.byte 0x11
.byte 1 // Number of memory card blocks (use "mcpad" tool for auto-adjust)
// Title 32*2 Shift-JIS zero padded (use "ascii2sjis" tool to generate this file)
.include "data/title.txt"
.space 12
.hword 1 // Number of File Viewer Mono Icon Frames
.ascii "MCX0"
.byte 1 // Number of entries in Executable Mono Icon List
.byte 0 // No Function Table
.word 0
.word _progstart
IconPS: .incbin "data/psicon.bin" // 16*word Palette + 16x16 4bits Icon
IconPK: .incbin "data/icon.bin" // File Viewer Mono Icon 32x32
.hword 1 // Number of Executable Mono Icon
.hword 1 // Icon Anim Speed
.word IconPK // Pointer to the same File Viewer Mono Icon
_progstart:
b main
//----------------------------------------
// Bios Calls
.globl SetCallbacks
SetCallbacks:
swi 1
mov pc, lr
.globl SetCpuSpeed
SetCpuSpeed:
swi 4
mov pc, lr
.globl PrepareExecute
PrepareExecute:
swi 8
mov pc, lr
.globl DoExecute
DoExecute:
swi 9
.globl SetComOnOff
SetComOnOff:
swi 17
mov pc, lr
.globl GetDirIndex
GetDirIndex:
swi 22
mov pc, lr
.globl IntIRQ
IntIRQ:
stmdb sp!,{r2-r3,lr}
bl IRQ_Handler
ldmia sp!,{r2-r3,pc}
.globl IntFIQ
IntFIQ:
stmdb sp!,{r2-r3,lr}
bl FIQ_Handler
ldmia sp!,{r2-r3,pc}
//----------------------------------------
// User Data
.end

63
player/ldscript Normal file
View File

@ -0,0 +1,63 @@
OUTPUT_ARCH(arm)
MEMORY
{
ram : o = 0x00000204, l = 0x5fc
rom : o = 0x02000000, l = 0x1E000
}
SECTIONS
{
.text :
{
*(.text)
*(.strings)
*(.rodata)
*(.rdata)
_etext = . ;
} > rom
.rodata :
{
*(.rodata)
*all.rodata*(*)
*(.roda)
*(.rodata.*)
*(.gnu.linkonce.r*)
SORT(CONSTRUCTORS)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} > rom
.tors :
{
___ctors = . ;
*(.ctors)
___ctors_end = . ;
___dtors = . ;
*(.dtors)
___dtors_end = . ;
} > rom
.data :
{
*(.data)
_edata = . ;
} > rom
.glue_7 :
{
*(.glue_7)
_glut_7 = . ;
} > rom
.glue_7t :
{
*(.glue_7t)
_glut_7t = . ;
} > rom
.buffer :
{
*(.buffer)
_buffer = . ;
} > rom
.bss :
{
_bss_start = . ;
*(.bss)
*(COMMON)
_end = .;
} > ram
}

109
player/player.c Normal file
View File

@ -0,0 +1,109 @@
#include <stdint.h>
const int res = 32;
#define setbit(arr, i) arr[i/8] |= (1 << (i%8))
#define clrbit(arr, i) arr[(i)/8] &= ~(1 << ((i) % 8))
#define flpbit(arr, i) arr[(i)/8] ^= 1 << ((i) % 8)
#define getbit(arr, i) arr[(i)/8] & (1 << ((i) % 8))
#ifdef RLE
#define NAME_BIN "badapple_rle_bin"
#else
#define NAME_BIN "badapple_diff_bin"
#endif
extern uint8_t _binary_badapple_bin_start[] asm("_binary_" NAME_BIN "_start");
extern uint8_t _binary_badapple_bin_end[] asm("_binary_" NAME_BIN "_end");
static uint8_t screen[0x80];
#ifdef __LINUX__
#include <unistd.h>
#define clear_screen "\033[2J\033[1;1H"
void display() {
char buf[res*res*2 + res];
char* p = buf;
for (int i = 0; i < res; i++) {
for (int j = 0; j < res; j++) {
uint8_t on = getbit(screen, (i * res) + j);
*p++ = on ? '#' : ' ';
*p++ = on ? '#' : ' ';
}
*p = '\n';
p++;
}
write(1, clear_screen, sizeof(clear_screen)-1);
write(1, buf, sizeof(buf));
// ""vsync"""
usleep(16666*FRAMESKIP);
}
#define ROMByteAccess(addr) *(uint8_t*)(addr)
#endif
#ifdef __POCKETSTATION__
#define FPS 24
#define CLOCK_SPEED CLOCK_4M
#include "pocketlib.h"
static void display() {
// ????
for(int i = 0; i<FRAMESKIP*2; i++) VSync();
uint32_t *src = (uint32_t*)screen;
volatile unsigned int *dst = LCD_VRAM_ADRS;
int i = 32;
while (i--) {*dst++ = *src++;}
}
uint8_t ROMByteAccess(unsigned char *addr)
{
uint16_t data = *(uint16_t*)(((uint32_t)addr) & ~1);
if (((uint32_t)addr) & 1)
return (data >> 8);
return (data & 0xFF);
}
#endif
int main(void) {
#ifdef __POCKETSTATION__
PocketInit();
#endif
do {
// read all frames
uint8_t* p = _binary_badapple_bin_start;
while(p < _binary_badapple_bin_end) {
// read a frame
uint16_t px = 0;
while(px < res*res && p < _binary_badapple_bin_end) {
uint8_t value = ROMByteAccess(p++);
uint8_t changed = value & 1;
uint8_t count = value >> 1;
#ifdef RLE
for(int i = px; i < count+px; i++) {
if(changed) setbit(screen, i);
else clrbit(screen, i);
}
#else // diff + rle
if(changed) {
for (int i = px; i < px+count; i++) flpbit(screen, i);
}
#endif
px += count;
}
display();
}
#ifdef LOOP
} while(1);
#else
} while(0);
#endif
#ifdef __POCKETSTATION__
PocketExit();
#endif
return 0;
}

218
player/pocketlib.h Normal file
View File

@ -0,0 +1,218 @@
/****************************************/
/* PocketStation Lib - by Orion_ [2013] */
/****************************************/
// Based on Miko Hoshina & Martin Korth work.
// If you use it, please give credits !
// v3.6
// Optional Functions, don't define this in your main .c file do reduce size
//#define USE_SPRITE
//#define USE_RANDOM
//#define USE_SOUND
#ifndef NULL
#define NULL ((void*)0)
#endif
#ifndef CLOCK_SPEED
#define CLOCK_SPEED CLOCK_4M
#endif
#ifndef FPS
#define FPS 64
#endif
#ifndef SOUND_FREQ
#define SOUND_FREQ 4000 // If 8000Hz, then use CLOCK_8M !
#endif
/**/
#define PAD_BUTTON 0x1
#define PAD_RIGHT 0x2
#define PAD_LEFT 0x4
#define PAD_DOWN 0x8
#define PAD_UP 0x10
#define PAD_STATUS ((IRQ_STATUS_RAW) & 0x1F)
int PadOnRelease, PadOnPress;
/**/
#define LCD_ON 0x40
#define LCD_OFF 0x00
#define LCD_64HZ 0x10
#define LCD_32HZ 0x20
#define LCD_16HZ 0x30
#define LCD_CPEN 0x08
#define LCD_MODE *((volatile unsigned int *)0xD000000)
#define LCD_VRAM(_line_) *((volatile unsigned int *)(0xD000100+(_line_ << 2)))
#define LCD_VRAM_ADRS (volatile unsigned int *)0xD000100
/**/
#define CLOCK_62_5K 0x1
#define CLOCK_125K 0x2
#define CLOCK_250K 0x3
#define CLOCK_500K 0x4
#define CLOCK_1M 0x5
#define CLOCK_2M 0x6
#define CLOCK_4M 0x7
#define CLOCK_8M 0x8
/**/
#define TIMER0_START() *((volatile unsigned int *)(0xA800008)) |= 0x4
#define TIMER1_START() *((volatile unsigned int *)(0xA800018)) |= 0x4
#define TIMER2_START() *((volatile unsigned int *)(0xA800028)) |= 0x4
#define TIMER0_STOP() *((volatile unsigned int *)(0xA800008)) &= ~0x4
#define TIMER1_STOP() *((volatile unsigned int *)(0xA800018)) &= ~0x4
#define TIMER2_STOP() *((volatile unsigned int *)(0xA800028)) &= ~0x4
#define TIMER0_SETCOUNT(_x_) *((volatile unsigned int *)(0xA800000)) = (_x_)
#define TIMER1_SETCOUNT(_x_) *((volatile unsigned int *)(0xA800010)) = (_x_)
#define TIMER2_SETCOUNT(_x_) *((volatile unsigned int *)(0xA800020)) = (_x_)
/**/
#define FIQ_COMM 0x40
#define IRQ_TIMER0 0x80
#define IRQ_TIMER1 0x100
#define IRQ_RTC 0x200
#define IRQ_BATTERY 0x400
#define IRQ_PSCOMM 0x800
#define IRQ_INFRARED 0x1000
#define FIQ_TIMER2 0x2000
#define IRQ_STATUS *((volatile unsigned int *)(0xA000000))
#define IRQ_STATUS_RAW *((volatile unsigned int *)(0xA000004))
#define IRQ_ENABLE *((volatile unsigned int *)(0xA000008))
#define IRQ_DISABLE *((volatile unsigned int *)(0xA00000c))
#define IRQ_CLEAR *((volatile unsigned int *)(0xA000010))
#define IRQ_DISABLE_ALL() IRQ_DISABLE = 0x3FFF;
/**/
#define IOCTL_CONFIG *((volatile unsigned int *)0xD800000)
#define IOCTL_OFF *((volatile unsigned int *)0xD800004)
#define IOCTL_ON *((volatile unsigned int *)0xD800008)
#define IOCTL_DAC *((volatile unsigned int *)0xD800010)
#define IOCTL_DASOUND *((volatile unsigned int *)0xD800014)
#define IOCTL_BATTERY *((volatile unsigned int *)0xD800020)
#define IOCTL_LED 0x02
#define IOCTL_SPEAKER 0x20
#define IOCTL_IRDA 0x40
/****************************************/
// From header.S
// Bios Calls
void *SetCallbacks(int index, void (*function));
int SetCpuSpeed(int speed);
int PrepareExecute(int flag, int dir_index, int param);
void DoExecute(int snapshot_flag);
void SetComOnOff(int flag);
int GetDirIndex(void);
// IRQ/FIQ Asm
void IntIRQ(void);
void IntFIQ(void);
void (*UserIRQ)(void);
int (*UserFIQ)(void); // Return 1 to Skip Library Sound Processing, else return 0
/****************************************/
// IRQ/Timer0 Handler (for VSync)
volatile int VCount;
void IRQ_Handler(void)
{
int status;
status = IRQ_STATUS;
status &= IRQ_ENABLE;
status &= ~(FIQ_TIMER2 | FIQ_COMM); // Clear FIQ Bits
if (status & IRQ_TIMER0)
VCount++;
if (UserIRQ)
UserIRQ();
IRQ_CLEAR = status;
}
/****************************************/
// FIQ/Timer2 Handler (for Sound)
void FIQ_Handler(void)
{
IRQ_CLEAR = FIQ_TIMER2;
}
/****************************************/
// Sync Functions
void VSync()
{
register int cnt = VCount;
register int PadState = PAD_STATUS;
PadOnRelease = PadState;
PadOnRelease ^= PadOnPress;
PadOnRelease &= PadOnPress;
PadOnPress = PadState;
while (VCount == cnt); // Wait For IRQ Timer0
}
/****************************************/
// Init, need to be called at first !
void PocketInit(void)
{
SetCpuSpeed(CLOCK_SPEED);
IRQ_DISABLE_ALL();
UserIRQ = NULL;
UserFIQ = NULL;
VCount = 0;
PadOnRelease = 0;
PadOnPress = 0;
SetCallbacks(1, IntIRQ); // VSync Interrupt
SetCallbacks(2, IntFIQ); // Audio Interrupt
IRQ_CLEAR = IRQ_TIMER0 | FIQ_TIMER2;
IRQ_ENABLE = IRQ_TIMER0 | FIQ_TIMER2;
// Start VSync Timer
TIMER0_SETCOUNT((15625 << CLOCK_SPEED) / FPS);
TIMER0_START();
while (PAD_STATUS & PAD_BUTTON); // Wait for Button Release (Button pressed when comming from Menu)
}
/****************************************/
// Exit, need to be called to exit app !
void PocketExit(void)
{
SetComOnOff(0);
TIMER0_STOP();
TIMER2_STOP();
IRQ_DISABLE_ALL();
IRQ_ENABLE = IRQ_RTC | IRQ_PSCOMM;
PrepareExecute(1, 0, GetDirIndex() | 0x30); // Return to GUI on our Program Icon
DoExecute(0);
}
/****************************************/

9
tools/Makefile Normal file
View File

@ -0,0 +1,9 @@
all: ascii2sjis bin2mcs bmp2ps1b mcpad
ascii2sjis: ascii2sjis.c
bin2mcs: bin2mcs.c
bmp2ps1b: bmp2ps1b.c
mcpad: mcpad.c
clean:
rm -f ascii2sjis bin2mcs bmp2ps1b mcpad

105
tools/ascii2sjis.c Normal file
View File

@ -0,0 +1,105 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char ShiftJISpunc[] = ",.:;?!^_-/\\~|()[]{}+-=<>'\"$£%#&*@";
unsigned char ShiftJISpuncCode[] = {0x43,0x44,0x46,0x47,0x48,0x49,0x4F,0x51,0x5D,0x5E,0x5F,0x60,0x62,0x69,0x6A,0x6D,0x6E,0x6F,0x70,0x7B,0x7C,0x81,0x83,0x84,0x8C,0x8D,0x90,0x92,0x93,0x94,0x95,0x96,0x97};
void ASCII2ShiftJIS(char *src, unsigned char *dst)
{
while (*src)
{
if (*src == ' ')
{
*dst++ = 0x81;
*dst++ = 0x40;
}
else if ((*src >= '0') && (*src <= '9'))
{
*dst++ = 0x82;
*dst++ = 0x4F + ((*src) - '0');
}
else if ((*src >= 'A') && (*src <= 'Z'))
{
*dst++ = 0x82;
*dst++ = 0x60 + ((*src) - 'A');
}
else if ((*src >= 'a') && (*src <= 'z'))
{
*dst++ = 0x82;
*dst++ = 0x81 + ((*src) - 'a');
}
else
{
int i;
for (i = 0; i < sizeof(ShiftJISpuncCode); i++)
if (*src == ShiftJISpunc[i])
{
*dst++ = 0x81;
*dst++ = ShiftJISpuncCode[i];
break;
}
}
src++;
}
}
unsigned char buffer[64];
int main(int argc, char *argv[])
{
FILE *f;
int size;
printf("ASCII2ShiftJIS for PocketStation Lib - by Orion_ [2013]\n\n");
if (argc > 2)
{
size = strlen(argv[1]);
if (size > 32)
{
printf("Title too long (must be <= 32)\n");
return (-1);
}
memset(buffer, 0, sizeof(buffer));
ASCII2ShiftJIS(argv[1], buffer);
f = fopen(argv[2], "wb");
if (!f)
{
printf("Cannot create file %s\n", argv[2]);
return (-1);
}
// Title
fprintf(f, "\t/* %s */\r\n", argv[1]); // Just to keep a record of the Original Title :)
fprintf(f, "\t.ascii\t\"");
fwrite(buffer, 1, size*2, f);
fprintf(f, "\"\r\n");
// Padding
if (size < 32)
{
fprintf(f, "\t.hword\t");
size = 32 - size;
while (size)
{
fprintf(f, "0");
size--;
if (size)
fprintf(f, ",");
}
fprintf(f, "\r\n");
}
fclose(f);
}
else
{
printf("Usage: ascii2sjis ASCII_Title file.sjis\n\n");
printf("Ex: ascii2sjis \"Test Program\" title.sjis\n\n");
}
return (0);
}

77
tools/bin2mcs.c Normal file
View File

@ -0,0 +1,77 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
unsigned char data[128*1025];
int main(int argc, char *argv[])
{
FILE *f;
int size, i;
printf("MemoryCard BIN TO MCS - by Orion_ [2013]\n\n");
if (argc > 3)
{
f = fopen(argv[2], "rb");
if (f)
{
memset(data, 0, sizeof(data));
size = fread(&data[128], 1, sizeof(data)-128, f);
if ((data[128] == 'S') && (data[129] == 'C'))
{
fclose(f);
size = (size + 8191) >> 13; // One Block = 8k
data[128+3] = size; // Adjust Block Number
size <<= 13; // Pad to 8k
f = fopen(argv[3], "wb");
if (f)
{
// Generate MCS header
data[0] = 0x51;
data[4] = (size >> 0) & 0xFF;
data[5] = (size >> 8) & 0xFF;
data[6] = (size >> 16) & 0xFF;
data[7] = (size >> 24) & 0xFF;
data[8] = 1; // next block
strncpy(&data[10], argv[1], 20);
for (i = 0; i < 127; i++)
data[127] ^= data[i];
fwrite(data, 1, 128+size, f);
fclose(f);
}
else
printf("Cannot create output file\n");
}
else
printf("Bad MemoryCard BIN file format\n");
}
else
printf("Cannot load input file\n");
}
else
{
printf("Usage: bin2mcs FileID file.bin file.mcs\n\n");
printf("FileID Description: BcSlCTxCCCCCFILENAME (20 char max)\n");
printf(" Bc -> BI = Japan, BA = America, BE = Europe\n");
printf(" Sl -> SC = Sony Computer, SL = Sony Licensed\n");
printf(" C -> P = Japan, U = America, E = Europe\n");
printf(" T -> S = Game, D = Demo, M = ?\n");
printf(" x -> - = Normal Save, P = PocketStation\n");
printf(" CCCCC -> Game Digit Code\n");
printf(" FILENAME -> This Save Specific Filename\n");
printf("\nFileID Example:\n");
printf("BISLPS-00000GAMENAME Sony Licensed Japan, Game Code:00000 Filename: GAMENAME\n");
printf("BASCUS-21042SAVEFILE Sony Computer America, Game Code:21042 Filename: SAVEFILE\n");
printf("BESCES-88888FILENAME Sony Computer Europe, Game Code:88888 Filename: FILENAME\n");
printf("BESLESP00000MINIGAME Sony Licensed Europe, PocketStation Filename: MINIGAME\n\n");
getchar();
}
return (0);
}

102
tools/bmp2ps1b.c Normal file
View File

@ -0,0 +1,102 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
FILE *in, *out;
unsigned short x, y;
unsigned int a, b;
char n[255], *p;
int i, j, k, s;
printf("2 Colors BMP - to - PocketStation Binary data -- by Orion_ [2007-2013]\n\n");
s = 0;
if (argc > 2)
{
if ((argv[1][0] == 's') || (argv[1][0] == 'h') || (argv[1][0] == 'b'))
{
in = fopen(argv[2], "rb");
if (in)
{
strcpy(n, argv[2]);
p = strstr(n, ".bmp");
if (p)
{
if (argv[1][0] == 'b')
{
strcpy(p + 1, "bin");
out = fopen(n, "wb");
}
else
{
strcpy(p + 1, argv[1]);
out = fopen(n, "w");
}
if (out)
{
fseek(in,18,SEEK_SET);
fread(&x,2,1,in);
x /= 32;
if (x >= 1)
{
fseek(in,22,SEEK_SET);
fread(&y,2,1,in);
*(p - 2) = '\0';
if (argv[1][0] == 'h')
fprintf(out, "const u32\t%s_gfx[] = {\n", n);
for (k = 0; k < y; k++)
{
fseek(in,-((k*x*4)+x*4),SEEK_END);
if (argv[1][0] == 's')
fprintf(out, "\t.word\t");
for (i = 0; i < x; i++)
{
fread(&a,4,1,in);
b = 0;
for (j = 0; j < 32; j++)
b |= (((a >> (31-j)) & 1) << j);
b ^= 0xFFFFFFFF;
b = (b >> 24) | (((b >> 16) & 0xFF) << 8) | (((b >> 8) & 0xFF) << 16) | ((b & 0xFF) << 24);
if (argv[1][0] == 'b')
fwrite(&b, 1, 4, out);
else
fprintf(out, "0x%x", b);
if ((argv[1][0] == 'h') || ((argv[1][0] == 's') && (i != x - 1)))
fprintf(out, ",");
}
if (argv[1][0] != 'b')
fprintf(out, "\n");
}
if (argv[1][0] == 'h')
fprintf(out, "};\n");
s = 1;
}
else
printf("Width must be at least 32\n");
}
else
printf("Cannot create output file\n");
}
else
printf("Bad filename\n");
}
else
printf("Cannot load input file\n");
}
else
printf("First argument must be 'h', 's', or 'b' (H = C Header File, S = ASM File, B = Binary File)\n");
}
if (s)
printf("done...\n");
else
{
printf("\nUsage: bmp2ps1b [h|s|b] file.bmp\n\n");
printf("First argument must be 'h', 's', or 'b' (H = C Header File, S = ASM File, B = Binary File)\n");
printf("BMP MUST BE 1BITS !! (Black and White 2 colors palette)\n\n");
}
return 0;
}

8
tools/bmp_to_1bit.py Executable file
View File

@ -0,0 +1,8 @@
#!/bin/python3
import sys
from PIL import Image
img = Image.open(sys.argv[1])
img = img.convert("1", dither=Image.Dither.NONE)
img = img.resize((32,32), Image.Resampling.NEAREST)
img.save(sys.argv[2])

51
tools/mcpad.c Normal file
View File

@ -0,0 +1,51 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned char data[128*1024];
int main(int argc, char *argv[])
{
FILE *f;
int size, osize;
printf("MemoryCard Block Padder & Adjust - by Orion_ [2013]\n\n");
if (argc > 1)
{
f = fopen(argv[1], "rb");
if (f)
{
memset(data, 0, sizeof(data));
osize = size = fread(data, 1, sizeof(data), f);
if ((data[0] == 'S') && (data[1] == 'C'))
{
fclose(f);
size = (size + 8191) >> 13; // One Block = 8k
data[3] = size; // Adjust Block Number
size <<= 13; // Pad to 8k
f = fopen(argv[1], "wb");
if (f)
{
fwrite(data, 1, size, f);
fclose(f);
printf("Free Space: %d\n", size - osize);
printf("%d Block(s)\n", data[3]);
}
else
printf("Cannot create output file\n");
}
else
printf("Bad MemoryCard file format\n");
}
else
printf("Cannot load input file\n");
}
else
printf("Usage: mcpad mcfile.bin\n\n");
return (0);
}