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:

168
asm/diskload8000.s Normal file
View File

@ -0,0 +1,168 @@
;diskload8000.s
org = $9000 ; should be $9000
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
endbas = $80C
target = $1000
; zero page parameters
begload = $00 ; begin load location LSB/MSB
endload = $02 ; end load location LSB/MSB
chksum = $04 ; checksum location
pointer = $0C ; LSB/MSB pointer
start:
.org endbas
move: ; end of BASIC, move code to readtape addr
ldx #0
move1:
lda moved,x
sta readtape,x
; lda moved+256,x
; sta readtape+256,x
inx
bne move1
phase1:
jsr crout ; print LOADING...
lda #<loadm
ldy #>loadm
jsr print
; diskload2 ORG
lda #$D0 ; store begin location LSB
sta begload
lda #$96 ; store begin location MSB
sta begload+1
; end of DOS + 1 for comparison
lda #$00 ; store end location LSB
sta endload
lda #$C0 ; store end location MSB
sta endload+1
jsr readtape ; get the code
jmp $9700 ; run it
loadm:
.byte "LOADING INSTA-DI8K, ETA "
loadsec: ; 10 bytes for "XX SEC. ",$00
.byte 0,0,0,0,0,0,0,0,0,0
moved:
.org org ; $9000
readtape:
lda begload ; load begin LSB location
sta store+1 ; store it
lda begload+1 ; load begin MSB location
sta store+2 ; store it
ldx #0 ; set X to 0
lda #1 ; set A to 0
nsync: bit tapein ; 4 cycles, sync bit ; first pulse
bpl nsync ; 2 + 1 cycles
main: ldy #0 ; 2 set Y to 0
psync: bit tapein ;
bmi psync
ploop: iny ; 2 cycles
bit tapein ; 4 cycles
bpl ploop ; 2 +1 if branch, +1 if in another page
; total ~9 cycles
cpy #$40 ; 2 cycles if Y - $40 > 0 endcode (770Hz)
bpl endcode ; 2(3)
cpy #$15 ; 2 cycles if Y - $15 > 0 main (2000Hz)
bpl main ; 2(3)
cpy #$07 ; 2, if Y<, then clear carry, if Y>= set carry
store: rol store+1,x ; 7, roll carry bit into store
ldy #0 ; 2
asl ; 2 A*=2
bne main ; 2(3)
lda #1 ; 2
inx ; 2 cycles
bne main ; 2(3)
inc store+2 ; 6 cycles
jmp main ; 3 cycles
; 34 subtotal max
; 36 subtotal max
endcode:
txa ; write end of file location + 1
clc
adc store+1
sta store+1
bcc endcheck ; LSB didn't roll over to zero
inc store+2 ; did roll over to zero, inc MSB
endcheck: ; check for match of expected length
lda endload
cmp store+1
bne error
lda endload+1
cmp store+2
bne error
jsr ok
sumcheck:
jsr crout
lda #<chkm
ldy #>chkm
jsr print
lda #0
sta pointer
lda begload+1
sta pointer+1
lda #$ff ; init checksum
ldy begload
sumloop:
eor (pointer),y
;last page?
ldx pointer+1
cpx endload+1
beq last
iny
bne sumloop
inc pointer+1
bne sumloop
last:
iny
cpy endload
bcc sumloop
ldy #0
eor (endload),y
; sta chksum
; lda chksum
bne error
jmp ok ; return to caller
error:
lda #<errm
ldy #>errm
jsr print
jmp warm
ok:
lda #<okm
ldy #>okm
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 "
okm: .asciiz "OK"
errm: .asciiz "ERROR"
end:

174
asm/diskload9600.s Normal file
View File

@ -0,0 +1,174 @@
;diskload9600.s
org = $9000 ; should be $9000
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
endbas = $80C
target = $1000
; zero page parameters
begload = $00 ; begin load location LSB/MSB
endload = $02 ; end load location LSB/MSB
chksum = $04 ; checksum location
pointer = $0C ; LSB/MSB pointer
start:
.org endbas
move: ; end of BASIC, move code to readtape addr
ldx #0
move1:
lda moved,x
sta readtape,x
; lda moved+256,x
; sta readtape+256,x
inx
bne move1
phase1:
jsr crout ; print LOADING...
lda #<loadm
ldy #>loadm
jsr print
; diskload2 ORG
lda #$D0 ; store begin location LSB
sta begload
lda #$96 ; store begin location MSB
sta begload+1
; end of DOS + 1 for comparison
lda #$00 ; store end location LSB
sta endload
lda #$C0 ; store end location MSB
sta endload+1
jsr readtape ; get the code
jmp $9700 ; run it
loadm:
.byte "LOADING INSTA-DISK, ETA "
loadsec: ; 10 bytes for "XX SEC. ",$00
.byte 0,0,0,0,0,0,0,0,0,0
moved:
.org org ; $9000
readtape:
lda begload ; load begin LSB location
sta store+1 ; store it
lda begload+1 ; load begin MSB location
sta store+2 ; store it
lda #$ff ; init checksum
sta chksum
wait: bit tapein
bpl wait
waithi: bit tapein ; Wait for input to go high.
bmi waithi
pre: lda #1 ; Load sentinel bit
ldx #0 ; Clear data index
clc ; Clear carry (byte complete flag)
data: bcc waitlo ; Skip if byte not complete
store: sta target,x ; Store data byte
eor chksum ; compute checksum
sta chksum ; store checksum
lda #1 ; Re-load sentinel bit
waitlo: bit tapein ; Wait for input to go low
bpl waitlo
bcc poll9 ; Poll at +9 cycles if no store
inx ; Stored, so increment data index
bne poll13 ; Poll at +13 cycles if no carry
inc store+2 ; Increment data page
bne poll21 ; (always) poll at +21 cycles
one: sec ; one bit detected
rol ; shift it into A
jmp data ; and go handle data (C = sentinel)
zero: clc ; zero bit detected
rol ; shift it into A
jmp data ; and go handle data (C = sentinel)
poll9: bit tapein
bpl zero ; zero bit (short)(9-15 cycles)
poll13: bit tapein ; (2 cycles early if branched here)
bpl zero ; zero bit (15-21 cycles)
poll21: bit tapein
bpl zero ; zero bit (21-27 cycles)
bit tapein
bpl zero ; zero bit (27-33 cycles)
bit tapein
bpl zero ; zero bit (33-39 cycles)
bit tapein
bpl zero ; zero bit (39-45 cycles)
bit tapein
bpl zero ; zero bit (45-51 cycles)
bit tapein
bpl zero ; zero bit (51-57 cycles)
bit tapein
bpl zero ; one bit (57-63 cycles)
bit tapein
bpl one ; one bit (63-69 cycles)
bit tapein
bpl one ; one bit (69-75 cycles)
bit tapein
bpl one ; one bit (75-81 cycles)
bit tapein
bpl one ; one pulse (81-87 cycles)
bit tapein
bpl pre ; pre pulse (87-93 cycles)
bit tapein
bpl pre ; pre pulse (93-99 cycles)
bit tapein
bpl pre ; pre pulse (99-105 cycles)
; low freq signals end of data
endcode:
txa ; write end of file location + 1
clc
adc store+1
sta store+1
bcc endcheck ; LSB didn't roll over to zero
inc store+2 ; did roll over to zero, inc MSB
endcheck: ; check for match of expected length
lda endload
cmp store+1
bne error
lda endload+1
cmp store+2
bne error
jsr ok
sumcheck:
jsr crout
lda #<chkm
ldy #>chkm
jsr print
lda chksum
bne error
jmp ok ; return to caller
error:
lda #<errm
ldy #>errm
jsr print
jmp warm
ok:
lda #<okm
ldy #>okm
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 "
okm: .asciiz "OK"
errm: .asciiz "ERROR"
end:

194
asm/fastload8000.s Normal file
View File

@ -0,0 +1,194 @@
;fastload8000.s
org = $BE80 ; should be $BE80
cout = $FDED ; character out sub
crout = $FD8E ; CR out sub
prbyte = $FDDA
warm = $FF69 ; back to monitor
tapein = $C060
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 fast,x
inx
bne move1 ; move 256 bytes
; ldx #0
move2: lda moved+256,x
sta fast+256,x
inx
bpl move2 ; only 128 bytes to move
jmp fast
moved:
.org org
fast:
lda #<loadm
ldy #>loadm
jsr print
lda ld_beg ; load begin LSB location
sta store+1 ; store it
lda ld_beg+1 ; load begin MSB location
sta store+2 ; store it
ldx #0 ; set X to 0
lda #1 ; set A to 0
nsync: bit tapein ; 4 cycles, sync bit ; first pulse
bpl nsync ; 2 + 1 cycles
main: ldy #0 ; 2 set Y to 0
psync: bit tapein ;
bmi psync
ploop: iny ; 2 cycles
bit tapein ; 4 cycles
bpl ploop ; 2 +1 if branch, +1 if in another page
; total ~9 cycles
cpy #$40 ; 2 cycles if Y - $40 > 0 endcode (770Hz)
bpl endcode ; 2(3)
cpy #$15 ; 2 cycles if Y - $15 > 0 main (2000Hz)
bpl main ; 2(3)
cpy #$07 ; 2, if Y<, then clear carry, if Y>= set carry
store: rol store+1,x ; 7, roll carry bit into store
ldy #0 ; 2
asl ; 2 A*=2
bne main ; 2(3)
lda #1 ; 2
inx ; 2 cycles
bne main ; 2(3)
inc store+2 ; 6 cycles
jmp main ; 3 cycles
; 34 subtotal max
; 36 subtotal max
endcode:
txa ; write end of file location + 1
clc
adc store+1
sta store+1
bcc endcheck ; LSB didn't roll over to zero
inc store+2 ; did roll over to zero, inc MSB
endcheck: ; check for match of expected length
lda ld_end
cmp store+1
bne error
lda ld_end+1
cmp store+2
bne error
sumcheck:
lda #0
sta pointer
lda ld_beg+1
sta pointer+1
lda #$ff ; init checksum
ldy ld_beg
sumloop:
eor (pointer),y
;last page?
ldx pointer+1
cpx ld_end+1
beq last
iny
bne sumloop
inc pointer+1
bne sumloop
last:
iny
cpy ld_end
bcc sumloop
; sty $01
sta chksum
lda chksum
bne sumerror
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:

200
asm/fastload9600.s Normal file
View File

@ -0,0 +1,200 @@
;fastload9600.s
org = $BE80 ; should be $BE80
cout = $FDED ; character out sub
crout = $FD8E ; CR out sub
prbyte = $FDDA
warm = $FF69 ; back to monitor
tapein = $C060
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 fast,x
inx
bne move1 ; move 256 bytes
; ldx #0
move2: lda moved+256,x
sta fast+256,x
inx
bpl move2 ; only 128 bytes to move
jmp fast
moved:
.org org
fast:
lda #<loadm
ldy #>loadm
jsr print
lda #$ff
sta chksum
lda ld_beg ; setup point to target
sta store+1
lda ld_beg+1
sta store+2
wait: bit tapein
bpl wait
waithi: bit tapein ; Wait for input to go high.
bmi waithi
pre: lda #1 ; Load sentinel bit
ldx #0 ; Clear data index
clc ; Clear carry (byte complete flag)
data: bcc waitlo ; Skip if byte not complete
store: sta store,x ; Store data byte
eor chksum
sta chksum
lda #1 ; Re-load sentinel bit
waitlo: bit tapein ; Wait for input to go low
bpl waitlo
bcc poll9 ; Poll at +9 cycles if no store
inx ; Stored, so increment data index
bne poll13 ; Poll at +13 cycles if no carry
inc store+2 ; Increment data page
bne poll21 ; (always) poll at +21 cycles
one: sec ; one bit detected
rol ; shift it into A
jmp data ; and go handle data (C = sentinel)
zero: clc ; zero bit detected
rol ; shift it into A
jmp data ; and go handle data (C = sentinel)
poll9: bit tapein
bpl zero ; zero bit (short)(9-15 cycles)
poll13: bit tapein ; (2 cycles early if branched here)
bpl zero ; zero bit (15-21 cycles)
poll21: bit tapein
bpl zero ; zero bit (21-27 cycles)
bit tapein
bpl zero ; zero bit (27-33 cycles)
bit tapein
bpl zero ; zero bit (33-39 cycles)
bit tapein
bpl zero ; zero bit (39-45 cycles)
bit tapein
bpl zero ; zero bit (45-51 cycles)
bit tapein
bpl zero ; zero bit (51-57 cycles)
bit tapein
bpl zero ; one bit (57-63 cycles)
bit tapein
bpl one ; one bit (63-69 cycles)
bit tapein
bpl one ; one bit (69-75 cycles)
bit tapein
bpl one ; one bit (75-81 cycles)
bit tapein
bpl one ; pre pulse (81-87 cycles)
bit tapein
bpl pre ; pre pulse (87-93 cycles)
bit tapein
bpl pre ; pre pulse (93-99 cycles)
bit tapein
bpl pre ; pre pulse (99-105 cycles)
endcode:
txa ; write end of file location + 1
clc
adc store+1
sta store+1
bcc endcheck
inc store+2
endcheck:
lda ld_end
cmp store+1
bne error
lda ld_end+1
cmp store+2
bne error
sumcheck:
lda chksum
bne sumerror
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:

202
asm/fastloadcd.s Normal file
View File

@ -0,0 +1,202 @@
;fastloadcd.s
org = $BE80 ; should be $BE80
cout = $FDED ; character out sub
crout = $FD8E ; CR out sub
prbyte = $FDDA
warm = $FF69 ; back to monitor
tapein = $C060
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 fast,x
inx
bne move1 ; move 256 bytes
; ldx #0
move2: lda moved+256,x
sta fast+256,x
inx
bpl move2 ; only 128 bytes to move
jmp fast
moved:
.org org
fast:
lda #<loadm
ldy #>loadm
jsr print
lda #$ff
sta chksum
lda ld_beg ; setup point to target
sta store+1
lda ld_beg+1
sta store+2
wait: bit tapein
bpl wait
waithi: bit tapein ; Wait for input to go high.
bmi waithi
pre: lda #1 ; Load sentinel bit
ldx #0 ; Clear data index
clc ; Clear carry (byte complete flag)
data: bcc waitlo ; Skip if byte not complete
store: sta store,x ; Store data byte
eor chksum
sta chksum
lda #1 ; Re-load sentinel bit
waitlo: bit tapein ; Wait for input to go low
bpl waitlo
bcc poll9 ; Poll at +9 cycles if no store
inx ; Stored, so increment data index
bne poll13 ; Poll at +13 cycles if no carry
inc store+2 ; Increment data page
bne poll21 ; (always) poll at +21 cycles
one: sec ; one bit detected
rol ; shift it into A
jmp data ; and go handle data (C = sentinel)
zero: clc ; zero bit detected
rol ; shift it into A
jmp data ; and go handle data (C = sentinel)
poll9: bit tapein
bpl zero ; zero bit (short)(9-15 cycles)
poll13: bit tapein ; (2 cycles early if branched here)
bpl zero ; zero bit (15-21 cycles)
poll21: bit tapein
bpl zero ; zero bit (21-27 cycles)
bit tapein
bpl zero ; zero bit (27-33 cycles)
bit tapein
bpl zero ; zero bit (33-39 cycles)
bit tapein
bpl zero ; zero bit (39-45 cycles)
bit tapein
bpl zero ; zero bit (45-51 cycles)
bit tapein
bpl zero ; zero bit (51-57 cycles)
bit tapein
bpl zero ; one bit (57-63 cycles)
bit tapein
bpl one ; one bit (63-69 cycles)
bit tapein
bpl one ; one bit (69-75 cycles)
bit tapein
bpl one ; one bit (75-81 cycles)
bit tapein
bpl one ; one pulse (81-87 cycles)
bit tapein
bpl one ; one pulse (87-93 cycles)
bit tapein
bpl pre ; pre pulse (93-99 cycles)
bit tapein
bpl pre ; pre pulse (99-105 cycles)
bit tapein
bpl pre ; pre pulse (99-111 cycles)
endcode:
txa ; write end of file location + 1
clc
adc store+1
sta store+1
bcc endcheck
inc store+2
endcheck:
lda ld_end
cmp store+1
bne error
lda ld_end+1
cmp store+2
bne error
sumcheck:
lda chksum
bne sumerror
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:

520
asm/inflate.s Normal file
View File

@ -0,0 +1,520 @@
; 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 = $BA00
inflate_zp = $0
inflate_data = $BC00
; 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
END:

1707
c2t.c Normal file

File diff suppressed because it is too large Load Diff

4352
c2t.h Normal file

File diff suppressed because it is too large Load Diff

72
c2t.h.0 Normal file
View File

@ -0,0 +1,72 @@
const char *usagetext="\n\
usage: c2t [-vh?]\n\
c2t [-elp] input[.mon],[addr] ... [output.mon]\n\
c2t {-1} [-cepr] input[.mon],[addr] ... [output.[aif[f]|wav[e]]]\n\
c2t {-2} [-abcdef8pmqr] input[.mon],[addr] ... [output.[aif[f]|wav[e]]]\n\
c2t [-n8] input.dsk ... [output.[aif[f]|wav[e]]]\n\
\n\
-1 or -2 for Apple I or II tape format\n\
-8 use 48k/8bit 8000 bps transfer (Apple II/II+/IIe 64K only)\n\
Implies -2a. Negates -f and -d.\n\
-a assembly autoload and run (Apple II/II+/IIe 64K only)\n\
-b basic autoload and run (Apple II+/IIe 64K only)\n\
Implies -2a.\n\
-c compress data\n\
-d use fast 44.1k/16bit transfer (Apple II/II+/IIe 64K only)\n\
Implies -2a. Negates -f and -8. Use for burning CDs.\n\
-e pad with $00 to end on page boundary\n\
-f use faster 48k/8bit (9600 bps) transfer (Apple II/II+/IIe 64K only)\n\
Implies -2a. Negates -8 and -d. Unreliable on some systems.\n\
-h|? this help\n\
-l long monitor format (24 bytes/line)\n\
-m jump to monitor after autoload\n\
-n do not format disks\n\
-p pipe to stdout\n\
-q parameters and data only (for use with custom client)\n\
-r #, where # overrides the sample rate (e.g. -r 48000)\n\
Negates -a, -b, -8, -q, -f, and -d\n\
-t 10 second preamble (default 4) for real tape use\n\
-v print version number and exit\n\
\n\
input(s) without a .mon or .dsk extension is assumed to be a binary with a 4\n\
byte header. If the header is missing then you must append ,load_address to\n\
each binary input missing a header, e.g. filename,800. The load address\n\
will be read as hex.\n\
\n\
input(s) with a .mon extension expected input format:\n\
\n\
0280: A2 FF 9A 20 8C 02 20 4F\n\
0288: 03 4C 00 FF 20 9E 02 A9\n\
\n\
A single input with a .dsk extension expected to be a 140K disk image.\n\
\n\
output must have aiff, aif, wav, wave, or mon extention.\n\
\n\
Examples:\n\
\n\
c2t hello hello.mon\n\
c2t -p hello.mon print.mon foo,800 | pbcopy\n\
c2t -2f moon.patrol,801 moon.patrol.aif\n\
c2t -2 hello,300 hello.aiff\n\
c2t -1 hello.mon hello.wav\n\
c2t -2 thief,801 thief.obj,3ffd thief.pic,2000 theif.aif\n\
c2t foo.dsk foo.wav\n\
\n\
";
//51 00 D5, 3 byte header, LENGTH LSB/MSB, D5 for autorun
unsigned char header[] = {0x00,0x00,0xD5};
/*
basic program "CALL 2060", 801.80B
end of code[LSB,MSB] = 0x0B,0x08
line #[LSB,MSG] = 0x01,0x00
CALL[1] = 0x8C
vec[4] = 0x32,0x30,0x36,0x30 (2060 in ASCII)
end[2] = 0x00,0x00
*/
unsigned char basic[] = {0x0B,0x08,0x01,0x00,0x8C,0x32,0x30,0x36,0x30,0x00,0x00};

1134
c2t.h.2 Normal file

File diff suppressed because it is too large Load Diff

998
fake6502.h Normal file
View File

@ -0,0 +1,998 @@
/* Fake6502 CPU emulator core v1.1 *******************
* (c)2011 Mike Chambers (miker00lz@gmail.com) *
*****************************************************
* v1.1 - Small bugfix in BIT opcode, but it was the *
* difference between a few games in my NES *
* emulator working and being broken! *
* I went through the rest carefully again *
* after fixing it just to make sure I didn't *
* have any other typos! (Dec. 17, 2011) *
* *
* v1.0 - First release (Nov. 24, 2011) *
*****************************************************
* LICENSE: This source code is released into the *
* public domain, but if you use it please do give *
* credit. I put a lot of effort into writing this! *
* *
*****************************************************
* Fake6502 is a MOS Technology 6502 CPU emulation *
* engine in C. It was written as part of a Nintendo *
* Entertainment System emulator I've been writing. *
* *
* It has been pretty well-tested in the NES emu, *
* and the clock-cycle timing in particular has been *
* VERY thoroughly checked out. It matches with the *
* real 6502 processor 100%. *
* *
* A couple important things to know about are two *
* defines in the code. One is "UNDOCUMENTED" which, *
* when defined, allows Fake6502 to compile with *
* full support for the more predictable *
* undocumented instructions of the 6502. If it is *
* undefined, undocumented opcodes just act as NOPs. *
* *
* The other define is "NES_CPU", which causes the *
* code to compile without support for binary-coded *
* decimal (BCD) support for the ADC and SBC *
* opcodes. The Ricoh 2A03 CPU in the NES does not *
* support BCD, but is otherwise identical to the *
* standard MOS 6502. (Note that this define is *
* enabled in this file if you haven't changed it *
* yourself. If you're not emulating a NES, you *
* should comment it out.) *
* *
* If you do discover an error in timing accuracy, *
* or operation in general please e-mail me at the *
* address above so that I can fix it. Thank you! *
* *
*****************************************************
* Usage: *
* *
* Fake6502 requires you to provide two external *
* functions: *
* *
* uint8_t read6502(uint16_t address) *
* void write6502(uint16_t address, uint8_t value) *
* *
* You may optionally pass Fake6502 the pointer to a *
* function which you want to be called after every *
* emulated instruction. This function should be a *
* void with no parameters expected to be passed to *
* it. *
* *
* This can be very useful. For example, in a NES *
* emulator, you check the number of clock ticks *
* that have passed so you can know when to handle *
* APU events. *
* *
* To pass Fake6502 this pointer, use the *
* hookexternal(void *funcptr) function provided. *
* *
* To disable the hook later, pass NULL to it. *
*****************************************************
* Useful functions in this emulator: *
* *
* void reset6502() *
* - Call this once before you begin execution. *
* *
* void exec6502(uint32_t tickcount) *
* - Execute 6502 code up to the next specified *
* count of clock ticks. *
* *
* void step6502() *
* - Execute a single instrution. *
* *
* void irq6502() *
* - Trigger a hardware IRQ in the 6502 core. *
* *
* void nmi6502() *
* - Trigger an NMI in the 6502 core. *
* *
* void hookexternal(void *funcptr) *
* - Pass a pointer to a void function taking no *
* parameters. This will cause Fake6502 to call *
* that function once after each emulated *
* instruction. *
* *
*****************************************************
* Useful variables in this emulator: *
* *
* uint32_t clockticks6502 *
* - A running total of the emulated cycle count. *
* *
* uint32_t instructions *
* - A running total of the total emulated *
* instruction count. This is not related to *
* clock cycle timing. *
* *
*****************************************************/
#include <stdio.h>
#include <stdint.h>
//6502 defines
//#define UNDOCUMENTED //when this is defined, undocumented opcodes are handled.
//otherwise, they're simply treated as NOPs.
//#define NES_CPU //when this is defined, the binary-coded decimal (BCD)
//status flag is not honored by ADC and SBC. the 2A03
//CPU in the Nintendo Entertainment System does not
//support BCD operation.
#define FLAG_CARRY 0x01
#define FLAG_ZERO 0x02
#define FLAG_INTERRUPT 0x04
#define FLAG_DECIMAL 0x08
#define FLAG_BREAK 0x10
#define FLAG_CONSTANT 0x20
#define FLAG_OVERFLOW 0x40
#define FLAG_SIGN 0x80
#define BASE_STACK 0x100
#define saveaccum(n) a = (uint8_t)((n) & 0x00FF)
//flag modifier macros
#define setcarry() status |= FLAG_CARRY
#define clearcarry() status &= (~FLAG_CARRY)
#define setzero() status |= FLAG_ZERO
#define clearzero() status &= (~FLAG_ZERO)
#define setinterrupt() status |= FLAG_INTERRUPT
#define clearinterrupt() status &= (~FLAG_INTERRUPT)
#define setdecimal() status |= FLAG_DECIMAL
#define cleardecimal() status &= (~FLAG_DECIMAL)
#define setoverflow() status |= FLAG_OVERFLOW
#define clearoverflow() status &= (~FLAG_OVERFLOW)
#define setsign() status |= FLAG_SIGN
#define clearsign() status &= (~FLAG_SIGN)
//flag calculation macros
#define zerocalc(n) {\
if ((n) & 0x00FF) clearzero();\
else setzero();\
}
#define signcalc(n) {\
if ((n) & 0x0080) setsign();\
else clearsign();\
}
#define carrycalc(n) {\
if ((n) & 0xFF00) setcarry();\
else clearcarry();\
}
#define overflowcalc(n, m, o) { /* n = result, m = accumulator, o = memory */ \
if (((n) ^ (uint16_t)(m)) & ((n) ^ (o)) & 0x0080) setoverflow();\
else clearoverflow();\
}
//6502 CPU registers
uint16_t pc;
uint8_t sp, a, x, y, status;
//helper variables
uint32_t instructions = 0; //keep track of total instructions executed
uint32_t clockticks6502 = 0, clockgoal6502 = 0;
uint16_t oldpc, ea, reladdr, value, result;
uint8_t opcode, oldstatus;
//externally supplied functions
extern uint8_t read6502(uint16_t address);
extern void write6502(uint16_t address, uint8_t value);
//a few general functions used by various other functions
void push16(uint16_t pushval) {
write6502(BASE_STACK + sp, (pushval >> 8) & 0xFF);
write6502(BASE_STACK + ((sp - 1) & 0xFF), pushval & 0xFF);
sp -= 2;
}
void push8(uint8_t pushval) {
write6502(BASE_STACK + sp--, pushval);
}
uint16_t pull16() {
uint16_t temp16;
temp16 = read6502(BASE_STACK + ((sp + 1) & 0xFF)) | ((uint16_t)read6502(BASE_STACK + ((sp + 2) & 0xFF)) << 8);
sp += 2;
return(temp16);
}
uint8_t pull8() {
return (read6502(BASE_STACK + ++sp));
}
void reset6502() {
pc = (uint16_t)read6502(0xFFFC) | ((uint16_t)read6502(0xFFFD) << 8);
a = 0;
x = 0;
y = 0;
sp = 0xFD;
status |= FLAG_CONSTANT;
}
static void (*addrtable[256])();
static void (*optable[256])();
uint8_t penaltyop, penaltyaddr;
//addressing mode functions, calculates effective addresses
static void imp() { //implied
}
static void acc() { //accumulator
}
static void imm() { //immediate
ea = pc++;
}
static void zp() { //zero-page
ea = (uint16_t)read6502((uint16_t)pc++);
}
static void zpx() { //zero-page,X
ea = ((uint16_t)read6502((uint16_t)pc++) + (uint16_t)x) & 0xFF; //zero-page wraparound
}
static void zpy() { //zero-page,Y
ea = ((uint16_t)read6502((uint16_t)pc++) + (uint16_t)y) & 0xFF; //zero-page wraparound
}
static void rel() { //relative for branch ops (8-bit immediate value, sign-extended)
reladdr = (uint16_t)read6502(pc++);
if (reladdr & 0x80) reladdr |= 0xFF00;
}
static void abso() { //absolute
ea = (uint16_t)read6502(pc) | ((uint16_t)read6502(pc+1) << 8);
pc += 2;
}
static void absx() { //absolute,X
uint16_t startpage;
ea = ((uint16_t)read6502(pc) | ((uint16_t)read6502(pc+1) << 8));
startpage = ea & 0xFF00;
ea += (uint16_t)x;
if (startpage != (ea & 0xFF00)) { //one cycle penlty for page-crossing on some opcodes
penaltyaddr = 1;
}
pc += 2;
}
static void absy() { //absolute,Y
uint16_t startpage;
ea = ((uint16_t)read6502(pc) | ((uint16_t)read6502(pc+1) << 8));
startpage = ea & 0xFF00;
ea += (uint16_t)y;
if (startpage != (ea & 0xFF00)) { //one cycle penlty for page-crossing on some opcodes
penaltyaddr = 1;
}
pc += 2;
}
static void ind() { //indirect
uint16_t eahelp, eahelp2;
eahelp = (uint16_t)read6502(pc) | (uint16_t)((uint16_t)read6502(pc+1) << 8);
eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); //replicate 6502 page-boundary wraparound bug
ea = (uint16_t)read6502(eahelp) | ((uint16_t)read6502(eahelp2) << 8);
pc += 2;
}
static void indx() { // (indirect,X)
uint16_t eahelp;
eahelp = (uint16_t)(((uint16_t)read6502(pc++) + (uint16_t)x) & 0xFF); //zero-page wraparound for table pointer
ea = (uint16_t)read6502(eahelp & 0x00FF) | ((uint16_t)read6502((eahelp+1) & 0x00FF) << 8);
}
static void indy() { // (indirect),Y
uint16_t eahelp, eahelp2, startpage;
eahelp = (uint16_t)read6502(pc++);
eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); //zero-page wraparound
ea = (uint16_t)read6502(eahelp) | ((uint16_t)read6502(eahelp2) << 8);
startpage = ea & 0xFF00;
ea += (uint16_t)y;
if (startpage != (ea & 0xFF00)) { //one cycle penlty for page-crossing on some opcodes
penaltyaddr = 1;
}
}
static uint16_t getvalue() {
if (addrtable[opcode] == acc) return((uint16_t)a);
else return((uint16_t)read6502(ea));
}
static uint16_t getvalue16() {
return((uint16_t)read6502(ea) | ((uint16_t)read6502(ea+1) << 8));
}
static void putvalue(uint16_t saveval) {
if (addrtable[opcode] == acc) a = (uint8_t)(saveval & 0x00FF);
else write6502(ea, (saveval & 0x00FF));
}
//instruction handler functions
static void adc() {
penaltyop = 1;
value = getvalue();
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
carrycalc(result);
zerocalc(result);
overflowcalc(result, a, value);
signcalc(result);
#ifndef NES_CPU
if (status & FLAG_DECIMAL) {
clearcarry();
if ((a & 0x0F) > 0x09) {
a += 0x06;
}
if ((a & 0xF0) > 0x90) {
a += 0x60;
setcarry();
}
clockticks6502++;
}
#endif
saveaccum(result);
}
static void and() {
penaltyop = 1;
value = getvalue();
result = (uint16_t)a & value;
zerocalc(result);
signcalc(result);
saveaccum(result);
}
static void asl() {
value = getvalue();
result = value << 1;
carrycalc(result);
zerocalc(result);
signcalc(result);
putvalue(result);
}
static void bcc() {
if ((status & FLAG_CARRY) == 0) {
oldpc = pc;
pc += reladdr;
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
else clockticks6502++;
}
}
static void bcs() {
if ((status & FLAG_CARRY) == FLAG_CARRY) {
oldpc = pc;
pc += reladdr;
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
else clockticks6502++;
}
}
static void beq() {
if ((status & FLAG_ZERO) == FLAG_ZERO) {
oldpc = pc;
pc += reladdr;
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
else clockticks6502++;
}
}
static void bit() {
value = getvalue();
result = (uint16_t)a & value;
zerocalc(result);
status = (status & 0x3F) | (uint8_t)(value & 0xC0);
}
static void bmi() {
if ((status & FLAG_SIGN) == FLAG_SIGN) {
oldpc = pc;
pc += reladdr;
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
else clockticks6502++;
}
}
static void bne() {
if ((status & FLAG_ZERO) == 0) {
oldpc = pc;
pc += reladdr;
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
else clockticks6502++;
}
}
static void bpl() {
if ((status & FLAG_SIGN) == 0) {
oldpc = pc;
pc += reladdr;
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
else clockticks6502++;
}
}
static void brk6502() {
pc++;
push16(pc); //push next instruction address onto stack
push8(status | FLAG_BREAK); //push CPU status to stack
setinterrupt(); //set interrupt flag
pc = (uint16_t)read6502(0xFFFE) | ((uint16_t)read6502(0xFFFF) << 8);
}
static void bvc() {
if ((status & FLAG_OVERFLOW) == 0) {
oldpc = pc;
pc += reladdr;
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
else clockticks6502++;
}
}
static void bvs() {
if ((status & FLAG_OVERFLOW) == FLAG_OVERFLOW) {
oldpc = pc;
pc += reladdr;
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
else clockticks6502++;
}
}
static void clc() {
clearcarry();
}
static void cld() {
cleardecimal();
}
static void cli() {
clearinterrupt();
}
static void clv() {
clearoverflow();
}
static void cmp() {
penaltyop = 1;
value = getvalue();
result = (uint16_t)a - value;
if (a >= (uint8_t)(value & 0x00FF)) setcarry();
else clearcarry();
if (a == (uint8_t)(value & 0x00FF)) setzero();
else clearzero();
signcalc(result);
}
static void cpx() {
value = getvalue();
result = (uint16_t)x - value;
if (x >= (uint8_t)(value & 0x00FF)) setcarry();
else clearcarry();
if (x == (uint8_t)(value & 0x00FF)) setzero();
else clearzero();
signcalc(result);
}
static void cpy() {
value = getvalue();
result = (uint16_t)y - value;
if (y >= (uint8_t)(value & 0x00FF)) setcarry();
else clearcarry();
if (y == (uint8_t)(value & 0x00FF)) setzero();
else clearzero();
signcalc(result);
}
static void dec() {
value = getvalue();
result = value - 1;
zerocalc(result);
signcalc(result);
putvalue(result);
}
static void dex() {
x--;
zerocalc(x);
signcalc(x);
}
static void dey() {
y--;
zerocalc(y);
signcalc(y);
}
static void eor() {
penaltyop = 1;
value = getvalue();
result = (uint16_t)a ^ value;
zerocalc(result);
signcalc(result);
saveaccum(result);
}
static void inc() {
value = getvalue();
result = value + 1;
zerocalc(result);
signcalc(result);
putvalue(result);
}
static void inx() {
x++;
zerocalc(x);
signcalc(x);
}
static void iny() {
y++;
zerocalc(y);
signcalc(y);
}
static void jmp() {
pc = ea;
}
static void jsr() {
push16(pc - 1);
pc = ea;
}
static void lda() {
penaltyop = 1;
value = getvalue();
a = (uint8_t)(value & 0x00FF);
zerocalc(a);
signcalc(a);
}
static void ldx() {
penaltyop = 1;
value = getvalue();
x = (uint8_t)(value & 0x00FF);
zerocalc(x);
signcalc(x);
}
static void ldy() {
penaltyop = 1;
value = getvalue();
y = (uint8_t)(value & 0x00FF);
zerocalc(y);
signcalc(y);
}
static void lsr() {
value = getvalue();
result = value >> 1;
if (value & 1) setcarry();
else clearcarry();
zerocalc(result);
signcalc(result);
putvalue(result);
}
static void nop() {
switch (opcode) {
case 0x1C:
case 0x3C:
case 0x5C:
case 0x7C:
case 0xDC:
case 0xFC:
penaltyop = 1;
break;
}
}
static void ora() {
penaltyop = 1;
value = getvalue();
result = (uint16_t)a | value;
zerocalc(result);
signcalc(result);
saveaccum(result);
}
static void pha() {
push8(a);
}
static void php() {
push8(status | FLAG_BREAK);
}
static void pla() {
a = pull8();
zerocalc(a);
signcalc(a);
}
static void plp() {
status = pull8() | FLAG_CONSTANT;
}
static void rol() {
value = getvalue();
result = (value << 1) | (status & FLAG_CARRY);
carrycalc(result);
zerocalc(result);
signcalc(result);
putvalue(result);
}
static void ror() {
value = getvalue();
result = (value >> 1) | ((status & FLAG_CARRY) << 7);
if (value & 1) setcarry();
else clearcarry();
zerocalc(result);
signcalc(result);
putvalue(result);
}
static void rti() {
status = pull8();
value = pull16();
pc = value;
}
static void rts() {
value = pull16();
pc = value + 1;
}
static void sbc() {
penaltyop = 1;
value = getvalue() ^ 0x00FF;
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
carrycalc(result);
zerocalc(result);
overflowcalc(result, a, value);
signcalc(result);
#ifndef NES_CPU
if (status & FLAG_DECIMAL) {
clearcarry();
a -= 0x66;
if ((a & 0x0F) > 0x09) {
a += 0x06;
}
if ((a & 0xF0) > 0x90) {
a += 0x60;
setcarry();
}
clockticks6502++;
}
#endif
saveaccum(result);
}
static void sec() {
setcarry();
}
static void sed() {
setdecimal();
}
static void sei() {
setinterrupt();
}
static void sta() {
putvalue(a);
}
static void stx() {
putvalue(x);
}
static void sty() {
putvalue(y);
}
static void tax() {
x = a;
zerocalc(x);
signcalc(x);
}
static void tay() {
y = a;
zerocalc(y);
signcalc(y);
}
static void tsx() {
x = sp;
zerocalc(x);
signcalc(x);
}
static void txa() {
a = x;
zerocalc(a);
signcalc(a);
}
static void txs() {
sp = x;
}
static void tya() {
a = y;
zerocalc(a);
signcalc(a);
}
//undocumented instructions
#ifdef UNDOCUMENTED
static void lax() {
lda();
ldx();
}
static void sax() {
sta();
stx();
putvalue(a & x);
if (penaltyop && penaltyaddr) clockticks6502--;
}
static void dcp() {
dec();
cmp();
if (penaltyop && penaltyaddr) clockticks6502--;
}
static void isb() {
inc();
sbc();
if (penaltyop && penaltyaddr) clockticks6502--;
}
static void slo() {
asl();
ora();
if (penaltyop && penaltyaddr) clockticks6502--;
}
static void rla() {
rol();
and();
if (penaltyop && penaltyaddr) clockticks6502--;
}
static void sre() {
lsr();
eor();
if (penaltyop && penaltyaddr) clockticks6502--;
}
static void rra() {
ror();
adc();
if (penaltyop && penaltyaddr) clockticks6502--;
}
#else
#define lax nop
#define sax nop
#define dcp nop
#define isb nop
#define slo nop
#define rla nop
#define sre nop
#define rra nop
#endif
static void (*addrtable[256])() = {
/* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */
/* 0 */ imp, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, abso, abso, abso, abso, /* 0 */
/* 1 */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* 1 */
/* 2 */ abso, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, abso, abso, abso, abso, /* 2 */
/* 3 */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* 3 */
/* 4 */ imp, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, abso, abso, abso, abso, /* 4 */
/* 5 */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* 5 */
/* 6 */ imp, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, ind, abso, abso, abso, /* 6 */
/* 7 */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* 7 */
/* 8 */ imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* 8 */
/* 9 */ rel, indy, imp, indy, zpx, zpx, zpy, zpy, imp, absy, imp, absy, absx, absx, absy, absy, /* 9 */
/* A */ imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* A */
/* B */ rel, indy, imp, indy, zpx, zpx, zpy, zpy, imp, absy, imp, absy, absx, absx, absy, absy, /* B */
/* C */ imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* C */
/* D */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* D */
/* E */ imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* E */
/* F */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx /* F */
};
static void (*optable[256])() = {
/* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */
/* 0 */ brk6502, ora, nop, slo, nop, ora, asl, slo, php, ora, asl, nop, nop, ora, asl, slo, /* 0 */
/* 1 */ bpl, ora, nop, slo, nop, ora, asl, slo, clc, ora, nop, slo, nop, ora, asl, slo, /* 1 */
/* 2 */ jsr, and, nop, rla, bit, and, rol, rla, plp, and, rol, nop, bit, and, rol, rla, /* 2 */
/* 3 */ bmi, and, nop, rla, nop, and, rol, rla, sec, and, nop, rla, nop, and, rol, rla, /* 3 */
/* 4 */ rti, eor, nop, sre, nop, eor, lsr, sre, pha, eor, lsr, nop, jmp, eor, lsr, sre, /* 4 */
/* 5 */ bvc, eor, nop, sre, nop, eor, lsr, sre, cli, eor, nop, sre, nop, eor, lsr, sre, /* 5 */
/* 6 */ rts, adc, nop, rra, nop, adc, ror, rra, pla, adc, ror, nop, jmp, adc, ror, rra, /* 6 */
/* 7 */ bvs, adc, nop, rra, nop, adc, ror, rra, sei, adc, nop, rra, nop, adc, ror, rra, /* 7 */
/* 8 */ nop, sta, nop, sax, sty, sta, stx, sax, dey, nop, txa, nop, sty, sta, stx, sax, /* 8 */
/* 9 */ bcc, sta, nop, nop, sty, sta, stx, sax, tya, sta, txs, nop, nop, sta, nop, nop, /* 9 */
/* A */ ldy, lda, ldx, lax, ldy, lda, ldx, lax, tay, lda, tax, nop, ldy, lda, ldx, lax, /* A */
/* B */ bcs, lda, nop, lax, ldy, lda, ldx, lax, clv, lda, tsx, lax, ldy, lda, ldx, lax, /* B */
/* C */ cpy, cmp, nop, dcp, cpy, cmp, dec, dcp, iny, cmp, dex, nop, cpy, cmp, dec, dcp, /* C */
/* D */ bne, cmp, nop, dcp, nop, cmp, dec, dcp, cld, cmp, nop, dcp, nop, cmp, dec, dcp, /* D */
/* E */ cpx, sbc, nop, isb, cpx, sbc, inc, isb, inx, sbc, nop, sbc, cpx, sbc, inc, isb, /* E */
/* F */ beq, sbc, nop, isb, nop, sbc, inc, isb, sed, sbc, nop, isb, nop, sbc, inc, isb /* F */
};
static const uint32_t ticktable[256] = {
/* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */
/* 0 */ 7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, /* 0 */
/* 1 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 1 */
/* 2 */ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, /* 2 */
/* 3 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 3 */
/* 4 */ 6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6, /* 4 */
/* 5 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 5 */
/* 6 */ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6, /* 6 */
/* 7 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 7 */
/* 8 */ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* 8 */
/* 9 */ 2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5, /* 9 */
/* A */ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* A */
/* B */ 2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4, /* B */
/* C */ 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* C */
/* D */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* D */
/* E */ 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* E */
/* F */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7 /* F */
};
void nmi6502() {
push16(pc);
push8(status);
status |= FLAG_INTERRUPT;
pc = (uint16_t)read6502(0xFFFA) | ((uint16_t)read6502(0xFFFB) << 8);
}
void irq6502() {
push16(pc);
push8(status);
status |= FLAG_INTERRUPT;
pc = (uint16_t)read6502(0xFFFE) | ((uint16_t)read6502(0xFFFF) << 8);
}
uint8_t callexternal = 0;
void (*loopexternal)();
/*
void exec6502(uint32_t tickcount) {
clockgoal6502 += tickcount;
while (clockticks6502 < clockgoal6502) {
opcode = read6502(pc++);
status |= FLAG_CONSTANT;
penaltyop = 0;
penaltyaddr = 0;
(*addrtable[opcode])();
(*optable[opcode])();
clockticks6502 += ticktable[opcode];
if (penaltyop && penaltyaddr) clockticks6502++;
instructions++;
if (callexternal) (*loopexternal)();
}
}
*/
void exec6502(unsigned int org) {
clockticks6502 = 0;
pc = org;
while ((opcode = read6502(pc++)) != 0x00) { // end on BRK
status |= FLAG_CONSTANT;
penaltyop = 0;
penaltyaddr = 0;
(*addrtable[opcode])();
(*optable[opcode])();
clockticks6502 += ticktable[opcode];
if (penaltyop && penaltyaddr) clockticks6502++;
instructions++;
if (callexternal) (*loopexternal)();
}
}
void step6502() {
opcode = read6502(pc++);
status |= FLAG_CONSTANT;
penaltyop = 0;
penaltyaddr = 0;
(*addrtable[opcode])();
(*optable[opcode])();
clockticks6502 += ticktable[opcode];
if (penaltyop && penaltyaddr) clockticks6502++;
clockgoal6502 = clockticks6502;
instructions++;
if (callexternal) (*loopexternal)();
}
void hookexternal(void *funcptr) {
if (funcptr != (void *)NULL) {
loopexternal = funcptr;
callexternal = 1;
} else callexternal = 0;
}

53
makeheader Executable file
View File

@ -0,0 +1,53 @@
#!/bin/bash
header()
{
FILE=$1
VAR=$2
EOL=$3
BYTES=$(hexdump -v $FILE | sed 's/^.......//' | wc -w | awk '{print $1}');
echo "/*"
expand ${FILE}.s
echo "*/"
printf "unsigned char $VAR[] = {\n\t"
for i in $(hexdump -v $FILE | sed 's/^.......//');
do
printf "0x%02X" 0x$i
BYTES=$((BYTES - 1))
if ((BYTES != 0))
then
printf ","
fi
EOL=$((EOL - 1))
if ((EOL == 0))
then
EOL=8
printf "\n\t"
fi
done
printf "\n};\n"
}
cd asm
make clean
make
(
header autoload autoloadcode 4
header inflate inflatecode 8
header fastload9600 fastload9600 4
header fastload8000 fastload8000 4
header fastloadcd fastloadcd 4
header diskload9600 diskload9600 4
header diskload8000 diskload8000 4
header diskload2 diskloadcode2 8
header diskload3 diskloadcode3 8
) > ../c2t.h.1
cd ..
cat c2t.h.[012] > c2t.h

4679
miniz.h Normal file

File diff suppressed because it is too large Load Diff

BIN
windows/c2t.exe Executable file

Binary file not shown.

4679
windows/miniz.h Normal file

File diff suppressed because it is too large Load Diff