mirror of
https://github.com/exoticorn/microw8.git
synced 2026-01-20 11:16:42 +01:00
178 lines
4.3 KiB
Plaintext
178 lines
4.3 KiB
Plaintext
import "env.memory" memory(4);
|
|
|
|
global mut base_end: i32 = 0;
|
|
|
|
export fn load_uw8(module_size: i32) -> i32 {
|
|
let lazy version = 0?0 - 1;
|
|
if version < 0 {
|
|
return module_size;
|
|
}
|
|
|
|
let module_end = 0x1e000 + module_size;
|
|
if version & 1 {
|
|
module_end = uncompress(1, 0x1e001);
|
|
} else {
|
|
copy(0x1e000, 0, module_size);
|
|
}
|
|
copy(0, 0x3c800, 8);
|
|
|
|
let base_start = 0x3c808;
|
|
let dest = 8;
|
|
let src = 0x1e001;
|
|
|
|
loop sections {
|
|
if src < module_end & (base_start >= base_end | src?0 <= base_start?0) {
|
|
let lazy length2 = copy_section(dest, src);
|
|
dest = dest + length2;
|
|
if base_start < base_end & src?0 == base_start?0 {
|
|
base_start = base_start + section_size(base_start);
|
|
}
|
|
src = src + length2;
|
|
branch sections;
|
|
}
|
|
|
|
if base_start < base_end {
|
|
let lazy length3 = copy_section(dest, base_start);
|
|
dest = dest + length3;
|
|
base_start = base_start + length3;
|
|
branch sections;
|
|
}
|
|
}
|
|
|
|
dest
|
|
}
|
|
|
|
fn section_size(ptr: i32) -> i32 {
|
|
let p = ptr + 1;
|
|
let l = 0;
|
|
let shift = 0;
|
|
loop size {
|
|
let lazy b = p?0;
|
|
l = l | ((b & 127) << shift);
|
|
shift = shift + 7;
|
|
p = p + 1;
|
|
branch_if b & 128: size;
|
|
}
|
|
p - ptr + l
|
|
}
|
|
|
|
fn copy_section(dest: i32, src: i32) -> i32 {
|
|
let lazy length = section_size(src);
|
|
copy(dest, src, length);
|
|
length
|
|
}
|
|
|
|
fn copy(dest: i32, src: i32, len: i32) {
|
|
if len > 0 {
|
|
loop bytes {
|
|
(dest + (len := len - 1))?0 = (src + len)?0;
|
|
branch_if len: bytes
|
|
}
|
|
}
|
|
}
|
|
|
|
// upkr unpacker
|
|
|
|
global mut upkr_src_ptr: i32 = 0;
|
|
global mut upkr_state: i32 = 0;
|
|
|
|
// uncompress upkr compressed data at `src` into the buffer at `dest`
|
|
// returns the end of the uncompressed data
|
|
export fn uncompress(src_ptr: i32, dest_ptr: i32) -> i32 {
|
|
upkr_src_ptr = src_ptr;
|
|
upkr_state = 0;
|
|
|
|
let offset: i32;
|
|
|
|
let byte: i32;
|
|
|
|
let i: i32;
|
|
loop init_contexts {
|
|
i?0x3c000 = 0x80;
|
|
branch_if (i := i + 1) < 256 + 1 + 128: init_contexts
|
|
}
|
|
|
|
let prev_was_match: i32;
|
|
|
|
block finished {
|
|
loop unpack_loop {
|
|
if upkr_bit(0) {
|
|
let inline new_offset = if prev_was_match { 1 } else { upkr_bit(256) };
|
|
if new_offset {
|
|
offset = upkr_length(257) - 1;
|
|
branch_if !offset: finished
|
|
}
|
|
let length = upkr_length(257 + 64);
|
|
loop copy {
|
|
dest_ptr?0 = (dest_ptr - offset)?0;
|
|
dest_ptr = dest_ptr + 1;
|
|
branch_if (length := length - 1): copy;
|
|
}
|
|
prev_was_match = 1;
|
|
} else {
|
|
// literal
|
|
i = 0;
|
|
byte = 1;
|
|
loop literal {
|
|
byte = (byte << 1) | upkr_bit(byte);
|
|
branch_if (i := i + 1) < 8: literal;
|
|
}
|
|
dest_ptr?0 = byte;
|
|
dest_ptr = dest_ptr + 1;
|
|
prev_was_match = 0;
|
|
}
|
|
branch unpack_loop;
|
|
}
|
|
}
|
|
|
|
dest_ptr
|
|
}
|
|
|
|
fn upkr_length(context_index: i32) -> i32 {
|
|
let length: i32;
|
|
let bit_pos: i32;
|
|
loop bits {
|
|
if upkr_bit(context_index) {
|
|
length = length | (upkr_bit(context_index + 1) << bit_pos);
|
|
context_index = context_index + 2;
|
|
bit_pos = bit_pos + 1;
|
|
branch bits;
|
|
}
|
|
}
|
|
length | (1 << bit_pos)
|
|
}
|
|
|
|
fn upkr_bit(context_index: i32) -> i32 {
|
|
let prob = context_index?0x3c000;
|
|
|
|
loop refill {
|
|
if upkr_state < 1<<12 {
|
|
upkr_state = (upkr_state << 8) | upkr_src_ptr?0;
|
|
upkr_src_ptr = upkr_src_ptr + 1;
|
|
branch refill;
|
|
}
|
|
}
|
|
|
|
let lazy state_low = upkr_state & 0xff;
|
|
let bit = state_low < prob;
|
|
|
|
if bit {
|
|
upkr_state = prob * (upkr_state >> 8) + state_low;
|
|
prob = prob + ((0x108 - prob) >> 4);
|
|
} else {
|
|
upkr_state = (0x100 - prob) * (upkr_state >> 8) + state_low - prob;
|
|
prob = prob - ((prob + 8) >> 4);
|
|
}
|
|
|
|
context_index?0x3c000 = prob;
|
|
|
|
bit
|
|
}
|
|
|
|
start fn unpack_base() {
|
|
base_end = uncompress(0, 0x3c800);
|
|
}
|
|
|
|
data 0 {
|
|
file("../target/base.upk")
|
|
} |