init files
This commit is contained in:
commit
8197a022bd
1409 changed files with 139317 additions and 0 deletions
42
loader/tools/subsizer-0.7pre1/src/Makefile
Normal file
42
loader/tools/subsizer-0.7pre1/src/Makefile
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# Makefile for subsizer
|
||||
|
||||
# configuration
|
||||
CPPFLAGS += -MMD -MP
|
||||
CFLAGS= -O3 -march=native -Wall
|
||||
|
||||
# top level targets
|
||||
all: subdirs subsizer
|
||||
|
||||
# source files
|
||||
SRC = subsizer.c \
|
||||
params.c match.c pathfinder.c universal.c bits-base.c \
|
||||
crunch_normal.c \
|
||||
buffer.c memory.c \
|
||||
histogram.c \
|
||||
bitfunc.c \
|
||||
message.c \
|
||||
utils.c \
|
||||
global.c
|
||||
|
||||
# targets
|
||||
subsizer: $(SRC:%.c=%.o) sfx/sfx.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
cp $@ ..
|
||||
|
||||
# clean
|
||||
clean: subdirs
|
||||
rm -f *~ \#*\#
|
||||
rm -f *.o
|
||||
rm -f *.d
|
||||
rm -f a.out
|
||||
rm -f subsizer
|
||||
|
||||
# handle dependencies
|
||||
-include $(SRC:%.c=%.d)
|
||||
|
||||
# handle sub directories
|
||||
export CC LD CPPFLAGS CFLAGS
|
||||
subdirs:
|
||||
$(MAKE) -C sfx $(MAKECMDGOALS)
|
||||
|
||||
# eof
|
||||
211
loader/tools/subsizer-0.7pre1/src/bitfunc.c
Normal file
211
loader/tools/subsizer-0.7pre1/src/bitfunc.c
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE bitfunc.c
|
||||
* Copyright (c) 2009-2011, 2013-2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* bitstream read/write functions.
|
||||
*
|
||||
******/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "bitfunc.h"
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION bit writer
|
||||
*
|
||||
******/
|
||||
void bitwr_init(BitWriteState *bws, uint8_t *destbuf, unsigned flags)
|
||||
{
|
||||
bws->ptr = destbuf;
|
||||
bws->pos = 0;
|
||||
bws->bits = 0;
|
||||
|
||||
bws->bit = 0;
|
||||
bws->buf = 0;
|
||||
bws->bpos = 0;
|
||||
|
||||
bws->flags = flags;
|
||||
|
||||
if (bws->flags & BITMODE_PRESHIFT) {
|
||||
/*
|
||||
* first byte shall be rol:ed one bit with a 1 inserted
|
||||
* we reserve this bit here and apply the shift afterwards
|
||||
*/
|
||||
bitwr_write(bws, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bitwr_write(BitWriteState *bws, uint32_t data, int n)
|
||||
{
|
||||
bws->bits += n;
|
||||
|
||||
/* mask source data */
|
||||
data &= (1 << n) - 1;
|
||||
|
||||
/* process bits */
|
||||
while (n) {
|
||||
int fr = 8-bws->bit;
|
||||
int nn = (n > fr) ? fr : n;
|
||||
if (bws->bit == 0) {
|
||||
bws->bpos = bws->pos;
|
||||
bws->pos++;
|
||||
}
|
||||
bws->buf <<= nn;
|
||||
bws->buf |= data >> (n-nn);
|
||||
bws->bit += nn;
|
||||
if (bws->bit == 8) {
|
||||
bws->ptr[bws->bpos] = bws->buf;
|
||||
bws->bit = 0;
|
||||
}
|
||||
n -= nn;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void bitwr_write8s(BitWriteState *bws, uint8_t data)
|
||||
{
|
||||
if ( !(bws->flags & BITMODE_SIDEBYTE) ) {
|
||||
bitwr_write(bws, data, 8);
|
||||
return;
|
||||
}
|
||||
|
||||
bws->bits += 8;
|
||||
|
||||
bws->ptr[bws->pos] = data;
|
||||
bws->pos++;
|
||||
}
|
||||
|
||||
|
||||
int bitwr_flush(BitWriteState *bws)
|
||||
{
|
||||
if (bws->bit > 0) {
|
||||
bitwr_write(bws, 0, 8-bws->bit);
|
||||
}
|
||||
|
||||
if (bws->flags & BITMODE_PRESHIFT) {
|
||||
/*
|
||||
* first byte shall be rol:ed one bit with a 1 inserted
|
||||
* apply the shift here (MSB was unused since before)
|
||||
*/
|
||||
bws->ptr[0] = (bws->ptr[0] << 1) | 0x01;
|
||||
}
|
||||
|
||||
return bws->pos;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION bit reader
|
||||
*
|
||||
******/
|
||||
void bitrd_init(BitReadState *brs, uint8_t *srcbuf, unsigned int flags)
|
||||
{
|
||||
brs->ptr = srcbuf;
|
||||
brs->pos = 0;
|
||||
brs->bits = 0;
|
||||
|
||||
brs->bit = 0;
|
||||
brs->buf = 0;
|
||||
|
||||
brs->flags = flags;
|
||||
|
||||
if (brs->flags & BITMODE_PRESHIFT) {
|
||||
/*
|
||||
* first byte shall be ror:ed one bit with a 1 inserted
|
||||
* and one bit pop:ed. Preserve buf[0] for later.
|
||||
*/
|
||||
uint8_t tmp = brs->ptr[0];
|
||||
brs->ptr[0] >>= 1;
|
||||
bitrd_read(brs, 1);
|
||||
brs->ptr[0] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t bitrd_read(BitReadState *brs, int n)
|
||||
{
|
||||
brs->bits += n;
|
||||
uint32_t data = 0;
|
||||
|
||||
while (n) {
|
||||
if (brs->bit == 0) {
|
||||
brs->buf = brs->ptr[brs->pos];
|
||||
brs->pos++;
|
||||
brs->bit = 8;
|
||||
}
|
||||
int nn = (n > brs->bit) ? brs->bit : n;
|
||||
|
||||
data <<= nn;
|
||||
data |= brs->buf >> (8-nn);
|
||||
brs->buf <<= nn;
|
||||
brs->bit -= nn;
|
||||
n -= nn;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
uint8_t bitrd_read8s(BitReadState *brs)
|
||||
{
|
||||
if ( !(brs->flags & BITMODE_SIDEBYTE) ) {
|
||||
return bitrd_read(brs, 8);
|
||||
}
|
||||
brs->bits += 8;
|
||||
uint8_t data = 0;
|
||||
|
||||
data = brs->ptr[brs->pos];
|
||||
brs->pos++;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION test functions
|
||||
*
|
||||
******/
|
||||
void bit_test(void)
|
||||
{
|
||||
int i;
|
||||
BitWriteState bws;
|
||||
BitReadState brs;
|
||||
uint8_t buf[256];
|
||||
int len;
|
||||
bitwr_init(&bws, buf, 0);
|
||||
|
||||
bitwr_write(&bws, 1, 1);
|
||||
bitwr_write(&bws, 0, 1);
|
||||
bitwr_write(&bws, 3, 2);
|
||||
bitwr_write(&bws, 0x5a6b7c, 24);
|
||||
|
||||
len=bitwr_flush(&bws);
|
||||
printf("buf (%d): ",bws.bits);
|
||||
for (i=0; i<len; i++) {
|
||||
printf("%02X ",buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
bitrd_init(&brs, buf, 0);
|
||||
uint32_t d;
|
||||
d=bitrd_read(&brs, 1);
|
||||
printf("rd: %08X\n",d);
|
||||
d=bitrd_read(&brs, 0);
|
||||
printf("rd: %08X\n",d);
|
||||
d=bitrd_read(&brs, 3);
|
||||
printf("rd: %08X\n",d);
|
||||
d=bitrd_read(&brs, 24);
|
||||
printf("rd: %08X\n",d);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* eof */
|
||||
51
loader/tools/subsizer-0.7pre1/src/bitfunc.h
Normal file
51
loader/tools/subsizer-0.7pre1/src/bitfunc.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE bitfunc.h
|
||||
* Copyright (c) 2009-2011, 2013-2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* bitstream read/write functions.
|
||||
*
|
||||
******/
|
||||
#ifndef BITFUNC_H
|
||||
#define BITFUNC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define BITMODE_SIDEBYTE (1<<0)
|
||||
#define BITMODE_PRESHIFT (1<<1)
|
||||
//#define BITMODE_ROR (1<<2)
|
||||
|
||||
/* bit writer */
|
||||
typedef struct {
|
||||
uint8_t *ptr;
|
||||
int pos;
|
||||
int bits;
|
||||
uint8_t buf;
|
||||
int bit;
|
||||
int bpos;
|
||||
unsigned int flags;
|
||||
} BitWriteState;
|
||||
|
||||
void bitwr_init(BitWriteState *bws, uint8_t *destbuf, unsigned int flags);
|
||||
void bitwr_write(BitWriteState *bws, uint32_t data, int n);
|
||||
void bitwr_write8s(BitWriteState *bws, uint8_t data);
|
||||
int bitwr_flush(BitWriteState *bws);
|
||||
|
||||
/* bit reader */
|
||||
typedef struct {
|
||||
uint8_t *ptr;
|
||||
int pos;
|
||||
int bits;
|
||||
uint8_t buf;
|
||||
int bit;
|
||||
unsigned int flags;
|
||||
} BitReadState;
|
||||
|
||||
void bitrd_init(BitReadState *brs, uint8_t *srcbuf, unsigned int flags);
|
||||
uint32_t bitrd_read(BitReadState *brs, int n);
|
||||
uint8_t bitrd_read8s(BitReadState *brs);
|
||||
|
||||
#endif /* BITFUNC_H */
|
||||
/* eof */
|
||||
390
loader/tools/subsizer-0.7pre1/src/bits-base.c
Normal file
390
loader/tools/subsizer-0.7pre1/src/bits-base.c
Normal file
|
|
@ -0,0 +1,390 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE bits-base.c
|
||||
* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* bits-base optimization
|
||||
*
|
||||
******/
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bitfunc.h"
|
||||
#include "bits-base.h"
|
||||
#include "global.h"
|
||||
#include "histogram.h"
|
||||
#include "universal.h"
|
||||
|
||||
#define DEBUG_COMPLEXITY 0
|
||||
#define HAVE_CACHE 1
|
||||
|
||||
#define MAX_VALUES 0x10000
|
||||
|
||||
static unsigned int base_cost[MAX_PARTS];
|
||||
static unsigned int so_far[MAX_VALUES+1];
|
||||
static unsigned int cost_left[MAX_VALUES+1];
|
||||
|
||||
#if DEBUG_COMPLEXITY
|
||||
static size_t n_entry, n_tested, n_copy, n_hits;
|
||||
#endif
|
||||
|
||||
#if HAVE_CACHE
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION optimization cache
|
||||
*
|
||||
******/
|
||||
#define CACHE_ENTRIES MAX_VALUES
|
||||
|
||||
typedef struct {
|
||||
int len;
|
||||
char parts[MAX_PARTS];
|
||||
} CacheEntry;
|
||||
|
||||
static CacheEntry cache[CACHE_ENTRIES][MAX_PARTS];
|
||||
|
||||
static void invalidate_cache(void)
|
||||
{
|
||||
int id, bit;
|
||||
for (id = 0; id < CACHE_ENTRIES; id++) {
|
||||
for (bit = 0; bit < MAX_PARTS; bit++) {
|
||||
cache[id][bit].len = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline int hash_func(int base)
|
||||
{
|
||||
return base;
|
||||
}
|
||||
|
||||
|
||||
static inline void add_cache(int n_b, int bit, int base, char *enc, int len)
|
||||
{
|
||||
int i;
|
||||
int id = hash_func(base);
|
||||
|
||||
cache[id][bit].len = len;
|
||||
for (i = bit; i < n_b; i++) {
|
||||
cache[id][bit].parts[i] = enc[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline int find_cache(int n_b, int bit, int base, char *enc)
|
||||
{
|
||||
int i;
|
||||
int id = hash_func(base);
|
||||
|
||||
int l = cache[id][bit].len;
|
||||
if (l >= 0) {
|
||||
for (i = bit; i < n_b; i++) {
|
||||
enc[i] = cache[id][bit].parts[i];
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION optimize encoding
|
||||
*
|
||||
******/
|
||||
static int calc_enc(int n_b, int bit, int base, char *enc)
|
||||
{
|
||||
int i, min_len = 0x10000000;
|
||||
char min_enc[MAX_PARTS];
|
||||
|
||||
#if DEBUG_COMPLEXITY
|
||||
n_entry++;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
int len;
|
||||
int lim = base + (1 << i);
|
||||
/*
|
||||
* this should consider the length encodings mapped to
|
||||
* the particular offset.
|
||||
* maybe it can be handled by subtracting from the costs.
|
||||
*/
|
||||
int cost = base_cost[bit] + i;
|
||||
|
||||
if (lim > MAX_VALUES-1) {
|
||||
if (bit < n_b-1) {
|
||||
break;
|
||||
}
|
||||
lim = MAX_VALUES;
|
||||
}
|
||||
|
||||
|
||||
len = (so_far[lim] - so_far[base]) * cost;
|
||||
|
||||
if (bit < n_b-1) {
|
||||
if (cost_left[lim]) {
|
||||
#if HAVE_CACHE
|
||||
int tmp = find_cache(n_b, bit + 1, lim, min_enc);
|
||||
if (tmp >= 0) {
|
||||
len += tmp;
|
||||
#if DEBUG_COMPLEXITY
|
||||
n_hits++;
|
||||
#endif
|
||||
} else {
|
||||
len += calc_enc(n_b, bit + 1, lim, min_enc);
|
||||
}
|
||||
#else
|
||||
len += calc_enc(n_b, bit + 1, lim, min_enc);
|
||||
#endif
|
||||
} else {
|
||||
/* didn't use all entries */
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* out of bits, return the alternative cost */
|
||||
len += cost_left[lim];
|
||||
}
|
||||
|
||||
|
||||
#if DEBUG_COMPLEXITY
|
||||
n_tested++;
|
||||
#endif
|
||||
|
||||
if (len < min_len) {
|
||||
int j;
|
||||
min_len = len;
|
||||
enc[bit] = i;
|
||||
for (j = bit+1; j < n_b; j++) {
|
||||
enc[j] = min_enc[j];
|
||||
}
|
||||
#if DEBUG_COMPLEXITY
|
||||
n_copy++;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if HAVE_CACHE
|
||||
add_cache(n_b, bit, base, enc, min_len);
|
||||
#endif
|
||||
return min_len;
|
||||
}
|
||||
|
||||
static void build_arrays(Hist *h)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(so_far, 0, sizeof(so_far));
|
||||
memset(cost_left, 0, sizeof(cost_left));
|
||||
|
||||
int acc = 0;
|
||||
for (i = 0; i < h->range; i++) {
|
||||
so_far[i] = acc;
|
||||
acc += h->bin[i];
|
||||
}
|
||||
so_far[i] = acc;
|
||||
|
||||
double cost = 0;
|
||||
cost_left[h->range] = 0;
|
||||
for (i = h->range-1; i >= 0; i--) {
|
||||
cost += h->cost[i];
|
||||
cost_left[i] = cost;
|
||||
}
|
||||
}
|
||||
|
||||
void optimize_enc(Hist *h, int floor, int n, prefix_t prefix, Encoding *enc)
|
||||
{
|
||||
int i;
|
||||
Encoding tmp;
|
||||
if (!enc) {
|
||||
enc = &tmp;
|
||||
}
|
||||
|
||||
enc->floor = floor;
|
||||
enc->n = n;
|
||||
enc->prefix = prefix;
|
||||
|
||||
build_arrays(h);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
switch (prefix) {
|
||||
case PRE_BINARY:
|
||||
base_cost[i] = ceil( log(n) / log(2) );
|
||||
break;
|
||||
case PRE_UNARY:
|
||||
case PRE_UNARY_INV:
|
||||
base_cost[i] = cost_unary(i, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG_COMPLEXITY
|
||||
n_entry = 0;
|
||||
n_tested = 0;
|
||||
n_copy = 0;
|
||||
n_hits = 0;
|
||||
#endif
|
||||
|
||||
#if HAVE_CACHE
|
||||
invalidate_cache();
|
||||
#endif
|
||||
|
||||
|
||||
char bits[MAX_PARTS];
|
||||
for (i = 0; i < n; i++) {
|
||||
bits[i] = 0;
|
||||
}
|
||||
|
||||
calc_enc(n, 0, floor, bits);
|
||||
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
enc->parts[i] = bits[i];
|
||||
}
|
||||
|
||||
#if DEBUG_COMPLEXITY
|
||||
printf(" n_entry=%zu, n_tested=%zu, n_copy=%zu, n_hits=%zu\n", n_entry, n_tested, n_copy, n_hits);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME print_enc, print_enc_long
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Print out encoding
|
||||
*
|
||||
******/
|
||||
void print_enc(Encoding *enc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < enc->n; i++) {
|
||||
printf("%X", enc->parts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void print_enc_long(Encoding *enc)
|
||||
{
|
||||
int i;
|
||||
int lim = enc->floor;
|
||||
|
||||
printf("enc = { ");
|
||||
for (i = 0; i < enc->n; i++) {
|
||||
lim += 1 << enc->parts[i];
|
||||
if (i != 0) {
|
||||
printf(", ");
|
||||
}
|
||||
printf("%d", enc->parts[i]);
|
||||
}
|
||||
lim--;
|
||||
|
||||
printf(" } %d..%d\n", enc->floor, lim);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION encoding
|
||||
*
|
||||
******/
|
||||
int cost_enc(Encoding *enc, int v)
|
||||
{
|
||||
int i, of, base;
|
||||
|
||||
base = enc->floor;
|
||||
of = -1;
|
||||
for (i = 0; i < enc->n; i++) {
|
||||
base += 1 << enc->parts[i];
|
||||
if (v < base) {
|
||||
of = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (of < 0) {
|
||||
/* fault */
|
||||
return 0x100000;
|
||||
}
|
||||
|
||||
switch (enc->prefix) {
|
||||
case PRE_BINARY:
|
||||
return ceil( log(enc->n) / log(2) ) + enc->parts[of];
|
||||
case PRE_UNARY:
|
||||
case PRE_UNARY_INV:
|
||||
return cost_unary(of, enc->n) + enc->parts[of];
|
||||
default:
|
||||
/* should never happen */
|
||||
return 0x100000;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void write_enc(BitWriteState *bws, Encoding *enc, int v)
|
||||
{
|
||||
int i, of, base;
|
||||
|
||||
base = enc->floor;
|
||||
of = -1;
|
||||
for (i = 0; i < enc->n; i++) {
|
||||
base += 1 << enc->parts[i];
|
||||
if (v < base) {
|
||||
of = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (of < 0) {
|
||||
/* fault */
|
||||
//return 0x100000;
|
||||
}
|
||||
|
||||
switch (enc->prefix) {
|
||||
case PRE_BINARY:
|
||||
bitwr_write(bws, of, ceil( log(enc->n) / log(2) ));
|
||||
break;
|
||||
case PRE_UNARY:
|
||||
write_unary(bws, of, enc->n, 0);
|
||||
break;
|
||||
case PRE_UNARY_INV:
|
||||
write_unary(bws, of, enc->n, 1);
|
||||
break;
|
||||
}
|
||||
bitwr_write(bws, v-base, enc->parts[of]);
|
||||
}
|
||||
|
||||
|
||||
int read_enc(BitReadState *brs, Encoding *enc)
|
||||
{
|
||||
int i, of, base;
|
||||
|
||||
switch (enc->prefix) {
|
||||
case PRE_BINARY:
|
||||
of = bitrd_read(brs, ceil( log(enc->n) / log(2) ));
|
||||
break;
|
||||
case PRE_UNARY:
|
||||
of = read_unary(brs, enc->n, 0);
|
||||
break;
|
||||
case PRE_UNARY_INV:
|
||||
of = read_unary(brs, enc->n, 1);
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
of = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
base = enc->floor;
|
||||
for (i = 0; i < of; i++) {
|
||||
base += 1 << enc->parts[i];
|
||||
}
|
||||
|
||||
return base + bitrd_read(brs, enc->parts[of]);
|
||||
}
|
||||
|
||||
/* eof */
|
||||
42
loader/tools/subsizer-0.7pre1/src/bits-base.h
Normal file
42
loader/tools/subsizer-0.7pre1/src/bits-base.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE bits-base.h
|
||||
* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* bits-base optimization
|
||||
*
|
||||
******/
|
||||
#ifndef BITS_BASE_H
|
||||
#define BITS_BASE_H
|
||||
|
||||
#include "bitfunc.h"
|
||||
#include "histogram.h"
|
||||
|
||||
typedef enum {
|
||||
PRE_BINARY = 0,
|
||||
PRE_UNARY = 1,
|
||||
PRE_UNARY_INV,
|
||||
} prefix_t;
|
||||
|
||||
#define MAX_PARTS 16
|
||||
typedef struct {
|
||||
int floor;
|
||||
int n;
|
||||
prefix_t prefix;
|
||||
char parts[MAX_PARTS];
|
||||
} Encoding;
|
||||
|
||||
void optimize_enc(Hist *h, int floor, int n, prefix_t prefix, Encoding *enc);
|
||||
|
||||
void print_enc(Encoding *enc);
|
||||
void print_enc_long(Encoding *enc);
|
||||
|
||||
int cost_enc(Encoding *enc, int v);
|
||||
void write_enc(BitWriteState *bws, Encoding *enc, int v);
|
||||
int read_enc(BitReadState *brs, Encoding *enc);
|
||||
|
||||
|
||||
#endif /* BITS_BASE_H */
|
||||
/* eof */
|
||||
164
loader/tools/subsizer-0.7pre1/src/buffer.c
Normal file
164
loader/tools/subsizer-0.7pre1/src/buffer.c
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE buffer.c
|
||||
* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* handling of buffers
|
||||
*
|
||||
******/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "buffer.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME create_buffer, destroy_buffer
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Create/destroy buffer.
|
||||
*
|
||||
******/
|
||||
Buffer *create_buffer(size_t size)
|
||||
{
|
||||
Buffer *bf;
|
||||
|
||||
bf = safe_malloc(sizeof(Buffer), "Buffer");
|
||||
bf->buf = safe_malloc(size, "Buffer buf");
|
||||
bf->size = size;
|
||||
|
||||
bf->pos = 0;
|
||||
bf->len = 0;
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
void destroy_buffer(Buffer *bf)
|
||||
{
|
||||
free(bf->buf);
|
||||
free(bf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME create_buffer_from_file
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Create a new buffer from file.
|
||||
*
|
||||
******/
|
||||
Buffer *create_buffer_from_file(const char *name)
|
||||
{
|
||||
Buffer *bf;
|
||||
size_t len;
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(name, "rb");
|
||||
if (!fp) {
|
||||
panic("couldn't open file for reading");
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
len = ftell(fp);
|
||||
bf = create_buffer(len);
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
uint8_t *b = bf->buf;
|
||||
int l = len;
|
||||
while (l > 0) {
|
||||
size_t n;
|
||||
n = fread(b, 1, l, fp);
|
||||
b += n;
|
||||
l -= n;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
bf->len = len;
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME write_buffer_to_file
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Write buffer contents to file.
|
||||
*
|
||||
******/
|
||||
void write_buffer_to_file(Buffer *bf, const char *name)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(name, "wb");
|
||||
if (!fp) {
|
||||
panic("couldn't open file for writing");
|
||||
}
|
||||
|
||||
fwrite(bf->buf, 1, bf->len, fp);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME compare_buffer
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Compare buffer contents
|
||||
*
|
||||
******/
|
||||
int compare_buffer(Buffer *bf1, Buffer *bf2)
|
||||
{
|
||||
if (bf1->len != bf2->len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(bf1->buf, bf2->buf, bf1->len) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME reverse_buffer
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Reverse buffer contents
|
||||
*
|
||||
******/
|
||||
void reverse_buffer(Buffer *bf)
|
||||
{
|
||||
size_t i, l;
|
||||
uint8_t *buf;
|
||||
|
||||
l = bf->len;
|
||||
buf = bf->buf;
|
||||
|
||||
for (i = 0; i < l/2; i++) {
|
||||
uint8_t b;
|
||||
b = buf[l-i-1];
|
||||
buf[l-i-1] = buf[i];
|
||||
buf[i] = b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* eof */
|
||||
36
loader/tools/subsizer-0.7pre1/src/buffer.h
Normal file
36
loader/tools/subsizer-0.7pre1/src/buffer.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE buffer.h
|
||||
* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* handling of buffers
|
||||
*
|
||||
******/
|
||||
#ifndef BUFFER_H
|
||||
#define BUFFER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t *buf;
|
||||
size_t size;
|
||||
|
||||
size_t pos;
|
||||
size_t len;
|
||||
|
||||
} Buffer;
|
||||
|
||||
|
||||
Buffer *create_buffer(size_t size);
|
||||
void destroy_buffer(Buffer *bf);
|
||||
Buffer *create_buffer_from_file(const char *name);
|
||||
void write_buffer_to_file(Buffer *bf, const char *name);
|
||||
int compare_buffer(Buffer *bf1, Buffer *bf2);
|
||||
void reverse_buffer(Buffer *bf);
|
||||
|
||||
|
||||
#endif /* BUFFER_H */
|
||||
/* eof */
|
||||
890
loader/tools/subsizer-0.7pre1/src/crunch_normal.c
Normal file
890
loader/tools/subsizer-0.7pre1/src/crunch_normal.c
Normal file
|
|
@ -0,0 +1,890 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE crunch_normal.c
|
||||
* Copyright (c) 2015, 2016, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* optimize encoding and generate
|
||||
*
|
||||
******/
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bitfunc.h"
|
||||
#include "bits-base.h"
|
||||
#include "buffer.h"
|
||||
#include "pathfinder.h"
|
||||
#include "global.h"
|
||||
#include "histogram.h"
|
||||
#include "match.h"
|
||||
#include "memory.h"
|
||||
#include "message.h"
|
||||
#include "utils.h"
|
||||
#include "sfx/fold.h"
|
||||
#include "sfx/generate_sfx.h"
|
||||
|
||||
#define HAVE_THREE_BYTE 1
|
||||
|
||||
#define LEN_PARTS 16
|
||||
#define SINGLE_BYTE_PARTS 4
|
||||
#define TWO_BYTE_PARTS 16
|
||||
#define THREE_BYTE_PARTS 16
|
||||
#define LONG_MATCH_PARTS 16
|
||||
|
||||
#define MIN_MATCH 1
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME optimize_encoding
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Use statistics of the primary units on the cheapest path to calculate
|
||||
* an optimized encoding.
|
||||
*
|
||||
******/
|
||||
struct EncodingSet {
|
||||
int endm;
|
||||
Encoding bitsl;
|
||||
Encoding bits1;
|
||||
Encoding bits2;
|
||||
#if HAVE_THREE_BYTE
|
||||
Encoding bits3;
|
||||
#endif
|
||||
Encoding bits;
|
||||
};
|
||||
|
||||
|
||||
static void print_enc_set(EncodingSet *es)
|
||||
{
|
||||
print_enc(&es->bitsl);
|
||||
printf(",");
|
||||
print_enc(&es->bits1);
|
||||
printf(",");
|
||||
print_enc(&es->bits2);
|
||||
#if HAVE_THREE_BYTE
|
||||
printf(",");
|
||||
print_enc(&es->bits3);
|
||||
#endif
|
||||
printf(",");
|
||||
print_enc(&es->bits);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void print_enc_stats(Hist *h, Encoding *enc, char *label)
|
||||
{
|
||||
printf("%s (n=%zu, e_min=%.2f): ", label, get_number(h), get_entropy(h));
|
||||
print_enc_long(enc);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Hist *h_len;
|
||||
Hist *h_offs1;
|
||||
Hist *h_offs2;
|
||||
Hist *h_offs3;
|
||||
Hist *h_offs;
|
||||
} Stats;
|
||||
|
||||
static Stats *create_stats(void)
|
||||
{
|
||||
Stats *st;
|
||||
|
||||
st = safe_malloc(sizeof(Stats), "Stats");
|
||||
|
||||
st->h_len = create_histogram(0x10000, 0);
|
||||
st->h_offs1 = create_histogram(0x10000, 0);
|
||||
st->h_offs2 = create_histogram(0x10000, 0);
|
||||
#if HAVE_THREE_BYTE
|
||||
st->h_offs3 = create_histogram(0x10000, 0);
|
||||
#endif
|
||||
st->h_offs = create_histogram(0x10000, 0);
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
static void destroy_stats(Stats *st)
|
||||
{
|
||||
if (st) {
|
||||
destroy_histogram(st->h_len);
|
||||
destroy_histogram(st->h_offs1);
|
||||
destroy_histogram(st->h_offs2);
|
||||
#if HAVE_THREE_BYTE
|
||||
destroy_histogram(st->h_offs3);
|
||||
#endif
|
||||
destroy_histogram(st->h_offs);
|
||||
}
|
||||
free(st);
|
||||
}
|
||||
|
||||
|
||||
static void collect_statistics(Stats *st, PrimaryPath *pp, CostFuncSet *cfs, EncodingSet *es)
|
||||
{
|
||||
Hist *h_lit = create_histogram(0x100, 0);
|
||||
Hist *h_lit_run = create_histogram(0x10000, 0);
|
||||
Hist *h_mat_run = create_histogram(0x10000, 0);
|
||||
|
||||
int src = 0;
|
||||
int r_lit = 0;
|
||||
int r_mat = 0;
|
||||
Match *m = pp->path;
|
||||
while (!is_end(m)) {
|
||||
|
||||
if (debug_g) {
|
||||
printf("%d: ", src);
|
||||
}
|
||||
if (is_match(m) && get_match_len(m) >= MIN_MATCH) {
|
||||
int l = get_match_len(m);
|
||||
int of = get_match_offs(m);
|
||||
|
||||
if (debug_g) {
|
||||
printf("match of=%d, l=%d", of, l);
|
||||
}
|
||||
/* accumulate histograms to optimize encoding */
|
||||
/*
|
||||
* these should also record the alternative cost of allowing a
|
||||
* particular offset.
|
||||
*
|
||||
*/
|
||||
double cost_lt = cfs->cost_lit(es, l);
|
||||
double cost_of = 1 + cfs->cost_moffs(es, of, l);
|
||||
double cost_l = 1 + cfs->cost_mlen(es, l);
|
||||
|
||||
hist_add(st->h_len, l, cost_lt - cost_of);
|
||||
switch (l) {
|
||||
case 1:
|
||||
hist_add(st->h_offs1, of, cost_lt - cost_l);
|
||||
break;
|
||||
case 2:
|
||||
hist_add(st->h_offs2, of, cost_lt - cost_l);
|
||||
break;
|
||||
#if HAVE_THREE_BYTE
|
||||
case 3:
|
||||
hist_add(st->h_offs3, of, cost_lt - cost_l);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
hist_add(st->h_offs, of, cost_lt - cost_l);
|
||||
break;
|
||||
}
|
||||
|
||||
src += l;
|
||||
|
||||
/* handle histograms for literal and match runs. */
|
||||
/*
|
||||
* this should probably record the first occurrance
|
||||
* and fill in the repeat there when flushed.
|
||||
*/
|
||||
if (r_lit) {
|
||||
hist_add(h_lit_run, r_lit, 0);
|
||||
r_lit = 0;
|
||||
}
|
||||
r_mat++;
|
||||
|
||||
} else {
|
||||
int l = get_literal_len(m);
|
||||
if (debug_g) {
|
||||
printf("literal l=%d (", l);
|
||||
}
|
||||
while (l) {
|
||||
uint8_t lit = pp->buf[src];
|
||||
if (debug_g) {
|
||||
printf("$%02x", lit);
|
||||
if (l > 1) {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
hist_add(h_lit, lit, 0);
|
||||
src++;
|
||||
--l;
|
||||
}
|
||||
if (debug_g) {
|
||||
printf(")");
|
||||
}
|
||||
|
||||
/* handle histograms for literal and match runs. */
|
||||
/*
|
||||
* this should probably record the first occurrance
|
||||
* and fill in the repeat there when flushed.
|
||||
*/
|
||||
if (r_mat) {
|
||||
hist_add(h_mat_run, r_mat, 0);
|
||||
r_mat = 0;
|
||||
}
|
||||
r_lit++;
|
||||
}
|
||||
m++;
|
||||
|
||||
if (debug_g) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
/* flush any unflushed runs */
|
||||
if (r_lit) {
|
||||
hist_add(h_lit_run, r_lit, 0);
|
||||
}
|
||||
if (r_mat) {
|
||||
hist_add(h_mat_run, r_mat, 0);
|
||||
}
|
||||
|
||||
if (debug_g) {
|
||||
printf("length=%d\n", src);
|
||||
|
||||
printf("max_lit_run=%d, max_mat_run=%d\n", get_histrange(h_lit_run), get_histrange(h_mat_run));
|
||||
|
||||
size_t n_lit = get_number(h_lit);
|
||||
double e_lit = get_entropy(h_lit);
|
||||
printf("literals (n=%zu, e_min=%.2f), theoretical gain = %d bytes\n", n_lit, e_lit, (int)(n_lit - (n_lit * e_lit / 8.0)));
|
||||
|
||||
#if 1
|
||||
printf(" val len l=1 l=2 l=3 l>3 lit\n");
|
||||
int i;
|
||||
for (i = 0; i < 256; i++) {
|
||||
printf(" %4d: %5zu %5zu %5zu %5zu %5zu %5zu\n", i, st->h_len->bin[i], st->h_offs1->bin[i], st->h_offs2->bin[i], st->h_offs3->bin[i], st->h_offs->bin[i], h_lit->bin[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
destroy_histogram(h_lit);
|
||||
destroy_histogram(h_lit_run);
|
||||
destroy_histogram(h_mat_run);
|
||||
|
||||
}
|
||||
|
||||
static void optimize_encoding(Stats *st, EncodingSet *es)
|
||||
{
|
||||
optimize_enc(st->h_len, MIN_MATCH, LEN_PARTS, PRE_UNARY, &es->bitsl);
|
||||
optimize_enc(st->h_offs1, 1, SINGLE_BYTE_PARTS, PRE_BINARY, &es->bits1);
|
||||
optimize_enc(st->h_offs2, 1, TWO_BYTE_PARTS, PRE_BINARY, &es->bits2);
|
||||
#if HAVE_THREE_BYTE
|
||||
optimize_enc(st->h_offs3, 1, THREE_BYTE_PARTS, PRE_BINARY, &es->bits3);
|
||||
#endif
|
||||
optimize_enc(st->h_offs, 1, LONG_MATCH_PARTS, PRE_BINARY, &es->bits);
|
||||
|
||||
/* find end marker candidate */
|
||||
es->endm = 0; /* impossible marker */
|
||||
int i;
|
||||
for (i = MIN_MATCH; i < st->h_len->range; i++) {
|
||||
if (st->h_len->bin[i] == 0) {
|
||||
es->endm = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if 1
|
||||
/* see if end marker is outside the encodable range (ugly, fixme!) */
|
||||
if (cost_enc(&es->bitsl, es->endm) > 0x1000) {
|
||||
printf("Warning: end marker out of range, forcing allocation!\n");
|
||||
hist_add(st->h_len, es->endm, 1);
|
||||
optimize_enc(st->h_len, MIN_MATCH, LEN_PARTS, PRE_UNARY, &es->bitsl);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (debug_g) {
|
||||
print_enc_stats(st->h_len, &es->bitsl, "lengths");
|
||||
print_enc_stats(st->h_offs1, &es->bits1, "offs (l=1)");
|
||||
print_enc_stats(st->h_offs2, &es->bits2, "offs (l=2)");
|
||||
#if HAVE_THREE_BYTE
|
||||
print_enc_stats(st->h_offs3, &es->bits3, "offs (l=3)");
|
||||
print_enc_stats(st->h_offs, &es->bits, "offs (l>3)");
|
||||
#else
|
||||
print_enc_stats(st->h_offs, &es->bits, "offs (l>2)");
|
||||
#endif
|
||||
printf("end marker: l=%d\n", es->endm);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION packer
|
||||
*
|
||||
******/
|
||||
static inline double cost_lit(EncodingSet *es, int l)
|
||||
{
|
||||
return l * 9;
|
||||
}
|
||||
|
||||
|
||||
static inline double cost_mlen(EncodingSet *es, int l)
|
||||
{
|
||||
return cost_enc(&es->bitsl, l);
|
||||
}
|
||||
|
||||
static void write_mlen(BitWriteState *bws, EncodingSet *es, int l)
|
||||
{
|
||||
write_enc(bws, &es->bitsl, l);
|
||||
}
|
||||
|
||||
static int read_mlen(BitReadState *brs, EncodingSet *es)
|
||||
{
|
||||
return read_enc(brs, &es->bitsl);
|
||||
}
|
||||
|
||||
|
||||
static inline double cost_moffs(EncodingSet *es, int of, int l)
|
||||
{
|
||||
switch (l) {
|
||||
case 1:
|
||||
return cost_enc(&es->bits1, of);
|
||||
case 2:
|
||||
return cost_enc(&es->bits2, of);
|
||||
#if HAVE_THREE_BYTE
|
||||
case 3:
|
||||
return cost_enc(&es->bits3, of);
|
||||
#endif
|
||||
default:
|
||||
return cost_enc(&es->bits, of);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_moffs(BitWriteState *bws, EncodingSet *es, int of, int l)
|
||||
{
|
||||
switch (l) {
|
||||
case 1:
|
||||
write_enc(bws, &es->bits1, of);
|
||||
break;
|
||||
case 2:
|
||||
write_enc(bws, &es->bits2, of);
|
||||
break;
|
||||
#if HAVE_THREE_BYTE
|
||||
case 3:
|
||||
write_enc(bws, &es->bits3, of);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
write_enc(bws, &es->bits, of);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int read_moffs(BitReadState *brs, EncodingSet *es, int l)
|
||||
{
|
||||
switch (l) {
|
||||
case 1:
|
||||
return read_enc(brs, &es->bits1);
|
||||
case 2:
|
||||
return read_enc(brs, &es->bits2);
|
||||
#if HAVE_THREE_BYTE
|
||||
case 3:
|
||||
return read_enc(brs, &es->bits3);
|
||||
#endif
|
||||
default:
|
||||
return read_enc(brs, &es->bits);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline int cost_endm(EncodingSet *es)
|
||||
{
|
||||
return 1 + cost_mlen(es, es->endm);
|
||||
}
|
||||
|
||||
static void write_endm(BitWriteState *bws, EncodingSet *es)
|
||||
{
|
||||
bitwr_write(bws, 0, 1);
|
||||
write_mlen(bws, es, es->endm);
|
||||
}
|
||||
|
||||
|
||||
static CostFuncSet cfs = {
|
||||
cost_lit,
|
||||
cost_mlen,
|
||||
cost_moffs
|
||||
};
|
||||
|
||||
|
||||
|
||||
static inline double cost_lit_init(EncodingSet *es, int l)
|
||||
{
|
||||
return l * 9;
|
||||
}
|
||||
|
||||
static inline double cost_mlen_init(EncodingSet *es, int l)
|
||||
{
|
||||
return ceil( 0 + log(l) / log(2) );
|
||||
}
|
||||
|
||||
static inline double cost_moffs_init(EncodingSet *es, int of, int l)
|
||||
{
|
||||
if (l == 1) {
|
||||
return ceil( 0 + log(of) / log(2) );
|
||||
}
|
||||
return ceil( 2 + log(of) / log(2) );
|
||||
}
|
||||
|
||||
static CostFuncSet cfs_init = {
|
||||
cost_lit_init,
|
||||
cost_mlen_init,
|
||||
cost_moffs_init
|
||||
};
|
||||
|
||||
static PrimaryPath *optimize_tree(MatchTree *mt, EncodingSet *es)
|
||||
{
|
||||
int max_passes = 16; /* should be configurable. */
|
||||
|
||||
int i;
|
||||
PrimaryPath *pp;
|
||||
Stats *st;
|
||||
|
||||
/* calculate initial encoding using doctored cost */
|
||||
pp = find_cheapest_path(mt, &cfs_init, es, FCP_INITIAL_LITERAL);
|
||||
st = create_stats();
|
||||
collect_statistics(st, pp, &cfs_init, es);
|
||||
optimize_encoding(st, es);
|
||||
destroy_stats(st);
|
||||
|
||||
/*
|
||||
* keep iterating find_cheapest_path + optimize_encoding until encoding
|
||||
* no longer changes.
|
||||
*/
|
||||
EncodingSet last_es;
|
||||
for (i = 0; i < max_passes; i++) {
|
||||
memcpy(&last_es, es, sizeof(EncodingSet));
|
||||
destroy_primarypath(pp);
|
||||
|
||||
if (verbose_g) {
|
||||
print_enc_set(es);
|
||||
printf("end marker: l=%d (cost=%d)\n", es->endm, cost_endm(es));
|
||||
}
|
||||
pp = find_cheapest_path(mt, &cfs, es, FCP_INITIAL_LITERAL);
|
||||
|
||||
/* endm + parts + space of end marker */
|
||||
int overhead = 8 + 4 * (4*16 + 4) + cost_endm(es);
|
||||
size_t cost = (pp->cost + overhead + 7) / 8;
|
||||
|
||||
msg(MSG_VERBOSE, " %zu (left %.2f%%)\n", cost, ((100.0 * cost) / pp->len));
|
||||
st = create_stats();
|
||||
collect_statistics(st, pp, &cfs, es);
|
||||
optimize_encoding(st, es);
|
||||
destroy_stats(st);
|
||||
|
||||
if (memcmp(es, &last_es, sizeof(EncodingSet)) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for impossible marker */
|
||||
if (es->endm == 0) {
|
||||
fprintf(stderr, "error: couldn't find an end marker!\n");
|
||||
}
|
||||
|
||||
return pp;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME generate
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Generate packed output from optimized structure.
|
||||
*
|
||||
******/
|
||||
static int generate(PrimaryPath *pp, EncodingSet *es, uint8_t *buf, int flags)
|
||||
{
|
||||
int i;
|
||||
BitWriteState bws;
|
||||
int l;
|
||||
|
||||
bitwr_init(&bws, buf, BITMODE_SIDEBYTE | flags);
|
||||
|
||||
bitwr_write8s(&bws, es->endm);
|
||||
|
||||
for (i = 0; i < es->bitsl.n; i++) {
|
||||
bitwr_write(&bws, es->bitsl.parts[i], 4);
|
||||
}
|
||||
for (i = 0; i < es->bits2.n; i++) {
|
||||
bitwr_write(&bws, es->bits2.parts[i], 4);
|
||||
}
|
||||
#if HAVE_THREE_BYTE
|
||||
for (i = 0; i < es->bits3.n; i++) {
|
||||
bitwr_write(&bws, es->bits3.parts[i], 4);
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < es->bits.n; i++) {
|
||||
bitwr_write(&bws, es->bits.parts[i], 4);
|
||||
}
|
||||
for (i = 0; i < es->bits1.n; i++) {
|
||||
bitwr_write(&bws, es->bits1.parts[i], 4);
|
||||
}
|
||||
|
||||
l = 0;
|
||||
Match *m = pp->path;
|
||||
|
||||
/* initial literal */
|
||||
if (is_literal(m) && get_literal_len(m) == 1) {
|
||||
bitwr_write8s(&bws, pp->buf[l]);
|
||||
l++;
|
||||
m++;
|
||||
} else {
|
||||
panic("internal fault");
|
||||
}
|
||||
|
||||
while (!is_end(m)) {
|
||||
|
||||
if (is_match(m)) {
|
||||
/* match */
|
||||
bitwr_write(&bws, 0, 1);
|
||||
write_mlen(&bws, es, get_match_len(m));
|
||||
write_moffs(&bws, es, get_match_offs(m), get_match_len(m));
|
||||
|
||||
l += get_match_len(m);
|
||||
} else {
|
||||
int n = get_literal_len(m);
|
||||
while (n) {
|
||||
/* literal */
|
||||
bitwr_write(&bws, 1, 1);
|
||||
bitwr_write8s(&bws, pp->buf[l]);
|
||||
l++;
|
||||
--n;
|
||||
}
|
||||
}
|
||||
m++;
|
||||
}
|
||||
|
||||
/* end marker */
|
||||
write_endm(&bws, es);
|
||||
|
||||
return bitwr_flush(&bws);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME crunch_normal_int
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Common cruncher parts
|
||||
*
|
||||
******/
|
||||
static int crunch_normal_int(Buffer *sbf, Buffer *dbf, int flags)
|
||||
{
|
||||
MatchTree *mt = create_matchtree();
|
||||
double t1, t2;
|
||||
EncodingSet es;
|
||||
memset(&es, 0, sizeof(EncodingSet));
|
||||
|
||||
msg(MSG_VERBOSE, "build matches...\n");
|
||||
t1 = get_time();
|
||||
build_match(mt, sbf->buf, sbf->len);
|
||||
t2 = get_time();
|
||||
msg(MSG_VERBOSE, "...%.2f s\n", t2 - t1);
|
||||
|
||||
msg(MSG_VERBOSE, "optimizing matches...\n");
|
||||
t1 = get_time();
|
||||
PrimaryPath *pp = optimize_tree(mt, &es);
|
||||
t2 = get_time();
|
||||
msg(MSG_VERBOSE, "...%.2f s\n", t2 - t1);
|
||||
|
||||
destroy_matchtree(mt);
|
||||
|
||||
msg(MSG_VERBOSE, "generating output...\n");
|
||||
t1 = get_time();
|
||||
dbf->len = generate(pp, &es, dbf->buf, flags);
|
||||
t2 = get_time();
|
||||
msg(MSG_VERBOSE, "...%.2f s\n", t2 - t1);
|
||||
|
||||
destroy_primarypath(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME decrunch_normal_int
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Common decruncher parts
|
||||
*
|
||||
******/
|
||||
static int decrunch_normal_int(Buffer *sbf, Buffer *dbf, int flags, size_t *safep)
|
||||
{
|
||||
int i;
|
||||
BitReadState brs;
|
||||
int cur;
|
||||
EncodingSet es;
|
||||
int safe;
|
||||
int spos;
|
||||
uint8_t *destbuf = dbf->buf;
|
||||
|
||||
bitrd_init(&brs, sbf->buf, BITMODE_SIDEBYTE | flags);
|
||||
|
||||
es.endm = bitrd_read8s(&brs);
|
||||
|
||||
es.bitsl.floor = MIN_MATCH;
|
||||
es.bitsl.n = LEN_PARTS;
|
||||
es.bitsl.prefix = PRE_UNARY;
|
||||
for (i = 0; i < es.bitsl.n; i++) {
|
||||
es.bitsl.parts[i] = bitrd_read(&brs, 4);
|
||||
}
|
||||
|
||||
es.bits2.floor = 1;
|
||||
es.bits2.n = TWO_BYTE_PARTS;
|
||||
es.bits2.prefix = PRE_BINARY;
|
||||
for (i = 0; i < es.bits2.n; i++) {
|
||||
es.bits2.parts[i] = bitrd_read(&brs, 4);
|
||||
}
|
||||
|
||||
#if HAVE_THREE_BYTE
|
||||
es.bits3.floor = 1;
|
||||
es.bits3.n = THREE_BYTE_PARTS;
|
||||
es.bits3.prefix = PRE_BINARY;
|
||||
for (i = 0; i < es.bits3.n; i++) {
|
||||
es.bits3.parts[i] = bitrd_read(&brs, 4);
|
||||
}
|
||||
#endif
|
||||
|
||||
es.bits.floor = 1;
|
||||
es.bits.n = LONG_MATCH_PARTS;
|
||||
es.bits.prefix = PRE_BINARY;
|
||||
for (i = 0; i < es.bits.n; i++) {
|
||||
es.bits.parts[i] = bitrd_read(&brs, 4);
|
||||
}
|
||||
|
||||
es.bits1.floor = 1;
|
||||
es.bits1.n = SINGLE_BYTE_PARTS;
|
||||
es.bits1.prefix = PRE_BINARY;
|
||||
for (i = 0; i < es.bits1.n; i++) {
|
||||
es.bits1.parts[i] = bitrd_read(&brs, 4);
|
||||
}
|
||||
|
||||
|
||||
cur = 0;
|
||||
safe = 0;
|
||||
spos = dbf->len - sbf->len; /* extremely ugly: assumes dbf contains the unpacked data */
|
||||
while (1) {
|
||||
if (cur == 0 || bitrd_read(&brs, 1)) {
|
||||
uint8_t c = bitrd_read8s(&brs);
|
||||
destbuf[cur] = c;
|
||||
cur++;
|
||||
} else {
|
||||
int len, offs;
|
||||
len = read_mlen(&brs, &es);
|
||||
if (len == es.endm) {
|
||||
break;
|
||||
}
|
||||
offs = read_moffs(&brs, &es, len);
|
||||
if (offs > cur) {
|
||||
fprintf(stderr, "error: offset out of range\n");
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
destbuf[cur] = destbuf[cur-offs];
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
/* check safe distance */
|
||||
int dist = cur - (brs.pos + spos);
|
||||
if (dist > safe) {
|
||||
safe = dist;
|
||||
}
|
||||
}
|
||||
dbf->len = cur;
|
||||
|
||||
msg(MSG_DEBUG, "safe = %d\n", safe);
|
||||
|
||||
if (safep) {
|
||||
*safep = safe;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME crunch_normal
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Cruncher for the "normal" algorithm
|
||||
*
|
||||
******/
|
||||
int crunch_normal(Buffer *sbf, Buffer *dbf)
|
||||
{
|
||||
return crunch_normal_int(sbf, dbf, 0);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME decrunch_normal
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Decruncher for the "normal" algorithm
|
||||
*
|
||||
******/
|
||||
int decrunch_normal(Buffer *sbf, Buffer *dbf)
|
||||
{
|
||||
return decrunch_normal_int(sbf, dbf, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME crunch_normal_mem
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Memory cruncher for the "normal" algorithm
|
||||
*
|
||||
******/
|
||||
int crunch_normal_mem(Memory *smem, Memory *dmem, int num_opts, char **opts)
|
||||
{
|
||||
int ret;
|
||||
Buffer *sbf;
|
||||
Buffer *dbf;
|
||||
size_t safe = 0;
|
||||
mem_ptr_t sa, ea, ca;
|
||||
uint8_t endm, first;
|
||||
int forwards_mode = num_opts; // FIXME: kludge!!!!
|
||||
|
||||
sbf = create_buffer(smem->high - smem->low);
|
||||
sbf->len = smem->high - smem->low;
|
||||
memcpy(sbf->buf, smem->buf + smem->low, sbf->len);
|
||||
dbf = create_buffer(0x100000);
|
||||
|
||||
if (!forwards_mode) {
|
||||
/* crunch in reverse */
|
||||
reverse_buffer(sbf);
|
||||
ret = crunch_normal_int(sbf, dbf, BITMODE_PRESHIFT);
|
||||
|
||||
/* check safe distance (reuse sbf as target) */
|
||||
decrunch_normal_int(dbf, sbf, BITMODE_PRESHIFT, &safe);
|
||||
destroy_buffer(sbf);
|
||||
|
||||
/* reverse result */
|
||||
reverse_buffer(dbf);
|
||||
} else {
|
||||
/* crunch forwards */
|
||||
ret = crunch_normal_int(sbf, dbf, BITMODE_PRESHIFT);
|
||||
|
||||
/* check safe distance (reuse sbf as target) */
|
||||
decrunch_normal_int(dbf, sbf, BITMODE_PRESHIFT, &safe);
|
||||
destroy_buffer(sbf);
|
||||
}
|
||||
|
||||
msg(MSG_VERBOSE, "safe = %zu\n", safe);
|
||||
|
||||
//sa = 0x1000;
|
||||
if (!forwards_mode) {
|
||||
/* default output address is the minimum margin required for safe uncrunch */
|
||||
sa = smem->low - safe;
|
||||
|
||||
/* generate output */
|
||||
ca = sa;
|
||||
ca += insert_mem(dmem, sa, dbf->buf, dbf->len);
|
||||
|
||||
/* pop first */
|
||||
first = get_byte(dmem, --ca);
|
||||
/* pop endm */
|
||||
endm = get_byte(dmem, --ca);
|
||||
|
||||
/* add first */
|
||||
set_byte(dmem, ca++, first);
|
||||
/* add target address (in reverse) */
|
||||
set_byte(dmem, ca++, (smem->high) & 0xff);
|
||||
set_byte(dmem, ca++, (smem->high) >> 8);
|
||||
/* add endm (adjusted) */
|
||||
set_byte(dmem, ca++, endm - 1);
|
||||
|
||||
ea = ca;
|
||||
} else {
|
||||
/* default output address is the minimum margin required for safe uncrunch */
|
||||
ea = smem->high + safe;
|
||||
|
||||
/* generate output */
|
||||
ca = ea - dbf->len;
|
||||
insert_mem(dmem, ca, dbf->buf, dbf->len);
|
||||
|
||||
/* pop first */
|
||||
first = get_byte(dmem, ca++);
|
||||
/* pop endm */
|
||||
endm = get_byte(dmem, ca++);
|
||||
|
||||
/* add first */
|
||||
set_byte(dmem, --ca, first);
|
||||
/* add target address (in reverse) */
|
||||
set_byte(dmem, --ca, (smem->low) & 0xff);
|
||||
set_byte(dmem, --ca, (smem->low) >> 8);
|
||||
/* add endm (adjusted) */
|
||||
set_byte(dmem, --ca, endm - 1);
|
||||
|
||||
sa = ca;
|
||||
}
|
||||
|
||||
dmem->low = sa;
|
||||
dmem->high = ea;
|
||||
|
||||
destroy_buffer(dbf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME crunch_normal_sfx
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Executable cruncher for the "normal" algorithm
|
||||
*
|
||||
******/
|
||||
int crunch_normal_sfx(Memory *smem, Memory *dmem, int num_opts, char **opts, int jmp)
|
||||
{
|
||||
int ret;
|
||||
Buffer *sbf;
|
||||
Buffer *dbf;
|
||||
int endm;
|
||||
uint8_t tmp;
|
||||
size_t safe = 0;
|
||||
SfxConfig *conf;
|
||||
|
||||
/* get initial options */
|
||||
conf = prepare_sfx(num_opts, opts, jmp);
|
||||
|
||||
/* fold if applicable */
|
||||
if (conf->fold) {
|
||||
/* this should probably not change smem */
|
||||
conf = fold(smem, 0, conf->fold, 0x10000, conf);
|
||||
}
|
||||
|
||||
sbf = create_buffer(smem->high - smem->low);
|
||||
sbf->len = smem->high - smem->low;
|
||||
memcpy(sbf->buf, smem->buf + smem->low, sbf->len);
|
||||
dbf = create_buffer(0x100000);
|
||||
|
||||
/* crunch in reverse */
|
||||
reverse_buffer(sbf);
|
||||
ret = crunch_normal_int(sbf, dbf, BITMODE_PRESHIFT);
|
||||
|
||||
/* check safe distance (reuse sbf as target) */
|
||||
decrunch_normal_int(dbf, sbf, BITMODE_PRESHIFT, &safe);
|
||||
destroy_buffer(sbf);
|
||||
|
||||
/* reverse result */
|
||||
reverse_buffer(dbf);
|
||||
|
||||
/* pop endm from the end of the stream */
|
||||
tmp = dbf->buf[dbf->len-1];
|
||||
endm = dbf->buf[dbf->len-2];
|
||||
dbf->buf[dbf->len-2] = tmp;
|
||||
dbf->len--;
|
||||
|
||||
msg(MSG_VERBOSE, "safe = %zu\n", safe);
|
||||
|
||||
/* generate output */
|
||||
generate_sfx(dbf, dmem, smem, safe, endm, conf);
|
||||
|
||||
destroy_buffer(dbf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* eof */
|
||||
25
loader/tools/subsizer-0.7pre1/src/crunch_normal.h
Normal file
25
loader/tools/subsizer-0.7pre1/src/crunch_normal.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE crunch_normal.h
|
||||
* Copyright (c) 2015, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* create encoding structure
|
||||
*
|
||||
******/
|
||||
#ifndef CRUNCH_NORMAL_H
|
||||
#define CRUNCH_NORMAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "buffer.h"
|
||||
#include "memory.h"
|
||||
|
||||
int crunch_normal(Buffer *sbf, Buffer *dbf);
|
||||
int decrunch_normal(Buffer *sbf, Buffer *dbf);
|
||||
int crunch_normal_mem(Memory *smem, Memory *dmem, int num_opts, char **opts);
|
||||
int crunch_normal_sfx(Memory *smem, Memory *dmem, int num_opts, char **opts, int jmp);
|
||||
|
||||
#endif /* CRUNCH_NORMAL_H */
|
||||
/* eof */
|
||||
33
loader/tools/subsizer-0.7pre1/src/global.c
Normal file
33
loader/tools/subsizer-0.7pre1/src/global.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE global.c
|
||||
* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Global functions.
|
||||
*
|
||||
******/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "global.h"
|
||||
|
||||
/* global variables */
|
||||
int verbose_g;
|
||||
int debug_g;
|
||||
|
||||
void panic(const char *str, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
fprintf(stderr, "%s: ", program_g);
|
||||
va_start(args, str);
|
||||
vfprintf(stderr, str, args);
|
||||
va_end(args);
|
||||
fputc('\n', stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* eof */
|
||||
27
loader/tools/subsizer-0.7pre1/src/global.h
Normal file
27
loader/tools/subsizer-0.7pre1/src/global.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE global.h
|
||||
* Copyright (c) 2015, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Global functions.
|
||||
*
|
||||
******/
|
||||
#ifndef GLOBAL_H
|
||||
#define GLOBAL_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define PACKAGE "subsizer"
|
||||
#define VERSION "0.7pre1"
|
||||
|
||||
/* global variables */
|
||||
extern const char program_g[];
|
||||
extern int verbose_g;
|
||||
extern int debug_g;
|
||||
|
||||
void panic(const char *str, ...);
|
||||
|
||||
#endif /* GLOBAL_H */
|
||||
/* eof */
|
||||
181
loader/tools/subsizer-0.7pre1/src/histogram.c
Normal file
181
loader/tools/subsizer-0.7pre1/src/histogram.c
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE histogram.c
|
||||
* Copyright (c) 2015, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* handling of histograms
|
||||
*
|
||||
******/
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "histogram.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
Hist *create_histogram(int range, int window)
|
||||
{
|
||||
Hist *h;
|
||||
|
||||
h = safe_malloc(sizeof(Hist), "Histogram");
|
||||
h->range = range;
|
||||
h->bin = safe_calloc(range, sizeof(size_t), "histogram bins");
|
||||
h->cost = safe_calloc(range, sizeof(double), "histogram costs");
|
||||
|
||||
h->window = window;
|
||||
h->wbuf = 0;
|
||||
h->wcnt = 0;
|
||||
if (h->window) {
|
||||
h->wbuf = safe_calloc(h->window, sizeof(HistEntry), "histogram window");
|
||||
}
|
||||
|
||||
h->he = 0;
|
||||
return h;
|
||||
}
|
||||
|
||||
void destroy_histogram(Hist *h)
|
||||
{
|
||||
free(h->he);
|
||||
free(h->wbuf);
|
||||
free(h->bin);
|
||||
free(h->cost);
|
||||
free(h);
|
||||
}
|
||||
|
||||
void hist_reset(Hist *h)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < h->range; i++) {
|
||||
h->bin[i] = 0;
|
||||
h->cost[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hist_add(Hist *h, int v, double cost)
|
||||
{
|
||||
h->bin[v]++;
|
||||
h->cost[v] += cost;
|
||||
|
||||
if (h->wbuf) {
|
||||
HistEntry *he = &h->wbuf[h->wcnt];
|
||||
if (he->n) {
|
||||
h->bin[he->val]--;
|
||||
h->cost[he->val] -= he->cost;
|
||||
}
|
||||
|
||||
he->n = 1;
|
||||
he->val = v;
|
||||
he->cost = cost;
|
||||
|
||||
h->wcnt = (h->wcnt + 1) % h->window;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HistEntry *get_histlist(Hist *h)
|
||||
{
|
||||
int i;
|
||||
int n;
|
||||
HistEntry *he = h->he;
|
||||
|
||||
if (he) {
|
||||
return he;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
for (i = 0; i < h->range; i++) {
|
||||
if (h->bin[i]) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
he = safe_malloc(sizeof(HistEntry) * (n + 1), "histogram list");
|
||||
h->he = he;
|
||||
for (i = 0; i < h->range; i++) {
|
||||
if (h->bin[i]) {
|
||||
he->val = i;
|
||||
he->n = h->bin[i];
|
||||
he->cost = h->cost[i];
|
||||
he++;
|
||||
}
|
||||
}
|
||||
he->n = 0;
|
||||
|
||||
return h->he;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME get_histrange
|
||||
*
|
||||
* DESCRIPTION
|
||||
* get the actual range used.
|
||||
*
|
||||
******/
|
||||
int get_histrange(Hist *h)
|
||||
{
|
||||
int i;
|
||||
for (i = h->range-1; i >= 0; --i) {
|
||||
if (h->bin[i])
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME get_number
|
||||
*
|
||||
* DESCRIPTION
|
||||
* get the number of values added.
|
||||
*
|
||||
******/
|
||||
size_t get_number(Hist *h)
|
||||
{
|
||||
int i;
|
||||
size_t n;
|
||||
|
||||
n = 0;
|
||||
for (i = 0; i < h->range; i++) {
|
||||
n += h->bin[i];
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME get_entropy
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Calculate the Shannon entropy of a histogram
|
||||
*
|
||||
******/
|
||||
double get_entropy(Hist *h)
|
||||
{
|
||||
int i;
|
||||
double e;
|
||||
|
||||
size_t n = get_number(h);
|
||||
|
||||
e = 0.0;
|
||||
for (i = 0; i < h->range; i++) {
|
||||
if (h->bin[i]) {
|
||||
double p = (double)h->bin[i] / n;
|
||||
e += -(log(p)/log(2)) * p;
|
||||
}
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
/* eof */
|
||||
45
loader/tools/subsizer-0.7pre1/src/histogram.h
Normal file
45
loader/tools/subsizer-0.7pre1/src/histogram.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE histogram.h
|
||||
* Copyright (c) 2015, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* handling of histograms
|
||||
*
|
||||
******/
|
||||
#ifndef HISTOGRAM_H
|
||||
#define HISTOGRAM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
int val;
|
||||
size_t n;
|
||||
double cost;
|
||||
} HistEntry;
|
||||
|
||||
typedef struct {
|
||||
int range;
|
||||
size_t *bin;
|
||||
double *cost;
|
||||
|
||||
int window;
|
||||
HistEntry *wbuf;
|
||||
int wcnt;
|
||||
|
||||
HistEntry *he;
|
||||
} Hist;
|
||||
|
||||
Hist *create_histogram(int range, int window);
|
||||
void destroy_histogram(Hist *h);
|
||||
void hist_reset(Hist *h);
|
||||
void hist_add(Hist *h, int v, double cost);
|
||||
HistEntry *get_histlist(Hist *h);
|
||||
int get_histrange(Hist *h);
|
||||
size_t get_number(Hist *h);
|
||||
double get_entropy(Hist *h);
|
||||
|
||||
#endif /* HISTOGRAM_H */
|
||||
/* eof */
|
||||
220
loader/tools/subsizer-0.7pre1/src/match.c
Normal file
220
loader/tools/subsizer-0.7pre1/src/match.c
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE match.c
|
||||
* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* create match structure
|
||||
*
|
||||
******/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "match.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION packer
|
||||
*
|
||||
******/
|
||||
|
||||
MatchTree *create_matchtree(void)
|
||||
{
|
||||
MatchTree *mt;
|
||||
|
||||
mt = safe_malloc(sizeof(MatchTree), "MatchTree");
|
||||
mt->match = 0;
|
||||
mt->match_buf = 0;
|
||||
|
||||
mt->min_offs = 1;
|
||||
mt->max_offs = 0x10000;
|
||||
|
||||
/* shortest match is l=1 */
|
||||
/* 1 + 1 + 1 + 5 bits is less than 1 * literal */
|
||||
//mt->min_offs1 = 1;
|
||||
mt->max_offs1 = 32;
|
||||
#if 0
|
||||
/* 1 + 2 + 1 + 13 bits is less than 2 * literal */
|
||||
//mt->min_offs2 = 1;
|
||||
mt->max_offs2 = 0x2000;
|
||||
#else
|
||||
/* shortest match is l=2 */
|
||||
/* 1 + 1 + 1 + 14 bits is less than 2 * literal */
|
||||
//mt->min_offs2 = 1;
|
||||
mt->max_offs2 = 0x4000;
|
||||
#endif
|
||||
mt->min_len = 1;
|
||||
mt->max_len = 0x100;
|
||||
mt->min_rle = 2;
|
||||
mt->max_rle = 0x100;
|
||||
mt->rle_holdoff = 8;
|
||||
//mt->rle_holdoff = 1000000;
|
||||
|
||||
/* maybe allocate entries for the actual buffer already here? */
|
||||
|
||||
//printf("sizeof(Match) = %d\n", sizeof(Match));
|
||||
|
||||
return mt;
|
||||
}
|
||||
|
||||
void destroy_matchtree(MatchTree *mt)
|
||||
{
|
||||
if (mt) {
|
||||
free(mt->match);
|
||||
free(mt->match_buf);
|
||||
free(mt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int build_match(MatchTree *mt, uint8_t *buf, int len)
|
||||
{
|
||||
int cur;
|
||||
int rcnt;
|
||||
|
||||
mt->buf = buf;
|
||||
mt->len = len;
|
||||
mt->match = safe_malloc(len * sizeof(Match *), "match table");
|
||||
|
||||
/* this should be replaced by some dynamic realloc! */
|
||||
mt->match_buf = safe_malloc(200000000 * sizeof(Match), "matches");
|
||||
|
||||
|
||||
Match *cur_m = mt->match_buf;
|
||||
|
||||
/* do the processing */
|
||||
rcnt = 0;
|
||||
cur = 0;
|
||||
while (cur < len) {
|
||||
int i;
|
||||
int window;
|
||||
int rlen;
|
||||
Match **mp = &mt->match[cur];
|
||||
uint8_t v = buf[cur];
|
||||
Match *last_m = cur_m;
|
||||
|
||||
/* find matches */
|
||||
*mp = 0;
|
||||
|
||||
/* check rle */
|
||||
rlen = 1;
|
||||
while ((cur + rlen < len) && buf[cur + rlen] == v) {
|
||||
rlen++;
|
||||
if (rlen == mt->max_rle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rlen >= mt->min_rle) {
|
||||
/* skip the first rle */
|
||||
if (rcnt > 0) {
|
||||
make_rle(cur_m, cur, rlen);
|
||||
cur_m++;
|
||||
}
|
||||
rcnt++;
|
||||
if (rcnt > mt->rle_holdoff) {
|
||||
goto cont; /* gaah! Clean me up! */
|
||||
}
|
||||
} else {
|
||||
rcnt = 0;
|
||||
}
|
||||
|
||||
/* max search range from the current offset */
|
||||
window = (cur < mt->max_offs) ? cur : mt->max_offs;
|
||||
|
||||
/* seek for matches within that window */
|
||||
for (i = mt->min_offs; i <= window; i++) {
|
||||
int moffs = i;
|
||||
int mlen = 0;
|
||||
|
||||
/*
|
||||
* optimized search, first check if at least one byte matches,
|
||||
* then start scanning with end check and similar
|
||||
*/
|
||||
if (buf[cur-i] == v) {
|
||||
mlen++;
|
||||
|
||||
while ((cur+mlen < len) && buf[cur-i+mlen] == buf[cur+mlen]) {
|
||||
mlen++;
|
||||
if (mlen == mt->max_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* this should probably consider the min_len. */
|
||||
if ( (mlen >= mt->min_len) && (
|
||||
(mlen >= 1 && moffs <= mt->max_offs1) ||
|
||||
(mlen >= 2 && moffs <= mt->max_offs2) ||
|
||||
(mlen >= 3) )
|
||||
) {
|
||||
make_match(cur_m, moffs, mlen);
|
||||
cur_m++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cont:
|
||||
if (last_m != cur_m) {
|
||||
make_end(cur_m);
|
||||
cur_m++;
|
||||
*mp = last_m;
|
||||
}
|
||||
|
||||
cur++;
|
||||
}
|
||||
|
||||
if (debug_g) {
|
||||
int n_tot = 0, n_rle_tot = 0;
|
||||
for (cur = 0; cur < len; cur++) {
|
||||
printf("%d: $%02x, ", cur, mt->buf[cur]);
|
||||
if (mt->match[cur] == 0) {
|
||||
printf("literal\n");
|
||||
} else {
|
||||
int n = 0, n_rle = 0;
|
||||
int max_match = 0, max_rle = 0;
|
||||
Match *m = mt->match[cur];
|
||||
while (m && !is_end(m)) {
|
||||
if (is_rle(m)) {
|
||||
int l = get_rle_len(m);
|
||||
if (l > max_rle) {
|
||||
max_rle = l;
|
||||
}
|
||||
n_rle++;
|
||||
} else if (is_match(m)) {
|
||||
int l = get_match_len(m);
|
||||
if (l > max_match) {
|
||||
max_match = l;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
m++;
|
||||
}
|
||||
n_tot += n;
|
||||
n_rle_tot += n_rle;
|
||||
if (n_rle) {
|
||||
printf("%d rle (l=%d)", n_rle, max_rle);
|
||||
}
|
||||
if (n) {
|
||||
if (n_rle) {
|
||||
printf(", ");
|
||||
}
|
||||
printf("%d matches (l=%d)", n, max_match);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
printf("%d total rle\n", n_rle_tot);
|
||||
printf("%d total matches\n", n_tot);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* eof */
|
||||
134
loader/tools/subsizer-0.7pre1/src/match.h
Normal file
134
loader/tools/subsizer-0.7pre1/src/match.h
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE match.h
|
||||
* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* create match structure
|
||||
*
|
||||
******/
|
||||
#ifndef MATCH_H
|
||||
#define MATCH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
* MTYPE_END: ?
|
||||
* MTYPE_LITERAL: ?
|
||||
* MTYPE_MATCH: ?
|
||||
* MTYPE_RLE: ?
|
||||
*/
|
||||
#define MTYPE_END 0
|
||||
#define MTYPE_LITERAL 1
|
||||
#define MTYPE_MATCH 2
|
||||
#define MTYPE_RLE 3
|
||||
|
||||
uint32_t type:8;
|
||||
uint32_t len:24;
|
||||
uint32_t offs;
|
||||
} Match;
|
||||
|
||||
|
||||
|
||||
static inline void make_end(Match *m)
|
||||
{
|
||||
m->type = MTYPE_END;
|
||||
}
|
||||
|
||||
static inline int is_end(Match *m)
|
||||
{
|
||||
return m->type == MTYPE_END;
|
||||
}
|
||||
|
||||
|
||||
static inline void make_rle(Match *m, uint32_t src, int len)
|
||||
{
|
||||
m->type = MTYPE_RLE;
|
||||
m->offs = src;
|
||||
m->len = len;
|
||||
}
|
||||
|
||||
static inline int is_rle(Match *m)
|
||||
{
|
||||
return m->type == MTYPE_RLE;
|
||||
}
|
||||
static inline int get_rle_len(Match *m)
|
||||
{
|
||||
return m->len;
|
||||
}
|
||||
static inline int get_rle_src(Match *m)
|
||||
{
|
||||
return m->offs;
|
||||
}
|
||||
|
||||
|
||||
static inline void make_match(Match *m, uint32_t offs, int len)
|
||||
{
|
||||
m->type = MTYPE_MATCH;
|
||||
m->len = len;
|
||||
m->offs = offs;
|
||||
}
|
||||
|
||||
static inline int is_match(Match *m)
|
||||
{
|
||||
return m->type == MTYPE_MATCH;
|
||||
}
|
||||
static inline int get_match_len(Match *m)
|
||||
{
|
||||
return m->len;
|
||||
}
|
||||
static inline int get_match_offs(Match *m)
|
||||
{
|
||||
return m->offs;
|
||||
}
|
||||
|
||||
|
||||
static inline void make_literal(Match *m, uint32_t src, int len)
|
||||
{
|
||||
m->type = MTYPE_LITERAL;
|
||||
m->offs = src;
|
||||
m->len = len;
|
||||
}
|
||||
|
||||
static inline int is_literal(Match *m)
|
||||
{
|
||||
return m->type == MTYPE_LITERAL;
|
||||
}
|
||||
static inline int get_literal_len(Match *m)
|
||||
{
|
||||
return m->len;
|
||||
}
|
||||
static inline int get_literal_src(Match *m)
|
||||
{
|
||||
return m->offs;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int min_offs;
|
||||
int max_offs;
|
||||
int max_offs1;
|
||||
int max_offs2;
|
||||
int min_len;
|
||||
int max_len;
|
||||
int min_rle;
|
||||
int max_rle;
|
||||
int rle_holdoff;
|
||||
|
||||
uint8_t *buf;
|
||||
int len;
|
||||
Match **match;
|
||||
Match *match_buf;
|
||||
} MatchTree;
|
||||
|
||||
|
||||
MatchTree *create_matchtree(void);
|
||||
void destroy_matchtree(MatchTree *mt);
|
||||
|
||||
int build_match(MatchTree *mt, uint8_t *srcbuf, int srclen);
|
||||
|
||||
#endif /* MATCH_H */
|
||||
/* eof */
|
||||
253
loader/tools/subsizer-0.7pre1/src/memory.c
Normal file
253
loader/tools/subsizer-0.7pre1/src/memory.c
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE memory.c
|
||||
* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* handling of memory layouts
|
||||
*
|
||||
******/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "memory.h"
|
||||
#include "message.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME create_memory, destroy_memory
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Create/destroy memory.
|
||||
*
|
||||
******/
|
||||
Memory *create_memory(size_t size)
|
||||
{
|
||||
Memory *mem;
|
||||
|
||||
mem = safe_malloc(sizeof(Memory), "Memory");
|
||||
mem->buf = safe_calloc(size, 1, "Memory buf");
|
||||
mem->size = size;
|
||||
|
||||
mem->low = -1;
|
||||
mem->high = -1;
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void destroy_memory(Memory *mem)
|
||||
{
|
||||
free(mem->buf);
|
||||
free(mem);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME get_byte, set_byte, get_word, set_word
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Memory accessors.
|
||||
*
|
||||
******/
|
||||
uint8_t get_byte(Memory *mem, mem_ptr_t ad)
|
||||
{
|
||||
return mem->buf[ad & (mem->size-1)];
|
||||
}
|
||||
|
||||
|
||||
void set_byte(Memory *mem, mem_ptr_t ad, uint8_t val)
|
||||
{
|
||||
mem->buf[ad & (mem->size-1)] = val;
|
||||
}
|
||||
|
||||
uint16_t get_word(Memory *mem, mem_ptr_t ad)
|
||||
{
|
||||
return get_byte(mem, ad) | (get_byte(mem, ad+1) << 8);
|
||||
}
|
||||
|
||||
void set_word(Memory *mem, mem_ptr_t ad, uint16_t val)
|
||||
{
|
||||
set_byte(mem, ad, val & 0xff);
|
||||
set_byte(mem, ad+1, val >> 8);
|
||||
}
|
||||
|
||||
|
||||
size_t insert_mem(Memory *dmem, mem_ptr_t da, uint8_t *src, size_t len)
|
||||
{
|
||||
memcpy(dmem->buf + da, src, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME load_mem
|
||||
*
|
||||
* DESCRIPTION
|
||||
* load a file to memory.
|
||||
*
|
||||
******/
|
||||
void load_mem(Memory *mem, file_t *f, mem_ptr_t *aptr, size_t *lptr)
|
||||
{
|
||||
FILE *fp;
|
||||
size_t lrd;
|
||||
mem_ptr_t ad;
|
||||
mem_ptr_t la;
|
||||
int c;
|
||||
|
||||
fp = fopen(f->name, "rb");
|
||||
if (!fp) {
|
||||
panic("couldn't open source file");
|
||||
}
|
||||
|
||||
la = f->la;
|
||||
|
||||
switch (f->mode) {
|
||||
case MODE_NORMAL:
|
||||
/* get load address */
|
||||
la = fgetc(fp) + (fgetc(fp) << 8);
|
||||
break;
|
||||
case MODE_NEWADDR:
|
||||
/* skip load address */
|
||||
fgetc(fp);
|
||||
fgetc(fp);
|
||||
break;
|
||||
case MODE_RAW:
|
||||
/* no load address */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* skip offset if any */
|
||||
if (f->offs > 0) {
|
||||
fseek(fp, f->offs, SEEK_CUR);
|
||||
}
|
||||
|
||||
/* load file body */
|
||||
ad = la;
|
||||
lrd = 0;
|
||||
while ( c = fgetc(fp), c != EOF ) {
|
||||
set_byte(mem, ad, c);
|
||||
ad++;
|
||||
lrd++;
|
||||
/* if a max len is specified, then terminate when it has been
|
||||
reached. */
|
||||
if (f->len > 0 && lrd >= f->len)
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
msg(MSG_VERBOSE, "read '%s' $%04X-$%04X.\n", f->name, la, ad);
|
||||
|
||||
|
||||
if (mem->low < 0 || mem->low > la) {
|
||||
mem->low = la;
|
||||
}
|
||||
if (mem->high < 0 || mem->high < ad) {
|
||||
mem->high = ad;
|
||||
}
|
||||
|
||||
if (aptr) {
|
||||
*aptr = la;
|
||||
}
|
||||
if (lptr) {
|
||||
*lptr = lrd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME load_file_to_memory
|
||||
*
|
||||
* DESCRIPTION
|
||||
* load a file to memory.
|
||||
*
|
||||
******/
|
||||
void load_file_to_memory(Memory *mem, const char *name)
|
||||
{
|
||||
size_t len;
|
||||
FILE *fp;
|
||||
size_t la;
|
||||
size_t sa;
|
||||
size_t ea;
|
||||
|
||||
fp = fopen(name, "rb");
|
||||
if (!fp) {
|
||||
panic("couldn't open file for reading");
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
len = ftell(fp);
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
la = fgetc(fp) | (fgetc(fp) << 8);
|
||||
len -= 2;
|
||||
|
||||
sa = la;
|
||||
ea = sa + len;
|
||||
|
||||
uint8_t *b = mem->buf + sa;
|
||||
int l = len;
|
||||
while (l > 0) {
|
||||
size_t n;
|
||||
n = fread(b, 1, l, fp);
|
||||
b += n;
|
||||
l -= n;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (mem->low < 0 || mem->low > sa) {
|
||||
mem->low = sa;
|
||||
}
|
||||
if (mem->high < 0 || mem->high < ea) {
|
||||
mem->high = ea;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME save_file_from_memory
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Write memory contents to file.
|
||||
*
|
||||
******/
|
||||
void save_file_from_memory(Memory *mem, const char *name)
|
||||
{
|
||||
FILE *fp;
|
||||
size_t la;
|
||||
size_t sa;
|
||||
size_t ea;
|
||||
|
||||
sa = mem->low;
|
||||
ea = mem->high;
|
||||
la = sa;
|
||||
|
||||
fp = fopen(name, "wb");
|
||||
if (!fp) {
|
||||
panic("couldn't open file for writing");
|
||||
}
|
||||
|
||||
fputc(la & 0xff, fp);
|
||||
fputc(la >> 8, fp);
|
||||
fwrite(mem->buf + sa, 1, ea - sa, fp);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* eof */
|
||||
61
loader/tools/subsizer-0.7pre1/src/memory.h
Normal file
61
loader/tools/subsizer-0.7pre1/src/memory.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE memory.h
|
||||
* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* handling of memory layouts
|
||||
*
|
||||
******/
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef uint32_t mem_ptr_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *buf;
|
||||
size_t size;
|
||||
|
||||
int low;
|
||||
int high;
|
||||
} Memory;
|
||||
|
||||
|
||||
Memory *create_memory(size_t size);
|
||||
void destroy_memory(Memory *mem);
|
||||
|
||||
uint8_t get_byte(Memory *mem, mem_ptr_t ad);
|
||||
void set_byte(Memory *mem, mem_ptr_t ad, uint8_t val);
|
||||
uint16_t get_word(Memory *mem, mem_ptr_t ad);
|
||||
void set_word(Memory *mem, mem_ptr_t ad, uint16_t val);
|
||||
|
||||
size_t insert_mem(Memory *dmem, mem_ptr_t da, uint8_t *src, size_t len);
|
||||
|
||||
|
||||
|
||||
enum mode_t {
|
||||
MODE_NORMAL = 0,
|
||||
MODE_NEWADDR,
|
||||
MODE_RAW
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
enum mode_t mode;
|
||||
mem_ptr_t la;
|
||||
int offs;
|
||||
int len;
|
||||
} file_t;
|
||||
|
||||
void load_mem(Memory *mem, file_t *f, mem_ptr_t *aptr, size_t *lptr);
|
||||
|
||||
void load_file_to_memory(Memory *mem, const char *name);
|
||||
void save_file_from_memory(Memory *mem, const char *name);
|
||||
|
||||
|
||||
#endif /* MEMORY_H */
|
||||
/* eof */
|
||||
50
loader/tools/subsizer-0.7pre1/src/message.c
Normal file
50
loader/tools/subsizer-0.7pre1/src/message.c
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE message.c
|
||||
* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Message handling
|
||||
*
|
||||
******/
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "message.h"
|
||||
|
||||
|
||||
void vmsg(msg_level_t level, const char *s, va_list ap)
|
||||
{
|
||||
switch (level) {
|
||||
case MSG_DEBUG:
|
||||
if (!debug_g) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case MSG_VERBOSE:
|
||||
if (!verbose_g) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
vprintf(s, ap);
|
||||
}
|
||||
|
||||
|
||||
void msg(msg_level_t level, const char *s, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, s);
|
||||
|
||||
vmsg(level, s, ap);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
/* eof */
|
||||
22
loader/tools/subsizer-0.7pre1/src/message.h
Normal file
22
loader/tools/subsizer-0.7pre1/src/message.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE message.h
|
||||
* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Message handling.
|
||||
*
|
||||
******/
|
||||
#ifndef MESSAGE_H
|
||||
#define MESSAGE_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef enum { MSG_DEBUG, MSG_VERBOSE } msg_level_t;
|
||||
|
||||
void msg(msg_level_t level, const char *s, ...);
|
||||
void vmsg(msg_level_t level, const char *s, va_list ap);
|
||||
|
||||
#endif /* MESSAGE_H */
|
||||
/* eof */
|
||||
155
loader/tools/subsizer-0.7pre1/src/params.c
Normal file
155
loader/tools/subsizer-0.7pre1/src/params.c
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE params.c
|
||||
* Copyright (c) 2012, 2015 Daniel Kahlin
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* parameter parsing
|
||||
*
|
||||
******/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "memory.h"
|
||||
#include "global.h"
|
||||
#include "params.h"
|
||||
|
||||
|
||||
|
||||
static unsigned long int my_strtoul(char *ptr, char **eptr)
|
||||
{
|
||||
int base;
|
||||
unsigned long int v;
|
||||
|
||||
switch (*ptr) {
|
||||
case '$':
|
||||
base = 16;
|
||||
ptr++;
|
||||
break;
|
||||
case '@':
|
||||
base = 8;
|
||||
ptr++;
|
||||
break;
|
||||
case '%':
|
||||
base = 2;
|
||||
ptr++;
|
||||
break;
|
||||
default:
|
||||
base = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
v = strtoul(ptr, eptr, base);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
int parse_value(char *str)
|
||||
{
|
||||
char *eptr;
|
||||
unsigned long int v;
|
||||
|
||||
v = my_strtoul(str, &eptr);
|
||||
if ( str == eptr || *eptr != 0 )
|
||||
panic("couldn't parse value (%s)", str);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void parse_range(char *str, mem_ptr_t *low, mem_ptr_t *high)
|
||||
{
|
||||
char *p;
|
||||
if ( !(str && strlen(str)) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
p = strchr(str, '-');
|
||||
if (p) {
|
||||
*p++ = 0;
|
||||
if (*p != 0) {
|
||||
*high = parse_value(p);
|
||||
}
|
||||
}
|
||||
if (*str != 0) {
|
||||
*low = parse_value(str);
|
||||
}
|
||||
}
|
||||
|
||||
file_t parse_filename(char *name)
|
||||
{
|
||||
char *p, *name_end;
|
||||
char c;
|
||||
char *eptr;
|
||||
unsigned long int v;
|
||||
file_t file;
|
||||
|
||||
file.name = name;
|
||||
file.mode = MODE_NORMAL;
|
||||
file.la = 0;
|
||||
file.offs = -1;
|
||||
file.len = -1;
|
||||
|
||||
|
||||
p = name;
|
||||
/* parse */
|
||||
p = strpbrk(p, ",@");
|
||||
if (p) {
|
||||
name_end = p;
|
||||
c = *p++;
|
||||
|
||||
switch (c) {
|
||||
case ',':
|
||||
v = my_strtoul(p, &eptr);
|
||||
if (p == eptr && *p != ',') {
|
||||
panic("missing start address");
|
||||
}
|
||||
if (p != eptr) {
|
||||
file.la = v;
|
||||
file.mode = MODE_NEWADDR;
|
||||
}
|
||||
|
||||
p = eptr;
|
||||
break;
|
||||
case '@':
|
||||
file.la = my_strtoul(p, &eptr);
|
||||
if (p == eptr) {
|
||||
panic("missing start address");
|
||||
}
|
||||
file.mode = MODE_RAW;
|
||||
|
||||
p = eptr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
p = strchr(p, ',');
|
||||
if (p) {
|
||||
p++;
|
||||
v = my_strtoul(p, &eptr);
|
||||
if (p != eptr) {
|
||||
file.offs = v;
|
||||
}
|
||||
|
||||
p = strchr(p, ',');
|
||||
if (p) {
|
||||
p++;
|
||||
file.len = parse_value(p);
|
||||
}
|
||||
}
|
||||
|
||||
/* mark the end of the file name */
|
||||
*name_end = 0;
|
||||
}
|
||||
|
||||
if (debug_g) {
|
||||
printf("name='%s', ad=$%04X, offs=%d, len=%d, mode=%d\n", file.name, file.la, file.offs, file.len, file.mode);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/* eof */
|
||||
21
loader/tools/subsizer-0.7pre1/src/params.h
Normal file
21
loader/tools/subsizer-0.7pre1/src/params.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE params.h
|
||||
* Copyright (c) 2012, 2015 Daniel Kahlin
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* parameter parsing
|
||||
*
|
||||
******/
|
||||
#ifndef PARAMS_H
|
||||
#define PARAMS_H
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
int parse_value(char *str);
|
||||
void parse_range(char *str, mem_ptr_t *low, mem_ptr_t *high);
|
||||
file_t parse_filename(char *str);
|
||||
|
||||
#endif /* PARAMS_H */
|
||||
/* eof */
|
||||
327
loader/tools/subsizer-0.7pre1/src/pathfinder.c
Normal file
327
loader/tools/subsizer-0.7pre1/src/pathfinder.c
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE pathfinder.c
|
||||
* Copyright (c) 2015, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* find optimized path by considering encoding cost
|
||||
*
|
||||
******/
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bitfunc.h"
|
||||
#include "pathfinder.h"
|
||||
#include "global.h"
|
||||
#include "match.h"
|
||||
#include "message.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define DEBUG_COMPLEXITY 0
|
||||
|
||||
|
||||
PrimaryPath *create_primarypath(int n, uint8_t *buf)
|
||||
{
|
||||
PrimaryPath *pp;
|
||||
|
||||
pp = safe_malloc(sizeof(PrimaryPath), "primarypath");
|
||||
/* allocate n+1 entries to allow for the end marker */
|
||||
pp->path = safe_malloc( (n + 1) * sizeof(Match), "matches");
|
||||
pp->n = n;
|
||||
pp->buf = buf;
|
||||
|
||||
/* insert end marker */
|
||||
make_end(&(pp->path[n]));
|
||||
|
||||
return pp;
|
||||
}
|
||||
|
||||
void destroy_primarypath(PrimaryPath *pp)
|
||||
{
|
||||
if (pp) {
|
||||
free(pp->path);
|
||||
free(pp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION fast cost functions
|
||||
*
|
||||
******/
|
||||
double litcost[0x10000];
|
||||
double lencost[0x10000];
|
||||
double offscost1[0x10000];
|
||||
double offscost2[0x10000];
|
||||
double offscost3[0x10000];
|
||||
double offscost[0x10000];
|
||||
|
||||
static void prepare_fast(CostFuncSet *cfs, EncodingSet *es)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* prepare tables for fast cost calculations */
|
||||
for (i = 0; i < 0x10000; i++) {
|
||||
litcost[i] = cfs->cost_lit(es, i);
|
||||
lencost[i] = cfs->cost_mlen(es, i);
|
||||
offscost1[i] = cfs->cost_moffs(es, i, 1);
|
||||
offscost2[i] = cfs->cost_moffs(es, i, 2);
|
||||
offscost3[i] = cfs->cost_moffs(es, i, 3);
|
||||
offscost[i] = cfs->cost_moffs(es, i, 4);
|
||||
}
|
||||
}
|
||||
|
||||
static inline double fast_lit(int l)
|
||||
{
|
||||
return litcost[l];
|
||||
}
|
||||
|
||||
static inline double fast_mlen(int l)
|
||||
{
|
||||
return lencost[l];
|
||||
}
|
||||
|
||||
static inline double fast_moffs(int of, int l)
|
||||
{
|
||||
switch (l) {
|
||||
case 1:
|
||||
return offscost1[of];
|
||||
case 2:
|
||||
return offscost2[of];
|
||||
case 3:
|
||||
return offscost3[of];
|
||||
default:
|
||||
return offscost[of];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME find_cheapest_path
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Consider encoding cost to find the cheapest path through all matches
|
||||
*
|
||||
******/
|
||||
PrimaryPath *find_cheapest_path(MatchTree *mt, CostFuncSet *cfs, EncodingSet *es, unsigned int flags)
|
||||
{
|
||||
int i, j;
|
||||
int cur;
|
||||
int len = mt->len;
|
||||
double *dist;
|
||||
double *prev;
|
||||
Match *path;
|
||||
|
||||
/* configuration */
|
||||
int min_match = 1;
|
||||
int enforce_exclusion = (flags & FCP_ENFORCE_EXCLUSION);
|
||||
int literal_sequences = (flags & FCP_LITERAL_SEQUENCES);
|
||||
int initial_literal = (flags & FCP_INITIAL_LITERAL);
|
||||
|
||||
/* construct lookup tables */
|
||||
prepare_fast(cfs, es);
|
||||
|
||||
/* create path tables */
|
||||
dist = safe_malloc(sizeof(double) * (len + 1), "dist table");
|
||||
prev = safe_malloc(sizeof(double) * (len + 1), "prev table");
|
||||
path = safe_malloc(sizeof(Match) * (len + 1), "match table");
|
||||
|
||||
/* initialize costs */
|
||||
for (i = 0; i < len+1; i++) {
|
||||
/* make sure we have headroom for a few additions. */
|
||||
dist[i] = INT_MAX - 0x10000;
|
||||
prev[i] = -1;
|
||||
//path[i] = 0;
|
||||
}
|
||||
dist[0] = 0;
|
||||
|
||||
#if DEBUG_COMPLEXITY
|
||||
int n_match, n_match_taken, n_rle, n_rle_taken, n_lt, n_lt_taken;
|
||||
n_match = 0;
|
||||
n_match_taken = 0;
|
||||
n_rle = 0;
|
||||
n_rle_taken = 0;
|
||||
n_lt = 0;
|
||||
n_lt_taken = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* calculate costs
|
||||
*/
|
||||
cur = 0;
|
||||
while (cur < len) {
|
||||
int v;
|
||||
double w;
|
||||
Match *m = mt->match[cur];
|
||||
|
||||
while (m && !is_end(m)) {
|
||||
|
||||
if (is_match(m) && get_match_len(m) >= min_match ) {
|
||||
/* match */
|
||||
int l = get_match_len(m);
|
||||
int of = get_match_offs(m);
|
||||
/*
|
||||
* - does not consider when the escape bit isn't needed.
|
||||
*/
|
||||
/*
|
||||
* scan through all possible shorter lengths and see if
|
||||
* any are cheaper.
|
||||
* TODO: which choices are actually interesting here?
|
||||
*/
|
||||
int c = 4;
|
||||
while (c && l >= min_match) {
|
||||
w = 1 + fast_mlen(l) + fast_moffs(of, l);
|
||||
v = cur + l;
|
||||
|
||||
#if DEBUG_COMPLEXITY
|
||||
n_match++;
|
||||
#endif
|
||||
if (dist[v] > dist[cur] + w) {
|
||||
dist[v] = dist[cur] + w;
|
||||
prev[v] = cur;
|
||||
make_match(&path[v], of, l);
|
||||
#if DEBUG_COMPLEXITY
|
||||
n_match_taken++;
|
||||
#endif
|
||||
}
|
||||
|
||||
l--;
|
||||
c--;
|
||||
}
|
||||
} else if (is_rle(m) && get_rle_len(m) >= min_match) {
|
||||
/* match */
|
||||
int l = get_rle_len(m);
|
||||
int of = 1;
|
||||
/*
|
||||
* - does not consider when the escape bit isn't needed.
|
||||
*/
|
||||
/*
|
||||
* scan through all possible shorter lengths and see if
|
||||
* any are cheaper.
|
||||
* TODO: which choices are actually interesting here?
|
||||
*/
|
||||
int c = 4;
|
||||
while (c && l >= min_match) {
|
||||
w = 1 + fast_mlen(l) + fast_moffs(of, l);
|
||||
v = cur + l;
|
||||
|
||||
#if DEBUG_COMPLEXITY
|
||||
n_rle++;
|
||||
#endif
|
||||
if (dist[v] > dist[cur] + w) {
|
||||
dist[v] = dist[cur] + w;
|
||||
prev[v] = cur;
|
||||
make_match(&path[v], of, l);
|
||||
#if DEBUG_COMPLEXITY
|
||||
n_rle_taken++;
|
||||
#endif
|
||||
}
|
||||
|
||||
l--;
|
||||
c--;
|
||||
}
|
||||
}
|
||||
|
||||
m++;
|
||||
}
|
||||
|
||||
/* literal */
|
||||
/*
|
||||
* - should be expanded to handle all possible literal
|
||||
* sequences
|
||||
*/
|
||||
if ( enforce_exclusion &&
|
||||
(cur > 0) && (mt->buf[cur-1] == mt->buf[cur]) ) {
|
||||
/* force unbearable cost for bytes breaking the
|
||||
exclusion property */
|
||||
w = 30000;
|
||||
} else {
|
||||
w = fast_lit(1);
|
||||
}
|
||||
|
||||
v = cur + 1;
|
||||
#if DEBUG_COMPLEXITY
|
||||
n_lt++;
|
||||
#endif
|
||||
if (dist[v] > dist[cur] + w) {
|
||||
dist[v] = dist[cur] + w;
|
||||
prev[v] = cur;
|
||||
make_literal(&path[v], cur, 1);
|
||||
#if DEBUG_COMPLEXITY
|
||||
n_lt_taken++;
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( !( initial_literal && (cur == 0) ) && literal_sequences ) {
|
||||
int l = (cur + 256 < len) ? 256 : len - cur;
|
||||
while (l > 1) {
|
||||
w = fast_lit(l);
|
||||
v = cur + l;
|
||||
#if DEBUG_COMPLEXITY
|
||||
n_lt++;
|
||||
#endif
|
||||
if (dist[v] > dist[cur] + w) {
|
||||
dist[v] = dist[cur] + w;
|
||||
prev[v] = cur;
|
||||
make_literal(&path[v], cur, l);
|
||||
#if DEBUG_COMPLEXITY
|
||||
n_lt_taken++;
|
||||
#endif
|
||||
}
|
||||
|
||||
l--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cur++;
|
||||
}
|
||||
|
||||
msg(MSG_DEBUG, "cost=%f bits (%f bytes)\n", dist[len], (dist[len]+7)/8);
|
||||
|
||||
#if DEBUG_COMPLEXITY
|
||||
printf("n_match=%d (%d), n_rle=%d (%d), n_lit=%d (%d)\n", n_match, n_match_taken, n_rle, n_rle_taken, n_lt, n_lt_taken);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Backtrack the cheapest path to find the number of primary units
|
||||
* to allocate.
|
||||
*/
|
||||
i = len;
|
||||
j = 0;
|
||||
while (i > 0) {
|
||||
j++;
|
||||
i = prev[i];
|
||||
}
|
||||
|
||||
PrimaryPath *pp;
|
||||
pp = create_primarypath(j, mt->buf);
|
||||
pp->len = len;
|
||||
pp->cost = dist[len];
|
||||
|
||||
/*
|
||||
* Backtrack the cheapest path and create primary units accordingly.
|
||||
*/
|
||||
i = len;
|
||||
j = pp->n-1;
|
||||
while (i > 0) {
|
||||
pp->path[j] = path[i];
|
||||
j--;
|
||||
i = prev[i];
|
||||
}
|
||||
|
||||
|
||||
/* free up path tables */
|
||||
free(dist);
|
||||
free(prev);
|
||||
free(path);
|
||||
|
||||
return pp;
|
||||
}
|
||||
|
||||
|
||||
/* eof */
|
||||
47
loader/tools/subsizer-0.7pre1/src/pathfinder.h
Normal file
47
loader/tools/subsizer-0.7pre1/src/pathfinder.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE pathfinder.h
|
||||
* Copyright (c) 2015, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* create encoding structure
|
||||
*
|
||||
******/
|
||||
#ifndef PATHFINDER_H
|
||||
#define PATHFINDER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "match.h"
|
||||
|
||||
typedef struct {
|
||||
int n;
|
||||
double cost;
|
||||
Match *path;
|
||||
uint8_t *buf;
|
||||
size_t len;
|
||||
} PrimaryPath;
|
||||
|
||||
PrimaryPath *create_primarypath(int n, uint8_t *buf);
|
||||
void destroy_primarypath(PrimaryPath *pp);
|
||||
|
||||
|
||||
typedef struct EncodingSet EncodingSet;
|
||||
|
||||
typedef struct {
|
||||
double (*cost_lit)(EncodingSet *es, int l);
|
||||
double (*cost_mlen)(EncodingSet *es, int l);
|
||||
double (*cost_moffs)(EncodingSet *es, int of, int l);
|
||||
} CostFuncSet;
|
||||
|
||||
#define FCP_ENFORCE_EXCLUSION (1 << 0)
|
||||
#define FCP_LITERAL_SEQUENCES (1 << 1)
|
||||
#define FCP_INITIAL_LITERAL (1 << 2)
|
||||
|
||||
PrimaryPath *find_cheapest_path(MatchTree *mt, CostFuncSet *cfs, EncodingSet *es, unsigned int flags);
|
||||
|
||||
|
||||
#endif /* PATHFINDER_H */
|
||||
/* eof */
|
||||
22
loader/tools/subsizer-0.7pre1/src/sfx/Makefile
Normal file
22
loader/tools/subsizer-0.7pre1/src/sfx/Makefile
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Makefile
|
||||
|
||||
# top level targets
|
||||
all: sfx.o
|
||||
|
||||
# source files
|
||||
SRC = detect_start.c generate_sfx.c fold.c
|
||||
|
||||
# targets
|
||||
sfx.o: $(SRC:%.c=%.o)
|
||||
$(LD) -r $^ -o $@
|
||||
# clean
|
||||
clean:
|
||||
rm -f *~ \#*\#
|
||||
rm -f *.o
|
||||
rm -f *.d
|
||||
rm -f a.out
|
||||
|
||||
# handle dependencies
|
||||
-include $(SRC:%.c=%.d)
|
||||
|
||||
# eof
|
||||
450
loader/tools/subsizer-0.7pre1/src/sfx/decrunch_normal.asm
Normal file
450
loader/tools/subsizer-0.7pre1/src/sfx/decrunch_normal.asm
Normal file
|
|
@ -0,0 +1,450 @@
|
|||
;**************************************************************************
|
||||
;*
|
||||
;* FILE decrunch_normal.asm
|
||||
;* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
;* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
;*
|
||||
;* DESCRIPTION
|
||||
;* subsizer 0.7pre1 executable decruncher
|
||||
;*
|
||||
;******
|
||||
processor 6502
|
||||
|
||||
seg code
|
||||
|
||||
mac NEW_PART
|
||||
org $0000
|
||||
dc.b {1},0
|
||||
endm
|
||||
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* Configuration options
|
||||
;*
|
||||
;******
|
||||
ifnconst MAKE_EXE
|
||||
HAVE_CLI equ 1
|
||||
endif
|
||||
HAVE_LONG_PARTS equ 1
|
||||
|
||||
|
||||
if HAVE_LONG_PARTS
|
||||
PART_MASK equ %00001111
|
||||
N_PARTS equ 16
|
||||
else
|
||||
PART_MASK equ %00000111
|
||||
N_PARTS equ 8
|
||||
endif
|
||||
|
||||
|
||||
NEW_PART "header"
|
||||
subroutine header
|
||||
org $0801
|
||||
begin_header:
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* Basic line!
|
||||
;*
|
||||
;******
|
||||
if 0
|
||||
start_of_line:
|
||||
dc.w end_line
|
||||
dc.w 0
|
||||
dc.b $9e,"2069 /T.L.R/",0
|
||||
end_line:
|
||||
dc.w 0
|
||||
else
|
||||
start_of_line:
|
||||
dc.w end_line
|
||||
dc.w 0
|
||||
dc.b $9e,"2063 SUBSIZER!",0
|
||||
end_line:
|
||||
dc.b $a0,$00
|
||||
endif
|
||||
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME start
|
||||
;*
|
||||
;******
|
||||
start:
|
||||
ifnconst MAKE_EXE
|
||||
sei
|
||||
lda #$34
|
||||
sta $01
|
||||
jmp tail
|
||||
endif
|
||||
|
||||
end_header:
|
||||
|
||||
|
||||
|
||||
NEW_PART "tail"
|
||||
subroutine tail
|
||||
org $1000
|
||||
begin_tail:
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME tail
|
||||
;*
|
||||
;******
|
||||
tail:
|
||||
ifnconst MAKE_EXE
|
||||
wrap equ $07e8
|
||||
wrap_st equ $3000
|
||||
WRAP_LEN equ $10
|
||||
|
||||
|
||||
ldy #DECRUNCHER_LEN
|
||||
tl_lp1:
|
||||
lda.w decruncher_st-1,y
|
||||
sta.w decruncher-1,y
|
||||
cpy #WRAP_LEN+1
|
||||
bcs tl_skp1
|
||||
lda.w wrap_st-1,y
|
||||
sta.w wrap-1,y
|
||||
tl_skp1:
|
||||
dey
|
||||
bne tl_lp1
|
||||
; Y = 0
|
||||
endif
|
||||
|
||||
; ldy #0
|
||||
dc_lp01:
|
||||
ldx #4
|
||||
jsr dc_get_bits
|
||||
sta bits,y
|
||||
|
||||
tya
|
||||
and #PART_MASK
|
||||
bne dc_skp01
|
||||
; Acc = 0
|
||||
sta base_l,y
|
||||
sta base_h,y
|
||||
beq dc_skp02 ; always taken
|
||||
dc_skp01:
|
||||
lda #0
|
||||
sta.z tmp_zp
|
||||
ldx bits-1,y
|
||||
sec
|
||||
dc_lp02:
|
||||
rol
|
||||
rol.z tmp_zp
|
||||
dex
|
||||
bpl dc_lp02
|
||||
; C = 0
|
||||
; clc
|
||||
adc base_l-1,y
|
||||
sta base_l,y
|
||||
lda.z tmp_zp
|
||||
adc base_h-1,y
|
||||
sta base_h,y
|
||||
dc_skp02:
|
||||
iny
|
||||
cpy #N_PARTS*4+4
|
||||
bne dc_lp01
|
||||
|
||||
; perform decrunch
|
||||
ldy #0
|
||||
jmp decrunch_entry
|
||||
|
||||
end_tail:
|
||||
|
||||
|
||||
NEW_PART "decruncher"
|
||||
org zp_end
|
||||
subroutine decruncher
|
||||
begin_decruncher:
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME decruncher
|
||||
;*
|
||||
;* DESCRIPTION
|
||||
;* decruncher
|
||||
;*
|
||||
;******
|
||||
seg.u zp
|
||||
org $f9
|
||||
tmp_zp:
|
||||
len_zp:
|
||||
ds.b 1
|
||||
copy_zp:
|
||||
ds.w 1
|
||||
hibits_zp:
|
||||
ds.b 1
|
||||
zp_end:
|
||||
seg code
|
||||
decruncher_st:
|
||||
rorg zp_end
|
||||
decruncher: ;+0ftDecruncher
|
||||
|
||||
dest_zp:
|
||||
dc.w $0000 ;+0ftDestEnd
|
||||
buf_zp:
|
||||
dc.b $80 ;+0ftBufZp
|
||||
|
||||
|
||||
if HAVE_LONG_PARTS
|
||||
tabo:
|
||||
dc.b 48,0,16,32
|
||||
tabb:
|
||||
dc.b 2,4,4,4
|
||||
else
|
||||
tabo:
|
||||
dc.b 24,0,8,16
|
||||
tabb:
|
||||
dc.b 2,3,3,3
|
||||
endif
|
||||
|
||||
decrunch_entry:
|
||||
dc_literal:
|
||||
lda dest_zp
|
||||
bne dc_skp5
|
||||
dec dest_zp+1
|
||||
dc_skp5:
|
||||
dec dest_zp
|
||||
jsr dc_get_byte
|
||||
; ldy #0
|
||||
sta (dest_zp),y
|
||||
; bcs dc_lp1 ; always taken
|
||||
|
||||
decrunch_main:
|
||||
; Y = 0
|
||||
;------
|
||||
; perform actual decrunch
|
||||
dc_lp1:
|
||||
jsr dc_get_bit
|
||||
bcs dc_literal
|
||||
; Y = 0
|
||||
; get length as bits/base.
|
||||
; ldy #$ff+1
|
||||
dc_lp2:
|
||||
iny
|
||||
cpy #N_PARTS
|
||||
beq dc_skp0
|
||||
jsr dc_get_bit
|
||||
bcc dc_lp2
|
||||
dc_skp0:
|
||||
ldx bits_len-1,y
|
||||
jsr dc_get_bits
|
||||
; C = 0
|
||||
adc base_len-1,y
|
||||
sta len_zp
|
||||
; C = 0
|
||||
|
||||
;******
|
||||
;* IN: len = $01..$100 (Acc = $00..$ff)
|
||||
;* OUT: dest_zp = dest_zp - len, Y = len-1
|
||||
;*
|
||||
tay
|
||||
; clc
|
||||
eor #$ff
|
||||
adc dest_zp
|
||||
sta dest_zp
|
||||
bcs dc_skp22
|
||||
dec dest_zp+1
|
||||
dc_skp22:
|
||||
|
||||
; check end marker here to avoid thrashing carry earlier
|
||||
cpy #$00 ;+1ftEndMarkerMinusOne
|
||||
beq done
|
||||
|
||||
;******
|
||||
;* Get selector bits depending on length.
|
||||
;*
|
||||
;* IN: len = $01..$100 (Y = $00..$ff)
|
||||
;* OUT:
|
||||
;*
|
||||
cpy #4
|
||||
bcc dc_skp2
|
||||
ldy #3
|
||||
dc_skp2:
|
||||
|
||||
; get offset as bits/base.
|
||||
ldx tabb,y
|
||||
jsr dc_get_bits
|
||||
; C = 0
|
||||
adc tabo,y
|
||||
tay
|
||||
|
||||
ldx bits_offs,y
|
||||
jsr dc_get_bits
|
||||
; C = 0
|
||||
adc base_offs_l,y
|
||||
tax
|
||||
lda hibits_zp
|
||||
adc base_offs_h,y
|
||||
tay
|
||||
; X/Y = offset - 1
|
||||
|
||||
sec
|
||||
txa
|
||||
adc dest_zp
|
||||
sta copy_zp
|
||||
tya
|
||||
adc dest_zp+1
|
||||
sta copy_zp+1
|
||||
|
||||
;******
|
||||
;* Reverse fast copy
|
||||
;*
|
||||
;* IN: len = $01..$100 (len_zp = $00..$ff), C = 0
|
||||
;*
|
||||
ldy len_zp
|
||||
beq dc_skp4
|
||||
dc_lp4:
|
||||
lda (copy_zp),y
|
||||
sta (dest_zp),y
|
||||
dey
|
||||
bne dc_lp4
|
||||
dc_skp4:
|
||||
lda (copy_zp),y
|
||||
sta (dest_zp),y
|
||||
bcc dc_lp1 ; always taken
|
||||
|
||||
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME dc_get_bits
|
||||
;*
|
||||
;* DESCRIPTION
|
||||
;* Get bits from the packed stream.
|
||||
;*
|
||||
;* IN:
|
||||
;* X = number of bits to get
|
||||
;*
|
||||
;* OUT:
|
||||
;* Acc = bit 7-0
|
||||
;* hibits_zp = bit 15-8
|
||||
;* C = bit 16
|
||||
;* Y = preserved
|
||||
;* X = 0
|
||||
;* Z = 1
|
||||
;*
|
||||
;******
|
||||
dc_get_bits:
|
||||
lda #0
|
||||
sta hibits_zp
|
||||
cpx #1
|
||||
bcc dcg_ex1
|
||||
dcg_lp1:
|
||||
asl buf_zp
|
||||
bne dcg_skp1
|
||||
; C=1 (because the marker bit was just shifted out)
|
||||
pha
|
||||
jsr dc_get_byte
|
||||
rol
|
||||
sta buf_zp
|
||||
pla
|
||||
dcg_skp1:
|
||||
rol
|
||||
rol hibits_zp
|
||||
dex
|
||||
bne dcg_lp1 ; C=0 for all X!=0
|
||||
dcg_ex1:
|
||||
rts
|
||||
|
||||
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME dc_get_bit
|
||||
;*
|
||||
;* DESCRIPTION
|
||||
;* Get one bit from the packed stream into carry
|
||||
;*
|
||||
;* IN:
|
||||
;* -
|
||||
;*
|
||||
;* OUT:
|
||||
;* Acc = ?
|
||||
;* C = bit 0
|
||||
;* Y = preserved
|
||||
;* X = preserved
|
||||
;* Z = 0
|
||||
;*
|
||||
;******
|
||||
dc_get_bit:
|
||||
asl buf_zp
|
||||
bne dcgb_ex1
|
||||
; C=1 (because the marker bit was just shifted out)
|
||||
jsr dc_get_byte
|
||||
rol
|
||||
sta buf_zp
|
||||
dcgb_ex1:
|
||||
rts
|
||||
|
||||
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME dc_get_byte
|
||||
;*
|
||||
;* DESCRIPTION
|
||||
;* Get byte from the packed stream.
|
||||
;*
|
||||
;******
|
||||
dc_get_byte:
|
||||
lda dc_ptr
|
||||
bne dcgb_skp1
|
||||
dec dc_ptr+1
|
||||
dcgb_skp1:
|
||||
dec dc_ptr
|
||||
dc_ptr equ . + 1
|
||||
lda.w $0000 ;+1ftSrcEnd
|
||||
rts
|
||||
|
||||
;******
|
||||
;* exit out
|
||||
done:
|
||||
ifnconst MAKE_EXE
|
||||
lda #$37
|
||||
sta $01
|
||||
if HAVE_CLI
|
||||
cli
|
||||
endif
|
||||
jmp $0830
|
||||
endif
|
||||
|
||||
rend
|
||||
DECRUNCHER_LEN equ . - decruncher_st
|
||||
|
||||
|
||||
end_decruncher:
|
||||
|
||||
seg.u tables
|
||||
org $0334
|
||||
begin_tables:
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME base_l, base_h, bits
|
||||
;*
|
||||
;* DESCRIPTION
|
||||
;* Data for bits/base decoding.
|
||||
;*
|
||||
;******
|
||||
base_l:
|
||||
base_len:
|
||||
ds.b N_PARTS,0
|
||||
base_offs_l:
|
||||
ds.b N_PARTS*3+4,0
|
||||
base_h equ . - N_PARTS
|
||||
; ds.b N_PARTS,0
|
||||
base_offs_h:
|
||||
ds.b N_PARTS*3+4,0
|
||||
|
||||
bits:
|
||||
bits_len:
|
||||
ds.b N_PARTS,0
|
||||
bits_offs:
|
||||
ds.b N_PARTS*3+4,0
|
||||
|
||||
end_tables:
|
||||
|
||||
|
||||
ifnconst MAKE_EXE
|
||||
echo "header", begin_header, end_header, end_header-begin_header
|
||||
echo "tail", begin_tail, end_tail, end_tail-begin_tail
|
||||
echo "decruncher", begin_decruncher, end_decruncher, end_decruncher-begin_decruncher
|
||||
echo "[run] decruncher", decruncher, decruncher+DECRUNCHER_LEN, DECRUNCHER_LEN
|
||||
echo "[run] tables", begin_tables, end_tables, end_tables-begin_tables
|
||||
endif
|
||||
; eof
|
||||
474
loader/tools/subsizer-0.7pre1/src/sfx/decrunch_normal_dirty.asm
Normal file
474
loader/tools/subsizer-0.7pre1/src/sfx/decrunch_normal_dirty.asm
Normal file
|
|
@ -0,0 +1,474 @@
|
|||
;**************************************************************************
|
||||
;*
|
||||
;* FILE decrunch_normal_dirty.asm
|
||||
;* Copyright (c) 2015, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
;* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
;*
|
||||
;* DESCRIPTION
|
||||
;* subsizer 0.7pre1 executable decruncher - dirty version
|
||||
;*
|
||||
;******
|
||||
processor 6502
|
||||
|
||||
seg code
|
||||
|
||||
mac NEW_PART
|
||||
org $0000
|
||||
dc.b {1},0
|
||||
endm
|
||||
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* Configuration options
|
||||
;*
|
||||
;******
|
||||
ifnconst MAKE_EXE
|
||||
HAVE_CLI equ 1
|
||||
endif
|
||||
HAVE_LONG_PARTS equ 1
|
||||
|
||||
|
||||
if HAVE_LONG_PARTS
|
||||
PART_MASK equ %00001111
|
||||
N_PARTS equ 16
|
||||
else
|
||||
PART_MASK equ %00000111
|
||||
N_PARTS equ 8
|
||||
endif
|
||||
|
||||
|
||||
NEW_PART "header"
|
||||
subroutine header
|
||||
org $0801
|
||||
begin_header:
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* Basic line!
|
||||
;*
|
||||
;******
|
||||
if 0
|
||||
start_of_line:
|
||||
dc.w end_line
|
||||
dc.w 0
|
||||
dc.b $9e,"2069 /T.L.R/",0
|
||||
end_line:
|
||||
dc.w 0
|
||||
else
|
||||
start_of_line:
|
||||
dc.w end_line
|
||||
dc.w 0
|
||||
dc.b $9e,"2063 SUBSIZER!",0
|
||||
end_line:
|
||||
dc.b $a0,$00
|
||||
endif
|
||||
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME start
|
||||
;*
|
||||
;******
|
||||
start:
|
||||
ifnconst MAKE_EXE
|
||||
sei
|
||||
lda #$34
|
||||
sta $01
|
||||
jmp tail
|
||||
endif
|
||||
|
||||
end_header:
|
||||
|
||||
|
||||
|
||||
NEW_PART "tail"
|
||||
subroutine tail
|
||||
org $1000
|
||||
begin_tail:
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME tail
|
||||
;*
|
||||
;******
|
||||
tail:
|
||||
ifnconst MAKE_EXE
|
||||
wrap equ $07e8
|
||||
wrap_st equ $3000
|
||||
WRAP_LEN equ $10
|
||||
|
||||
|
||||
ldx #DECRUNCHER_LEN
|
||||
tl_lp1:
|
||||
lda.w decruncher_st-1,x
|
||||
sta.w decruncher-1,x
|
||||
cpx #WRAP_LEN+1
|
||||
bcs tl_skp1
|
||||
lda.w wrap_st-1,x
|
||||
sta.w wrap-1,x
|
||||
tl_skp1:
|
||||
dex
|
||||
bne tl_lp1
|
||||
; X = 0
|
||||
endif
|
||||
|
||||
; ldx #0
|
||||
dc_lp01:
|
||||
|
||||
;******
|
||||
;* get 4 bits
|
||||
; could be optimized by storing the bits in zp from the beginning and
|
||||
; then shifting out 4 bits at a time, increasing the ptr.
|
||||
lda #%11100000
|
||||
dcg_lp1:
|
||||
asl.z buf_zp
|
||||
bne dcg_skp1
|
||||
; C=1 (because the marker bit was just shifted out)
|
||||
tay
|
||||
jsr dc_get_byte
|
||||
rol
|
||||
sta.z buf_zp
|
||||
tya
|
||||
dcg_skp1:
|
||||
rol
|
||||
bcs dcg_lp1
|
||||
; Acc = 4 bits.
|
||||
sta.z bits,x
|
||||
|
||||
txa
|
||||
and #PART_MASK
|
||||
tay
|
||||
beq dc_skp01
|
||||
|
||||
lda #0
|
||||
sta.z hibits_zp
|
||||
ldy.z bits-1,x
|
||||
sec
|
||||
dc_lp02:
|
||||
rol
|
||||
rol.z hibits_zp
|
||||
dey
|
||||
bpl dc_lp02
|
||||
; C = 0
|
||||
; clc
|
||||
adc.z base_l-1,x
|
||||
tay
|
||||
lda.z hibits_zp
|
||||
adc.z base_h-1,x
|
||||
|
||||
dc_skp01:
|
||||
sta.z base_h,x
|
||||
sty.z base_l,x
|
||||
|
||||
inx
|
||||
cpx #N_PARTS*4+4
|
||||
bne dc_lp01
|
||||
|
||||
; perform decrunch
|
||||
ldy #0
|
||||
jmp decrunch_entry
|
||||
|
||||
|
||||
|
||||
end_tail:
|
||||
|
||||
|
||||
NEW_PART "decruncher"
|
||||
org zp_end
|
||||
subroutine decruncher
|
||||
begin_decruncher:
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME decruncher
|
||||
;*
|
||||
;* DESCRIPTION
|
||||
;* decruncher
|
||||
;*
|
||||
;******
|
||||
seg.u zp
|
||||
org $be
|
||||
hibits_zp:
|
||||
ds.b 1
|
||||
zp_end:
|
||||
seg code
|
||||
decruncher_st:
|
||||
rorg zp_end
|
||||
decruncher: ;+0ftDecruncher
|
||||
|
||||
buf_zp:
|
||||
dc.b $80 ;+0ftBufZp
|
||||
|
||||
if HAVE_LONG_PARTS
|
||||
tabb:
|
||||
dc.b %10000000 | [48 >> 2] ; 2 bits
|
||||
dc.b %11100000 | [0 >> 4] ; 4 bits
|
||||
dc.b %11100000 | [16 >> 4] ; 4 bits
|
||||
dc.b %11100000 | [32 >> 4] ; 4 bits
|
||||
else
|
||||
tabb:
|
||||
dc.b %10000000 | [24 >> 2] ; 2 bits
|
||||
dc.b %11000000 | [0 >> 3] ; 3 bits
|
||||
dc.b %11000000 | [8 >> 3] ; 3 bits
|
||||
dc.b %11000000 | [16 >> 3] ; 3 bits
|
||||
endif
|
||||
|
||||
;******
|
||||
;* get bit macro
|
||||
mac get_bit
|
||||
asl.z buf_zp
|
||||
bne .gb_skp1
|
||||
; C=1 (because the marker bit was just shifted out)
|
||||
jsr dc_get_byte
|
||||
rol
|
||||
sta.z buf_zp
|
||||
.gb_skp1:
|
||||
endm
|
||||
|
||||
;******
|
||||
;* get bits max8 macro
|
||||
mac get_bits_max8
|
||||
.gb_lp1:
|
||||
asl.z buf_zp
|
||||
bne .gb_skp1
|
||||
; C=1 (because the marker bit was just shifted out)
|
||||
pha
|
||||
jsr dc_get_byte
|
||||
rol
|
||||
sta.z buf_zp
|
||||
pla
|
||||
.gb_skp1:
|
||||
rol
|
||||
dey
|
||||
bne .gb_lp1
|
||||
endm
|
||||
|
||||
|
||||
;******
|
||||
;* get bits max8 masked macro
|
||||
mac get_bits_max8_masked
|
||||
.gb_lp1:
|
||||
asl.z buf_zp
|
||||
bne .gb_skp1
|
||||
; C=1 (because the marker bit was just shifted out)
|
||||
tay
|
||||
jsr dc_get_byte
|
||||
rol
|
||||
sta.z buf_zp
|
||||
tya
|
||||
.gb_skp1:
|
||||
rol
|
||||
bcs .gb_lp1
|
||||
endm
|
||||
|
||||
|
||||
;******
|
||||
;* get bits max16 macro
|
||||
mac get_bits_max16
|
||||
.gb_lp1:
|
||||
asl.z buf_zp
|
||||
bne .gb_skp1
|
||||
; C=1 (because the marker bit was just shifted out)
|
||||
pha
|
||||
jsr dc_get_byte
|
||||
rol
|
||||
sta.z buf_zp
|
||||
pla
|
||||
.gb_skp1:
|
||||
rol
|
||||
rol.z hibits_zp
|
||||
dey
|
||||
bne .gb_lp1 ; C=0 for all Y!=0
|
||||
endm
|
||||
|
||||
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME dc_get_byte
|
||||
;*
|
||||
;* DESCRIPTION
|
||||
;* Get byte from the packed stream.
|
||||
;*
|
||||
;******
|
||||
dc_get_byte:
|
||||
lda.z dc_ptr
|
||||
bne dcgb_skp1
|
||||
dec.z dc_ptr+1
|
||||
dcgb_skp1:
|
||||
dec.z dc_ptr
|
||||
dc_ptr equ . + 1
|
||||
lda.w $0000 ;+1ftSrcEnd
|
||||
rts
|
||||
|
||||
|
||||
;******
|
||||
;* Reverse fast copy
|
||||
;*
|
||||
;* IN: len = $01..$100 (len_zp = $00..$ff), C = 0
|
||||
;*
|
||||
copy:
|
||||
len_zp equ . + 1
|
||||
ldy #0
|
||||
beq dc_skp4
|
||||
dc_lp4:
|
||||
copy_zp equ .+1
|
||||
lda.w $0000,y
|
||||
dest_zp equ .+1
|
||||
sta.w $0000,y ;+1ftDestEnd
|
||||
dey
|
||||
bne dc_lp4
|
||||
dc_skp4:
|
||||
lda (copy_zp),y
|
||||
; sta (dest_zp),y
|
||||
bcc dc_common ; always taken
|
||||
|
||||
decrunch_entry:
|
||||
dc_literal:
|
||||
lda dest_zp
|
||||
bne dc_skp5
|
||||
dec dest_zp+1
|
||||
dc_skp5:
|
||||
dec dest_zp
|
||||
jsr dc_get_byte
|
||||
; ldy #0
|
||||
dc_common:
|
||||
sta (dest_zp),y
|
||||
; fall through
|
||||
|
||||
decrunch_main:
|
||||
;------
|
||||
; perform actual decrunch
|
||||
dc_lp1:
|
||||
get_bit
|
||||
bcs dc_literal
|
||||
|
||||
; get length as bits/base.
|
||||
ldx #$100-N_PARTS
|
||||
dc_lp2:
|
||||
inx
|
||||
beq dc_skp0
|
||||
get_bit
|
||||
bcc dc_lp2
|
||||
clc
|
||||
dc_skp0:
|
||||
; C = 0, Y = 0
|
||||
; lda #0
|
||||
tya
|
||||
ldy.z [bits_len+N_PARTS-1]&$ff,x
|
||||
beq dcb1_skp2
|
||||
get_bits_max8
|
||||
dcb1_skp2:
|
||||
; C = 0
|
||||
adc.z [base_len+N_PARTS-1]&$ff,x
|
||||
sta len_zp
|
||||
; C = 0
|
||||
|
||||
;******
|
||||
;* IN: len = $01..$100 (Acc = $00..$ff)
|
||||
;* OUT: dest_zp = dest_zp - len, X = len-1
|
||||
;*
|
||||
tax
|
||||
; clc
|
||||
eor #$ff
|
||||
adc dest_zp
|
||||
sta dest_zp
|
||||
bcs dc_skp22
|
||||
dec dest_zp+1
|
||||
dc_skp22:
|
||||
|
||||
; check end marker here to avoid thrashing carry earlier
|
||||
cpx #$00 ;+1ftEndMarkerMinusOne
|
||||
beq done
|
||||
|
||||
;******
|
||||
;* Get selector bits depending on length.
|
||||
;*
|
||||
;* IN: len = $01..$100 (X = $00..$ff)
|
||||
;* OUT:
|
||||
;*
|
||||
cpx #4
|
||||
bcc dc_skp2
|
||||
ldx #3
|
||||
dc_skp2:
|
||||
|
||||
; get offset as bits/base.
|
||||
lda tabb,x
|
||||
get_bits_max8_masked
|
||||
tax
|
||||
; C = 0
|
||||
|
||||
lda #0
|
||||
sta hibits_zp
|
||||
ldy.z bits_offs,x
|
||||
beq dcb3_skp2
|
||||
get_bits_max16
|
||||
dcb3_skp2:
|
||||
; C = 0, Acc/hibits_zp + base_offs,x = offset - 1
|
||||
|
||||
; perform: copy_zp = Acc/hibits_zp + base_offs,x + 1 + dest_zp
|
||||
; result: copy_zp = dest_zp + offset
|
||||
adc.z base_offs_l,x
|
||||
bcc dcb3_skp3
|
||||
inc hibits_zp
|
||||
dcb3_skp3:
|
||||
sec
|
||||
adc dest_zp
|
||||
sta copy_zp
|
||||
lda hibits_zp
|
||||
adc.z base_offs_h,x
|
||||
; C = 0
|
||||
adc dest_zp+1
|
||||
sta copy_zp+1
|
||||
|
||||
jmp copy
|
||||
|
||||
done:
|
||||
ifnconst MAKE_EXE
|
||||
lda #$37
|
||||
sta $01
|
||||
if HAVE_CLI
|
||||
cli
|
||||
endif
|
||||
jmp $0830
|
||||
endif
|
||||
|
||||
rend
|
||||
DECRUNCHER_LEN equ . - decruncher_st
|
||||
|
||||
|
||||
end_decruncher:
|
||||
|
||||
seg.u tables
|
||||
org $0002
|
||||
begin_tables:
|
||||
;**************************************************************************
|
||||
;*
|
||||
;* NAME base_l, base_h, bits
|
||||
;*
|
||||
;* DESCRIPTION
|
||||
;* Data for bits/base decoding.
|
||||
;*
|
||||
;******
|
||||
base_l:
|
||||
base_len:
|
||||
ds.b N_PARTS,0
|
||||
base_offs_l:
|
||||
ds.b N_PARTS*3+4,0
|
||||
base_h equ . - N_PARTS
|
||||
; ds.b N_PARTS,0
|
||||
base_offs_h:
|
||||
ds.b N_PARTS*3+4,0
|
||||
|
||||
bits:
|
||||
bits_len:
|
||||
ds.b N_PARTS,0
|
||||
bits_offs:
|
||||
ds.b N_PARTS*3+4,0
|
||||
|
||||
end_tables:
|
||||
|
||||
|
||||
ifnconst MAKE_EXE
|
||||
echo "header", begin_header, end_header, end_header-begin_header
|
||||
echo "tail", begin_tail, end_tail, end_tail-begin_tail
|
||||
echo "decruncher", begin_decruncher, end_decruncher, end_decruncher-begin_decruncher
|
||||
echo "[run] decruncher", decruncher, decruncher+DECRUNCHER_LEN, DECRUNCHER_LEN
|
||||
echo "[run] tables", begin_tables, end_tables, end_tables-begin_tables
|
||||
endif
|
||||
; eof
|
||||
37
loader/tools/subsizer-0.7pre1/src/sfx/decrunchers.h
Normal file
37
loader/tools/subsizer-0.7pre1/src/sfx/decrunchers.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/* autogenerated by make_exe.pl, do not edit */
|
||||
#ifndef DECRUNCHERS_H
|
||||
#define DECRUNCHERS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum fixtype_t {
|
||||
ftBufZp = 1,
|
||||
ftDecruncher,
|
||||
ftDestEnd,
|
||||
ftEndMarkerMinusOne,
|
||||
ftSrcEnd,
|
||||
ftEnd = -1
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
enum fixtype_t type;
|
||||
uint16_t addr;
|
||||
} FixEntry;
|
||||
|
||||
#define FLAG_DIRTY (1<<0)
|
||||
#define FLAG_NOCLI (1<<1)
|
||||
#define FLAG_MASK (FLAG_DIRTY | FLAG_NOCLI)
|
||||
|
||||
#define FLAG_XBASE (1<<2)
|
||||
|
||||
typedef struct {
|
||||
uint16_t addr;
|
||||
uint8_t *data;
|
||||
int len;
|
||||
FixEntry *fix_entry;
|
||||
int flags;
|
||||
} FixStruct;
|
||||
|
||||
|
||||
#endif /* DECRUNCHERS_H */
|
||||
/* eof */
|
||||
259
loader/tools/subsizer-0.7pre1/src/sfx/decrunchers_data.h
Normal file
259
loader/tools/subsizer-0.7pre1/src/sfx/decrunchers_data.h
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
/* autogenerated by make_exe.pl, do not edit */
|
||||
#include <stdint.h>
|
||||
#include "decrunchers.h"
|
||||
|
||||
#define XOR_MAGIC 0xa7
|
||||
|
||||
static uint8_t default_header[] = {
|
||||
0xb2,0xaf,0xa7,0xa7,0x39,0x95,0x97,0x91,
|
||||
0x94,0x87,0xf4,0xf2,0xe5,0xf4,0xee,0xfd,
|
||||
0xe2,0xf5,0x86,0xa7,0x07,0xa7
|
||||
};
|
||||
static uint8_t default_tail[] = {
|
||||
0x05,0xa3,0x87,0xdd,0xa6,0x3e,0x0b,0xa4,
|
||||
0x3f,0x8e,0xa8,0x77,0xaf,0x3e,0x93,0xa4,
|
||||
0x3e,0xcf,0xa4,0x57,0xbb,0x0e,0xa7,0x22,
|
||||
0x5e,0x19,0x0c,0xa4,0x9f,0x8d,0x81,0x5e,
|
||||
0x6d,0xb7,0x5d,0xde,0x94,0xa4,0x3e,0x93,
|
||||
0xa4,0x02,0x5e,0xde,0xc0,0xa4,0x3e,0xcf,
|
||||
0xa4,0x6f,0x67,0xe3,0x77,0x6d,0x07,0xa7,
|
||||
0xeb,0xaf,0xa6
|
||||
};
|
||||
static uint8_t default_decruncher[] = {
|
||||
0xa7,0xa7,0x27,0x97,0xa7,0xb7,0x87,0xa5,
|
||||
0xa3,0xa3,0xa3,0x02,0x5a,0x77,0xa5,0x61,
|
||||
0x59,0x61,0x5a,0x87,0x07,0xa6,0x36,0x5a,
|
||||
0x87,0x32,0xa6,0x17,0x49,0x6f,0x67,0xb7,
|
||||
0x57,0xa2,0x87,0x32,0xa6,0x37,0x51,0x19,
|
||||
0x0c,0xa4,0x87,0xdd,0xa6,0xde,0x94,0xa4,
|
||||
0x22,0x5e,0x0f,0xee,0x58,0xc2,0x5a,0x22,
|
||||
0x5a,0x17,0xa5,0x61,0x59,0x67,0xa7,0x57,
|
||||
0xd6,0x67,0xa3,0x37,0xa5,0x07,0xa4,0x19,
|
||||
0xa3,0xa6,0x87,0xdd,0xa6,0xde,0xa7,0xa6,
|
||||
0x0f,0x19,0x1b,0xa4,0x87,0xdd,0xa6,0xde,
|
||||
0xe3,0xa4,0x0d,0x02,0x5b,0xde,0xdf,0xa4,
|
||||
0x0f,0x9f,0x2d,0xc2,0x5a,0x22,0x5d,0x3f,
|
||||
0xc2,0x59,0x22,0x5c,0x03,0x5e,0x57,0xa0,
|
||||
0x16,0x5d,0x36,0x5a,0x2f,0x77,0x5e,0x16,
|
||||
0x5d,0x36,0x5a,0x37,0x3c,0x0e,0xa7,0x22,
|
||||
0x5b,0x47,0xa6,0x37,0xb5,0xa1,0x58,0x77,
|
||||
0xaf,0xef,0x87,0x07,0xa6,0x8d,0x22,0x58,
|
||||
0xcf,0x8d,0x81,0x5b,0x6d,0x77,0x49,0xc7,
|
||||
0xa1,0x58,0x77,0xa1,0x87,0x07,0xa6,0x8d,
|
||||
0x22,0x58,0xc7,0x0a,0x0b,0xa6,0x77,0xa4,
|
||||
0x69,0x0a,0xa6,0x69,0x0b,0xa6,0x0a,0xa7,
|
||||
0xa7,0xc7
|
||||
};
|
||||
static FixEntry ft_default_header[] = {
|
||||
{ftEnd, 0}
|
||||
};
|
||||
|
||||
static FixEntry ft_default_tail[] = {
|
||||
{ftEnd, 0}
|
||||
};
|
||||
|
||||
static FixEntry ft_default_decruncher[] = {
|
||||
{ftDecruncher, 0x00fd},
|
||||
{ftDestEnd, 0x00fd},
|
||||
{ftBufZp, 0x00ff},
|
||||
{ftEndMarkerMinusOne, 0x013b},
|
||||
{ftSrcEnd, 0x01ac},
|
||||
{ftEnd, 0}
|
||||
};
|
||||
|
||||
static uint8_t nocli_header[] = {
|
||||
0xb2,0xaf,0xa7,0xa7,0x39,0x95,0x97,0x91,
|
||||
0x94,0x87,0xf4,0xf2,0xe5,0xf4,0xee,0xfd,
|
||||
0xe2,0xf5,0x86,0xa7,0x07,0xa7
|
||||
};
|
||||
static uint8_t nocli_tail[] = {
|
||||
0x05,0xa3,0x87,0xdd,0xa6,0x3e,0x0b,0xa4,
|
||||
0x3f,0x8e,0xa8,0x77,0xaf,0x3e,0x93,0xa4,
|
||||
0x3e,0xcf,0xa4,0x57,0xbb,0x0e,0xa7,0x22,
|
||||
0x5e,0x19,0x0c,0xa4,0x9f,0x8d,0x81,0x5e,
|
||||
0x6d,0xb7,0x5d,0xde,0x94,0xa4,0x3e,0x93,
|
||||
0xa4,0x02,0x5e,0xde,0xc0,0xa4,0x3e,0xcf,
|
||||
0xa4,0x6f,0x67,0xe3,0x77,0x6d,0x07,0xa7,
|
||||
0xeb,0xaf,0xa6
|
||||
};
|
||||
static uint8_t nocli_decruncher[] = {
|
||||
0xa7,0xa7,0x27,0x97,0xa7,0xb7,0x87,0xa5,
|
||||
0xa3,0xa3,0xa3,0x02,0x5a,0x77,0xa5,0x61,
|
||||
0x59,0x61,0x5a,0x87,0x07,0xa6,0x36,0x5a,
|
||||
0x87,0x32,0xa6,0x17,0x49,0x6f,0x67,0xb7,
|
||||
0x57,0xa2,0x87,0x32,0xa6,0x37,0x51,0x19,
|
||||
0x0c,0xa4,0x87,0xdd,0xa6,0xde,0x94,0xa4,
|
||||
0x22,0x5e,0x0f,0xee,0x58,0xc2,0x5a,0x22,
|
||||
0x5a,0x17,0xa5,0x61,0x59,0x67,0xa7,0x57,
|
||||
0xd6,0x67,0xa3,0x37,0xa5,0x07,0xa4,0x19,
|
||||
0xa3,0xa6,0x87,0xdd,0xa6,0xde,0xa7,0xa6,
|
||||
0x0f,0x19,0x1b,0xa4,0x87,0xdd,0xa6,0xde,
|
||||
0xe3,0xa4,0x0d,0x02,0x5b,0xde,0xdf,0xa4,
|
||||
0x0f,0x9f,0x2d,0xc2,0x5a,0x22,0x5d,0x3f,
|
||||
0xc2,0x59,0x22,0x5c,0x03,0x5e,0x57,0xa0,
|
||||
0x16,0x5d,0x36,0x5a,0x2f,0x77,0x5e,0x16,
|
||||
0x5d,0x36,0x5a,0x37,0x3c,0x0e,0xa7,0x22,
|
||||
0x5b,0x47,0xa6,0x37,0xb5,0xa1,0x58,0x77,
|
||||
0xaf,0xef,0x87,0x07,0xa6,0x8d,0x22,0x58,
|
||||
0xcf,0x8d,0x81,0x5b,0x6d,0x77,0x49,0xc7,
|
||||
0xa1,0x58,0x77,0xa1,0x87,0x07,0xa6,0x8d,
|
||||
0x22,0x58,0xc7,0x0a,0x0b,0xa6,0x77,0xa4,
|
||||
0x69,0x0a,0xa6,0x69,0x0b,0xa6,0x0a,0xa7,
|
||||
0xa7,0xc7
|
||||
};
|
||||
static FixEntry ft_nocli_header[] = {
|
||||
{ftEnd, 0}
|
||||
};
|
||||
|
||||
static FixEntry ft_nocli_tail[] = {
|
||||
{ftEnd, 0}
|
||||
};
|
||||
|
||||
static FixEntry ft_nocli_decruncher[] = {
|
||||
{ftDecruncher, 0x00fd},
|
||||
{ftDestEnd, 0x00fd},
|
||||
{ftBufZp, 0x00ff},
|
||||
{ftEndMarkerMinusOne, 0x013b},
|
||||
{ftSrcEnd, 0x01ac},
|
||||
{ftEnd, 0}
|
||||
};
|
||||
|
||||
static uint8_t dirty_default_header[] = {
|
||||
0xb2,0xaf,0xa7,0xa7,0x39,0x95,0x97,0x91,
|
||||
0x94,0x87,0xf4,0xf2,0xe5,0xf4,0xee,0xfd,
|
||||
0xe2,0xf5,0x86,0xa7,0x07,0xa7
|
||||
};
|
||||
static uint8_t dirty_default_tail[] = {
|
||||
0x0e,0x47,0xa1,0x18,0x77,0xaf,0x0f,0x87,
|
||||
0x63,0xa7,0x8d,0x22,0x18,0x3f,0x8d,0x17,
|
||||
0x56,0x32,0xdd,0x2d,0x8e,0xa8,0x0f,0x57,
|
||||
0xb3,0x0e,0xa7,0x22,0x19,0x13,0xde,0x9f,
|
||||
0x8d,0x81,0x19,0x2f,0xb7,0x5d,0xd2,0xa6,
|
||||
0x0f,0x02,0x19,0xd2,0x92,0x32,0x91,0x33,
|
||||
0xa5,0x4f,0x47,0xe3,0x77,0x6d,0x07,0xa7,
|
||||
0xeb,0x46,0xa7
|
||||
};
|
||||
static uint8_t dirty_default_decruncher[] = {
|
||||
0x27,0x2b,0x47,0x46,0x45,0x02,0x6a,0x77,
|
||||
0xa5,0x61,0x69,0x61,0x6a,0x0a,0xa7,0xa7,
|
||||
0xc7,0x07,0xa7,0x57,0xae,0x1e,0xa7,0xa7,
|
||||
0x3e,0xa7,0xa7,0x2f,0x77,0x50,0x16,0x72,
|
||||
0x37,0xac,0x02,0x7f,0x77,0xa5,0x61,0x7e,
|
||||
0x61,0x7f,0x87,0x63,0xa7,0x36,0x7f,0xa1,
|
||||
0x18,0x77,0xa1,0x87,0x63,0xa7,0x8d,0x22,
|
||||
0x18,0x17,0x40,0x05,0x57,0x4f,0x57,0xaa,
|
||||
0xa1,0x18,0x77,0xa1,0x87,0x63,0xa7,0x8d,
|
||||
0x22,0x18,0x37,0x56,0xbf,0x3f,0x13,0x2e,
|
||||
0x57,0xb7,0xa1,0x18,0x77,0xaf,0xef,0x87,
|
||||
0x63,0xa7,0x8d,0x22,0x18,0xcf,0x8d,0x2f,
|
||||
0x77,0x57,0xd2,0xb6,0x22,0x76,0x0d,0xee,
|
||||
0x58,0xc2,0x7f,0x22,0x7f,0x17,0xa5,0x61,
|
||||
0x7e,0x47,0xa7,0x57,0xef,0x47,0xa3,0x37,
|
||||
0xa5,0x05,0xa4,0x12,0x67,0xa1,0x18,0x77,
|
||||
0xaf,0x0f,0x87,0x63,0xa7,0x8d,0x22,0x18,
|
||||
0x3f,0x8d,0x17,0x56,0x0d,0x0e,0xa7,0x22,
|
||||
0x19,0x13,0x2d,0x57,0xb5,0xa1,0x18,0x77,
|
||||
0xaf,0xef,0x87,0x63,0xa7,0x8d,0x22,0x18,
|
||||
0xcf,0x8d,0x81,0x19,0x2f,0x77,0x49,0xd2,
|
||||
0xb5,0x37,0xa5,0x41,0x19,0x9f,0xc2,0x7f,
|
||||
0x22,0x72,0x02,0x19,0xd2,0xe1,0xc2,0x7e,
|
||||
0x22,0x71,0xeb,0x77,0xa7
|
||||
};
|
||||
static FixEntry ft_dirty_default_header[] = {
|
||||
{ftEnd, 0}
|
||||
};
|
||||
|
||||
static FixEntry ft_dirty_default_tail[] = {
|
||||
{ftEnd, 0}
|
||||
};
|
||||
|
||||
static FixEntry ft_dirty_default_decruncher[] = {
|
||||
{ftDecruncher, 0x00bf},
|
||||
{ftBufZp, 0x00bf},
|
||||
{ftSrcEnd, 0x00cd},
|
||||
{ftDestEnd, 0x00d8},
|
||||
{ftEndMarkerMinusOne, 0x0131},
|
||||
{ftEnd, 0}
|
||||
};
|
||||
|
||||
static uint8_t dirty_nocli_header[] = {
|
||||
0xb2,0xaf,0xa7,0xa7,0x39,0x95,0x97,0x91,
|
||||
0x94,0x87,0xf4,0xf2,0xe5,0xf4,0xee,0xfd,
|
||||
0xe2,0xf5,0x86,0xa7,0x07,0xa7
|
||||
};
|
||||
static uint8_t dirty_nocli_tail[] = {
|
||||
0x0e,0x47,0xa1,0x18,0x77,0xaf,0x0f,0x87,
|
||||
0x63,0xa7,0x8d,0x22,0x18,0x3f,0x8d,0x17,
|
||||
0x56,0x32,0xdd,0x2d,0x8e,0xa8,0x0f,0x57,
|
||||
0xb3,0x0e,0xa7,0x22,0x19,0x13,0xde,0x9f,
|
||||
0x8d,0x81,0x19,0x2f,0xb7,0x5d,0xd2,0xa6,
|
||||
0x0f,0x02,0x19,0xd2,0x92,0x32,0x91,0x33,
|
||||
0xa5,0x4f,0x47,0xe3,0x77,0x6d,0x07,0xa7,
|
||||
0xeb,0x46,0xa7
|
||||
};
|
||||
static uint8_t dirty_nocli_decruncher[] = {
|
||||
0x27,0x2b,0x47,0x46,0x45,0x02,0x6a,0x77,
|
||||
0xa5,0x61,0x69,0x61,0x6a,0x0a,0xa7,0xa7,
|
||||
0xc7,0x07,0xa7,0x57,0xae,0x1e,0xa7,0xa7,
|
||||
0x3e,0xa7,0xa7,0x2f,0x77,0x50,0x16,0x72,
|
||||
0x37,0xac,0x02,0x7f,0x77,0xa5,0x61,0x7e,
|
||||
0x61,0x7f,0x87,0x63,0xa7,0x36,0x7f,0xa1,
|
||||
0x18,0x77,0xa1,0x87,0x63,0xa7,0x8d,0x22,
|
||||
0x18,0x17,0x40,0x05,0x57,0x4f,0x57,0xaa,
|
||||
0xa1,0x18,0x77,0xa1,0x87,0x63,0xa7,0x8d,
|
||||
0x22,0x18,0x37,0x56,0xbf,0x3f,0x13,0x2e,
|
||||
0x57,0xb7,0xa1,0x18,0x77,0xaf,0xef,0x87,
|
||||
0x63,0xa7,0x8d,0x22,0x18,0xcf,0x8d,0x2f,
|
||||
0x77,0x57,0xd2,0xb6,0x22,0x76,0x0d,0xee,
|
||||
0x58,0xc2,0x7f,0x22,0x7f,0x17,0xa5,0x61,
|
||||
0x7e,0x47,0xa7,0x57,0xef,0x47,0xa3,0x37,
|
||||
0xa5,0x05,0xa4,0x12,0x67,0xa1,0x18,0x77,
|
||||
0xaf,0x0f,0x87,0x63,0xa7,0x8d,0x22,0x18,
|
||||
0x3f,0x8d,0x17,0x56,0x0d,0x0e,0xa7,0x22,
|
||||
0x19,0x13,0x2d,0x57,0xb5,0xa1,0x18,0x77,
|
||||
0xaf,0xef,0x87,0x63,0xa7,0x8d,0x22,0x18,
|
||||
0xcf,0x8d,0x81,0x19,0x2f,0x77,0x49,0xd2,
|
||||
0xb5,0x37,0xa5,0x41,0x19,0x9f,0xc2,0x7f,
|
||||
0x22,0x72,0x02,0x19,0xd2,0xe1,0xc2,0x7e,
|
||||
0x22,0x71,0xeb,0x77,0xa7
|
||||
};
|
||||
static FixEntry ft_dirty_nocli_header[] = {
|
||||
{ftEnd, 0}
|
||||
};
|
||||
|
||||
static FixEntry ft_dirty_nocli_tail[] = {
|
||||
{ftEnd, 0}
|
||||
};
|
||||
|
||||
static FixEntry ft_dirty_nocli_decruncher[] = {
|
||||
{ftDecruncher, 0x00bf},
|
||||
{ftBufZp, 0x00bf},
|
||||
{ftSrcEnd, 0x00cd},
|
||||
{ftDestEnd, 0x00d8},
|
||||
{ftEndMarkerMinusOne, 0x0131},
|
||||
{ftEnd, 0}
|
||||
};
|
||||
|
||||
static FixStruct fs_list_decruncher[] = {
|
||||
{0x00fd, default_decruncher, sizeof(default_decruncher), ft_default_decruncher, },
|
||||
{0x00fd, nocli_decruncher, sizeof(nocli_decruncher), ft_nocli_decruncher, FLAG_NOCLI},
|
||||
{0x00bf, dirty_default_decruncher, sizeof(dirty_default_decruncher), ft_dirty_default_decruncher, FLAG_DIRTY},
|
||||
{0x00bf, dirty_nocli_decruncher, sizeof(dirty_nocli_decruncher), ft_dirty_nocli_decruncher, FLAG_NOCLI|FLAG_DIRTY},
|
||||
{0, NULL, 0, NULL, 0}
|
||||
};
|
||||
static FixStruct fs_list_header[] = {
|
||||
{0x0801, default_header, sizeof(default_header), ft_default_header, },
|
||||
{0x0801, nocli_header, sizeof(nocli_header), ft_nocli_header, FLAG_NOCLI},
|
||||
{0x0801, dirty_default_header, sizeof(dirty_default_header), ft_dirty_default_header, FLAG_DIRTY},
|
||||
{0x0801, dirty_nocli_header, sizeof(dirty_nocli_header), ft_dirty_nocli_header, FLAG_NOCLI|FLAG_DIRTY},
|
||||
{0, NULL, 0, NULL, 0}
|
||||
};
|
||||
static FixStruct fs_list_tail[] = {
|
||||
{0x1000, default_tail, sizeof(default_tail), ft_default_tail, },
|
||||
{0x1000, nocli_tail, sizeof(nocli_tail), ft_nocli_tail, FLAG_NOCLI},
|
||||
{0x1000, dirty_default_tail, sizeof(dirty_default_tail), ft_dirty_default_tail, FLAG_DIRTY},
|
||||
{0x1000, dirty_nocli_tail, sizeof(dirty_nocli_tail), ft_dirty_nocli_tail, FLAG_NOCLI|FLAG_DIRTY},
|
||||
{0, NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
/* eof */
|
||||
44
loader/tools/subsizer-0.7pre1/src/sfx/detect_start.c
Normal file
44
loader/tools/subsizer-0.7pre1/src/sfx/detect_start.c
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE detect_start.c
|
||||
* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Try to detect start address for a program file.
|
||||
*
|
||||
******/
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../global.h"
|
||||
#include "../memory.h"
|
||||
#include "detect_start.h"
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION memory functions
|
||||
*
|
||||
******/
|
||||
int detect_start(Memory *mem)
|
||||
{
|
||||
int jmp = -1;
|
||||
|
||||
if (mem->low == 0x0801) {
|
||||
/* try to find jmp by looking at the sys */
|
||||
if (get_byte(mem, 0x0805) == 0x9e) {
|
||||
int ad;
|
||||
for (ad = 0x0806; ad < 0x900; ad++) {
|
||||
if (isdigit(get_byte(mem, ad))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
jmp = atoi((char *)&mem->buf[ad]);
|
||||
}
|
||||
}
|
||||
return jmp;
|
||||
}
|
||||
|
||||
|
||||
/* eof */
|
||||
19
loader/tools/subsizer-0.7pre1/src/sfx/detect_start.h
Normal file
19
loader/tools/subsizer-0.7pre1/src/sfx/detect_start.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE detect_start.h
|
||||
* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Try to detect start address for a program file.
|
||||
*
|
||||
******/
|
||||
#ifndef DETECT_START_H
|
||||
#define DETECT_START_H
|
||||
|
||||
#include "../memory.h"
|
||||
|
||||
int detect_start(Memory *mem);
|
||||
|
||||
#endif /* DETECT_START_H */
|
||||
/* eof */
|
||||
362
loader/tools/subsizer-0.7pre1/src/sfx/fold.c
Normal file
362
loader/tools/subsizer-0.7pre1/src/sfx/fold.c
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE fold.c
|
||||
* Copyright (c) 2015, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
******/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "decrunchers.h"
|
||||
#include "fold.h"
|
||||
#include "generate_sfx.h"
|
||||
#include "ops6502.h"
|
||||
#include "../global.h"
|
||||
#include "../memory.h"
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME is_basic(), is_io(), is_kernal()
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Identify if address is within special section.
|
||||
*
|
||||
******/
|
||||
static int is_basic(mem_ptr_t ad)
|
||||
{
|
||||
if (ad >= 0xa000 && ad <= 0xbfff) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_io(mem_ptr_t ad)
|
||||
{
|
||||
if (ad >= 0xd000 && ad <= 0xdfff) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_kernal(mem_ptr_t ad)
|
||||
{
|
||||
if (ad >= 0xe000 && ad <= 0xffff) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION rle parser
|
||||
*
|
||||
******/
|
||||
typedef struct {
|
||||
mem_ptr_t sa;
|
||||
size_t n;
|
||||
uint8_t val;
|
||||
} RleEntry;
|
||||
|
||||
static int cmp_rle(const void *a, const void *b)
|
||||
{
|
||||
const RleEntry *ar = a;
|
||||
const RleEntry *br = b;
|
||||
|
||||
/* sort on I/O area first */
|
||||
if (is_io(ar->sa) && !is_io(br->sa)) {
|
||||
return 1;
|
||||
}
|
||||
if (!is_io(ar->sa) && is_io(br->sa)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* sort on kernal area second */
|
||||
if (is_kernal(ar->sa) && !is_kernal(br->sa)) {
|
||||
return 1;
|
||||
}
|
||||
if (!is_kernal(ar->sa) && is_kernal(br->sa)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* sort on basic area third */
|
||||
if (is_basic(ar->sa) && !is_basic(br->sa)) {
|
||||
return 1;
|
||||
}
|
||||
if (!is_basic(ar->sa) && is_basic(br->sa)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* lastly sort on size */
|
||||
if (ar->n < br->n) {
|
||||
return 1;
|
||||
}
|
||||
if (ar->n > br->n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t n_entries;
|
||||
static RleEntry rle[256];
|
||||
|
||||
static void scan_rle(Memory *mem, mem_ptr_t sa, mem_ptr_t ea)
|
||||
{
|
||||
mem_ptr_t ad = sa;
|
||||
int n_rle;
|
||||
int last_byte;
|
||||
int min_rle = 50;
|
||||
|
||||
n_entries = 0;
|
||||
n_rle = 0;
|
||||
last_byte = -1;
|
||||
while (ad < ea) {
|
||||
uint8_t c = get_byte(mem, ad);
|
||||
if (c != last_byte) {
|
||||
if (n_rle >= min_rle) {
|
||||
rle[n_entries].sa = ad - n_rle - 1;
|
||||
rle[n_entries].n = n_rle;
|
||||
rle[n_entries].val = last_byte;
|
||||
n_entries++;
|
||||
}
|
||||
n_rle = 0;
|
||||
last_byte = c;
|
||||
} else {
|
||||
n_rle++;
|
||||
}
|
||||
ad++;
|
||||
}
|
||||
/* here we should flush the last entry */
|
||||
|
||||
qsort(rle, n_entries, sizeof(RleEntry), cmp_rle);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static void dump_rle_entries(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n_entries; i++) {
|
||||
size_t n = rle[i].n;
|
||||
mem_ptr_t sa = rle[i].sa;
|
||||
mem_ptr_t ea = sa + n;
|
||||
uint8_t val = rle[i].val;
|
||||
|
||||
if (n == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("slot: $%04X-$%04X = $%02X (%zu bytes)\n", sa, ea - 1, val, n);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION folding logic
|
||||
*
|
||||
******/
|
||||
static int generate_copy(uint8_t *buf, mem_ptr_t sa, mem_ptr_t da, size_t n)
|
||||
{
|
||||
uint8_t *p = buf;
|
||||
|
||||
/* generate copy */
|
||||
MNE_LDXI(p, n);
|
||||
int lp1 = p - buf;
|
||||
MNE_LDAX(p, sa - 1);
|
||||
MNE_STAX(p, da - 1);
|
||||
MNE_DEX(p);
|
||||
int br1 = p - buf;
|
||||
MNE_BNE(p, lp1 - br1);
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
static int generate_fill(uint8_t *buf, mem_ptr_t ta, size_t n, uint8_t val)
|
||||
{
|
||||
uint8_t *p = buf;
|
||||
|
||||
MNE_LDXI(p, n);
|
||||
MNE_LDAI(p, val);
|
||||
int lp1 = p - buf;
|
||||
MNE_STAX(p, ta - 1);
|
||||
MNE_DEX(p);
|
||||
int br1 = p - buf;
|
||||
MNE_BNE(p, lp1 - br1);
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
|
||||
static int generate_trampoline(uint8_t *buf, mem_ptr_t ca, mem_ptr_t ta, size_t n, uint8_t val, mem_ptr_t sa, SfxConfig *conf)
|
||||
{
|
||||
uint8_t *p = buf;
|
||||
int tl;
|
||||
mem_ptr_t tra = 0xd000;
|
||||
|
||||
/* length of trampoline */
|
||||
tl = (conf->flags & FLAG_NOCLI) ? 9 : 10;
|
||||
|
||||
/* if trampoline fits below the decrunched data, put it there */
|
||||
if ( (0x0002 + tl) <= sa ) {
|
||||
tra = sa - tl;
|
||||
}
|
||||
|
||||
/* generate copy */
|
||||
MNE_LDAI(p, conf->mem);
|
||||
MNE_STAZ(p, 0x01);
|
||||
|
||||
MNE_LDXI(p, tl);
|
||||
int lp1 = p - buf;
|
||||
MNE_LDAX(p, ca + 22 - 1);
|
||||
MNE_STAX(p, tra - 1);
|
||||
MNE_DEX(p);
|
||||
int br1 = p - buf;
|
||||
MNE_BNE(p, lp1 - br1);
|
||||
MNE_LDXI(p, n);
|
||||
MNE_LDAI(p, val);
|
||||
MNE_JMP(p, tra);
|
||||
|
||||
int lp2 = p - buf;
|
||||
MNE_STAX(p, ta - 1);
|
||||
MNE_DEX(p);
|
||||
int br2 = p - buf;
|
||||
MNE_BNE(p, lp2 - br2);
|
||||
if ( !(conf->flags & FLAG_NOCLI) ) {
|
||||
MNE_CLI(p);
|
||||
}
|
||||
MNE_JMP(p, conf->jump);
|
||||
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
static void do_fold_a(Memory *smem, mem_ptr_t low_limit, SfxConfig *conf)
|
||||
{
|
||||
mem_ptr_t sa = smem->low;
|
||||
|
||||
mem_ptr_t ad = low_limit;
|
||||
mem_ptr_t last_ca = 0;
|
||||
int last_val = -1;
|
||||
int last_n = -1;
|
||||
uint8_t *last_jmpaddr = 0;
|
||||
int i;
|
||||
|
||||
int count = 0;
|
||||
int areas = 0;
|
||||
|
||||
for (i = 0; i < n_entries; i++) {
|
||||
mem_ptr_t ca = rle[i].sa;
|
||||
int n = rle[i].n;
|
||||
int val = rle[i].val;
|
||||
uint8_t *buf = smem->buf + ca;
|
||||
uint8_t *p = buf;
|
||||
int left = ad - sa;
|
||||
|
||||
if (last_jmpaddr) {
|
||||
OP_ADR(last_jmpaddr, ca);
|
||||
last_jmpaddr = 0;
|
||||
}
|
||||
|
||||
if (left <= 0) {
|
||||
p += generate_fill(p, last_ca, last_n, last_val);
|
||||
generate_trampoline(p, ca+10, ca, n, val, sa, conf);
|
||||
|
||||
/* the counters should be possible to unify */
|
||||
areas++;
|
||||
count += p - buf;
|
||||
break;
|
||||
}
|
||||
|
||||
if (last_n < 0) {
|
||||
int nmax = n - 14;
|
||||
if ( left < nmax ) {
|
||||
nmax = left;
|
||||
n = nmax + 14;
|
||||
}
|
||||
ad -= nmax;
|
||||
p += generate_copy(p, ca+14, ad, nmax);
|
||||
last_jmpaddr = p + 1;
|
||||
MNE_JMP(p, 0x0000);
|
||||
memcpy(p, smem->buf + ad, nmax);
|
||||
p += nmax;
|
||||
} else {
|
||||
int nmax = n - 24;
|
||||
if ( left < nmax ) {
|
||||
nmax = left;
|
||||
n = nmax + 24;
|
||||
}
|
||||
ad -= nmax;
|
||||
p += generate_fill(p, last_ca, last_n, last_val);
|
||||
p += generate_copy(p, ca+24, ad, nmax);
|
||||
last_jmpaddr = p + 1;
|
||||
MNE_JMP(p, 0x0000);
|
||||
memcpy(p, smem->buf + ad, nmax);
|
||||
p += nmax;
|
||||
}
|
||||
|
||||
areas++;
|
||||
count += p - buf;
|
||||
|
||||
last_ca = ca;
|
||||
last_n = n;
|
||||
last_val = val;
|
||||
}
|
||||
|
||||
conf->mem = 0x34;
|
||||
conf->flags |= FLAG_NOCLI;
|
||||
conf->jump = rle[0].sa;
|
||||
|
||||
smem->low = low_limit;
|
||||
|
||||
printf("folded $%04x-$%04x into %d chunks (%d bytes overhead)\n", sa, low_limit, areas, count - (low_limit-sa));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME fold()
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Fold low part in rle segments.
|
||||
*
|
||||
******/
|
||||
SfxConfig *fold(Memory *smem, Memory *dmem, mem_ptr_t low_limit, mem_ptr_t high_limit, SfxConfig *conf)
|
||||
{
|
||||
mem_ptr_t sa = smem->low;
|
||||
mem_ptr_t ea = smem->high;
|
||||
|
||||
if (sa >= low_limit) {
|
||||
/* no fold required */
|
||||
return conf;
|
||||
}
|
||||
#if 0
|
||||
size_t n = low_limit - sa;
|
||||
|
||||
if (ea <= high_limit - n) {
|
||||
/* simple copy possible (should consider the size of the copy routine) */
|
||||
printf("simple fold possible\n");
|
||||
return conf;
|
||||
}
|
||||
#endif
|
||||
/* perform full fold */
|
||||
|
||||
/* find rle slots above the desired low limit */
|
||||
scan_rle(smem, low_limit, ea);
|
||||
|
||||
do_fold_a(smem, low_limit, conf);
|
||||
|
||||
//dump_rle_entries();
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
/* eof */
|
||||
20
loader/tools/subsizer-0.7pre1/src/sfx/fold.h
Normal file
20
loader/tools/subsizer-0.7pre1/src/sfx/fold.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE fold.h
|
||||
* Copyright (c) 2015, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
******/
|
||||
#ifndef FOLD_H
|
||||
#define FOLD_H
|
||||
|
||||
#include "generate_sfx.h"
|
||||
#include "../memory.h"
|
||||
|
||||
SfxConfig *fold(Memory *smem, Memory *dmem, mem_ptr_t low_limit, mem_ptr_t high_limit, SfxConfig *conf);
|
||||
|
||||
|
||||
#endif /* FOLD_H */
|
||||
/* eof */
|
||||
441
loader/tools/subsizer-0.7pre1/src/sfx/generate_sfx.c
Normal file
441
loader/tools/subsizer-0.7pre1/src/sfx/generate_sfx.c
Normal file
|
|
@ -0,0 +1,441 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE generate_sfx.c
|
||||
* Copyright (c) 2015, 2016, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
******/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "decrunchers_data.h"
|
||||
#include "generate_sfx.h"
|
||||
#include "ops6502.h"
|
||||
#include "../buffer.h"
|
||||
#include "../global.h"
|
||||
#include "../memory.h"
|
||||
|
||||
|
||||
static size_t wrap_len;
|
||||
static mem_ptr_t tail_addr;
|
||||
static mem_ptr_t src_end_addr;
|
||||
static mem_ptr_t wrap_src_addr;
|
||||
static mem_ptr_t decr_store_addr;
|
||||
static mem_ptr_t decr_addr;
|
||||
static size_t decr_len;
|
||||
static uint8_t first_bitbuf;
|
||||
static int endm_v;
|
||||
static mem_ptr_t dest_end_addr;
|
||||
|
||||
|
||||
uint8_t header_buf[256];
|
||||
int header_l;
|
||||
|
||||
uint8_t prologue_buf[256];
|
||||
int prologue_l;
|
||||
|
||||
uint8_t epilogue_buf[16];
|
||||
int epilogue_l;
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION common stage processing
|
||||
*
|
||||
******/
|
||||
static SfxConfig config;
|
||||
|
||||
#define FLAG_SYSLESS (FLAG_XBASE << 0)
|
||||
|
||||
static void get_options(char *opts)
|
||||
{
|
||||
char *next;
|
||||
char *curr;
|
||||
|
||||
if (*opts == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
curr = opts;
|
||||
do {
|
||||
char *val;
|
||||
next = strchr(curr, ',');
|
||||
if (next) {
|
||||
*next++ = 0;
|
||||
}
|
||||
|
||||
val = strchr(curr, '=');
|
||||
if (val) {
|
||||
*val++ = 0;
|
||||
}
|
||||
|
||||
if (debug_g) {
|
||||
printf("flag: %s, val: %s\n", curr, val);
|
||||
}
|
||||
|
||||
if (strcmp("clean", curr) == 0) {
|
||||
config.flags &= ~FLAG_DIRTY;
|
||||
config.fold = 0x400;
|
||||
continue;
|
||||
}
|
||||
if (strcmp("dirty", curr) == 0) {
|
||||
config.flags |= FLAG_DIRTY;
|
||||
config.fold = 0x200;
|
||||
continue;
|
||||
}
|
||||
if (strcmp("fold", curr) == 0) {
|
||||
if (val) {
|
||||
uint16_t v;
|
||||
v = strtoul(val, 0, 0);
|
||||
config.fold = v;
|
||||
} else {
|
||||
config.fold = 0x200;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcmp("nofold", curr) == 0) {
|
||||
config.fold = 0;
|
||||
continue;
|
||||
}
|
||||
if (strcmp("sei", curr) == 0) {
|
||||
config.flags |= FLAG_NOCLI;
|
||||
continue;
|
||||
}
|
||||
if (strcmp("mem", curr) == 0) {
|
||||
uint8_t v;
|
||||
v = strtoul(val, 0, 0);
|
||||
config.mem = v;
|
||||
continue;
|
||||
}
|
||||
if (strcmp("jmp", curr) == 0) {
|
||||
uint16_t v;
|
||||
v = strtoul(val, 0, 0);
|
||||
config.jump = v;
|
||||
continue;
|
||||
}
|
||||
if (strcmp("sysless", curr) == 0) {
|
||||
config.flags |= FLAG_SYSLESS;
|
||||
continue;
|
||||
}
|
||||
if (strcmp("load", curr) == 0) {
|
||||
uint16_t v;
|
||||
v = strtoul(val, 0, 0);
|
||||
config.loadback = v;
|
||||
config.flags |= FLAG_SYSLESS;
|
||||
continue;
|
||||
}
|
||||
panic("unknown option: %s", curr);
|
||||
} while ( (curr = next) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
SfxConfig *prepare_sfx(int num_opts, char **opts, int jmp)
|
||||
{
|
||||
|
||||
config.loadback = 0x0801;
|
||||
config.mem = 0x37;
|
||||
config.mem_during = 0x34;
|
||||
config.jump = jmp;
|
||||
config.fold = 0x0400;
|
||||
config.flags = 0;
|
||||
|
||||
while (num_opts) {
|
||||
get_options(*opts++);
|
||||
num_opts--;
|
||||
}
|
||||
|
||||
return &config;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION variants
|
||||
*
|
||||
******/
|
||||
static FixStruct *find_variant(FixStruct *fs, int flags)
|
||||
{
|
||||
while (fs->addr) {
|
||||
if (fs->flags == (flags & FLAG_MASK)) {
|
||||
return fs;
|
||||
}
|
||||
fs++;
|
||||
}
|
||||
|
||||
panic("couldn't find variant");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION common stage processing
|
||||
*
|
||||
******/
|
||||
static void scan_ft(FixStruct *fs)
|
||||
{
|
||||
FixEntry *fe = fs->fix_entry;
|
||||
|
||||
for (; fe->type != ftEnd; fe++) {
|
||||
int offs = fe->addr - fs->addr;
|
||||
|
||||
switch (fe->type) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int process_ft(Memory *mem, mem_ptr_t sa, FixStruct *fs)
|
||||
{
|
||||
int i;
|
||||
FixEntry *fe = fs->fix_entry;
|
||||
int len = fs->len;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
set_byte(mem, sa + i, fs->data[i] ^ XOR_MAGIC);
|
||||
}
|
||||
|
||||
for (; fe->type != ftEnd; fe++) {
|
||||
mem_ptr_t ad = sa + fe->addr - fs->addr;
|
||||
switch (fe->type) {
|
||||
case ftBufZp:
|
||||
set_byte(mem, ad, first_bitbuf);
|
||||
break;
|
||||
case ftDestEnd:
|
||||
set_word(mem, ad, dest_end_addr);
|
||||
break;
|
||||
case ftEndMarkerMinusOne:
|
||||
set_byte(mem, ad, endm_v - 1);
|
||||
break;
|
||||
case ftSrcEnd:
|
||||
set_word(mem, ad, src_end_addr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int generate_header(uint8_t *buf)
|
||||
{
|
||||
uint8_t *p = buf;
|
||||
|
||||
/* generate memory setup */
|
||||
MNE_SEI(p);
|
||||
MNE_LDAI(p, config.mem_during);
|
||||
MNE_STAZ(p, 0x01);
|
||||
MNE_JMP(p, tail_addr);
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
|
||||
static int generate_prologue(uint8_t *buf, mem_ptr_t ca, mem_ptr_t la, int xy)
|
||||
{
|
||||
uint8_t *p = buf;
|
||||
|
||||
#if 0
|
||||
/* generate memory setup */
|
||||
MNE_SEI(p);
|
||||
MNE_LDAI(p, 0x34);
|
||||
MNE_STAZ(p, 0x01);
|
||||
#endif
|
||||
|
||||
mem_ptr_t src1, dest1;
|
||||
size_t len1;
|
||||
mem_ptr_t src2, dest2;
|
||||
size_t len2;
|
||||
|
||||
src1 = decr_store_addr;
|
||||
dest1 = decr_addr;
|
||||
len1 = decr_len;
|
||||
|
||||
src2 = wrap_src_addr;
|
||||
dest2 = la;
|
||||
len2 = wrap_len;
|
||||
|
||||
/* generate copy */
|
||||
MNE_LDXYI(p, len1, xy);
|
||||
if ( xy & (dest2 <= 0x1f6) ) {
|
||||
/*
|
||||
* this is a bit kludgy: sets stack to ~$CA on the dirty decruncher
|
||||
* if required for safe uncrunch. FIXME: should check if overlap!
|
||||
*/
|
||||
MNE_TXS(p);
|
||||
}
|
||||
int lp1 = p - buf;
|
||||
MNE_LDAXY(p, src1 - 1, xy);
|
||||
MNE_STAXY(p, dest1 - 1, xy);
|
||||
if (len2 && len1 > len2) {
|
||||
MNE_CPXYI(p, len2 + 1, xy);
|
||||
MNE_BCS(p, 8);
|
||||
MNE_LDAXY(p, src2 - 1, xy);
|
||||
MNE_STAXY(p, dest2 - 1, xy);
|
||||
}
|
||||
MNE_DEXY(p, xy);
|
||||
int br1 = p - buf;
|
||||
MNE_BNE(p, lp1 - br1);
|
||||
|
||||
if (len2 > len1) {
|
||||
int offs = (0x100-len2) & 0xff;
|
||||
int pages = (len2 >> 8) + 1; /* fix me */
|
||||
|
||||
MNE_LDXYI(p, pages, !xy);
|
||||
MNE_LDXYI(p, offs, xy);
|
||||
int lp2 = p - buf;
|
||||
MNE_LDAXY(p, src2 - offs, xy);
|
||||
MNE_STAXY(p, dest2 - offs, xy);
|
||||
MNE_INXY(p, xy);
|
||||
int br2 = p - buf;
|
||||
MNE_BNE(p, lp2 - br2);
|
||||
MNE_INC(p, ca + lp2 + 2);
|
||||
MNE_INC(p, ca + lp2 + 5);
|
||||
MNE_DEXY(p, !xy);
|
||||
int br3 = p - buf;
|
||||
MNE_BNE(p, lp2 - br3);
|
||||
}
|
||||
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
|
||||
static int generate_epilogue(uint8_t *buf)
|
||||
{
|
||||
uint8_t *p = buf;
|
||||
|
||||
/* generate memory setup */
|
||||
if ( config.mem != config.mem_during ) {
|
||||
MNE_LDAI(p, config.mem);
|
||||
MNE_STAZ(p, 0x01);
|
||||
}
|
||||
|
||||
/* generate CLI */
|
||||
if ( !(config.flags & FLAG_NOCLI) ) {
|
||||
MNE_CLI(p);
|
||||
}
|
||||
|
||||
/* generate jump */
|
||||
MNE_JMP(p, config.jump);
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
|
||||
int generate_sfx(Buffer *sbf, Memory *dmem, Memory *smem, int safe, int endm, SfxConfig *conf)
|
||||
{
|
||||
/* should actually use conf instead of config directly */
|
||||
mem_ptr_t dest_end = smem->high;
|
||||
|
||||
mem_ptr_t sa = config.loadback;
|
||||
mem_ptr_t la = smem->low - safe;
|
||||
|
||||
mem_ptr_t ca = sa;
|
||||
mem_ptr_t ea = sa;
|
||||
int xy = 0;
|
||||
|
||||
if (config.flags & FLAG_DIRTY) {
|
||||
xy = 1;
|
||||
}
|
||||
|
||||
|
||||
FixStruct *fs_header = find_variant(fs_list_header, config.flags);
|
||||
FixStruct *fs_tail = find_variant(fs_list_tail, config.flags);
|
||||
FixStruct *fs_decruncher = find_variant(fs_list_decruncher, config.flags);
|
||||
|
||||
endm_v = endm;
|
||||
dest_end_addr = dest_end;
|
||||
|
||||
/* pop first bitbuf from the end of the stream */
|
||||
first_bitbuf = sbf->buf[sbf->len-1];
|
||||
sbf->len--;
|
||||
|
||||
|
||||
/******
|
||||
* generate header (= sys + memory init + jump)
|
||||
*
|
||||
*/
|
||||
mem_ptr_t header_end;
|
||||
header_l = generate_header(header_buf);
|
||||
header_end = sa + header_l;
|
||||
if ( !(config.flags & FLAG_SYSLESS) ) {
|
||||
header_end += fs_header->len;
|
||||
}
|
||||
|
||||
/*
|
||||
* determine if the header overlaps the highest possible start
|
||||
* of the packed data
|
||||
*/
|
||||
if (header_end > la) {
|
||||
/* yes, we need an overlap */
|
||||
wrap_len = header_end - la;
|
||||
} else {
|
||||
/* no, force the start of the packed data to be where it already is */
|
||||
wrap_len = 0;
|
||||
la = header_end;
|
||||
}
|
||||
src_end_addr = la + sbf->len;
|
||||
wrap_src_addr = src_end_addr;
|
||||
tail_addr = src_end_addr + wrap_len;
|
||||
generate_header(header_buf);
|
||||
|
||||
/* emit header */
|
||||
if ( !(config.flags & FLAG_SYSLESS) ) {
|
||||
ca += process_ft(dmem, ca, fs_header);
|
||||
}
|
||||
ca += insert_mem(dmem, ca, header_buf, header_l);
|
||||
|
||||
/* emit packed data (wrap_len may be 0) */
|
||||
ca += insert_mem(dmem, ca, sbf->buf + wrap_len, sbf->len - wrap_len);
|
||||
ca += insert_mem(dmem, ca, sbf->buf, wrap_len);
|
||||
|
||||
|
||||
/******
|
||||
* generate decruncher
|
||||
*
|
||||
*/
|
||||
epilogue_l = generate_epilogue(epilogue_buf);
|
||||
decr_addr = fs_decruncher->addr;
|
||||
decr_len = fs_decruncher->len + epilogue_l;
|
||||
|
||||
|
||||
/******
|
||||
* generate prologue + tail
|
||||
*
|
||||
*/
|
||||
prologue_l = generate_prologue(prologue_buf, ca, la, xy);
|
||||
decr_store_addr = ca + prologue_l + fs_tail->len;
|
||||
generate_prologue(prologue_buf, ca, la, xy);
|
||||
|
||||
/* emit prologue + tail */
|
||||
ca += insert_mem(dmem, ca, prologue_buf, prologue_l);
|
||||
ca += process_ft(dmem, ca, fs_tail);
|
||||
|
||||
/* emit decruncher */
|
||||
ca += process_ft(dmem, ca, fs_decruncher);
|
||||
ca += insert_mem(dmem, ca, epilogue_buf, epilogue_l);
|
||||
|
||||
|
||||
/* clean up */
|
||||
ea = ca;
|
||||
|
||||
dmem->low = sa;
|
||||
dmem->high = ea;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* eof */
|
||||
32
loader/tools/subsizer-0.7pre1/src/sfx/generate_sfx.h
Normal file
32
loader/tools/subsizer-0.7pre1/src/sfx/generate_sfx.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE generate_sfx.h
|
||||
* Copyright (c) 2015, 2016 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
******/
|
||||
#ifndef GENERATE_SFX_H
|
||||
#define GENERATE_SFX_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../buffer.h"
|
||||
#include "../memory.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
mem_ptr_t loadback;
|
||||
uint8_t mem;
|
||||
uint8_t mem_during;
|
||||
mem_ptr_t jump;
|
||||
mem_ptr_t fold;
|
||||
int flags;
|
||||
} SfxConfig;
|
||||
|
||||
|
||||
SfxConfig *prepare_sfx(int num_opts, char **opts, int jmp);
|
||||
int generate_sfx(Buffer *sbf, Memory *dmem, Memory *smem, int safe, int endm, SfxConfig *conf);
|
||||
|
||||
#endif /* GENERATE_SFX_H */
|
||||
/* eof */
|
||||
48
loader/tools/subsizer-0.7pre1/src/sfx/mach_c64.c
Normal file
48
loader/tools/subsizer-0.7pre1/src/sfx/mach_c64.c
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE mach_c64.c
|
||||
* Copyright (c) 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
******/
|
||||
|
||||
#include "../memory.h"
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME is_basic(), is_io(), is_kernal()
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Identify if address is within special section.
|
||||
*
|
||||
******/
|
||||
int is_basic(mem_ptr_t ad)
|
||||
{
|
||||
if (ad >= 0xa000 && ad <= 0xbfff) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_io(mem_ptr_t ad)
|
||||
{
|
||||
if (ad >= 0xd000 && ad <= 0xdfff) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_kernal(mem_ptr_t ad)
|
||||
{
|
||||
if (ad >= 0xe000 && ad <= 0xffff) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* eof */
|
||||
20
loader/tools/subsizer-0.7pre1/src/sfx/mach_c64.h
Normal file
20
loader/tools/subsizer-0.7pre1/src/sfx/mach_c64.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE mach_c64.h
|
||||
* Copyright (c) 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
******/
|
||||
#ifndef MACH_C64_H
|
||||
#define MACH_C64_H
|
||||
|
||||
#include "../memory.h"
|
||||
|
||||
int is_basic(mem_ptr_t ad);
|
||||
int is_io(mem_ptr_t ad);
|
||||
int is_kernal(mem_ptr_t ad);
|
||||
|
||||
#endif /* MACH_C64_H */
|
||||
/* eof */
|
||||
63
loader/tools/subsizer-0.7pre1/src/sfx/ops6502.h
Normal file
63
loader/tools/subsizer-0.7pre1/src/sfx/ops6502.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE ops6502.h
|
||||
* Copyright (c) 2015, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
******/
|
||||
#ifndef OPS6502_H
|
||||
#define OPS6502_H
|
||||
|
||||
|
||||
#define OP_ADR(p, ad) { *p++ = (ad) & 0xff; *p++ = ((ad) >> 8) & 0xff; }
|
||||
|
||||
#define MNE_CLD(p) { *p++ = 0xd8; }
|
||||
#define MNE_CLI(p) { *p++ = 0x58; }
|
||||
#define MNE_SED(p) { *p++ = 0xf8; }
|
||||
#define MNE_SEI(p) { *p++ = 0x78; }
|
||||
#define MNE_LDAI(p, imm) { *p++ = 0xa9; *p++ = imm; }
|
||||
#define MNE_STAZ(p, zp) { *p++ = 0x85; *p++ = zp; }
|
||||
#define MNE_JMP(p, ad) { *p++ = 0x4c; OP_ADR(p, ad); }
|
||||
|
||||
#define MNE_TAX(p) { *p++ = 0xaa; }
|
||||
#define MNE_TSX(p) { *p++ = 0xba; }
|
||||
#define MNE_TAY(p) { *p++ = 0xa8; }
|
||||
#define MNE_TXA(p) { *p++ = 0x8a; }
|
||||
#define MNE_TXS(p) { *p++ = 0x9a; }
|
||||
#define MNE_TYA(p) { *p++ = 0x98; }
|
||||
|
||||
|
||||
#define MNE_BCS(p, offs) { *p++ = 0xb0; *p++ = offs - 2; }
|
||||
#define MNE_BNE(p, offs) { *p++ = 0xd0; *p++ = offs - 2; }
|
||||
|
||||
#define MNE_LDAI(p, imm) { *p++ = 0xa9; *p++ = imm; }
|
||||
#define MNE_LDXI(p, imm) { *p++ = 0xa2; *p++ = imm; }
|
||||
#define MNE_LDYI(p, imm) { *p++ = 0xa0; *p++ = imm; }
|
||||
#define MNE_LDAX(p, ad) { *p++ = 0xbd; OP_ADR(p, ad); }
|
||||
#define MNE_LDAY(p, ad) { *p++ = 0xb9; OP_ADR(p, ad); }
|
||||
#define MNE_STAX(p, ad) { *p++ = 0x9d; OP_ADR(p, ad); }
|
||||
#define MNE_STAZX(p, zp) { *p++ = 0x95; *p++ = zp; }
|
||||
#define MNE_STAY(p, ad) { *p++ = 0x99; OP_ADR(p, ad); }
|
||||
#define MNE_DEX(p) { *p++ = 0xca; }
|
||||
#define MNE_DEY(p) { *p++ = 0x88; }
|
||||
#define MNE_INX(p) { *p++ = 0xe8; }
|
||||
#define MNE_INY(p) { *p++ = 0xc8; }
|
||||
#define MNE_CPXI(p, imm) { *p++ = 0xe0; *p++ = imm; }
|
||||
#define MNE_CPYI(p, imm) { *p++ = 0xc0; *p++ = imm; }
|
||||
|
||||
#define MNE_INC(p, ad) { *p++ = 0xee; OP_ADR(p, ad); }
|
||||
#define MNE_DEC(p, ad) { *p++ = 0xce; OP_ADR(p, ad); }
|
||||
|
||||
/* special X/Y optional */
|
||||
#define MNE_LDXYI(p, imm, xy) if (xy) MNE_LDXI(p, imm) else MNE_LDYI(p, imm)
|
||||
#define MNE_LDAXY(p, ad, xy) if (xy) MNE_LDAX(p, ad) else MNE_LDAY(p, ad)
|
||||
#define MNE_STAXY(p, ad, xy) if (xy) MNE_STAX(p, ad) else MNE_STAY(p, ad)
|
||||
#define MNE_DEXY(p, xy) if (xy) MNE_DEX(p) else MNE_DEY(p)
|
||||
#define MNE_INXY(p, xy) if (xy) MNE_INX(p) else MNE_INY(p)
|
||||
#define MNE_CPXYI(p, imm, xy) if (xy) MNE_CPXI(p, imm) else MNE_CPYI(p, imm)
|
||||
|
||||
|
||||
#endif /* OPS6502_H */
|
||||
/* eof */
|
||||
460
loader/tools/subsizer-0.7pre1/src/subsizer.c
Normal file
460
loader/tools/subsizer-0.7pre1/src/subsizer.c
Normal file
|
|
@ -0,0 +1,460 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE subsizer.c
|
||||
* Copyright (c) 2012, 2015, 2016, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* CBM packer/cruncher
|
||||
*
|
||||
******/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "bitfunc.h"
|
||||
#include "buffer.h"
|
||||
#include "crunch_normal.h"
|
||||
#include "pathfinder.h"
|
||||
#include "global.h"
|
||||
#include "match.h"
|
||||
#include "memory.h"
|
||||
#include "message.h"
|
||||
#include "params.h"
|
||||
#include "sfx/detect_start.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define MAX_DECRUNCH_SIZE 0x100000
|
||||
|
||||
#define HAVE_CRUNCH_LEVEL 0
|
||||
|
||||
|
||||
#define PROGRAM "subsizer"
|
||||
|
||||
const char program_g[] = PROGRAM;
|
||||
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int (*pack_func)(Buffer *, Buffer *);
|
||||
int (*depack_func)(Buffer *, Buffer *);
|
||||
int (*mem_func)(Memory *, Memory *, int num_opts, char **opts);
|
||||
int (*sfx_func)(Memory *, Memory *, int num_opts, char **opts, int jmp);
|
||||
} Type;
|
||||
|
||||
Type types[] = {
|
||||
{ /* crunch_normal */
|
||||
"normal",
|
||||
crunch_normal, decrunch_normal,
|
||||
crunch_normal_mem,
|
||||
crunch_normal_sfx
|
||||
},
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
static int crunch_raw(Type *p, int num_files, char **srcnames, char *destname, int backwards_mode);
|
||||
static int decrunch_raw(Type *p, int num_files, char **srcnames, char *destname, int backwards_mode);
|
||||
|
||||
static int crunch_mem(Type *p, int num_files, char **srcnames, char *destname, int forwards_mode);
|
||||
#if HAVE_CRUNCH_LEVEL
|
||||
static int crunch_level(Type *p, int num_files, char **srcnames, char *destname);
|
||||
#endif
|
||||
|
||||
static int crunch_sfx(Type *p, int num_files, char **srcnames, char *destname, int num_sfx_opts, char **sfx_opts);
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
char **srcnames = 0;
|
||||
char *destname = "a.out";
|
||||
enum { MODE_RAW, MODE_SFX, MODE_MEM, MODE_LEVEL } mode;
|
||||
int num_sfx_opts = 0;
|
||||
char *sfx_opts[256];
|
||||
int backwards_mode;
|
||||
int forwards_mode;
|
||||
int depack_mode;
|
||||
char *pack_type;
|
||||
|
||||
|
||||
/* defaults */
|
||||
verbose_g = 1;
|
||||
debug_g = 0;
|
||||
mode = MODE_RAW; /* always raw mode for now */
|
||||
backwards_mode = 0;
|
||||
forwards_mode = 0;
|
||||
depack_mode = 0;
|
||||
pack_type = "normal";
|
||||
|
||||
/*
|
||||
* scan for valid options
|
||||
*/
|
||||
while (EOF != (c = getopt(argc, argv, "o:t:rmlxX:bfdqvDVh"))) {
|
||||
switch (c) {
|
||||
|
||||
/* a missing parameter */
|
||||
case ':':
|
||||
/* an illegal option */
|
||||
case '?':
|
||||
exit(1);
|
||||
|
||||
/* set quiet mode */
|
||||
case 'q':
|
||||
verbose_g = 0;
|
||||
break;
|
||||
|
||||
/* set verbose mode */
|
||||
case 'v':
|
||||
verbose_g++;
|
||||
break;
|
||||
|
||||
/* set debug mode */
|
||||
case 'D':
|
||||
debug_g = 1;
|
||||
break;
|
||||
|
||||
/* print version */
|
||||
case 'V':
|
||||
fprintf (stdout, PROGRAM " " VERSION "\n");
|
||||
exit(0);
|
||||
|
||||
/* print help */
|
||||
case 'h':
|
||||
fprintf(stderr,
|
||||
PROGRAM " " VERSION ": CBM packer/cruncher\n"
|
||||
"Copyright (c) 2012, 2015, 2016, 2017 Daniel Kahlin <daniel@kahlin.net>\n"
|
||||
"Written by Daniel Kahlin <daniel@kahlin.net>\n"
|
||||
"\n"
|
||||
"usage: " PROGRAM " [OPTION] FILE...\n"
|
||||
"\n"
|
||||
"Valid options:\n"
|
||||
" -t<type> select algorithm type (default: normal)\n"
|
||||
" -r raw file\n"
|
||||
" -m memory file\n"
|
||||
#if HAVE_CRUNCH_LEVEL
|
||||
" -l level file\n"
|
||||
#endif
|
||||
" -x executable file\n"
|
||||
" -X<opts> executable options (implies '-x')\n"
|
||||
" -b backwards mode\n"
|
||||
" -f forwards mode\n"
|
||||
" -d decompress\n"
|
||||
" -o<name> output file\n"
|
||||
" -q be quiet\n"
|
||||
" -v be verbose (can be multiple)\n"
|
||||
" -D display debug information\n"
|
||||
" -h displays this help text\n"
|
||||
" -V output program version\n"
|
||||
);
|
||||
exit(0);
|
||||
|
||||
/* set destination name */
|
||||
case 'o':
|
||||
destname = optarg;
|
||||
break;
|
||||
|
||||
/* set algorithm type */
|
||||
case 't':
|
||||
pack_type = optarg;
|
||||
break;
|
||||
|
||||
/* run in raw mode */
|
||||
case 'r':
|
||||
mode = MODE_RAW;
|
||||
break;
|
||||
|
||||
/* run in memory mode */
|
||||
case 'm':
|
||||
mode = MODE_MEM;
|
||||
break;
|
||||
|
||||
/* run in level mode */
|
||||
case 'l':
|
||||
mode = MODE_LEVEL;
|
||||
break;
|
||||
|
||||
/* set executable mode */
|
||||
case 'x':
|
||||
mode = MODE_SFX;
|
||||
break;
|
||||
|
||||
/* set executable options (implying -x) */
|
||||
case 'X':
|
||||
mode = MODE_SFX;
|
||||
sfx_opts[num_sfx_opts] = optarg;
|
||||
num_sfx_opts++;
|
||||
break;
|
||||
|
||||
/* run in backwards mode */
|
||||
case 'b':
|
||||
backwards_mode = 1;
|
||||
break;
|
||||
|
||||
/* run in forwards mode */
|
||||
case 'f':
|
||||
forwards_mode = 1;
|
||||
break;
|
||||
|
||||
/* run in depack mode */
|
||||
case 'd':
|
||||
depack_mode = 1;
|
||||
break;
|
||||
|
||||
/* default behavior */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* optind now points at the first non option argument
|
||||
* expect one or more arguments
|
||||
*/
|
||||
int num_files = argc - optind;
|
||||
if (num_files < 1) {
|
||||
panic("too few arguments");
|
||||
}
|
||||
srcnames = &argv[optind];
|
||||
|
||||
Type *p = types;
|
||||
while (p->name) {
|
||||
if (strcmp(p->name, pack_type) == 0) {
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
if (!p->name) {
|
||||
panic("unknown type '%s'", pack_type);
|
||||
}
|
||||
|
||||
|
||||
if (!depack_mode) {
|
||||
/* handle crunching */
|
||||
switch (mode) {
|
||||
case MODE_RAW:
|
||||
crunch_raw(p, num_files, srcnames, destname, backwards_mode);
|
||||
break;
|
||||
case MODE_MEM:
|
||||
crunch_mem(p, num_files, srcnames, destname, forwards_mode);
|
||||
break;
|
||||
#if HAVE_CRUNCH_LEVEL
|
||||
case MODE_LEVEL:
|
||||
crunch_level(p, num_files, srcnames, destname);
|
||||
break;
|
||||
#endif
|
||||
case MODE_SFX:
|
||||
|
||||
if (!p->sfx_func) {
|
||||
panic("sfx not available for '%s'", p->name);
|
||||
}
|
||||
crunch_sfx(p, num_files, srcnames, destname, num_sfx_opts, sfx_opts);
|
||||
break;
|
||||
default:
|
||||
panic("internal: invalid mode (%d)", mode);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* handle decrunching */
|
||||
switch (mode) {
|
||||
case MODE_RAW:
|
||||
decrunch_raw(p, num_files, srcnames, destname, backwards_mode);
|
||||
break;
|
||||
case MODE_SFX:
|
||||
panic("cannot depack sfx");
|
||||
break;
|
||||
default:
|
||||
panic("internal: invalid mode (%d)", mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
static int crunch_raw(Type *p, int num_files, char **srcnames, char *destname, int backwards_mode)
|
||||
{
|
||||
int ret;
|
||||
Buffer *sbf;
|
||||
Buffer *dbf;
|
||||
|
||||
/* this should handle more than one file */
|
||||
sbf = create_buffer_from_file(srcnames[0]);
|
||||
|
||||
dbf = create_buffer(MAX_DECRUNCH_SIZE);
|
||||
|
||||
if (backwards_mode) {
|
||||
reverse_buffer(sbf);
|
||||
}
|
||||
|
||||
ret = p->pack_func(sbf, dbf);
|
||||
if (ret) {
|
||||
printf("warning: packing failed. packer returned non-zero!\n");
|
||||
}
|
||||
|
||||
msg(MSG_VERBOSE, "packed %zu bytes into %zu bytes\n", sbf->len, dbf->len);
|
||||
|
||||
#if 1
|
||||
/* verify */
|
||||
Buffer *vbf;
|
||||
vbf = create_buffer(MAX_DECRUNCH_SIZE);
|
||||
ret = p->depack_func(dbf, vbf);
|
||||
if (ret) {
|
||||
printf("warning: verify failed. depacker returned non-zero!\n");
|
||||
} else if (compare_buffer(sbf, vbf) != 0) {
|
||||
printf("warning: verify failed. depacked data does not match source data!\n");
|
||||
} else {
|
||||
msg(MSG_VERBOSE, "verifed %zu bytes...ok\n", sbf->len);
|
||||
}
|
||||
destroy_buffer(vbf);
|
||||
#endif
|
||||
|
||||
if (backwards_mode) {
|
||||
reverse_buffer(dbf);
|
||||
}
|
||||
|
||||
write_buffer_to_file(dbf, destname);
|
||||
|
||||
destroy_buffer(dbf);
|
||||
destroy_buffer(sbf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int decrunch_raw(Type *p, int num_files, char **srcnames, char *destname, int backwards_mode)
|
||||
{
|
||||
int ret;
|
||||
Buffer *sbf;
|
||||
Buffer *dbf;
|
||||
|
||||
/* this should handle more than one file */
|
||||
sbf = create_buffer_from_file(srcnames[0]);
|
||||
|
||||
dbf = create_buffer(MAX_DECRUNCH_SIZE);
|
||||
|
||||
if (backwards_mode) {
|
||||
reverse_buffer(sbf);
|
||||
}
|
||||
|
||||
ret = p->depack_func(sbf, dbf);
|
||||
if (ret) {
|
||||
printf("warning: depacking failed. depacker returned non-zero!\n");
|
||||
}
|
||||
msg(MSG_VERBOSE, "depacked %zu bytes into %zu bytes\n", sbf->len, dbf->len);
|
||||
|
||||
if (backwards_mode) {
|
||||
reverse_buffer(dbf);
|
||||
}
|
||||
|
||||
write_buffer_to_file(dbf, destname);
|
||||
|
||||
destroy_buffer(dbf);
|
||||
destroy_buffer(sbf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int crunch_mem(Type *p, int num_files, char **srcnames, char *destname, int forwards_mode)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
Memory *smem;
|
||||
Memory *dmem;
|
||||
int srclen, destlen;
|
||||
|
||||
smem = create_memory(0x10000);
|
||||
dmem = create_memory(0x10000);
|
||||
|
||||
for (i = 0; i < num_files; i++) {
|
||||
char *name = srcnames[i];
|
||||
file_t f;
|
||||
|
||||
f = parse_filename(name);
|
||||
load_mem(smem, &f, 0, 0);
|
||||
}
|
||||
srclen = smem->high - smem->low;
|
||||
|
||||
// ret = p->mem_func(smem, dmem, 0, 0);
|
||||
ret = p->mem_func(smem, dmem, forwards_mode, 0); // FIXME: kludge!!!!
|
||||
if (ret) {
|
||||
printf("warning: packing failed. packer returned non-zero!\n");
|
||||
}
|
||||
|
||||
destlen = dmem->high - dmem->low;
|
||||
msg(MSG_VERBOSE, "packed %d bytes (%d blocks) into %d bytes (%d blocks)\n", srclen, (srclen+2+253)/254, destlen, (destlen+2+253)/254 );
|
||||
|
||||
save_file_from_memory(dmem, destname);
|
||||
|
||||
destroy_memory(dmem);
|
||||
destroy_memory(smem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int crunch_sfx(Type *p, int num_files, char **srcnames, char *destname, int num_sfx_opts, char **sfx_opts)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
Memory *smem;
|
||||
Memory *dmem;
|
||||
int srclen, destlen;
|
||||
int jmp = -1;
|
||||
|
||||
smem = create_memory(0x10000);
|
||||
dmem = create_memory(0x10000);
|
||||
|
||||
for (i = 0; i < num_files; i++) {
|
||||
char *name = srcnames[i];
|
||||
file_t f;
|
||||
|
||||
f = parse_filename(name);
|
||||
load_mem(smem, &f, 0, 0);
|
||||
}
|
||||
srclen = smem->high - smem->low;
|
||||
|
||||
if (jmp < 0) {
|
||||
int r;
|
||||
r = detect_start(smem);
|
||||
#if 0
|
||||
if (r < 0) {
|
||||
panic("couldn't detect start address!");
|
||||
}
|
||||
#endif
|
||||
jmp = r;
|
||||
|
||||
msg(MSG_VERBOSE, "detected sys: $%04X\n", jmp);
|
||||
}
|
||||
|
||||
/* if presumable basic start, make sure $0800 ends up $00 */
|
||||
if (smem->low == 0x0801) {
|
||||
set_byte(smem, 0x0800, 0x00);
|
||||
smem->low = 0x0800;
|
||||
}
|
||||
|
||||
ret = p->sfx_func(smem, dmem, num_sfx_opts, sfx_opts, jmp);
|
||||
if (ret) {
|
||||
printf("warning: packing failed. packer returned non-zero!\n");
|
||||
}
|
||||
|
||||
destlen = dmem->high - dmem->low;
|
||||
msg(MSG_VERBOSE, "packed %d bytes (%d blocks) into %d bytes (%d blocks)\n", srclen, (srclen+2+253)/254, destlen, (destlen+2+253)/254 );
|
||||
|
||||
save_file_from_memory(dmem, destname);
|
||||
|
||||
destroy_memory(dmem);
|
||||
destroy_memory(smem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* eof */
|
||||
108
loader/tools/subsizer-0.7pre1/src/universal.c
Normal file
108
loader/tools/subsizer-0.7pre1/src/universal.c
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE universal.c
|
||||
* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* universal encodings
|
||||
*
|
||||
******/
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bitfunc.h"
|
||||
#include "universal.h"
|
||||
#include "global.h"
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME cost_unary, write_unary, read_unary
|
||||
*
|
||||
******/
|
||||
int cost_unary(int v, int lim)
|
||||
{
|
||||
if (v == lim-1) {
|
||||
return v;
|
||||
}
|
||||
return v+1;
|
||||
}
|
||||
|
||||
|
||||
void write_unary(BitWriteState *bws, int v, int lim, int pol)
|
||||
{
|
||||
uint32_t mask = pol ? 0xfffffff : 0;
|
||||
int endbit = pol ? 0 : 1;
|
||||
|
||||
bitwr_write(bws, mask, v);
|
||||
if (v < lim-1) {
|
||||
bitwr_write(bws, endbit, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int read_unary(BitReadState *brs, int lim, int pol)
|
||||
{
|
||||
int n = 0;
|
||||
while (bitrd_read(brs, 1) == pol) {
|
||||
n++;
|
||||
if (n == lim-1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* NAME cost_eliasgamma, write_eliasgamma, read_eliasgamma
|
||||
*
|
||||
******/
|
||||
int cost_eliasgamma(int v)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* find first 1 */
|
||||
for (n = 31; n >= 0; n--) {
|
||||
if ( (v>>n) & 0x01)
|
||||
break;
|
||||
}
|
||||
return n + n+1;
|
||||
}
|
||||
|
||||
|
||||
void write_eliasgamma(BitWriteState *bws, int v)
|
||||
{
|
||||
int n;
|
||||
/* find first 1 */
|
||||
for (n = 31; n >= 0; n--) {
|
||||
if ( (v>>n) & 0x01)
|
||||
break;
|
||||
}
|
||||
|
||||
bitwr_write(bws, 0, n);
|
||||
bitwr_write(bws, v, n+1);
|
||||
}
|
||||
|
||||
|
||||
int read_eliasgamma(BitReadState *brs)
|
||||
{
|
||||
int v;
|
||||
int n = 0;
|
||||
while (bitrd_read(brs, 1) == 0) {
|
||||
n++;
|
||||
}
|
||||
if (n == 16) {
|
||||
/* short cut to end marker */
|
||||
return 0x10000;
|
||||
}
|
||||
|
||||
v = bitrd_read(brs, n);
|
||||
v |= 1<<n;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
/* eof */
|
||||
25
loader/tools/subsizer-0.7pre1/src/universal.h
Normal file
25
loader/tools/subsizer-0.7pre1/src/universal.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE universal.h
|
||||
* Copyright (c) 2015 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* universal encodings
|
||||
*
|
||||
******/
|
||||
#ifndef UNIVERSAL_H
|
||||
#define UNIVERSAL_H
|
||||
|
||||
#include "bitfunc.h"
|
||||
|
||||
int cost_unary(int v, int lim);
|
||||
void write_unary(BitWriteState *bws, int v, int lim, int pol);
|
||||
int read_unary(BitReadState *brs, int lim, int pol);
|
||||
|
||||
int cost_eliasgamma(int v);
|
||||
void write_eliasgamma(BitWriteState *bws, int v);
|
||||
int read_eliasgamma(BitReadState *brs);
|
||||
|
||||
#endif /* UNIVERSAL_H */
|
||||
/* eof */
|
||||
93
loader/tools/subsizer-0.7pre1/src/utils.c
Normal file
93
loader/tools/subsizer-0.7pre1/src/utils.c
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE utils.c
|
||||
* Copyright (c) 2012, 2015, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* utility functions.
|
||||
*
|
||||
******/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "utils.h"
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION memory functions
|
||||
*
|
||||
******/
|
||||
void *safe_malloc(size_t size, const char *msg)
|
||||
{
|
||||
void *ptr = malloc(size);
|
||||
if (!ptr) {
|
||||
panic("couldn't malloc: %s", msg);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *safe_calloc(size_t nmemb, size_t size, const char *msg)
|
||||
{
|
||||
void *ptr = calloc(nmemb, size);
|
||||
if (!ptr) {
|
||||
panic("couldn't calloc: %s", msg);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *safe_realloc(void *ptr, size_t size, const char *msg)
|
||||
{
|
||||
ptr = realloc(ptr, size);
|
||||
if (!ptr) {
|
||||
panic("couldn't realloc: %s", msg);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
char *safe_strdup(const char *str, const char *msg)
|
||||
{
|
||||
char *dup = strdup(str);
|
||||
if (!dup) {
|
||||
panic("couldn't strdup: %s", msg);
|
||||
}
|
||||
|
||||
return dup;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/* apparently not present in mingw32 */
|
||||
char *safe_strndup(const char *str, int n, const char *msg)
|
||||
{
|
||||
char *dup = strndup(str, n);
|
||||
if (!dup) {
|
||||
panic("couldn't strndup: %s", msg);
|
||||
}
|
||||
|
||||
return dup;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* SECTION time functions
|
||||
*
|
||||
******/
|
||||
double get_time(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
|
||||
return tv.tv_sec + 0.000001 * tv.tv_usec;
|
||||
}
|
||||
|
||||
|
||||
/* eof */
|
||||
31
loader/tools/subsizer-0.7pre1/src/utils.h
Normal file
31
loader/tools/subsizer-0.7pre1/src/utils.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* FILE utils.h
|
||||
* Copyright (c) 2012, 2015, 2017 Daniel Kahlin <daniel@kahlin.net>
|
||||
* Written by Daniel Kahlin <daniel@kahlin.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* utility functions.
|
||||
*
|
||||
******/
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* memory functions */
|
||||
void *safe_malloc(size_t size, const char *msg);
|
||||
void *safe_calloc(size_t nmemb, size_t size, const char *msg);
|
||||
void *safe_realloc(void *ptr, size_t size, const char *msg);
|
||||
char *safe_strdup(const char *str, const char *msg);
|
||||
#if 0
|
||||
/* apparently not present in mingw32 */
|
||||
char *safe_strndup(const char *str, int n, const char *msg);
|
||||
#endif
|
||||
|
||||
/* time functions */
|
||||
double get_time(void);
|
||||
|
||||
|
||||
#endif /* UTILS_H */
|
||||
/* eof */
|
||||
Loading…
Add table
Add a link
Reference in a new issue