#include #include #include #include #include #include #include "unalf.h" #include "addrs.h" int bad_checksum, bad_checksum_count = 0; char *out_filename; void dpoke(int addr, u16 value) { mem[addr] = value & 0xff; mem[addr + 1] = value >> 8; } u16 dpeek(int addr) { return mem[addr] | (mem[addr + 1] << 8); } void fix_filename(void) { char *p; if(!out_filename) return; if(opts.lowercase) { for(p = out_filename; *p; p++) *p = tolower(*p); } if(!opts.keepdot) { for(p = out_filename; *p; p++) if(p[0] == '.' && !p[1]) *p = '\0'; } } void make_backup(void) { char backup[PATH_MAX]; strcpy(backup, out_filename); strcat(backup, "~"); /* silently ignore errors! */ rename(out_filename, backup); } void extract_alf(void) { /* get ready to call fake 6502 stuff. set up memory like the Atari. */ dpoke(MEMTOP, 0xbc1f); while(read_alf_header()) { out_filename = (char *)(mem + alf_hdr_filename); fix_filename(); if(!file_wanted(out_filename)) { if(fseek(in_file, getquad(alf_hdr_compsize0), SEEK_CUR) != 0) { fputs(self, stderr); perror(": fseek"); exit(1); } out_filename = 0; continue; } if(!opts.quiet) { printf("%s %s\n", opts.testonly ? "Testing" : "Uncrunching", out_filename); } if(opts.extract_to_stdout) { out_file = stdout; } else { char *realname = out_filename; if(opts.testonly) { out_filename = "/dev/null"; } else if(!opts.overwrite) { make_backup(); } if(!(out_file = fopen(out_filename, "wb"))) { perror(out_filename); exit(1); } out_filename = realname; } bad_checksum = 0; uncrunch_file(); if(bad_checksum) bad_checksum_count++; if(!opts.extract_to_stdout) fclose(out_file); out_filename = 0; } if(opts.testonly && !opts.quiet) { if(bad_checksum_count) printf("%d file%s with bad checksum!\n", bad_checksum_count, bad_checksum_count == 1 ? "" : "s"); else printf("All files OK.\n"); } } static void chksum_err(void) { bad_checksum = 1; fprintf(stderr, "%s: checksum error on %s\n", self, out_filename); } void uncrunch_file(void) { lda_i(0x00); sta(L71AF); sta(L71B0); sta(outbuf_len_l); sta(outbuf_len_h); sta(L71B6); sta(L71B7); sta(L718C); sta(cksum_l); sta(cksum_h); lda_i(0x09); sta(shift_counter); lda_i(0x00); sta(L71AD); lda_i(0x02); sta(L71AE); lda_i(0x00); sta(stackptr_l); lda_i(0x60); sta(stackptr_h); jsr(setup_io_bufs); ldx_i(0x10); lda(inbuf_adr_l); sta(buf_adr_l); lda(inbuf_adr_h); sta(buf_adr_h); lda(inbuf_len_l); sta(buf_len_l); lda(inbuf_len_h); sta(buf_len_h); jsr(L7A19); sty(L718C); jsr(L79E7); lda(buf_len_l); ora(buf_len_h); bne(L75B1); rts(); L75B1: jsr(L76D0); lda(acc16_h); cmp_i(0x01); bne(uncrunch_blk); lda(acc16_l); cmp_i(0x01); bne(uncrunch_blk); jsr(write_output); lda(alf_hdr_cksum_l); cmp(cksum_l); bne(print_emsg_checksum); lda(alf_hdr_cksum_h); cmp(cksum_h); beq(cksum_ok); print_emsg_checksum: chksum_err(); cksum_ok: rts(); uncrunch_blk: lda(acc16_l); cmp_i(0x00); bne(L760B); lda(acc16_h); cmp_i(0x01); bne(L760B); jsr(init_counters); jsr(L76D0); lda(acc16_l); sta(L717D); sta(L7179); lda(acc16_h); sta(L717E); sta(L717A); lda(acc16_l); sta(L7177); sta(L7178); jsr(store_outbyte); jmp(L75B1); L760B: lda(acc16_l); sta(L717D); sta(L7175); lda(acc16_h); sta(L717E); sta(L7176); lda(acc16_h); cmp(L717C); bcc(L7641); lda(acc16_l); cmp(L717B); bcc(L7641); lda(L7179); sta(acc16_l); sta(L717D); lda(L717A); sta(acc16_h); sta(L717E); lda(L7178); sta(acc16_l); jsr(push_acc16); L7641: lda(L717E); beq(L7670); lda(L717D); sta(zp_b4); lda(L717E); sta(zp_b5); jsr(L7899); ldy_i(0x02); lda_ind_y(zp_b0); sta(acc16_l); jsr(push_acc16); ldy_i(0x00); lda_ind_y(zp_b0); sta(acc16_l); sta(L717D); iny(); lda_ind_y(zp_b0); sta(acc16_h); sta(L717E); jmp(L7641); L7670: lda(L717D); sta(acc16_l); sta(L7178); sta(L7177); lda(L717E); sta(acc16_h); jsr(push_acc16); L7683: lda(L71AF); ora(L71B0); beq(L7694); jsr(pop_acc16); jsr(store_outbyte); jmp(L7683); L7694: jsr(L78C2); lda(L7175); sta(acc16_l); sta(L7179); lda(L7176); sta(acc16_h); sta(L717A); lda(L717B); sta(zp_b4); lda(L717C); sta(zp_b5); cmp(L71AE); bcc(L76CD); lda(zp_b4); cmp(L71AD); bcc(L76CD); lda(shift_counter); cmp_i(0x0C); beq(L76CD); inc(shift_counter); asl(L71AD); rol(L71AE); L76CD: jmp(L75B1); } void L76D0(void) { L76D0: lda(L71B6); sta(zp_b8); lda(L71B7); sta(zp_b9); ldx_i(0x02); L76DC: lsr(zp_b9); ror(zp_b8); dex(); bpl(L76DC); lda(zp_b8); sta(L71AA); lda(zp_b9); sta(L71AB); lda(inbuf_len_l); sec(); sbc(zp_b8); sta(zp_bc); lda(inbuf_len_h); sbc(zp_b9); sta(zp_bd); lda(zp_bd); bne(L770F); lda(zp_bc); cmp_i(0x03); bcs(L770F); ldx(L718C); bpl(L771C); cmp_i(0x02); bcc(L7712); L770F: jmp(L779B); /* ---------------------------------------------------------------------------- */ L7712: #if 0 ldx_i(0x0A); ldy_i(0x0A); jsr(printstr); jmp(cleanup_and_exit); #endif fprintf(stderr, "%s: unknown error (L7712)\n", self); exit(1); /* ---------------------------------------------------------------------------- */ L771C: tay(); dey(); ldx(inbuf_adr_l); stx(zp_be); ldx(inbuf_adr_h); stx(zp_bf); lda(inbuf_adr_l); clc(); adc(zp_b8); sta(zp_b8); lda(inbuf_adr_h); adc(zp_b9); sta(zp_b9); L7737: lda_ind_y(zp_b8); sta_ind_y(zp_be); dey(); bpl(L7737); lda(inbuf_len_l); sec(); sbc(zp_bc); sta(buf_len_l); lda(inbuf_len_h); sbc_i(0x00); sta(buf_len_h); lda(inbuf_adr_l); clc(); adc(zp_bc); sta(buf_adr_l); lda(inbuf_adr_h); adc_i(0x00); sta(buf_adr_h); ldx_i(0x10); jsr(L7A19); sty(L718C); bpl(L7771); cpy_i(0x88); beq(L7771); // jmp(cleanup_and_exit); exit(0); /* ---------------------------------------------------------------------------- */ L7771: jsr(L79E7); lda(L71AA); sta(zp_b8); lda(L71AB); sta(zp_b9); ldx_i(0x02); L7780: asl(zp_b8); rol(zp_b9); dex(); bpl(L7780); lda(L71B6); sec(); sbc(zp_b8); sta(L71B6); lda(L71B7); sbc(zp_b9); sta(L71B7); jmp(L76D0); /* ---------------------------------------------------------------------------- */ L779B: lda(zp_b8); sta(zp_bc); clc(); adc(inbuf_adr_l); sta(zp_b8); lda(zp_b9); sta(zp_bd); adc(inbuf_adr_h); sta(zp_b9); ldy_i(0x00); lda(L71B6); and_i(0x07); bne(L77E1); lda_ind_y(zp_b8); sta(acc16_h); iny(); lda_ind_y(zp_b8); sta(acc16_l); L77C0: lda_i(0x0F); sec(); sbc(shift_counter); tax(); L77C7: lsr(acc16_h); ror(acc16_l); dex(); bpl(L77C7); lda(shift_counter); clc(); adc(L71B6); sta(L71B6); lda_i(0x00); adc(L71B7); sta(L71B7); rts(); /* ---------------------------------------------------------------------------- */ L77E1: ldx_i(0x02); L77E3: lda_ind_y(zp_b8); sta_abs_x(L7189); iny(); dex(); bpl(L77E3); lda(L71B6); and_i(0x07); tax(); dex(); L77F3: asl(L7189); rol(L718A); rol(L718B); dex(); bpl(L77F3); lda(L718A); sta(acc16_l); lda(L718B); sta(acc16_h); jmp(L77C0); } void L7A19(void) { L7A19: lda(alf_hdr_compsize2); ora(alf_hdr_compsize3); beq(L7A28); L7A21: jsr(readblock); Y = 1; /* CIO would set this */ jsr(L7A5D); rts(); L7A28: lda(alf_hdr_compsize1); cmp(buf_len_h); bcc(L7A40); beq(L7A34); bcs(L7A21); L7A34: lda(alf_hdr_compsize0); cmp(buf_len_l); bcc(L7A40); beq(L7A40); bcs(L7A21); L7A40: lda(alf_hdr_compsize0); sta(buf_len_l); lda(alf_hdr_compsize1); sta(buf_len_h); lda(buf_len_l); ora(buf_len_h); beq(L7A57); jsr(readblock); Y = 1; /* CIO would set this */ L7A57: ldy_i(0x88); jsr(L7A5D); rts(); } void L7A5D(void) { L7A5D: lda(alf_hdr_compsize0); sec(); sbc(buf_len_l); sta(alf_hdr_compsize0); lda(alf_hdr_compsize1); sbc(buf_len_h); sta(alf_hdr_compsize1); lda(alf_hdr_compsize2); sbc_i(0x00); sta(alf_hdr_compsize2); rts(); } void setup_io_bufs(void) { setup_io_bufs: lda(MEMTOP_lo); sec(); sbc_i(0xDC); sta(inbuf_len_l); lda(MEMTOP_hi); sbc_i(0x7F); sta(inbuf_len_h); lsr(inbuf_len_h); ror(inbuf_len_l); lda(inbuf_len_h); cmp_i(0x1F); bcc(L79A0); lda_i(0x00); sta(inbuf_len_l); lda_i(0x1F); sta(inbuf_len_h); L79A0: lda_i(0xDC); sta(inbuf_adr_l); lda_i(0x7F); sta(inbuf_adr_h); lda_i(0xDC); clc(); adc(inbuf_len_l); sta(outbuf_adr_l); sta(outbuf_ptr_l); lda_i(0x7F); adc(inbuf_len_h); sta(outbuf_adr_h); sta(outbuf_ptr_h); rts(); } void init_counters(void) { init_counters: lda_i(0x09); sta(shift_counter); lda_i(0x00); sta(L71AD); lda_i(0x02); sta(L71AE); lda_i(0x02); sta(L717B); lda_i(0x01); sta(L717C); rts(); } /* save decrunched byte in outbuf, update checksum, write outbuf if full */ void store_outbyte(void) { ldy_i(0x00); lda(acc16_l); sta_ind_y(outbuf_ptr_l); clc(); adc(cksum_l); sta(cksum_l); lda_i(0x00); adc(cksum_h); sta(cksum_h); inc(outbuf_ptr_l); bne(out_ptr_hi_ok); inc(outbuf_ptr_h); out_ptr_hi_ok: inc(outbuf_len_l); bne(out_len_hi_ok); inc(outbuf_len_h); out_len_hi_ok: lda(outbuf_len_h); cmp(inbuf_len_h); bcc(outbuf_not_full); lda(outbuf_len_l); cmp(inbuf_len_l); bcc(outbuf_not_full); lda(outbuf_adr_l); sta(buf_adr_l); lda(outbuf_adr_h); sta(buf_adr_h); lda(outbuf_len_l); sta(buf_len_l); lda(outbuf_len_h); sta(buf_len_h); /* TODO: call C writeblock() */ ldx_i(0x30); jsr(writeblock); bpl(init_outbuf); #if 0 /* ldx #emsg_checksum */ print_emsg_write_output_2: ldx_i(0xD5); ldy_i(0x72); jsr(printstr); cleanup_and_exit: pla(); pla(); pla(); pla(); jmp(exit); #endif chksum_err(); /* ---------------------------------------------------------------------------- */ init_outbuf: lda(outbuf_adr_l); sta(outbuf_ptr_l); lda(outbuf_adr_h); sta(outbuf_ptr_h); lda_i(0x00); sta(outbuf_len_l); sta(outbuf_len_h); outbuf_not_full: rts(); } /* ---------------------------------------------------------------------------- */ /* push 2 byte 'register' to software stack */ void push_acc16(void) { push_acc16: ldy_i(0x00); lda(acc16_l); sta_ind_y(stackptr_l); iny(); lda(acc16_h); sta_ind_y(stackptr_l); lda(stackptr_l); clc(); adc_i(0x02); sta(stackptr_l); bcc(L790C); inc(stackptr_h); L790C: lda(stackptr_h); cmp_i(0x70); bcc(L791C); #if 0 /* ldx #emsg_stk_overrun */ print_emsg_stk_overrun: ldx_i(0x25); ldy_i(0x79); jsr(printstr); jmp(cleanup_and_exit); #endif fprintf(stderr, "%s: stack overrun\n", self); exit(1); /* ---------------------------------------------------------------------------- */ L791C: inc(L71AF); bne(L7924); inc(L71B0); L7924: rts(); } void pop_acc16(void) { /* pop 2 byte 'register' from software stack */ pop_acc16: lda(stackptr_l); sec(); sbc_i(0x02); sta(stackptr_l); lda(stackptr_h); sbc_i(0x00); sta(stackptr_h); ldy_i(0x00); lda_ind_y(stackptr_l); sta(acc16_l); iny(); lda_ind_y(stackptr_l); sta(acc16_h); lda(stackptr_h); cmp_i(0x60); bcs(L796C); #if 0 /* ldx #emsg_stk_underrun */ print_emsg_stk_underrun: ldx_i(0x34); ldy_i(0x79); jsr(printstr); jmp(cleanup_and_exit); #endif fprintf(stderr, "%s: stack underrun\n", self); exit(1); /* ---------------------------------------------------------------------------- */ L796C: lda(L71AF); bne(L7974); dec(L71B0); L7974: dec(L71AF); rts(); } void L79E7(void) { L79E7: lda(buf_adr_l); clc(); adc(buf_len_l); sta(zp_be); lda(buf_adr_h); adc(buf_len_h); sta(zp_bf); ldx_i(0x02); bne(L7A0A); L79FC: ldy_i(0x00); tya(); sta_ind_y(zp_be); inc(zp_be); bne(L7A07); inc(zp_bf); L7A07: dex(); bmi(L7A18); L7A0A: lda(zp_bf); cmp(outbuf_adr_h); bcc(L79FC); lda(zp_be); cmp(outbuf_adr_l); bcc(L79FC); L7A18: rts(); } void L7899(void) { L7899: lda(zp_b4); sta(zp_b0); lda(zp_b5); sta(zp_b1); asl(zp_b0); rol(zp_b1); lda(zp_b0); clc(); adc(zp_b4); sta(zp_b0); lda(zp_b1); adc(zp_b5); sta(zp_b1); lda(zp_b0); clc(); adc(L7181); sta(zp_b0); lda(zp_b1); adc(L7182); sta(zp_b1); rts(); } void L78C2(void) { L78C2: lda(L717B); sta(zp_b4); lda(L717C); sta(zp_b5); jsr(L7899); lda(L7177); sta(acc16_l); ldy_i(0x02); sta_ind_y(zp_b0); lda(L7179); sta(acc16_l); lda(L717A); sta(acc16_h); ldy_i(0x00); lda(acc16_l); sta_ind_y(zp_b0); iny(); lda(acc16_h); sta_ind_y(zp_b0); inc(L717B); bne(L78F5); inc(L717C); L78F5: rts(); } void write_output(void) { write_output: lda(outbuf_len_l); ora(outbuf_len_h); bne(have_output); rts(); /* ---------------------------------------------------------------------------- */ have_output: lda(outbuf_adr_l); sta(buf_adr_l); lda(outbuf_adr_h); sta(buf_adr_h); lda(outbuf_len_l); sta(buf_len_l); lda(outbuf_len_h); sta(buf_len_h); ldx_i(0x30); jsr(writeblock); rts(); }