init commit

This commit is contained in:
Egan Ford 2014-11-23 17:26:22 -07:00
commit 55d29a682a
23 changed files with 20660 additions and 0 deletions

12
MANIFEST Normal file
View File

@ -0,0 +1,12 @@
README
README.1st
MANIFEST
c2t
c2t.c
c2t.h
fake6502.h
miniz.h
windows/c2t.exe
windows/miniz.h
Makefile
makeheader

14
Makefile Normal file
View File

@ -0,0 +1,14 @@
all: c2t
clean:
rm c2t.h c2t
cd asm; make clean
c2t: c2t.h
gcc -Wall -O3 -o c2t c2t.c
c2t.h:
./makeheader

22
README.1st Normal file
View File

@ -0,0 +1,22 @@
Read the README for help.
Read c2t.c for build instructions.
Description of files:
README Documentation
README.1st This file
MANIFEST Files that should have been in this archive
c2t OS/X Intel binary
c2t.c c2t main
c2t.h c2t header including all 6502 ASM source and binaries
fake6502.h 6502 simulator source
miniz.h compression code source
windows/c2t.exe Windows Intel binary
windows/miniz.h compression code source (for windows)
To install c2t on OS/X type:
sudo cp c2t /usr/local/bin
sudo chmod 755 /usr/local/bin/c2t

267
README.md Normal file
View File

@ -0,0 +1,267 @@
c2t Documentation
AUTHOR
Egan Ford (egan@sense.net, datajerk@gmail.com)
DESCRIPTION
c2t is a command line tool that can convert binary code/data and/or
Apple-1/II Monitor text, as well as 140K disk images, into audio files
suitable for use with the Apple-1 and II (II, II+, //e) cassette interface.
c2t offers three high-speed options for the 64K Apple II+ and Apple //e:
8000 bps, 8820 bps, and 9600 bps. The c2t compression option may be used to
speedup the delivery of data with all three as well as the native 1333 bps
cassette interface ROM routines.
8820 bps (used to burn CDs) and 9600 bps are not compatible with all II+s
and //es. If you plan to distribute your audio files, then use 8000 bps.
8820 bps and 1333 bps is not an option for disk images.
High-speed and compress options require c2t's custom loader, and at this
time that limits you to a single segment. You can overcome this limitation
by concatenating all your code together and creating your own code to
shuffle your data around, or, pad each segment with enough zeros to align
subsequent segments with their target address and then use the compress
option to minimize this overhead.
Multi-segment audio files can be created for the Apple-1, II, II+, and //e
that can be loaded using the standard cassette interface ROM routines.
WHY?
I created this because I needed a convenient way to get data loaded into my
//e without dragging my computer out of my office (2nd floor) to my mancave
(basement). IOW, I needed an iPhone/iPad/mobile solution. That, and
CFFA3000 was sold out.
SYNOPSIS
Output of "c2t -h":
usage: c2t [-vh?]
c2t [-elp] input[.mon],[addr] ... [output.mon]
c2t {-1} [-cepr] input[.mon],[addr] ... [output.[aif[f]|wav[e]]]
c2t {-2} [-abcdef8pmqr] input[.mon],[addr] ... [output.[aif[f]|wav[e]]]
c2t [-n8] input.dsk ... [output.[aif[f]|wav[e]]]
-1 or -2 for Apple I or II tape format
-8 use 48k/8bit 8000 bps transfer (Apple II/II+/IIe 64K only)
Implies -2a. Negates -f and -d.
-a assembly autoload and run (Apple II/II+/IIe 64K only)
-b basic autoload and run (Apple II+/IIe 64K only)
Implies -2a.
-c compress data
-d use fast 44.1k/16bit transfer (Apple II/II+/IIe 64K only)
Implies -2a. Negates -f and -8. Use for burning CDs.
-e pad with $00 to end on page boundary
-f use faster 48k/8bit (9600 bps) transfer (Apple II/II+/IIe 64K only)
Implies -2a. Negates -8 and -d. Unreliable on some systems.
-h|? this help
-l long monitor format (24 bytes/line)
-m jump to monitor after autoload
-n do not format disks
-p pipe to stdout
-q parameters and data only (for use with custom client)
-r #, where # overrides the sample rate (e.g. -r 48000)
-t 10 second preamble (default 4) for real tape use
-v print version number and exit
input(s) without a .mon or .dsk extension is assumed to be a binary with a 4
byte header. If the header is missing then you must append ,load_address to
each binary input missing a header, e.g. filename,800. The load address
will be read as hex.
input(s) with a .mon extension expected input format:
0280: A2 FF 9A 20 8C 02 20 4F
0288: 03 4C 00 FF 20 9E 02 A9
A single input with a .dsk extension expected to be a 140K disk image.
output must have aiff, aif, wav, wave, or mon extention.
EXAMPLES
------------------------------------------------------------------------------
Input: Apple 1 monitor file with two segments. First 4 lines:
0: 00 05 00 10 00 00 00 00
8: 00 00 00 00 00 00 00 00
280: A9 00 85 07 A9 00 A8 AA
288: 85 06 A5 00 85 04 A5 01
Command:
c2t -1 a1mt.mon a1mt.aif
Output:
Reading a1mt.mon, type monitor, segment 1, start: 0x0000, length: 16
Reading a1mt.mon, type monitor, segment 2, start: 0x0280, length: 290
Writing a1mt.aif as Apple I formatted aiff.
To load up and run on your Apple I, type:
C100R
0.FR 280.3A1R
------------------------------------------------------------------------------
Input: cc65/ca65 Apple II binary with DOS 4-byte header. The DOS header
contains the starting address of the program.
Command:
c2t -2 hello hello.wav
Output:
Reading hello, type binary, segment 1, start: 0x0803, length: 2958
Writing hello.wav as Apple II formatted wave.
To load up and run on your Apple II, type:
CALL -151
803.1390R
803G
------------------------------------------------------------------------------
Input: cc65/ca65 Apple II binary with DOS 4-byte header. The DOS header
contains the starting address of the program.
Command:
c2t hello hello.mon
Output:
Reading hello, type binary, segment 1, start: 0x0803, length: 2958
Writing hello.mon as Apple formatted monitor.
Example hello.mon output:
0803: A2 FF 9A 2C 81
0808: C0 2C 81 C0 A9 91 A0 13
0810: 85 9B 84 9C A9 91 A0 13
0818: 85 96 84 97 A9 00 A0 D4
------------------------------------------------------------------------------
Input: Binary game without DOS header that should be loaded at $801.
Command:
c2t -2 moon.patrol,801 moon.patrol.aif
Output:
Reading moon.patrol, type binary, segment 1, start: 0x0801, length: 18460
Writing moon.patrol.aif as Apple II formatted aiff.
To load up and run on your Apple II, type:
CALL -151
801.501CR
801G
------------------------------------------------------------------------------
Input: Binary game without DOS header that should be loaded at $801 as fast
as possible while being compatible with all Apple IIs.
Command:
c2t -8c moon.patrol,801 moon.patrol.aif
Reading moon.patrol, type binary, segment 1, start: 0x0801, length: 18460
Writing moon.patrol.aif as Apple II formatted aiff.
start: 0x7226, length: 18393, deflated: 0.36%, data time:18.95, inflate time:6.83
WARNING: compression disabled: no significant gain (18.11)
To load up and run on your Apple II, type:
LOAD
NOTE: Compression was disabled because it didn't help.
------------------------------------------------------------------------------
Input: Binary game without DOS header that should be loaded at $800 as fast
as possible while being compatible with all Apple IIs.
Command:
c2t -8c super_puckman,800 super_puckman.wav
Reading super_puckman, type binary, segment 1, start: 0x0800, length: 30719
Writing super_puckman.wav as Apple II formatted wave.
start: 0x886C, length: 12691, deflated: 58.69%, data time:13.25, inflate time:5.79
To load up and run on your Apple II, type:
LOAD
------------------------------------------------------------------------------
Input: Three binary files to be loaded at three different addresses.
c2t -2 foo,801 foo.obj,3ffd foo.pic,2000 foo.aif
Reading foo, type binary, segment 1, start: 0x0801, length: 91
Reading foo.obj, type binary, segment 2, start: 0x3FFD, length: 18947
Reading foo.pic, type binary, segment 3, start: 0x2000, length: 8192
Writing foo.aif as Apple II formatted aiff.
To load up and run on your Apple II, type:
CALL -151
801.85BR 3FFD.89FFR 2000.3FFFR
------------------------------------------------------------------------------
Input: DOS 3.3 140K diskette image to be loaded with maximum II
compatibility. Disk will be formatted first.
Command:
c2t -8 dos33.dsk dos33.wav
Output:
Reading dos33.dsk, type disk, segment 1, start: 0x1000, length: 28672
Reading dos33.dsk, type disk, segment 2, start: 0x1000, length: 28672
Reading dos33.dsk, type disk, segment 3, start: 0x1000, length: 28672
Reading dos33.dsk, type disk, segment 4, start: 0x1000, length: 28672
Reading dos33.dsk, type disk, segment 5, start: 0x1000, length: 28672
Writing dos33.wav as Apple II formatted wave.
Segment: 0, start: 0x459B, length: 19044, deflated: 33.58%, data time:19, inflate time:7.68
Segment: 1, start: 0x74A5, length: 7002, deflated: 75.58%, data time:7, inflate time:3.70
Segment: 2, start: 0x8514, length: 2795, deflated: 90.25%, data time:3, inflate time:2.28
Segment: 3, start: 0x6CD4, length: 9003, deflated: 68.60%, data time:9, inflate time:4.33
Segment: 4, start: 0x6DE6, length: 8729, deflated: 69.56%, data time:9, inflate time:4.27
To load up and run on your Apple II, type:
LOAD
------------------------------------------------------------------------------

27
asm/Makefile Normal file
View File

@ -0,0 +1,27 @@
CL = cl65
CL_FLAGS = -t none --listing --list-bytes 100
#CL_FLAGS = -t apple1 -C apple1-16k.cfg --listing --list-bytes 100
CC = cl65
CC_FLAGS = --static-locals -t apple1 -C apple1-16k.cfg
C2T = c2t
ASRC = $(shell echo *.s)
AOBJ = $(ASRC:%.s=%.o)
ALST = $(ASRC:%.s=%.lst)
AMON = $(ASRC:%.s=%.mon)
ABIN = $(ASRC:%.s=%)
all: $(ABIN)
clean:
-rm -f $(ABIN) $(AOBJ) $(ALST) $(AMON)
%: %.s
$(CL) $(CL_FLAGS) $<
%: %.c
$(CC) $(CC_FLAGS) $<
%.mon: %
$(C2T) $< $@

117
asm/autoload.s Normal file
View File

@ -0,0 +1,117 @@
;autoload.s
org = $BF00 ; should be $BF00
cout = $FDED ; character out sub
crout = $FD8E ; CR out sub
prbyte = $FDDA
warm = $FF69 ; back to monitor
readblk = $FEFD
pointer = $06
endbas = $80C
;target = $1000
target = $801
chksum = $00
inflate = $BA00
inf_zp = $0
start:
.org endbas
move:
ldx #0
move1: lda moved,x
sta load,x
inx
bne move1 ; move 256 bytes
jmp load
moved:
.org org
load:
lda #<loadm
ldy #>loadm
jsr print
lda ld_beg
sta $3C ; starting tape address low
lda ld_beg+1
sta $3D ; starting tape address high
lda ld_end
sta $3E ; ending tape address low
lda ld_end+1
sta $3F ; ending tape address high
jsr readblk ; read block from tape
lda inf_flag ; if inf_flag = 0 runit
beq runit
inf:
jsr crout
lda #<infm
ldy #>infm
jsr print
lda inf_src ;src lsb
sta inf_zp+0
lda inf_src+1 ;src msb
sta inf_zp+1
lda inf_dst ;dst lsb
sta inf_zp+2
lda inf_dst+1 ;dst msb
sta inf_zp+3
jsr inflate
lda inf_end ;dst end +1 lsb
cmp inf_zp+2
bne error
lda inf_end+1 ;dst end +1 msb
cmp inf_zp+3
bne error
runit:
lda warm_flag ; if warm_flag = 1 warm boot
bne warmit
jmp (runcode)
warmit:
jmp warm ; run it
sumerror:
jsr crout
lda #<chkm
ldy #>chkm
jsr print
error:
lda #<errm
ldy #>errm
jsr print
jmp warm
print:
sta pointer
sty pointer+1
ldy #0
lda (pointer),y ; load initial char
print1: ora #$80
jsr cout
iny
lda (pointer),y
bne print1
rts
chkm: .asciiz "CHKSUM "
errm: .asciiz "ERROR"
infm: .asciiz "INFLATING "
ld_beg:
.org *+2
ld_end:
.org *+2
inf_src:
.org *+2
runcode:
inf_dst:
.org *+2
inf_end:
.org *+2
inf_flag:
.org *+1
warm_flag:
.org *+1
loadm:
;.asciiz "LOADING "
end:

545
asm/diskload2.s Normal file
View File

@ -0,0 +1,545 @@
;diskload2.s
; apple vectors
cout = $FDED ; character out sub
crout = $FD8E ; CR out sub
prbyte = $FDDA ; print byte in hex
tapein = $C060 ; read tape interface
warm = $FF69 ; back to monitor
clear = $FC58 ; clear screen
movecur = $FB5B ; move cursor to ch,a
dos = $9D84
asrom = $9D72
locrpl = $3E3 ; locate RWTS paramlist jsr
rwts = $3D9 ; RWTS jsr
cleos = $FC42 ; clear to end of screen
init = $A54F
motoroff= $C088 ; Turn drive motor off
motoron = $C089 ; Turn drive motor on
reboot = $FAA6 ; reboot machine
bell = $FBDD ; ding
rdkey = $FD0C ; read key
; my vectors
;print = $90CE ; from diskload.s
readtape= $9000
inflate = $9B00
; zero page parameters
begload = $00 ; begin load location LSB/MSB
endload = $02 ; end load location LSB/MSB
chksum = $04 ; checksum location
secnum = $05 ; loop var
trknum = $06 ; loop var
segcnt = $07 ; loop var
buffer = $08 ; MSB of RWTS buffer
trkcnt = $09 ; track counter (0-6)
pointer = $0A ; pointer LSB/MSB
prtptr = $0C ; pointer LSB/MSB
fmptr = $0E ; file manager pointer
inf_zp = $10 ; inflate vars (10)
temp = $1E ; temp var
ch = $24 ; cursor horizontal
preg = $48 ; mon p reg
; other vars
org = $9700 ; should be $9700
invsp = $60 ; inverse space for draw
data = $1000 ; 7 track dump from inflate
boot1o = $96D0 ; tape loaded boot 1 location
boot1 = $3D0 ; target boot 1 location
cmpbuf = $9200 ; buffer for sector check
count = $900
.org org
ldx #0 ; move 9cd0 to 3d0
move1:
lda boot1o,x
sta boot1,x
inx
cpx #$48
bne move1 ; branch on positive (0-127)
patch:
lda #$B3 ; hack since chksum could not be written to C000
sta $BFFF ; chksum was written do BFFF
start:
jsr clear ; clear screen
lda #<title ; print title
ldy #>title
jsr inv
; TRACK
lda #19 ; col 20
sta ch
lda #0 ; row 0
jsr movecur
lda #<track ; print track
ldy #>track
jsr print
lda #<header ; print header
ldy #>header
jsr print
ldx #35 ; length of line
jsr line
lda #<left ; print left side of grid
ldy #>left
jsr print
setupiob:
jsr locrpl ; locate rwts paramlist
sty pointer ; and save pointer
sta pointer+1
lda #1 ; table type
ldy #0 ; offset in RWTS
sta (pointer),y ; write it to RWTS
lda #6 * 16 ; slot 6
ldy #1 ; offset in RWTS
sta (pointer),y ; write it to RWTS
lda #1 ; drive number
ldy #2 ; offset in RWTS
sta (pointer),y ; write it to RWTS
lda #254 ; volume number
ldy #3 ; offset in RWTS
sta (pointer),y ; write it to RWTS
format: ; format the diskette
lda infdata+20 ; check noformat flag
bne endformat ; if not 0 jump to endformat
jsr status
lda #<formatm ; print formatting
ldy #>formatm
jsr print
;;; RWTS format (issues)
; lda #4 ; format(4) command
; ldy #$0C ; offset in RWTS
; sta (pointer),y ; write it to RWTS
; jsr locrpl ; locate rwts paramlist
; jsr rwts ; do it!
; bcs formaterror
; lda #0
; sta preg ; fix p reg so mon is happy
; jmp endformat
;;; file manager format (works!)
jsr $3DC ; load up Y and A
sty fmptr
sta fmptr+1
lda #$0B ; init command
ldy #0
sta (fmptr),y
lda #$9D ; DOS location
ldy #1
sta (fmptr),y
lda #254 ; volume number
ldy #4
sta (fmptr),y
lda #$01 ; drive number
ldy #5
sta (fmptr),y
lda #$06 ; slot number
ldy #6
sta (fmptr),y
lda #$00 ; scratch area LSB
ldy #$0C
sta (fmptr),y
lda #$92 ; scratch area MSB
ldy #$0D
sta (fmptr),y
jsr $3D6 ; doit!
ldy #$0A ; return code
lda (fmptr),y
beq endformat
formaterror:
jmp diskerror
endformat:
;;;begin segment loop (5)
lda #0 ; 256 bytes/sector
ldy #$0b ; offset in RWTS
sta (pointer),y ; write it to RWTS
lda #0 ; buffer LSB
ldy #8 ; offset in RWTS
sta (pointer),y ; write it to RWTS
lda #0
sta trknum ; start with track 0
lda #5
sta segcnt
segloop:
;;; fancy status here
; jsr status
; lda #<waitm ; print waiting for data
; ldy #>waitm
; jsr print
;countdown:
; lda #<count ; store begin location LSB
; sta begload
; lda #>count ; store begin location MSB
; sta begload+1
; lda #<count+4 ; store end location LSB
; sta endload
; lda #>count ; store end location MSB
; sta endload+1
;;;; hack readtape, fix later, POC for now
; lda #$60 ; return without check
; sta $9091
; jsr readtape ; get the code
; lda #$8A ; put TXA back
; sta $9091
;;;; end hack
; lda #18
; sta $24 ; horiz
; lda #22 ; vert
; jsr movecur ; move cursor to $24,a; 0 base
; jsr cleos
; lda #<count ; print count down
; ldy #>count
; jsr print
; lda count
; cmp #$B0
; bne countdown
; lda count+1
; cmp #$B0
; bne countdown
;;; end fancy stuff
;;; get 7 tracks from tape
load:
jsr status
lda #<loadm ; print loading data
ldy #>loadm
jsr flash
lda #<loadm2 ; print loading data
ldy #>loadm2
jsr print
sec
lda #5
sbc segcnt
asl
asl
tax
stx temp
lda infdata+2,x ; get sec
jsr cout
lda infdata+3,x ; get sec
beq second
jsr cout
second:
lda #<secm ; print sec
ldy #>secm
jsr print
ldx temp
lda infdata+0,x ; store begin location LSB
sta begload
lda infdata+1,x ; store begin location MSB
sta begload+1
lda #$00 ; store end location LSB
sta endload
lda #$90 ; store end location MSB
sta endload+1
jsr readtape ; get the code
inf:
; turn motor on to save 1-2 sec
ldx #$60 ; slot #6
lda motoron,x ; turn it on
jsr status
lda #<inflatem ; print inflating
ldy #>inflatem
jsr print
ldx temp
lda infdata+0,x ;src lsb
sta inf_zp+0
lda infdata+1,x ;src msb
sta inf_zp+1
lda #<data ;dst lsb
sta inf_zp+2
lda #>data ;dst msb
sta inf_zp+3
jsr inflate
lda #$00 ;dst end +1 lsb
cmp inf_zp+2
bne error
lda #$80 ;dst end +1 msb
cmp inf_zp+3
bne error
;;;begin track loop (7)
jsr status
lda #<writem ; print writing
ldy #>writem
jsr print
lda #>data
sta buffer
lda #7
sta trkcnt ; do 7 tracks/segment
trkloop:
lda trknum ; track number
ldy #4 ; offset in RWTS
sta (pointer),y ; write it to RWTS
; lda #0 ; seek(0) command
; ldy #$0C ; offset in RWTS
; sta (pointer),y ; write it to RWTS
; jsr locrpl ; locate rwts paramlist
; jsr rwts ; do it!
; bcs diskerror
;;;begin sector loop (16), backwards is faster, much faster
lda #$F
sta secnum
secloop:
;jsr draw_w ; write sector from buffer to disk
jsr draw_s ; write sector from buffer to disk
lda secnum ; sector number
ldy #5 ; offset in RWTS
sta (pointer),y ; write it to RWTS
lda buffer ; buffer MSB
clc
adc secnum
ldy #9 ; offset in RWTS
sta (pointer),y ; write it to RWTS
lda #2 ; read(1)/write(2) command
ldy #$0C ; offset in RWTS
sta (pointer),y ; write it to RWTS
jsr locrpl ; locate rwts paramlist
jsr rwts ; do it!
bcs diskerror
lda #0
sta preg ; fix p reg so mon is happy
;jsr draw_r ; read sector from disk to compare addr
;lda #>cmpbuf ; compare MSB
;ldy #9 ; offset in RWTS
;sta (pointer),y ; write it to RWTS
;lda #1 ; read(1)/write(2) command
;ldy #$0C ; offset in RWTS
;sta (pointer),y ; write it to RWTS
;jsr locrpl ; locate rwts paramlist
;jsr rwts ; do it!
;bcs diskerror
;lda #0
;sta preg ; fix p reg so mon is happy
;;; compare code
;jsr draw_s ; draw a space in the grid if OK
dec secnum
bpl secloop
;;;end sector loop
lda buffer ; buffer += $10
clc
adc #$10
sta buffer
inc trknum ; next track
dec trkcnt ;
bne trkloop ; 0, all done with 7 tracks
;;;end track loop
dec segcnt ;
beq done ; 0, all done with 5 segments
jmp segloop
;;;end segment loop
;;; prompt for data only load?
done:
jsr status
lda #<donem ; print done
ldy #>donem
jsr print
jsr bell
jsr rdkey
jmp reboot
error:
; turn motor off, just in case left on
ldx #$60 ; slot #6
lda motoroff,x ; turn it off
lda #<errorm ; print error
ldy #>errorm
jsr print
jmp warm
diskerror:
lda #0
sta preg ; fix p reg so mon is happy
jsr status
lda #<diskerrorm ; print error
ldy #>diskerrorm
jsr print
jmp warm
status:
lda #0
sta $24 ; horiz
lda #22 ; vert
jsr movecur ; move cursor to $24,a; 0 base
jmp cleos
draw_w: ; print a 'W' in the grid
clc
lda #4
adc secnum
tay
lda #4
adc trknum
ldx #'W'
jmp draw
draw_r: ; print a 'R' in the grid
clc
lda #4
adc secnum
tay
lda #4
adc trknum
ldx #'R'
jmp draw
draw_s: ; print a ' ' in the grid
clc
lda #4
adc secnum
tay
lda #4
adc trknum
ldx #invsp
draw: ; a=horiz, y=vert, x=letter
sta $24 ; horiz
tya
jsr movecur
txa
eor #$40
jsr cout
rts
line:
lda #'-'
ora #$80
loop0:
jsr cout
dex
bne loop0
jsr crout
rts
inv:
sta prtptr
sty prtptr+1
ldy #0
lda (prtptr),y ; load initial char
inv1: and #$3F
jsr cout
iny
lda (prtptr),y
bne inv1
rts
flash:
sta prtptr
sty prtptr+1
ldy #0
lda (prtptr),y ; load initial char
flash1: ora #$40
jsr cout
iny
lda (prtptr),y
bne flash1
rts
print:
sta prtptr
sty prtptr+1
ldy #0
lda (prtptr),y ; load initial char
print1: ora #$80
jsr cout
iny
lda (prtptr),y
bne print1
rts
title:
.asciiz "INSTA-DISK"
errorm:
.asciiz "ERROR"
diskerrorm:
.asciiz "DISK ERROR"
donem:
.asciiz "DONE. PRESS [RETURN] TO REBOOT."
inflatem:
.asciiz "INFLATING DATA "
loadm:
.asciiz "LOADING DATA"
loadm2:
.asciiz ", ETA "
secm:
.asciiz " SEC. "
formatm:
.asciiz "FORMATTING DISK "
waitm:
.asciiz "WAITING FOR DATA: "
writem:
.asciiz "WRITING DATA "
track:
.byte "TRACK",$0D,0
header:
.byte " 1111111111222222222233333",$0D
.byte " 01234567890123456789012345678901234",$0D
.byte " ",0
left:
.byte " 0|",$0D
.byte " 1|",$0D
.byte " 2|",$0D
.byte " 3|",$0D
.byte " 4|",$0D
.byte "S 5|",$0D
.byte "E 6|",$0D
.byte "C 7|",$0D
.byte "T 8|",$0D
.byte "O 9|",$0D
.byte "R A|",$0D
.byte " B|",$0D
.byte " C|",$0D
.byte " D|",$0D
.byte " E|",$0D
.byte " F|",$0D,0
infdata:
;.byte 0,0,0,0 ; LSB/MSB start, ETA in sec
;.byte 0,0,0,0 ; LSB/MSB start, ETA in sec
;.byte 0,0,0,0 ; LSB/MSB start, ETA in sec
;.byte 0,0,0,0 ; LSB/MSB start, ETA in sec
;.byte 0,0,0,0 ; LSB/MSB start, ETA in sec
;.byte 0 ; format flag, 1 = no format

524
asm/diskload3.s Normal file
View File

@ -0,0 +1,524 @@
;diskload3.s
; inflate - uncompress data stored in the DEFLATE format
; by Piotr Fusik <fox@scene.pl>
; Last modified: 2007-06-17
; Compile with xasm (http://xasm.atari.org/), for example:
; xasm inflate.asx /l /d:inflate=$b700 /d:inflate_data=$b900 /d:inflate_zp=$f0
; inflate is 509 bytes of code and initialized data
; inflate_data is 764 bytes of uninitialized data
; inflate_zp is 10 bytes on page zero
; hacked for apple ii and ca65 by Egan Ford <egan@sense.net>
; dates
; compile nodes
; changes
;EFF
.define equ =
inflate = $9B00
inflate_zp = $10
inflate_data = $9200
; Pointer to compressed data
inputPointer equ inflate_zp ; 2 bytes
; Pointer to uncompressed data
outputPointer equ inflate_zp+2 ; 2 bytes
; Local variables
getBit_buffer equ inflate_zp+4 ; 1 byte
getBits_base equ inflate_zp+5 ; 1 byte
inflateStoredBlock_pageCounter equ inflate_zp+5 ; 1 byte
inflateCodes_sourcePointer equ inflate_zp+6 ; 2 bytes
inflateDynamicBlock_lengthIndex equ inflate_zp+6 ; 1 byte
inflateDynamicBlock_lastLength equ inflate_zp+7 ; 1 byte
inflateDynamicBlock_tempCodes equ inflate_zp+7 ; 1 byte
inflateCodes_lengthMinus2 equ inflate_zp+8 ; 1 byte
inflateDynamicBlock_allCodes equ inflate_zp+8 ; 1 byte
inflateCodes_primaryCodes equ inflate_zp+9 ; 1 byte
; Argument values for getBits
GET_1_BIT equ $81
GET_2_BITS equ $82
GET_3_BITS equ $84
GET_4_BITS equ $88
GET_5_BITS equ $90
GET_6_BITS equ $a0
GET_7_BITS equ $c0
; Maximum length of a Huffman code
MAX_CODE_LENGTH equ 15
; Huffman trees
TREE_SIZE equ MAX_CODE_LENGTH+1
PRIMARY_TREE equ 0
DISTANCE_TREE equ TREE_SIZE
; Alphabet
LENGTH_SYMBOLS equ 1+29+2
DISTANCE_SYMBOLS equ 30
CONTROL_SYMBOLS equ LENGTH_SYMBOLS+DISTANCE_SYMBOLS
TOTAL_SYMBOLS equ 256+CONTROL_SYMBOLS
; Optional (recommend for c2t or DOS)
; DOS header location and size LSB/MSB
; .byte <START,>START,<(END-START),>(END-START)
; Uncompress DEFLATE stream starting from the address stored in inputPointer
; to the memory starting from the address stored in outputPointer
;; org inflate
.org inflate
START:
;; mvy #0 getBit_buffer
LDY #0
STY getBit_buffer
inflate_blockLoop:
; Get a bit of EOF and two bits of block type
; ldy #0
sty getBits_base
lda #GET_3_BITS
jsr getBits
;; lsr @
lsr A
php
tax
bne inflateCompressedBlock
; Copy uncompressed block
; ldy #0
sty getBit_buffer
jsr getWord
jsr getWord
sta inflateStoredBlock_pageCounter
; jmp inflateStoredBlock_firstByte
bcs inflateStoredBlock_firstByte
inflateStoredBlock_copyByte:
jsr getByte
inflateStoreByte:
jsr storeByte
bcc inflateCodes_loop
inflateStoredBlock_firstByte:
inx
bne inflateStoredBlock_copyByte
inc inflateStoredBlock_pageCounter
bne inflateStoredBlock_copyByte
inflate_nextBlock:
plp
bcc inflate_blockLoop
rts
inflateCompressedBlock:
; Decompress a block with fixed Huffman trees
; :144 dta 8
; :112 dta 9
; :24 dta 7
; :6 dta 8
; :2 dta 8 ; codes with no meaning
; :30 dta 5+DISTANCE_TREE
; ldy #0
inflateFixedBlock_setCodeLengths:
lda #4
cpy #144
;; rol @
rol A
sta literalSymbolCodeLength,y
cpy #CONTROL_SYMBOLS
bcs inflateFixedBlock_noControlSymbol
lda #5+DISTANCE_TREE
cpy #LENGTH_SYMBOLS
bcs inflateFixedBlock_setControlCodeLength
cpy #24
adc #2-DISTANCE_TREE
inflateFixedBlock_setControlCodeLength:
sta controlSymbolCodeLength,y
inflateFixedBlock_noControlSymbol:
iny
bne inflateFixedBlock_setCodeLengths
; mva #LENGTH_SYMBOLS inflateCodes_primaryCodes
LDA #LENGTH_SYMBOLS
STA inflateCodes_primaryCodes
dex
beq inflateCodes
; Decompress a block reading Huffman trees first
; Build the tree for temporary codes
jsr buildTempHuffmanTree
; Use temporary codes to get lengths of literal/length and distance codes
ldx #0
; sec
inflateDynamicBlock_decodeLength:
php
stx inflateDynamicBlock_lengthIndex
; Fetch a temporary code
jsr fetchPrimaryCode
; Temporary code 0..15: put this length
tax
bpl inflateDynamicBlock_verbatimLength
; Temporary code 16: repeat last length 3 + getBits(2) times
; Temporary code 17: put zero length 3 + getBits(3) times
; Temporary code 18: put zero length 11 + getBits(7) times
jsr getBits
; sec
adc #1
cpx #GET_7_BITS
;; scc:adc #7
BCC S1
adc #7
S1:
tay
lda #0
cpx #GET_3_BITS
;; scs:lda inflateDynamicBlock_lastLength
BCS S2
lda inflateDynamicBlock_lastLength
S2:
inflateDynamicBlock_verbatimLength:
iny
ldx inflateDynamicBlock_lengthIndex
plp
inflateDynamicBlock_storeLength:
bcc inflateDynamicBlock_controlSymbolCodeLength
;; sta literalSymbolCodeLength,x+
sta literalSymbolCodeLength,x
INX
cpx #1
inflateDynamicBlock_storeNext:
dey
bne inflateDynamicBlock_storeLength
sta inflateDynamicBlock_lastLength
; jmp inflateDynamicBlock_decodeLength
beq inflateDynamicBlock_decodeLength
inflateDynamicBlock_controlSymbolCodeLength:
cpx inflateCodes_primaryCodes
;; scc:ora #DISTANCE_TREE
BCC S3
ora #DISTANCE_TREE
S3:
;; sta controlSymbolCodeLength,x+
sta controlSymbolCodeLength,x
INX
cpx inflateDynamicBlock_allCodes
bcc inflateDynamicBlock_storeNext
dey
; ldy #0
; jmp inflateCodes
; Decompress a block
inflateCodes:
jsr buildHuffmanTree
inflateCodes_loop:
jsr fetchPrimaryCode
bcc inflateStoreByte
tax
beq inflate_nextBlock
; Copy sequence from look-behind buffer
; ldy #0
sty getBits_base
cmp #9
bcc inflateCodes_setSequenceLength
tya
; lda #0
cpx #1+28
bcs inflateCodes_setSequenceLength
dex
txa
;; lsr @
lsr A
ror getBits_base
inc getBits_base
;; lsr @
lsr A
rol getBits_base
jsr getAMinus1BitsMax8
; sec
adc #0
inflateCodes_setSequenceLength:
sta inflateCodes_lengthMinus2
ldx #DISTANCE_TREE
jsr fetchCode
; sec
sbc inflateCodes_primaryCodes
tax
cmp #4
bcc inflateCodes_setOffsetLowByte
inc getBits_base
;; lsr @
lsr A
jsr getAMinus1BitsMax8
inflateCodes_setOffsetLowByte:
eor #$ff
sta inflateCodes_sourcePointer
lda getBits_base
cpx #10
bcc inflateCodes_setOffsetHighByte
lda getNPlus1Bits_mask-10,x
jsr getBits
clc
inflateCodes_setOffsetHighByte:
eor #$ff
; clc
adc outputPointer+1
sta inflateCodes_sourcePointer+1
jsr copyByte
jsr copyByte
inflateCodes_copyByte:
jsr copyByte
dec inflateCodes_lengthMinus2
bne inflateCodes_copyByte
; jmp inflateCodes_loop
beq inflateCodes_loop
buildTempHuffmanTree:
; ldy #0
tya
inflateDynamicBlock_clearCodeLengths:
sta literalSymbolCodeLength,y
sta literalSymbolCodeLength+TOTAL_SYMBOLS-256,y
iny
bne inflateDynamicBlock_clearCodeLengths
; numberOfPrimaryCodes = 257 + getBits(5)
; numberOfDistanceCodes = 1 + getBits(5)
; numberOfTemporaryCodes = 4 + getBits(4)
ldx #3
inflateDynamicBlock_getHeader:
lda inflateDynamicBlock_headerBits-1,x
jsr getBits
; sec
adc inflateDynamicBlock_headerBase-1,x
sta inflateDynamicBlock_tempCodes-1,x
sta inflateDynamicBlock_headerBase+1
dex
bne inflateDynamicBlock_getHeader
; Get lengths of temporary codes in the order stored in tempCodeLengthOrder
; ldx #0
inflateDynamicBlock_getTempCodeLengths:
lda #GET_3_BITS
jsr getBits
ldy tempCodeLengthOrder,x
sta literalSymbolCodeLength,y
ldy #0
inx
cpx inflateDynamicBlock_tempCodes
bcc inflateDynamicBlock_getTempCodeLengths
; Build Huffman trees basing on code lengths (in bits)
; stored in the *SymbolCodeLength arrays
buildHuffmanTree:
; Clear nBitCode_totalCount, nBitCode_literalCount, nBitCode_controlCount
tya
; lda #0
;; sta:rne nBitCode_clearFrom,y+
R1:
sta nBitCode_clearFrom,y
INY
BNE R1
; Count number of codes of each length
; ldy #0
buildHuffmanTree_countCodeLengths:
ldx literalSymbolCodeLength,y
inc nBitCode_literalCount,x
inc nBitCode_totalCount,x
cpy #CONTROL_SYMBOLS
bcs buildHuffmanTree_noControlSymbol
ldx controlSymbolCodeLength,y
inc nBitCode_controlCount,x
inc nBitCode_totalCount,x
buildHuffmanTree_noControlSymbol:
iny
bne buildHuffmanTree_countCodeLengths
; Calculate offsets of symbols sorted by code length
; lda #0
ldx #-3*TREE_SIZE
buildHuffmanTree_calculateOffsets:
sta nBitCode_literalOffset+3*TREE_SIZE-$100,x
;; add nBitCode_literalCount+3*TREE_SIZE-$100,x
CLC
ADC nBitCode_literalCount+3*TREE_SIZE-$100,x
inx
bne buildHuffmanTree_calculateOffsets
; Put symbols in their place in the sorted array
; ldy #0
buildHuffmanTree_assignCode:
tya
ldx literalSymbolCodeLength,y
;; ldy:inc nBitCode_literalOffset,x
ldy nBitCode_literalOffset,x
inc nBitCode_literalOffset,x
sta codeToLiteralSymbol,y
tay
cpy #CONTROL_SYMBOLS
bcs buildHuffmanTree_noControlSymbol2
ldx controlSymbolCodeLength,y
;; ldy:inc nBitCode_controlOffset,x
ldy nBitCode_controlOffset,x
inc nBitCode_controlOffset,x
sta codeToControlSymbol,y
tay
buildHuffmanTree_noControlSymbol2:
iny
bne buildHuffmanTree_assignCode
rts
; Read Huffman code using the primary tree
fetchPrimaryCode:
ldx #PRIMARY_TREE
; Read a code from input basing on the tree specified in X,
; return low byte of this code in A,
; return C flag reset for literal code, set for length code
fetchCode:
; ldy #0
tya
fetchCode_nextBit:
jsr getBit
;; rol @
rol A
inx
;; sub nBitCode_totalCount,x
SEC
SBC nBitCode_totalCount,x
bcs fetchCode_nextBit
; clc
adc nBitCode_controlCount,x
bcs fetchCode_control
; clc
adc nBitCode_literalOffset,x
tax
lda codeToLiteralSymbol,x
clc
rts
fetchCode_control:
;; add nBitCode_controlOffset-1,x
CLC
ADC nBitCode_controlOffset-1,x
tax
lda codeToControlSymbol,x
sec
rts
; Read A minus 1 bits, but no more than 8
getAMinus1BitsMax8:
rol getBits_base
tax
cmp #9
bcs getByte
lda getNPlus1Bits_mask-2,x
getBits:
jsr getBits_loop
getBits_normalizeLoop:
lsr getBits_base
;; ror @
ror A
bcc getBits_normalizeLoop
rts
; Read 16 bits
getWord:
jsr getByte
tax
; Read 8 bits
getByte:
lda #$80
getBits_loop:
jsr getBit
;; ror @
ror A
bcc getBits_loop
rts
; Read one bit, return in the C flag
getBit:
lsr getBit_buffer
bne getBit_return
pha
; ldy #0
lda (inputPointer),y
;; inw inputPointer
INC inputPointer
BNE S4
INC inputPointer+1
S4:
sec
;; ror @
ror A
sta getBit_buffer
pla
getBit_return:
rts
; Copy a previously written byte
copyByte:
ldy outputPointer
lda (inflateCodes_sourcePointer),y
ldy #0
; Write a byte
storeByte:
sta (outputPointer),y
inc outputPointer
bne storeByte_return
inc outputPointer+1
inc inflateCodes_sourcePointer+1
storeByte_return:
rts
getNPlus1Bits_mask:
.byte GET_1_BIT,GET_2_BITS,GET_3_BITS,GET_4_BITS,GET_5_BITS,GET_6_BITS,GET_7_BITS
tempCodeLengthOrder:
.byte GET_2_BITS,GET_3_BITS,GET_7_BITS,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15
inflateDynamicBlock_headerBits:
.byte GET_4_BITS,GET_5_BITS,GET_5_BITS
inflateDynamicBlock_headerBase:
.byte 3,0,0 ; second byte is modified at runtime!
.org inflate_data
; Data for building trees
literalSymbolCodeLength:
.org *+256
controlSymbolCodeLength:
.org *+CONTROL_SYMBOLS
; Huffman trees
nBitCode_clearFrom:
nBitCode_totalCount:
.org *+2*TREE_SIZE
nBitCode_literalCount:
.org *+TREE_SIZE
nBitCode_controlCount:
.org *+2*TREE_SIZE
nBitCode_literalOffset:
.org *+TREE_SIZE
nBitCode_controlOffset:
.org *+2*TREE_SIZE
codeToLiteralSymbol:
.org *+256
codeToControlSymbol:
.org *+CONTROL_SYMBOLS
.byte 0,0,0 ; round out block
END: