init files
This commit is contained in:
commit
8197a022bd
1409 changed files with 139317 additions and 0 deletions
161
loader/tools/b2/Decruncher.inc
Normal file
161
loader/tools/b2/Decruncher.inc
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
; ByteBoozer Decruncher /HCL May.2003
|
||||
; B2 Decruncher December 2014
|
||||
|
||||
; call: Y = AddrLo
|
||||
; X = AddrHi
|
||||
|
||||
;Variables.. #Bytes
|
||||
zp_base = $02 ; -
|
||||
bits = zp_base ;1
|
||||
put = zp_base+2 ;2
|
||||
|
||||
#macro GetNextBit() {.(
|
||||
asl bits
|
||||
bne DgEnd
|
||||
jsr GetNewBits
|
||||
DgEnd
|
||||
.)}
|
||||
|
||||
#macro GetLen() {.(
|
||||
lda #1
|
||||
GlLoop
|
||||
.GetNextBit()
|
||||
bcc GlEnd
|
||||
.GetNextBit()
|
||||
rol
|
||||
bpl GlLoop
|
||||
GlEnd
|
||||
.)}
|
||||
|
||||
Decrunch
|
||||
sty Get1+1
|
||||
sty Get2+1
|
||||
sty Get3+1
|
||||
stx Get1+2
|
||||
stx Get2+2
|
||||
stx Get3+2
|
||||
|
||||
ldx #0
|
||||
jsr GetNewBits
|
||||
sty put-1,x
|
||||
cpx #2
|
||||
bcc *-7
|
||||
lda #$80
|
||||
sta bits
|
||||
DLoop
|
||||
.GetNextBit()
|
||||
bcs Match
|
||||
Literal
|
||||
; Literal run.. get length.
|
||||
.GetLen()
|
||||
sta LLen+1
|
||||
|
||||
ldy #0
|
||||
LLoop
|
||||
Get3 lda $feed,x
|
||||
inx
|
||||
bne *+5
|
||||
jsr GnbInc
|
||||
L1 sta (put),y
|
||||
iny
|
||||
LLen cpy #0
|
||||
bne LLoop
|
||||
|
||||
clc
|
||||
tya
|
||||
adc put
|
||||
sta put
|
||||
bcc *+4
|
||||
inc put+1
|
||||
|
||||
iny
|
||||
beq DLoop
|
||||
|
||||
; Has to continue with a match..
|
||||
|
||||
Match
|
||||
; Match.. get length.
|
||||
.GetLen()
|
||||
sta MLen+1
|
||||
|
||||
; Length 255 -> EOF
|
||||
cmp #$ff
|
||||
beq End
|
||||
|
||||
; Get num bits
|
||||
cmp #2
|
||||
lda #0
|
||||
rol
|
||||
.GetNextBit()
|
||||
rol
|
||||
.GetNextBit()
|
||||
rol
|
||||
tay
|
||||
lda Tab,y
|
||||
beq M8
|
||||
|
||||
; Get bits < 8
|
||||
M_1 .GetNextBit()
|
||||
rol
|
||||
bcs M_1
|
||||
bmi MShort
|
||||
M8
|
||||
; Get byte
|
||||
eor #$ff
|
||||
tay
|
||||
Get2 lda $feed,x
|
||||
inx
|
||||
bne *+5
|
||||
jsr GnbInc
|
||||
jmp Mdone
|
||||
MShort
|
||||
ldy #$ff
|
||||
Mdone
|
||||
;clc
|
||||
adc put
|
||||
sta MLda+1
|
||||
tya
|
||||
adc put+1
|
||||
sta MLda+2
|
||||
|
||||
ldy #$ff
|
||||
MLoop iny
|
||||
MLda lda $beef,y
|
||||
sta (put),y
|
||||
MLen cpy #0
|
||||
bne MLoop
|
||||
|
||||
;sec
|
||||
tya
|
||||
adc put
|
||||
sta put
|
||||
bcc *+4
|
||||
inc put+1
|
||||
|
||||
jmp DLoop
|
||||
|
||||
End rts
|
||||
|
||||
GetNewBits
|
||||
Get1 ldy $feed,x
|
||||
sty bits
|
||||
rol bits
|
||||
inx
|
||||
bne GnbEnd
|
||||
GnbInc inc Get1+2
|
||||
inc Get2+2
|
||||
inc Get3+2
|
||||
GnbEnd
|
||||
rts
|
||||
|
||||
Tab
|
||||
; Short offsets
|
||||
.byte %11011111 ; 3
|
||||
.byte %11111011 ; 6
|
||||
.byte %00000000 ; 8
|
||||
.byte %10000000 ; 10
|
||||
; Long offsets
|
||||
.byte %11101111 ; 4
|
||||
.byte %11111101 ; 7
|
||||
.byte %10000000 ; 10
|
||||
.byte %11110000 ; 13
|
||||
9
loader/tools/b2/Makefile
Normal file
9
loader/tools/b2/Makefile
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
CC = gcc
|
||||
|
||||
OBJECTS = \
|
||||
file.c \
|
||||
cruncher.c \
|
||||
bb.c
|
||||
|
||||
all: $(OBJECTS)
|
||||
$(CC) -O3 $(OBJECTS) -o b2.exe
|
||||
77
loader/tools/b2/bb.c
Normal file
77
loader/tools/b2/bb.c
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#include "bb.h"
|
||||
#include "file.h"
|
||||
#include "cruncher.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
File myFile;
|
||||
File myBBFile;
|
||||
char* fileName;
|
||||
bool isExecutable = false;
|
||||
bool isRelocated = false;
|
||||
uint address = 0;
|
||||
|
||||
if((argc != 2 && argc != 4) ||
|
||||
(strcmp(argv[1], "-h") == 0) ||
|
||||
(strcmp(argv[1], "-help") == 0)){
|
||||
printf("Usage: b2 [-[c|e|r] xxxx] <filename>\n");
|
||||
printf(" -c: Make executable with start address xxxx.\n");
|
||||
printf(" -e: Same as -c :P.\n");
|
||||
printf(" -r: Relocate file to hex address xxxx.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(argc == 2) {
|
||||
fileName = argv[1];
|
||||
} else {
|
||||
int i;
|
||||
char *s = argv[2];
|
||||
fileName = argv[3];
|
||||
|
||||
if((strcmp(argv[1], "-c") == 0) ||
|
||||
(strcmp(argv[1], "-e") == 0))
|
||||
isExecutable = true;
|
||||
else if(strcmp(argv[1], "-r") == 0)
|
||||
isRelocated = true;
|
||||
else {
|
||||
printf("Don't understand, aborting.\n");
|
||||
return -1;
|
||||
}
|
||||
if(strlen(s) != 4){
|
||||
printf("Don't understand, aborting.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(i = 0; i < 4; ++i){
|
||||
byte c;
|
||||
if(s[i] >= '0' && s[i] <= '9') c = s[i] - '0';
|
||||
if(s[i] >= 'a' && s[i] <= 'f') c = s[i] - 'a' + 10;
|
||||
if(s[i] >= 'A' && s[i] <= 'F') c = s[i] - 'A' + 10;
|
||||
address *= 16;
|
||||
address += c;
|
||||
}
|
||||
}
|
||||
|
||||
if(!readFile(&myFile, fileName)) {
|
||||
printf("Error (B-1): Open file \"%s\", aborting.\n", fileName);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!crunch(&myFile, &myBBFile, address, isExecutable, isRelocated)) {
|
||||
freeFile(&myFile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!writeFile(&myBBFile, myFile.name)) {
|
||||
printf("Error (B-2): Write file \"%s\", aborting.\n", myBBFile.name);
|
||||
}
|
||||
|
||||
printf("B2: \"%s\" -> \"%s\"\n", myFile.name, myBBFile.name);
|
||||
|
||||
freeFile(&myFile);
|
||||
freeFile(&myBBFile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
19
loader/tools/b2/bb.h
Normal file
19
loader/tools/b2/bb.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef _bb_h_
|
||||
#define _bb_h_
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void*)0)
|
||||
#endif
|
||||
|
||||
#ifndef byte
|
||||
typedef unsigned char byte;
|
||||
#endif
|
||||
#ifndef uint
|
||||
typedef unsigned int uint;
|
||||
#endif
|
||||
|
||||
typedef enum { false = 0, true = 1 } bool;
|
||||
|
||||
#define memSize 65536
|
||||
|
||||
#endif // _bb_h_
|
||||
747
loader/tools/b2/cruncher.c
Normal file
747
loader/tools/b2/cruncher.c
Normal file
|
|
@ -0,0 +1,747 @@
|
|||
#include "cruncher.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define log(format, ...)
|
||||
//#define log(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
|
||||
|
||||
#define NUM_BITS_SHORT_0 3
|
||||
#define NUM_BITS_SHORT_1 6
|
||||
#define NUM_BITS_SHORT_2 8
|
||||
#define NUM_BITS_SHORT_3 10
|
||||
#define NUM_BITS_LONG_0 4
|
||||
#define NUM_BITS_LONG_1 7
|
||||
#define NUM_BITS_LONG_2 10
|
||||
#define NUM_BITS_LONG_3 13
|
||||
|
||||
#define LEN_SHORT_0 (1 << NUM_BITS_SHORT_0)
|
||||
#define LEN_SHORT_1 (1 << NUM_BITS_SHORT_1)
|
||||
#define LEN_SHORT_2 (1 << NUM_BITS_SHORT_2)
|
||||
#define LEN_SHORT_3 (1 << NUM_BITS_SHORT_3)
|
||||
#define LEN_LONG_0 (1 << NUM_BITS_LONG_0)
|
||||
#define LEN_LONG_1 (1 << NUM_BITS_LONG_1)
|
||||
#define LEN_LONG_2 (1 << NUM_BITS_LONG_2)
|
||||
#define LEN_LONG_3 (1 << NUM_BITS_LONG_3)
|
||||
|
||||
#define COND_SHORT_0(o) ((o) >= 0 && (o) < LEN_SHORT_0)
|
||||
#define COND_SHORT_1(o) ((o) >= LEN_SHORT_0 && (o) < LEN_SHORT_1)
|
||||
#define COND_SHORT_2(o) ((o) >= LEN_SHORT_1 && (o) < LEN_SHORT_2)
|
||||
#define COND_SHORT_3(o) ((o) >= LEN_SHORT_2 && (o) < LEN_SHORT_3)
|
||||
#define COND_LONG_0(o) ((o) >= 0 && (o) < LEN_LONG_0)
|
||||
#define COND_LONG_1(o) ((o) >= LEN_LONG_0 && (o) < LEN_LONG_1)
|
||||
#define COND_LONG_2(o) ((o) >= LEN_LONG_1 && (o) < LEN_LONG_2)
|
||||
#define COND_LONG_3(o) ((o) >= LEN_LONG_2 && (o) < LEN_LONG_3)
|
||||
|
||||
#define MAX_OFFSET LEN_LONG_3
|
||||
#define MAX_OFFSET_SHORT LEN_SHORT_3
|
||||
|
||||
#define DECRUNCHER_LENGTH 0xd5
|
||||
byte decrCode[DECRUNCHER_LENGTH] = {
|
||||
0x0b, 0x08, 0x00, 0x00, 0x9e, 0x32, 0x30, 0x36, 0x31, 0x00, 0x00, 0x00, 0x78, 0xa9, 0x34, 0x85,
|
||||
0x01, 0xa2, 0xb7, 0xbd, 0x1e, 0x08, 0x95, 0x0f, 0xca, 0xd0, 0xf8, 0x4c, 0x10, 0x00, 0xbd, 0xd6,
|
||||
0x07, 0x9d, 0x00, 0xff, 0xe8, 0xd0, 0xf7, 0xc6, 0x12, 0xc6, 0x15, 0xa5, 0x12, 0xc9, 0x07, 0xb0,
|
||||
0xed, 0x20, 0xa0, 0x00, 0xb0, 0x17, 0x20, 0x8e, 0x00, 0x85, 0x36, 0xa0, 0x00, 0x20, 0xad, 0x00,
|
||||
0x91, 0x77, 0xc8, 0xc0, 0x00, 0xd0, 0xf6, 0x20, 0x83, 0x00, 0xc8, 0xf0, 0xe4, 0x20, 0x8e, 0x00,
|
||||
0xaa, 0xe8, 0xf0, 0x71, 0x86, 0x7b, 0xa9, 0x00, 0xe0, 0x03, 0x2a, 0x20, 0x9b, 0x00, 0x20, 0x9b,
|
||||
0x00, 0xaa, 0xb5, 0xbf, 0xf0, 0x07, 0x20, 0x9b, 0x00, 0xb0, 0xfb, 0x30, 0x07, 0x49, 0xff, 0xa8,
|
||||
0x20, 0xad, 0x00, 0xae, 0xa0, 0xff, 0x65, 0x77, 0x85, 0x74, 0x98, 0x65, 0x78, 0x85, 0x75, 0xa0,
|
||||
0x00, 0xb9, 0xad, 0xde, 0x99, 0x00, 0x00, 0xc8, 0xc0, 0x00, 0xd0, 0xf5, 0x20, 0x83, 0x00, 0xd0,
|
||||
0xa0, 0x18, 0x98, 0x65, 0x77, 0x85, 0x77, 0x90, 0x02, 0xe6, 0x78, 0x60, 0xa9, 0x01, 0x20, 0xa0,
|
||||
0x00, 0x90, 0x05, 0x20, 0x9b, 0x00, 0x10, 0xf6, 0x60, 0x20, 0xa0, 0x00, 0x2a, 0x60, 0x06, 0xbe,
|
||||
0xd0, 0x08, 0x48, 0x20, 0xad, 0x00, 0x2a, 0x85, 0xbe, 0x68, 0x60, 0xad, 0xed, 0xfe, 0xe6, 0xae,
|
||||
0xd0, 0x02, 0xe6, 0xaf, 0x60, 0xa9, 0x37, 0x85, 0x01, 0x4c, 0x00, 0x00, 0x80, 0xdf, 0xfb, 0x00,
|
||||
0x80, 0xef, 0xfd, 0x80, 0xf0
|
||||
};
|
||||
|
||||
|
||||
byte *ibuf;
|
||||
byte *obuf;
|
||||
uint ibufSize;
|
||||
int get; //points to ibuf[]
|
||||
uint put; //points to obuf[]
|
||||
|
||||
typedef struct {
|
||||
uint cost;
|
||||
uint next;
|
||||
uint litLen;
|
||||
uint offset;
|
||||
} node;
|
||||
|
||||
typedef struct {
|
||||
byte value;
|
||||
byte valueAfter;
|
||||
uint length;
|
||||
} RLEInfo;
|
||||
|
||||
node *context;
|
||||
uint *link;
|
||||
RLEInfo *rleInfo;
|
||||
uint first[65536];
|
||||
uint last[65536];
|
||||
|
||||
byte curByte;
|
||||
byte curCnt;
|
||||
uint curIndex;
|
||||
|
||||
void wBit(uint bit) {
|
||||
if(curCnt == 0) {
|
||||
obuf[curIndex] = curByte;
|
||||
curIndex = put;
|
||||
curCnt = 8;
|
||||
curByte = 0;
|
||||
put++;
|
||||
}
|
||||
|
||||
curByte <<= 1;
|
||||
curByte |= (bit & 1);
|
||||
curCnt--;
|
||||
}
|
||||
|
||||
void wFlush() {
|
||||
while(curCnt != 0) {
|
||||
curByte <<= 1;
|
||||
curCnt--;
|
||||
}
|
||||
obuf[curIndex] = curByte;
|
||||
}
|
||||
|
||||
void wByte(uint b) {
|
||||
obuf[put] = b;
|
||||
put++;
|
||||
}
|
||||
|
||||
void wBytes(uint get, uint len) {
|
||||
uint i;
|
||||
for(i = 0; i < len; i++) {
|
||||
wByte(ibuf[get]);
|
||||
get++;
|
||||
}
|
||||
}
|
||||
|
||||
void wLength(uint len) {
|
||||
// if(len == 0) return; // Should never happen
|
||||
|
||||
byte bit = 0x80;
|
||||
while((len & bit) == 0) {
|
||||
bit >>= 1;
|
||||
}
|
||||
|
||||
while(bit > 1) {
|
||||
wBit(1);
|
||||
bit >>= 1;
|
||||
wBit(((len & bit) == 0) ? 0 : 1);
|
||||
}
|
||||
|
||||
if(len < 0x80) {
|
||||
wBit(0);
|
||||
}
|
||||
}
|
||||
|
||||
void wOffset(uint offset, uint len) {
|
||||
uint i = 0;
|
||||
uint n = 0;
|
||||
uint b;
|
||||
|
||||
if(len == 1) {
|
||||
if(COND_SHORT_0(offset)) {
|
||||
i = 0;
|
||||
n = NUM_BITS_SHORT_0;
|
||||
}
|
||||
if(COND_SHORT_1(offset)) {
|
||||
i = 1;
|
||||
n = NUM_BITS_SHORT_1;
|
||||
}
|
||||
if(COND_SHORT_2(offset)) {
|
||||
i = 2;
|
||||
n = NUM_BITS_SHORT_2;
|
||||
}
|
||||
if(COND_SHORT_3(offset)) {
|
||||
i = 3;
|
||||
n = NUM_BITS_SHORT_3;
|
||||
}
|
||||
} else {
|
||||
if(COND_LONG_0(offset)) {
|
||||
i = 0;
|
||||
n = NUM_BITS_LONG_0;
|
||||
}
|
||||
if(COND_LONG_1(offset)) {
|
||||
i = 1;
|
||||
n = NUM_BITS_LONG_1;
|
||||
}
|
||||
if(COND_LONG_2(offset)) {
|
||||
i = 2;
|
||||
n = NUM_BITS_LONG_2;
|
||||
}
|
||||
if(COND_LONG_3(offset)) {
|
||||
i = 3;
|
||||
n = NUM_BITS_LONG_3;
|
||||
}
|
||||
}
|
||||
|
||||
// First write number of bits
|
||||
wBit(((i & 2) == 0) ? 0 : 1);
|
||||
wBit(((i & 1) == 0) ? 0 : 1);
|
||||
|
||||
if(n >= 8) { // Offset is 2 bytes
|
||||
|
||||
// Then write the bits less than 8
|
||||
b = 1 << n;
|
||||
while(b > 0x100) {
|
||||
b >>= 1;
|
||||
wBit(((b & offset) == 0) ? 0 : 1);
|
||||
};
|
||||
|
||||
// Finally write a whole byte, if necessary
|
||||
wByte((offset & 255) ^ 255); // Inverted(!)
|
||||
offset >>= 8;
|
||||
|
||||
} else { // Offset is 1 byte
|
||||
|
||||
// Then write the bits less than 8
|
||||
b = 1 << n;
|
||||
while(b > 1) {
|
||||
b >>= 1;
|
||||
wBit(((b & offset) == 0) ? 1 : 0); // Inverted(!)
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Cost functions
|
||||
*/
|
||||
uint costOfLength(uint len) {
|
||||
if(len == 1) return 1;
|
||||
if(len >= 2 && len <= 3) return 3;
|
||||
if(len >= 4 && len <= 7) return 5;
|
||||
if(len >= 8 && len <= 15) return 7;
|
||||
if(len >= 16 && len <= 31) return 9;
|
||||
if(len >= 32 && len <= 63) return 11;
|
||||
if(len >= 64 && len <= 127) return 13;
|
||||
if(len >= 128 && len <= 255) return 14;
|
||||
|
||||
printf("costOfLength got wrong value: %i\n", len);
|
||||
return 10000;
|
||||
}
|
||||
|
||||
uint costOfOffset(uint offset, uint len) {
|
||||
if(len == 1) {
|
||||
if(COND_SHORT_0(offset)) return NUM_BITS_SHORT_0;
|
||||
if(COND_SHORT_1(offset)) return NUM_BITS_SHORT_1;
|
||||
if(COND_SHORT_2(offset)) return NUM_BITS_SHORT_2;
|
||||
if(COND_SHORT_3(offset)) return NUM_BITS_SHORT_3;
|
||||
} else {
|
||||
if(COND_LONG_0(offset)) return NUM_BITS_LONG_0;
|
||||
if(COND_LONG_1(offset)) return NUM_BITS_LONG_1;
|
||||
if(COND_LONG_2(offset)) return NUM_BITS_LONG_2;
|
||||
if(COND_LONG_3(offset)) return NUM_BITS_LONG_3;
|
||||
}
|
||||
|
||||
printf("costOfOffset got wrong offset: %i\n", offset);
|
||||
return 10000;
|
||||
}
|
||||
|
||||
uint calculateCostOfMatch(uint len, uint offset) {
|
||||
uint cost = 1; // Copy-bit
|
||||
cost += costOfLength(len - 1);
|
||||
cost += 2; // NumOffsetBits
|
||||
cost += costOfOffset(offset - 1, len - 1);
|
||||
return cost;
|
||||
}
|
||||
|
||||
uint calculateCostOfLiteral(uint oldCost, uint litLen) {
|
||||
uint newCost = oldCost + 8;
|
||||
|
||||
// FIXME, what if litLen > 255?
|
||||
//
|
||||
// FIXME, cost model for literals does not work.
|
||||
// Quick wins on short matches are prioritized before
|
||||
// a longer literal run, which in the end results in a
|
||||
// worse result.
|
||||
// Most obvious on files hard to crunch.
|
||||
switch(litLen) {
|
||||
case 1:
|
||||
case 128:
|
||||
newCost++;
|
||||
break;
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
case 16:
|
||||
case 32:
|
||||
case 64:
|
||||
newCost += 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return newCost;
|
||||
}
|
||||
|
||||
|
||||
void setupHelpStructures() {
|
||||
uint i;
|
||||
|
||||
// Setup RLE-info
|
||||
get = ibufSize - 1;
|
||||
while (get > 0) {
|
||||
|
||||
byte cur = ibuf[get];
|
||||
if (cur == ibuf[get-1]) {
|
||||
|
||||
uint len = 2;
|
||||
while ((get >= len) &&
|
||||
(cur == ibuf[get-len])) {
|
||||
len++;
|
||||
}
|
||||
|
||||
rleInfo[get].length = len;
|
||||
if (get >= len) {
|
||||
rleInfo[get].valueAfter = ibuf[get-len];
|
||||
} else {
|
||||
rleInfo[get].valueAfter = cur; // Avoid accessing ibuf[-1]
|
||||
}
|
||||
|
||||
get -= len;
|
||||
} else {
|
||||
get--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Setup Linked list
|
||||
for (i = 0; i < 65536; i++) {
|
||||
first[i] = 0;
|
||||
last[i] = 0;
|
||||
}
|
||||
|
||||
get = ibufSize - 1;
|
||||
uint cur = ibuf[get];
|
||||
|
||||
while (get > 0) {
|
||||
|
||||
cur = ((cur << 8) | ibuf[get-1]) & 65535;
|
||||
|
||||
if (first[cur] == 0) {
|
||||
first[cur] = last[cur] = get;
|
||||
} else {
|
||||
link[last[cur]] = get;
|
||||
last[cur] = get;
|
||||
}
|
||||
|
||||
if (rleInfo[get].length == 0) { // No RLE-match here..
|
||||
get--;
|
||||
} else { // if RLE-match..
|
||||
get -= (rleInfo[get].length - 1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void findMatches() {
|
||||
|
||||
typedef struct match {
|
||||
uint length;
|
||||
uint offset;
|
||||
} match;
|
||||
|
||||
match matches[256];
|
||||
|
||||
node lastNode;
|
||||
uint i;
|
||||
|
||||
get = ibufSize - 1;
|
||||
uint cur = ibuf[get];
|
||||
|
||||
lastNode.cost = 0;
|
||||
lastNode.next = 0;
|
||||
lastNode.litLen = 0;
|
||||
|
||||
while (get >= 0) {
|
||||
|
||||
// Clear matches for current position
|
||||
for (i = 0; i < 256; i++) {
|
||||
matches[i].length = 0;
|
||||
matches[i].offset = 0;
|
||||
}
|
||||
|
||||
cur = (cur << 8) & 65535; // Table65536 lookup
|
||||
if (get > 0) cur |= ibuf[get-1];
|
||||
int scn = first[cur];
|
||||
scn = link[scn];
|
||||
|
||||
uint longestMatch = 0;
|
||||
|
||||
if (rleInfo[get].length == 0) { // No RLE-match here..
|
||||
|
||||
// Scan until start of file, or max offset
|
||||
while (((get - scn) <= MAX_OFFSET) &&
|
||||
(scn > 0) &&
|
||||
(longestMatch < 255)) {
|
||||
|
||||
// Ok, we have a match of length 2
|
||||
// ..or longer, but max 255 or file start
|
||||
uint len = 2;
|
||||
while ((len < 255) &&
|
||||
(scn >= len) &&
|
||||
(ibuf[scn - len] == ibuf[get - len])) {
|
||||
++len;
|
||||
}
|
||||
|
||||
// Calc offset
|
||||
uint offset = get - scn;
|
||||
|
||||
// Store match only if it's the longest so far
|
||||
if(len > longestMatch) {
|
||||
longestMatch = len;
|
||||
|
||||
// Store the match only if first (= best) of this length
|
||||
while(len >= 2 && matches[len].length == 0) {
|
||||
|
||||
// If len == 2, check against short offset!!
|
||||
if ((len > 2) ||
|
||||
((len == 2) && (offset <= MAX_OFFSET_SHORT))) {
|
||||
matches[len].length = len;
|
||||
matches[len].offset = get - scn;
|
||||
}
|
||||
|
||||
len--;
|
||||
};
|
||||
}
|
||||
|
||||
scn = link[scn]; // Table65535 lookup
|
||||
};
|
||||
|
||||
first[cur] = link[first[cur]]; // Waste first entry
|
||||
|
||||
} else { // if RLE-match..
|
||||
|
||||
uint rleLen = rleInfo[get].length;
|
||||
byte rleValAfter = rleInfo[get].valueAfter;
|
||||
|
||||
|
||||
// First match with self-RLE, which is always
|
||||
// one byte shorter than the RLE itself.
|
||||
uint len = rleLen - 1;
|
||||
if (len > 1) {
|
||||
if (len > 255) len = 255;
|
||||
longestMatch = len;
|
||||
|
||||
// Store the match
|
||||
while(len >= 2) {
|
||||
matches[len].length = len;
|
||||
matches[len].offset = 1;
|
||||
|
||||
len--;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Search for more RLE-matches..
|
||||
// Scan until start of file, or max offset
|
||||
while (((get - scn) <= MAX_OFFSET) &&
|
||||
(scn > 0) &&
|
||||
(longestMatch < 255)) {
|
||||
|
||||
// Check for longer matches with same value and after..
|
||||
// FIXME, that is not what it does, is it?!
|
||||
if ((rleInfo[scn].length > longestMatch) &&
|
||||
(rleLen > longestMatch)) {
|
||||
|
||||
uint offset = get - scn;
|
||||
len = rleInfo[scn].length;
|
||||
|
||||
if (len > rleLen)
|
||||
len = rleLen;
|
||||
|
||||
if ((len > 2) ||
|
||||
((len == 2) && (offset <= MAX_OFFSET_SHORT))) {
|
||||
matches[len].length = len;
|
||||
matches[len].offset = offset;
|
||||
|
||||
longestMatch = len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check for matches beyond the RLE..
|
||||
if ((rleInfo[scn].length >= rleLen) &&
|
||||
(rleInfo[scn].valueAfter == rleValAfter)) {
|
||||
|
||||
// Here is a match that goes beyond the RLE..
|
||||
// Find out correct offset to use valueAfter..
|
||||
// Then search further to see if more bytes equal.
|
||||
|
||||
len = rleLen;
|
||||
uint offset = get - scn + (rleInfo[scn].length - rleLen);
|
||||
|
||||
if (offset <= MAX_OFFSET) {
|
||||
while ((len < 255) &&
|
||||
(get >= (offset + len)) &&
|
||||
(ibuf[get - (offset + len)] == ibuf[get - len])) {
|
||||
++len;
|
||||
}
|
||||
if (len > longestMatch){
|
||||
longestMatch = len;
|
||||
|
||||
// Store the match only if first (= best) of this length
|
||||
while(len >= 2 && matches[len].length == 0) {
|
||||
|
||||
// If len == 2, check against short offset!!
|
||||
if ((len > 2) ||
|
||||
((len == 2) && (offset <= MAX_OFFSET_SHORT))) {
|
||||
matches[len].length = len;
|
||||
matches[len].offset = offset;
|
||||
}
|
||||
|
||||
len--;
|
||||
}; //while
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scn = link[scn]; // Table65535 lookup
|
||||
}
|
||||
|
||||
|
||||
if (rleInfo[get].length > 2) {
|
||||
// Expand RLE to next position
|
||||
rleInfo[get-1].length = rleInfo[get].length - 1;
|
||||
rleInfo[get-1].value = rleInfo[get].value;
|
||||
rleInfo[get-1].valueAfter = rleInfo[get].valueAfter;
|
||||
} else {
|
||||
// End of RLE, advance link.
|
||||
first[cur] = link[first[cur]]; // Waste first entry
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now we have all matches from this position..
|
||||
// ..visit all nodes reached by the matches.
|
||||
|
||||
for (i = 255; i > 0; i--) {
|
||||
|
||||
// Find all matches we stored
|
||||
uint len = matches[i].length;
|
||||
uint offset = matches[i].offset;
|
||||
|
||||
if (len != 0) {
|
||||
|
||||
uint targetI = get - len + 1;
|
||||
node* target = &context[targetI];
|
||||
|
||||
// Calculate cost for this jump
|
||||
uint currentCost = lastNode.cost;
|
||||
currentCost += calculateCostOfMatch(len, offset);
|
||||
|
||||
// If this match is first or cheapest way to get here
|
||||
// then update node
|
||||
if (target->cost == 0 ||
|
||||
target->cost > currentCost) {
|
||||
|
||||
target->cost = currentCost;
|
||||
target->next = get + 1;
|
||||
target->litLen = 0;
|
||||
target->offset = offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Calc the cost for this node if using one more literal
|
||||
uint litLen = lastNode.litLen + 1;
|
||||
uint litCost = calculateCostOfLiteral(lastNode.cost, litLen);
|
||||
|
||||
// If literal run is first or cheapest way to get here
|
||||
// then update node
|
||||
node* this = &context[get];
|
||||
if (this->cost == 0 ||
|
||||
this->cost >= litCost) {
|
||||
this->cost = litCost;
|
||||
this->next = get + 1;
|
||||
this->litLen = litLen;
|
||||
}
|
||||
|
||||
lastNode.cost = this->cost;
|
||||
lastNode.next = this->next;
|
||||
lastNode.litLen = this->litLen;
|
||||
|
||||
// Loop to the next position
|
||||
get--;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Returns margin
|
||||
int writeOutput() {
|
||||
uint i;
|
||||
|
||||
put = 0;
|
||||
|
||||
curByte = 0;
|
||||
curCnt = 8;
|
||||
curIndex = put;
|
||||
put++;
|
||||
|
||||
int maxDiff = 0;
|
||||
|
||||
bool needCopyBit = true;
|
||||
|
||||
for (i = 0; i < ibufSize;) {
|
||||
|
||||
uint link = context[i].next;
|
||||
uint cost = context[i].cost;
|
||||
uint litLen = context[i].litLen;
|
||||
uint offset = context[i].offset;
|
||||
|
||||
if (litLen == 0) {
|
||||
// Put Match
|
||||
uint len = link - i;
|
||||
|
||||
log("$%04x: Mat(%i, %i)\n", i, len, offset);
|
||||
|
||||
if(needCopyBit) {
|
||||
wBit(1);
|
||||
}
|
||||
wLength(len - 1);
|
||||
wOffset(offset - 1, len - 1);
|
||||
|
||||
i = link;
|
||||
|
||||
needCopyBit = true;
|
||||
} else {
|
||||
// Put LiteralRun
|
||||
needCopyBit = false;
|
||||
|
||||
while(litLen > 0) {
|
||||
uint len = litLen < 255 ? litLen : 255;
|
||||
|
||||
log("$%04x: Lit(%i)\n", i, len);
|
||||
|
||||
wBit(0);
|
||||
wLength(len);
|
||||
wBytes(i, len);
|
||||
|
||||
if (litLen == 255) {
|
||||
needCopyBit = true;
|
||||
}
|
||||
|
||||
litLen -= len;
|
||||
i += len;
|
||||
};
|
||||
}
|
||||
|
||||
if ((int)(i - put) > maxDiff) {
|
||||
maxDiff = i - put;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
wBit(1);
|
||||
wLength(0xff);
|
||||
wFlush();
|
||||
|
||||
int margin = (maxDiff - (i - put));
|
||||
|
||||
return margin;
|
||||
}
|
||||
|
||||
|
||||
bool crunch(File *aSource,
|
||||
File *aTarget,
|
||||
uint address,
|
||||
bool isExecutable,
|
||||
bool isRelocated)
|
||||
{
|
||||
uint i;
|
||||
byte *target;
|
||||
|
||||
ibufSize = aSource->size - 2;
|
||||
ibuf = (byte*)malloc(ibufSize);
|
||||
context = (node*)malloc(sizeof(node) * ibufSize);
|
||||
link = (uint*)malloc(sizeof(uint) * ibufSize);
|
||||
rleInfo = (RLEInfo*)malloc(sizeof(RLEInfo) * ibufSize);
|
||||
|
||||
// Load ibuf and clear context
|
||||
for(i = 0; i < ibufSize; ++i) {
|
||||
ibuf[i] = aSource->data[i + 2];
|
||||
context[i].cost = 0;
|
||||
link[i] = 0;
|
||||
rleInfo[i].length = 0;
|
||||
}
|
||||
|
||||
setupHelpStructures();
|
||||
findMatches();
|
||||
obuf = (byte*)malloc(memSize);
|
||||
int margin = writeOutput();
|
||||
|
||||
uint packLen = put;
|
||||
uint fileLen = put;
|
||||
uint decrLen = 0;
|
||||
if(isExecutable) {
|
||||
decrLen = DECRUNCHER_LENGTH;
|
||||
fileLen += decrLen + 2;
|
||||
} else {
|
||||
fileLen += 4;
|
||||
}
|
||||
|
||||
aTarget->size = fileLen;
|
||||
aTarget->data = (byte*)malloc(aTarget->size);
|
||||
target = aTarget->data;
|
||||
|
||||
if(isExecutable) {
|
||||
uint startAddress = 0x10000 - packLen;
|
||||
uint transfAddress = fileLen + 0x6ff;
|
||||
|
||||
decrCode[0x1f] = transfAddress & 0xff; // Transfer from..
|
||||
decrCode[0x20] = transfAddress >> 8; //
|
||||
decrCode[0xbc] = startAddress & 0xff; // Depack from..
|
||||
decrCode[0xbd] = startAddress >> 8; //
|
||||
decrCode[0x85] = aSource->data[0]; // Depack to..
|
||||
decrCode[0x86] = aSource->data[1]; //
|
||||
decrCode[0xca] = address & 0xff; // Jump to..
|
||||
decrCode[0xcb] = address >> 8; //
|
||||
|
||||
target[0] = 0x01;
|
||||
target[1] = 0x08;
|
||||
|
||||
for(i = 0; i < decrLen; ++i) {
|
||||
target[i + 2] = decrCode[i];
|
||||
}
|
||||
|
||||
for(i = 0; i < put; ++i) {
|
||||
target[i + 2 + decrLen] = obuf[i];
|
||||
}
|
||||
|
||||
} else { // Not executable..
|
||||
|
||||
// Experimantal decision of start address
|
||||
// uint startAddress = 0xfffa - packLen - 2;
|
||||
uint startAddress = (aSource->data[1] << 8) | aSource->data[0];
|
||||
startAddress += (ibufSize - packLen - 2 + margin);
|
||||
|
||||
if (isRelocated) {
|
||||
startAddress = address - packLen - 2;
|
||||
}
|
||||
|
||||
target[0] = startAddress & 0xff; // Load address
|
||||
target[1] = startAddress >> 8;
|
||||
target[2] = aSource->data[0]; // Depack to address
|
||||
target[3] = aSource->data[1];
|
||||
|
||||
for(i = 0; i < put; ++i) {
|
||||
target[i + 4] = obuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
free(ibuf);
|
||||
free(context);
|
||||
free(link);
|
||||
free(rleInfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
9
loader/tools/b2/cruncher.h
Normal file
9
loader/tools/b2/cruncher.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _cruncher_h_
|
||||
#define _cruncher_h_
|
||||
|
||||
#include "bb.h"
|
||||
#include "file.h"
|
||||
|
||||
bool crunch(File *aSource, File *aTarget, uint startAdress, uint decrFlag, bool isRelocated);
|
||||
|
||||
#endif // _cruncher_h_
|
||||
72
loader/tools/b2/file.c
Normal file
72
loader/tools/b2/file.c
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
#include "file.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void freeFile(File *aFile)
|
||||
{
|
||||
free(aFile->name);
|
||||
free(aFile->data);
|
||||
}
|
||||
|
||||
bool readFile(File *aFile, const char *fileName)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
struct stat fileStatus;
|
||||
|
||||
aFile->name = (char *)strdup(fileName);
|
||||
|
||||
if(stat(aFile->name, &fileStatus) == -1) {
|
||||
return false;
|
||||
}
|
||||
aFile->size = fileStatus.st_size;
|
||||
|
||||
fp = fopen(aFile->name, "rb");
|
||||
if(fp == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aFile->data = (byte *)malloc(aFile->size);
|
||||
if(aFile->data == NULL) {
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(fread(aFile->data, 1, aFile->size, fp) != aFile->size) {
|
||||
fclose(fp);
|
||||
free(aFile->data);
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool writeFile(File *aFile, const char *fileName)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
size_t length;
|
||||
char *ext;
|
||||
|
||||
length = strlen(fileName);
|
||||
aFile->name = (char *)malloc(length + 4);
|
||||
|
||||
if(aFile->name == NULL){
|
||||
return false;
|
||||
}
|
||||
|
||||
strncpy(aFile->name, fileName, length);
|
||||
strncpy(aFile->name + length, ".b2\0", 4);
|
||||
|
||||
fp = fopen(aFile->name, "wb");
|
||||
if(fp == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(fwrite(aFile->data, 1, aFile->size, fp) != aFile->size) {
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
19
loader/tools/b2/file.h
Normal file
19
loader/tools/b2/file.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef _file_h_
|
||||
#define _file_h_
|
||||
|
||||
#include "bb.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
size_t size;
|
||||
byte *data;
|
||||
} File;
|
||||
|
||||
void freeFile(File *aFile);
|
||||
bool readFile(File *aFile, const char *fileName);
|
||||
bool writeFile(File *aFile, const char *fileName);
|
||||
|
||||
#endif // _file_h_
|
||||
Loading…
Add table
Add a link
Reference in a new issue