mirror of
https://github.com/Michaelangel007/c2t.git
synced 2024-12-26 03:32:38 +00:00
init commit
This commit is contained in:
commit
55d29a682a
12
MANIFEST
Normal file
12
MANIFEST
Normal 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
14
Makefile
Normal 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
22
README.1st
Normal 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
267
README.md
Normal 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
27
asm/Makefile
Normal 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
117
asm/autoload.s
Normal 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
545
asm/diskload2.s
Normal 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
524
asm/diskload3.s
Normal 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
168
asm/diskload8000.s
Normal 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
174
asm/diskload9600.s
Normal 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
194
asm/fastload8000.s
Normal 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
200
asm/fastload9600.s
Normal 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
202
asm/fastloadcd.s
Normal 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
520
asm/inflate.s
Normal 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:
|
72
c2t.h.0
Normal file
72
c2t.h.0
Normal 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};
|
||||
|
998
fake6502.h
Normal file
998
fake6502.h
Normal 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
53
makeheader
Executable 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
|
BIN
windows/c2t.exe
Executable file
BIN
windows/c2t.exe
Executable file
Binary file not shown.
4679
windows/miniz.h
Normal file
4679
windows/miniz.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user