Compare commits

...

42 Commits

Author SHA1 Message Date
Egan Ford 768284e5d2 md5sum now shasum 2016-01-10 13:12:17 -07:00
Egan Ford 8ec4fcf11b md5sum now shasum 2016-01-10 13:09:37 -07:00
Egan Ford 7d97de48d5 README updates 2016-01-10 12:32:54 -07:00
Egan Ford 42a3dff7f8 README updates 2016-01-10 12:22:15 -07:00
Egan Ford ded24fe8ec README updates 2016-01-10 12:21:20 -07:00
Egan Ford d6e79062b3 README updates 2016-01-10 12:20:48 -07:00
Egan Ford e8b8b7a6ce README updates 2016-01-10 12:11:10 -07:00
Egan Ford 95bde7d24c added more tests, minor updates, cleanup 2016-01-08 22:14:17 -07:00
Egan Ford 8609827333 added more tests, minor updates, cleanup 2016-01-08 22:11:25 -07:00
Egan Ford 0ed8296925 minor test changes 2016-01-08 20:14:21 -07:00
Egan Ford f8f98e6cbd minor test changes 2016-01-08 20:00:53 -07:00
Egan Ford 4ce806aa07 more clean up 2016-01-08 19:49:20 -07:00
Egan Ford b20d3d15b9 more clean up 2016-01-08 16:19:52 -07:00
Egan Ford eb29f562ff more clean up 2016-01-08 16:19:30 -07:00
Egan Ford a77b3f7a54 major test clean up 2016-01-08 16:07:19 -07:00
Egan Ford 2312f396dc major test clean up 2016-01-08 16:06:21 -07:00
Egan Ford 08e7b20117 major test clean up 2016-01-08 15:58:07 -07:00
Egan Ford 9c129921ae major test clean up 2016-01-08 15:55:11 -07:00
Egan Ford 7794f7a173 major test clean up 2016-01-08 15:54:46 -07:00
Egan Ford 9d3f517423 minor test clean up 2016-01-07 10:10:09 -07:00
Egan Ford ca16f8b782 minor test clean up 2016-01-06 20:50:39 -07:00
Egan Ford 34bf509d62 minor test clean up 2016-01-06 20:48:46 -07:00
Egan Ford a464aa0147 merged windows cross build makefile with main makefile, updated test scripts and docs to support change 2016-01-06 20:35:27 -07:00
Egan Ford 0bc19b0dbd merged windows cross build makefile with main makefile, updated test scripts and docs to support change 2016-01-06 20:23:46 -07:00
Egan Ford 95bff8e9cb merged windows cross build makefile with main makefile, updated test scripts and docs to support change 2016-01-06 20:21:04 -07:00
Egan Ford e677758a9d merged windows cross build makefile with main makefile, updated test scripts and docs to support change 2016-01-06 20:17:55 -07:00
Egan Ford 122d72b905 merged windows cross build makefile with main makefile, updated test scripts and docs to support change 2016-01-06 20:17:39 -07:00
Egan Ford 0960c1e566 improved test scripts 2016-01-06 19:35:27 -07:00
Egan Ford ef95c2c024 improved test scripts 2016-01-06 16:09:22 -07:00
Egan Ford c35403276b improved test scripts 2016-01-06 16:05:37 -07:00
Egan Ford 0e05f6a197 play list to stderr, added automated testing on OS/X with virtual ][ 2016-01-05 23:10:10 -07:00
Egan Ford 1369765ae0 play list to stderr, added automated testing on OS/X with virtual ][ 2016-01-05 23:09:38 -07:00
Egan Ford 6028a9d287 minor cleanup 2016-01-04 16:56:44 -07:00
Egan Ford dd10e6ce06 patch to c2t-96h to default to -8 for no opt on .dsk/.po, added windows cross makefile 2016-01-04 16:43:31 -07:00
Egan Ford 542686ab6e minor updates 2016-01-01 12:35:20 -07:00
Egan Ford 5a6174f01e minor updates 2016-01-01 12:34:07 -07:00
Egan Ford f20a508c6a minor updates 2015-12-31 18:59:49 -07:00
Egan Ford 0c24760704 minor updates 2015-12-31 12:19:51 -07:00
Egan Ford c96332b204 c2t-96h minor updates, doc updates, article added/updated, windows 96h binary 2015-12-31 12:19:07 -07:00
Egan Ford dc09517573 minor doc update 2014-11-29 11:58:07 -07:00
Egan Ford cf05d8804b minor doc update 2014-11-29 11:57:30 -07:00
Egan Ford 23e9c33781 lots of testing, source comments and doc updates 2014-11-29 11:54:56 -07:00
38 changed files with 2795 additions and 26 deletions

View File

@ -1,13 +1,36 @@
WIN32GCC = /usr/local/gcc-4.8.0-qt-4.8.4-for-mingw32/win32-gcc/bin/i586-mingw32-gcc
all: c2t
all: bin/c2t bin/c2t-96h
clean:
rm c2t.h c2t
windows: bin/c2t.exe bin/c2t-96h.exe
dist: all windows
clean: testclean
rm -f c2t.h bin/c2t bin/c2t-96h bin/c2t.exe bin/c2t-96h.exe
cd asm; make clean
c2t: c2t.h
gcc -Wall -O3 -o c2t c2t.c
bin/c2t: c2t.c c2t.h
gcc -Wall -Wno-unused-value -Wno-unused-function -I. -O3 -o bin/c2t c2t.c
bin/c2t-96h: c2t-96h.c c2t.h
gcc -Wall -Wno-unused-value -Wno-unused-function -I. -O3 -o bin/c2t-96h c2t-96h.c
bin/c2t.exe: c2t.c c2t.h
$(WIN32GCC) -Wall -Wno-unused-value -Wno-unused-function -I. -O3 -o bin/c2t.exe c2t.c
bin/c2t-96h.exe: c2t-96h.c c2t.h
$(WIN32GCC) -Wall -Wno-unused-value -Wno-unused-function -I. -O3 -o bin/c2t-96h.exe c2t-96h.c
c2t.h: mon/dos33.boot1.mon mon/dos33.boot2.mon asm/autoload.s asm/diskload2.s asm/diskload3.s asm/diskload8000.s asm/diskload9600.s asm/fastload8000.s asm/fastload9600.s asm/fastloadcd.s asm/inflate.s
./makeheader
test: bin/c2t-96h bin/c2t-96h.exe tests/test.md
cd tests; ./test.sh test.md
quicktest: testclean bin/c2t-96h tests/quicktest.md
cd tests; ./test.sh quicktest.md
testclean:
cd tests; rm -f passed test.log

135
README.md
View File

@ -1,12 +1,18 @@
## Use c2t-96h version, see below
> Any place you read `c2t`, substitute `c2t-96h` for now (except for `github.com` lines).
## Introduction
`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.
`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.
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.
High-speed and compression 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.
> 8820 bps and 1333 bps is not an option for disk images.
High-speed and compression 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.
@ -15,17 +21,24 @@ Examples of `c2t` in action:
- <http://asciiexpress.net/gameserver/readme.html>
- <http://asciiexpress.net/diskserver/readme.html>
For more info on `c2t` internals please read: <https://github.com/datajerk/c2t/raw/master/article/article.pdf>.
## Why?
### 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 man cave (basement). IOW, I needed an iPhone/iPad/mobile solution. That, and CFFA3000 was sold out--at the time.
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 retro man cave (basement). IOW, I needed an iPhone/iPad/mobile solution. That, and CFFA3000 was sold out--at the time.
## Yeah, but why?
#### Yeah, but why?
You clearly do not understand the awesomeness of the Apple II, move along.
## Version
* c2t 0.996 (Nov 29 2014)
* c2t-96h 0.997 (Dec 31 2015)
## Installation
```
@ -36,9 +49,10 @@ git clone https://github.com/datajerk/c2t.git
Download <https://github.com/datajerk/c2t/archive/master.zip> and extract.
Both the archive and the repo contain an OS/X 64-bit binary (`c2t`) as well as a Windows binary (`windows/c2t.exe`). Just copy to the to any directory in your path. OS/X users may need to adjust the permissions, e.g.:
Both the archive and the repo `bin` directory contain OS/X 64-bit (`c2t`) and Windows 32-bit (`c2t.exe`) binaries. Just copy to any directory in your path.
> OS/X users may need to adjust the permissions, e.g.:
```
cp c2t /usr/local/bin
cp bin/c2t /usr/local/bin
chmod 755 /usr/local/bin/c2t
```
@ -48,15 +62,106 @@ make clean
make
```
To build for/from Windows, first install MinGW (<http://www.mingw.org/>), then type from the root of this distribution:
To build from Windows, first install MinGW (<http://www.mingw.org/>), then type from the root of this distribution:
```
PATH=C:\MinGW\bin;%PATH%
cd windows
copy ..\c2t.*
copy ..\fake6502.h
gcc -Wall -O3 -static -o c2t c2t.c
gcc -Wall -Wno-unused-value -Wno-unused-function -O3 -static -o c2t c2t.c
```
> Use the `miniz.h` in the `windows` directory.
To cross build for Windows from OS/X, first install <http://crossgcc.rts-software.org/download/gcc-4.8.0-qt-4.8.4-win32/gcc-4.8.0-qt-4.8.4-for-mingw32.dmg>, then type:
```
make clean
make windows # or 'make dist' if you want both OS/X and Windows built
```
## c2t-96h Version
`c2t-96h` is a hacked up version of `c2t` that fixes a few bugs (e.g. `.po` files) and adds better universal (should work on all Apple IIs) 9600 BPS code. Both `-8` and `-f` activate this new 9600 BPS code.
`c2t-96h` will eventually replace `c2t`. IOW, use `c2t-96h` for now.
Read <https://github.com/datajerk/c2t/raw/master/article/article.pdf> for details.
## Quick Start
To create an audio file that can auto extract to disk type:
`c2t-96h diskimage.dsk audiofilename.aif` or use `.wav`.
> `c2t-96h` supports `.dsk`, `.do`, and `.po` extensions.
> The disk image must be exactly 143360 bytes (140K). 800K disks are not supported.
> Use the `-n` option, e.g. `c2t-96h -n diskimage.dsk audiofilename.aif` if the disk ][ is emulated (e.g. CFFA3000, SDISK //, etc...)
To create an audio file for a single load binary than can auto extract and execute type:
`c2t-96h -2bc8 super_puckman,800 audiofilename.wav` or use `.aif`.
> The input image must be an Apple II binary with or without a 4-byte header. The 4-byte header is the standard DOS header that defines the binary size and memory location. Depending on how you extracted the single load binary you may or may not have this header. If this header is missing you'll have to append to the binary name `,memorylocation` e.g. `,800`.
> A *Single Load Binary* is defined as a self contained executable that has no disk dependancies (e.g. data, overlays, game save data, high scores, etc...). The binary must be 100% stateless or it will fail to function properly. <http://asciiexpress.net/gameserver> has many examples.
In both cases you'll have a `.aif` or `.wav` formatted audio file. It is critical that they file not be compress to MP3 or other format. Read <https://github.com/datajerk/c2t/raw/master/article/article.pdf> for details.
To load up your disk or binary to a physical Apple //e or ][+:
* Connect an audio patch code from your phone, tablet, computer, etc... to the cassette-in port of the Apple II.
> I just use Dropbox to quickly get these audio files to my iPhone. I also play them from the Dropbox app.
* From the Apple II:
* Remove any disks
* Reboot or power on
* CTRL-RESET to get to a `]` prompt
* *Optionally* insert a blank disk if loading a disk image
* At the `]` prompt type `LOAD` and press *RETURN*
* From your phone, tablet, computer *play* the audio file
Single load binaries will auto extract and execute. Disk images will auto extract and expand to disk.
## Testing
Automated testing is only supported on OS/X and requires the following:
* Virtual ][ (<http://http://www.virtualii.com/>)
* Windows cross-compiling tools <http://crossgcc.rts-software.org/download/gcc-4.8.0-qt-4.8.4-win32/gcc-4.8.0-qt-4.8.4-for-mingw32.dmg>
* Wine (<http://winehq.org>) installed in `~/wine` (extract the tarball in `~/wine` and move the contents of `~/wine/usr` to `~/wine`, or change the path to `wine` in `tests/test.sh`).
> You can edit `tests/test.md` if you do not want to test Windows binaries or want to use different images for test.
To test, type:
```
make testclean # only once, unless you want to start over
make test
```
> If Virtual ][ crashes while testing, just `make test` again to restart failed test and continue where it left off. Do not type `make testclean` again unless you want to start over.
Example output: <https://youtu.be/FCOb4f2hYN8>
## Tested disk ][ Configurations
> Most, if not all, disk ][ emulators (e.g. CFFA3000, SDISK //, etc...) do not support formatting. The `-n` must be used for testing in these cases.
The following configurations have been tested:
* Apple //e
* Apple disk ][ verified (format and no-format)
* Apple duodisk verified (format and no-format)
* CFFA3000 3.1 verified with USB stick (no-format only)
* CFFA3000 3.1 *failed* with IBM 4GB Microdrive (too slow)
* Nishida Radio SDISK // verified (no-format only)
* Apple II+
* Apple disk ][ verified (format and no-format)
* Nishida Radio SDISK // verified (no-format only)
* Virtual ][ Emulator
* Apple disk ][ verified (format and no-format)
## Synopsis
@ -106,7 +211,7 @@ 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
## Examples
------------------------------------------------------------------------------
```

BIN
article/article.docx Normal file

Binary file not shown.

BIN
article/article.pdf Normal file

Binary file not shown.

BIN
article/article.pptx Normal file

Binary file not shown.

34
article/c12k.txt Normal file
View File

@ -0,0 +1,34 @@
12000
12000
-2
2 main: ldy #0
4 psync: bit tapein
2 bmi psync
2 ploop: iny
4 bit tapein
3 bpl ploop
2 ploop: iny
4 bit tapein
3 bpl ploop
2 ploop: iny
4 bit tapein
3 bpl ploop
2 ploop: iny
4 bit tapein
3 bpl ploop
2 ploop: iny
4 bit tapein
2 bpl ploop
2 cpy #$40
2 bpl endcode
2 cpy #$15
2 bpl main
2 cpy #$07
7 store: rol nnnn,x
2 asl
2 bne main
2 lda #1
2 inx
2 bne main
6 inc store+2
3 jmp main

49
article/c6k.txt Normal file
View File

@ -0,0 +1,49 @@
6000
6000
-2
2 main: ldy #0
4 psync: bit tapein
2 bmi psync
2 ploop: iny
4 bit tapein
3 bpl ploop
2 ploop: iny
4 bit tapein
3 bpl ploop
2 ploop: iny
4 bit tapein
3 bpl ploop
2 ploop: iny
4 bit tapein
3 bpl ploop
2 ploop: iny
4 bit tapein
3 bpl ploop
2 ploop: iny
4 bit tapein
3 bpl ploop
2 ploop: iny
4 bit tapein
3 bpl ploop
2 ploop: iny
4 bit tapein
3 bpl ploop
2 ploop: iny
4 bit tapein
3 bpl ploop
2 ploop: iny
4 bit tapein
2 bpl ploop
2 cpy #$40
2 bpl endcode
2 cpy #$15
2 bpl main
2 cpy #$07
7 store: rol nnnn,x
2 asl
3 bne main
2 lda #1
2 inx
3 bne main
6 inc store+2
3 jmp main

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

89
article/plot.py Executable file
View File

@ -0,0 +1,89 @@
#!/usr/bin/env python
import sys, math, os
try:
cycles_file = sys.argv[1]
except:
print "usage: %s cycles.txt" % sys.argv[0]
sys.exit(1)
f = open(cycles_file,'r')
freq0 = f.readline().strip()
freq1 = f.readline().strip()
start = int(f.readline().strip())
a2freq = 1020484.4497 # src: openemulator, src: https://discussions.apple.com/thread/559102
#rot = True
rot = False
xr = a2freq / float(freq0)
xcross = xr / float(2.0)
xc2 = int(xcross * 100) / float(100)
ycross = 0
xdiv = xcross / float(math.pi)
yb = -0.25
g = open('plot.gnuplot','w')
if rot:
g.write('set title " %d/%d KHz Cycle" offset 0,-2\n' % (int(freq0)/1000,int(freq1)/1000))
else:
g.write('set ylabel "%d/%d KHz Cycle"\n' % (int(freq0)/1000,int(freq1)/1000))
g.write('set term postscript \n')
g.write('set size ratio 0.5\n')
g.write('set output "plot.ps"\n')
g.write('set key off\n')
g.write('set grid xtics lt 0 lw 1 lc rgb "#000000"\n')
g.write('set grid ytics lt 0 lw 1 lc rgb "#000000"\n')
g.write('set xrange [%d:%f]\n' % (start,xr))
g.write('set yrange [%f:1]\n' % yb)
g.write('set xtics 1 font "courier,10"\n')
g.write('set x2tics 1 font "courier,10"\n')
g.write('set ytics 1 font "courier,10"\n')
g.write('set arrow from %d,0 to %f,0 nohead lw 1 lc rgb "black"\n' % (start,xr))
g.write('set arrow from %f,%f to %f,1 nohead lw 1 lc rgb "black"\n' % (xcross,yb,xcross))
if start < 0:
g.write('set arrow from %f,%f to %f,1 nohead lw 1 lc rgb "black"\n' % (0,yb,0))
g.write('set xtic rotate by 90 right \n')
g.write('set x2tic rotate by 90 left \n')
x2tics = {}
xtics = {}
base = start
ll = 0
for i in f.readlines():
cycles = int(i.split(' ')[0])
text = i.split(' ',1)[1].rstrip().upper()
if len(text) > ll:
ll = len(text)
xtics[str(base)] = text
x2tics[str(base)] = str(base)
base += cycles
x2tics[str(xc2)] = ' ZC'
if start < 0:
x2tics['0'] = '0 ZC'
g.write('set x2tics (')
for k, v in x2tics.iteritems():
g.write('"%s" %f, ' % (v,float(k)))
g.write(')\n')
g.write('set xtics (')
for k, v in xtics.iteritems():
g.write('"%s" %d, ' % (v + ' '*(ll-len(v)),int(k)))
g.write(')\n')
f.close()
g.write('set ytics ("0" 0, "+" 1, "-" %f)\n' % yb)
g.write('plot sin(x/%f)\n' % xdiv)
g.write('quit\n')
g.close()
os.system('gnuplot plot.gnuplot')
os.system('pstopdf plot.ps -o plot.pdf')
if rot:
os.system('pdf90 plot.pdf')

74
article/timeline.py Executable file
View File

@ -0,0 +1,74 @@
#!/usr/bin/env python
import sys, math, os
try:
timeline_file = sys.argv[1]
except:
print "usage: %s timeline.txt" % sys.argv[0]
sys.exit(1)
f = open(timeline_file,'r')
title = f.readline().strip() + " Audio Timeline"
start = 0
rot = True
g = open('timeline.gnuplot','w')
if rot:
g.write('set x2label "%s"\n' % title);
#else:
# g.write('set ylabel "%d/%d KHz Cycle"\n' % (int(freq0)/1000,int(freq1)/1000))
g.write('set term postscript \n')
#g.write('set size ratio 0.5\n')
g.write('set output "timeline.ps"\n')
g.write('set key off\n')
g.write('set grid xtics lt 0 lw 1 lc rgb "#000000"\n')
g.write('set grid ytics lt 0 lw 1 lc rgb "#000000"\n')
g.write('set yrange [0:1]\n')
g.write('set xtics 1 font "courier,9"\n')
g.write('set x2tics 1 font "courier,9"\n')
g.write('set xtic rotate by 90 right \n')
g.write('set x2tic rotate by 90 left \n')
g.write('unset ytics\n')
g.write('unset y2tics\n')
x2tics = {}
xtics = {}
ll = 0
for i in f.readlines():
if i[0] == '#':
continue
timestamp = float(i.split(',')[0])
label = i.split(',')[1].rstrip()
if len(label) > ll:
ll = len(label)
xtics[str(timestamp)] = label
x2tics[str(timestamp)] = str(timestamp)
g.write('set arrow from %f,0 to %f,1 nohead lw 1 lc rgb "black"\n' % (timestamp,timestamp))
xr = timestamp
g.write('set x2tics (')
for k, v in x2tics.iteritems():
g.write('"%s" %f, ' % (v,float(k)))
g.write(')\n')
g.write('set xtics (')
for k, v in xtics.iteritems():
#g.write('"%s" %f, ' % (v + ' '*(ll-len(v)),float(k)))
g.write('"%s" %f, ' % (v,float(k)))
g.write(')\n')
f.close()
#g.write('set ytics ("0" 0, "+" 1, "-" %f)\n' % yb)
g.write('set xrange [%d:%f]\n' % (start,xr))
g.write('plot 0\n')
g.write('quit\n')
g.close()
os.system('gnuplot timeline.gnuplot')
os.system('pstopdf timeline.ps -o timeline.pdf')
if rot:
os.system('pdf90 timeline.pdf')

View File

@ -47,7 +47,7 @@ phase1:
jsr readtape ; get the code
jmp $9700 ; run it
loadm:
.byte "LOADING INSTA-DI8K, ETA "
.byte "LOADING INSTA-DISK, ETA "
loadsec: ; 10 bytes for "XX SEC. ",$00
.byte 0,0,0,0,0,0,0,0,0,0
moved:

BIN
bin/c2t Executable file

Binary file not shown.

BIN
bin/c2t-96h Executable file

Binary file not shown.

BIN
bin/c2t-96h.exe Executable file

Binary file not shown.

BIN
bin/c2t.exe Executable file

Binary file not shown.

BIN
c2t

Binary file not shown.

1860
c2t-96h.c Normal file

File diff suppressed because it is too large Load Diff

20
c2t.c
View File

@ -69,19 +69,24 @@ Bugs:
*/
#if defined(_WIN32)
#include "miniz_win32.h"
#else
#include "miniz.h"
#include "fake6502.h"
#endif
#include <fake6502.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
#include "c2t.h"
#include <c2t.h>
#define ABS(x) (((x) < 0) ? -(x) : (x))
#define VERSION "Version 0.995"
#define VERSION "Version 0.996"
#define OUTFILE argv[argc-1]
#define BINARY 0
#define MONITOR 1
@ -1277,7 +1282,16 @@ int main(int argc, char **argv)
}
else {
//j = 6 + ceil(inflate_times[i-1]); // 6 = write track time, may need to make it 7
// disk ][ verified (format and no-format)
// Virtual ][ emulator verified (format and no-format, 8K only)
// CFFA3000 3.1 failed, needs more time
j = ceil(6.5 + inflate_times[i-1]); // 6 = write track time, may need to make it 7
// disk ][ verified (format and no-format)
// Apple duodisk verified (format and no-format)
// CFFA3000 3.1 verified with USB stick (no-format only)
// CFFA3000 3.1 failed with IBM 4GB Microdrive (too slow)
// Nishida Radio SDISK // (no-format only)
}
if(i==1) // seek time for track 0, just in case
j+=2;

4
c2t.h
View File

@ -1802,7 +1802,7 @@ phase1:
jsr readtape ; get the code
jmp $9700 ; run it
loadm:
.byte "LOADING INSTA-DI8K, ETA "
.byte "LOADING INSTA-DISK, ETA "
loadsec: ; 10 bytes for "XX SEC. ",$00
.byte 0,0,0,0,0,0,0,0,0,0
moved:
@ -1930,7 +1930,7 @@ unsigned char diskload8000[] = {
0x01,0xA9,0x00,0x85,0x02,0xA9,0xC0,0x85,
0x03,0x20,0x00,0x90,0x4C,0x00,0x97,0x4C,
0x4F,0x41,0x44,0x49,0x4E,0x47,0x20,0x49,
0x4E,0x53,0x54,0x41,0x2D,0x44,0x49,0x38,
0x4E,0x53,0x54,0x41,0x2D,0x44,0x49,0x53,
0x4B,0x2C,0x20,0x45,0x54,0x41,0x20,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0xA5,0x00,0x8D,0x2B,0x90,0xA5,0x01,

View File

@ -0,0 +1,78 @@
From: http://support.apple.com/kb/TA40730
This note is about the cassette interface built into the Apple II and
Apple II+, subroutines. An assumption made here is that the cassette
recorder is in the proper mode, play or record, when the read and write
routines are executed. Note also that the timing is approximate and may
vary from one Apple to another.
A record is a block of binary data. This data may be a BASIC or APPLESOFT
program, a machine language program, or just binary data. Records representing
BASIC or APPLESOFT programs are really two records, the length of the program
and the actual program. A record consists of a header, synchronous bit, the
actual data, and a checksum byte for error detection.
Monitor record format
+--------+-+-----------------------+-+
| HEADER |S| DATA |C|
+--------+-+-----------------------+-+
BASIC program record format
+--------+-+----+-+--------+-+----------------+-+
| HEADER |S| LB |C| HEADER |S| PROGRAM |C|
+--------+-+----+-+--------+-+----------------+-+
Key: S = SYNC bit
C = CHECKSUM byte
LB = BASIC program length
The header consists of 10 seconds of 770 Hz tone, (1 cycle equals 1300
microseconds). This gives enough time for the cassette motor to attain speed
and the plastic tape leader to go by. A subroutine called HEADR generates a
shortened header between the BASIC length bytes and the BASIC program itself.
The length of the header tone is controlled by the value of the accumulator on
entry to the subroutine. This can vary from 0.2 seconds to 40 seconds. On
entry the X register should be 0 and the carry flag should be set. HEADR also
generates a synchronous bit at the end of the tone. HEADR resides at
hexadecimal address $FCC9, or decimal address -882.
The last cycle of header tone and SYNC bit
---+ +-------------+ +-----+
| | | | |
+-------------+ +----+ |
| 1300 microseconds | 200 | 250 | header tone | synchronous bit |
The synchronous bit, generated by HEADR, is one half cycle of 2500 Hz, (200
microseconds) and one half cycle of 2000 Hz, (250 microseconds). It is used to
signal the end of the header tone and the start of the data.
The data is recorded on the tape with a low starting address and a high ending
address. Each byte of data is shifted out most significant bit first, least
significant bit last. A zero bit is made up of one cycle of 2 kHz, (250
microseconds per half cycle) and a one bit is one cycle of 1 kHz, (500
microseconds per half cycle). This works out to 2000 baud for zeros only and
1000 baud for ones, or an average of 1500 baud.
A zero bit and a one bit
+-----+ +----------+ +
| | | | |
+ +-----+ +----------+
| 500 usec | 1000 usec |
The checksum byte is written on the tape at the end of the data block. All
during reading or writing each data byte is EXCLUSIVE OR-ed with the checksum
byte. If the checksum computed during a read agrees with the checksum that was
written out, then the data is probably good. This method will detect an odd
number of errors for any of the eight bits of the byte.
In writing data, the cassette output uses quite simple circuitry, a flip-flop
connected through a voltage divider to the jack on the back panel of the
Apple. Any time the address $C020 is accessed this flip-flop changes state.
Accessing the flip-flop once every 500 microseconds generates a 1000 Hz
tone.

View File

@ -0,0 +1,65 @@
From: http://support.apple.com/kb/TA40737
For reading data, the cassette recorder uses a more complicated input circuit
consisting of a 741 operational amplifier configured as a zero crossing
detector. Zero crossing detection means that whenever the voltage at the input
jack goes from positive to negative (or negative to positive) the output of
the amplifier switches from a 1 to a 0 (or 0 to 1). The detector is accessed
by any read to address $C060. The sign bit (most significant bit) of the byte
read reflects the detector status. The read routines continually EXCLUSIVE
ORs this bit with the value most recently read to detect a change in state.
The amount of time required to change state indicates the incoming frequency
which then is used to determine if a one or a zero has been received. After
detecting the first zero crossing at the start of the header, the read routine
uses HEADR to generate a 3.5 delay, and then the read routine waits for the
sync bit. After HEADR generates the synchronous bit, the read routine reads
the data and puts it in the specified memory range.
In using the cassette interface to either read or write, all you need do is
specify an address range and execute the read or write subroutine. The
address range is stored in four bytes, two for the first address to be saved
and two for the last to be saved. In both cases the least significant byte is
first.
Commanding the cassette interface:
1. from the monitor:
If the start is $800 and the end is $9FF, then
800.9FFW will write the data to the cassette and
800.9FFR will retrieve it.
2. from machine language:
Again, if the start is $800 and the end is $9FF then store the address
range,
LDA #$00
STA $3C starting address low
LDA #$08
STA $3D starting address high
LDA #$FF
STA $3E ending address low
LDA #$09
STA $3F ending address high
JSR $FEDC write to block to tape
The JSR $FEDC will write to the cassette; JSR $FEFD will read from the
cassette.
3. from BASIC:
First set up the address range. If S = the start and E = the end then from
integer BASIC,
POKE 60,S MOD 256
POKE 61,S / 256
POKE 62,E MOD 256
POKE 63,E / 256
4. from APPLESOFT,
POKE 60,S - INT(S / 256) * 256
POKE 61,S / 256
POKE 62,E - INT(E / 256) * 256
POKE 63,E / 256
Then, to write out to cassette, use CALL -307; to read in from the cassette,
use CALL -259.

62
tests/gentiff.scrp Normal file
View File

@ -0,0 +1,62 @@
on run argv
set my_path to (system attribute "PWD") & "/"
set my_test to item 1 of argv
set my_machine to item 2 of argv
set my_done to item 3 of argv
set dsk to item 4 of argv
set loadcmd to item 5 of argv
set my_delay to item 6 of argv
tell application "Virtual ]["
activate
-- delay 0.5
delay 1
-- Close all open machines
close every machine saving no
-- Create a new (AppleIIe, AppleIIPlus, AppleII)
if my_machine = "iie" then
set theMachine to (make new AppleIIe)
end if
if my_machine = "iip" then
set theMachine to (make new AppleIIPlus)
end if
if my_machine = "ii" then
set theMachine to (make new AppleII)
end if
tell theMachine
-- Change to a color screen
-- set monochrome screen to false
set scanlines to true
set speaker volume to 0.25
if dsk = "1" then
insert my_path & my_test into device "S6D1"
end if
-- Now wait for the startup screen
delay 0.5
reset
set my_prompt to "*"
if loadcmd = "LOAD" then
set my_prompt to "]"
end if
repeat until the last line of the compact screen text = my_prompt
delay 0.5
end repeat
-- type line "LOAD"
type line loadcmd
play my_path & "test.aif" on device "cassette recorder"
set speed to maximum
delay my_delay
snap screen picture to POSIX path of (my_path & my_done) format tiff
end tell
delay 1
close every machine saving no
quit
end tell
end run

97
tests/gentiff.sh Executable file
View File

@ -0,0 +1,97 @@
#!/bin/bash
TIFFDIR=tiffs
C2T=../bin/c2t
_gentiff()
{
MACHINE=$1
TIFF=$2
DSK=$3
LOAD="$4"
DELAY=$5
if [ "$DSK" = "1" ]
then
dd if=/dev/zero of=test.dsk bs=1k count=140 >/dev/null 2>&1
fi
if ! OUTPUT=$(osascript gentiff.scrp test.dsk $MACHINE $TIFF $DSK "$LOAD" $DELAY)
then
echo
return 1
fi
#if echo $OUTPUT | grep ERROR >/dev/null 2>&1
#then
# echo $OUTPUT
# echo
# return 1
#fi
if test -s $TIFF
then
return 0
fi
return 1
}
mkdir -p ${TIFFDIR}
TIFF=${TIFFDIR}/dskiie.tiff
if [ ! -s "$TIFF" ]
then
eval $C2T images/zork.dsk test.aif
if ! _gentiff iie $TIFF 1 "LOAD" 15
then
echo "$TIFF failed"
exit 1
fi
fi
TIFF=${TIFFDIR}/dskiip.tiff
if [ ! -s "$TIFF" ]
then
eval $C2T images/zork.dsk test.aif
if ! _gentiff iip $TIFF 1 "LOAD" 15
then
echo "$TIFF failed"
exit 1
fi
fi
TIFF=${TIFFDIR}/mpiie.tiff
if [ ! -s "$TIFF" ]
then
eval $C2T -2bf images/moon.patrol,801 test.aif
if ! _gentiff iie $TIFF 0 "LOAD" 15
then
echo "$TIFF failed"
exit 1
fi
fi
TIFF=${TIFFDIR}/mpii.tiff
if [ ! -s "$TIFF" ]
then
eval $C2T -2af images/moon.patrol,801 test.aif
if ! _gentiff ii $TIFF 0 "800.A00R 800G" 15
then
echo "$TIFF failed"
exit 1
fi
fi
TIFF=${TIFFDIR}/spiie.tiff
if [ ! -s "$TIFF" ]
then
eval $C2T -2bc8 images/super_puckman,800 test.aif
if ! _gentiff iie $TIFF 0 "LOAD" 12
then
echo "$TIFF failed"
exit 1
fi
fi
rm -f test.aif test.dsk

BIN
tests/images/dd.po Normal file

Binary file not shown.

BIN
tests/images/moon.patrol Normal file

Binary file not shown.

BIN
tests/images/super_puckman Normal file

Binary file not shown.

BIN
tests/images/zork.dsk Normal file

Binary file not shown.

9
tests/quicktest.md Normal file
View File

@ -0,0 +1,9 @@
## Quick Test
| Test | Command | Input | Machine | Load | Compare | Offset | Timeout |
|:----:|------------------------------|-------------------|---------|---------------|-------------|:------:|:-------:|
| 1 | ../bin/c2t-96h | zork.dsk | iie | LOAD | dskiie.tiff | 0 | 25 |
| 2 | ../bin/c2t-96h -2bcf | moon.patrol,801 | iie | LOAD | mpiie.tiff | 0 | 25 |
| 3 | ../bin/c2t-96h -2bc8 | super_puckman,800 | iie | LOAD | spiie.tiff | 0 | 25 |
### Future Edit Instructions Here

26
tests/test.md Normal file
View File

@ -0,0 +1,26 @@
## Automated Tests
| Test | Command | Input | Machine | Load | Compare | Offset | Timeout |
|:----:|-------------------------------|-------------------|---------|---------------|-------------|:------:|:-------:|
| 1 | ../bin/c2t-96h | zork.dsk | iie | LOAD | dskiie.tiff | 0 | 25 |
| 2 | ../bin/c2t-96h | dd.po | iie | LOAD | dskiie.tiff | 0 | 25 |
| 3 | ../bin/c2t-96h | zork.dsk | iip | LOAD | dskiip.tiff | 0 | 25 |
| 4 | ../bin/c2t-96h | dd.po | iip | LOAD | dskiip.tiff | 0 | 25 |
| 5 | ../bin/c2t-96h -2bcf | moon.patrol,801 | iie | LOAD | mpiie.tiff | 0 | 25 |
| 6 | ../bin/c2t-96h -2bcf | moon.patrol,801 | iip | LOAD | mpiie.tiff | 0 | 25 |
| 7 | ../bin/c2t-96h -2acf | moon.patrol,801 | ii | 800.A00R 800G | mpii.tiff | 0 | 25 |
| 8 | ../bin/c2t-96h -2bc8 | super_puckman,800 | iie | LOAD | spiie.tiff | 0 | 25 |
| 9 | ../bin/c2t-96h -2bc8 | super_puckman,800 | iip | LOAD | spiie.tiff | 0 | 25 |
| 10 | ../bin/c2t-96h -2ac8 | super_puckman,800 | ii | 800.A00R 800G | spiie.tiff | 0 | 25 |
| 11 | wine ../bin/c2t-96h.exe | zork.dsk | iie | LOAD | dskiie.tiff | 0 | 25 |
| 12 | wine ../bin/c2t-96h.exe | dd.po | iie | LOAD | dskiie.tiff | 0 | 25 |
| 13 | wine ../bin/c2t-96h.exe | zork.dsk | iip | LOAD | dskiip.tiff | 0 | 25 |
| 14 | wine ../bin/c2t-96h.exe | dd.po | iip | LOAD | dskiip.tiff | 0 | 25 |
| 15 | wine ../bin/c2t-96h.exe -2bcf | moon.patrol,801 | iie | LOAD | mpiie.tiff | 0 | 25 |
| 16 | wine ../bin/c2t-96h.exe -2bcf | moon.patrol,801 | iip | LOAD | mpiie.tiff | 0 | 25 |
| 17 | wine ../bin/c2t-96h.exe -2acf | moon.patrol,801 | ii | 800.A00R 800G | mpii.tiff | 0 | 25 |
| 18 | wine ../bin/c2t-96h.exe -2bc8 | super_puckman,800 | iie | LOAD | spiie.tiff | 0 | 25 |
| 19 | wine ../bin/c2t-96h.exe -2bc8 | super_puckman,800 | iip | LOAD | spiie.tiff | 0 | 25 |
| 20 | wine ../bin/c2t-96h.exe -2ac8 | super_puckman,800 | ii | 800.A00R 800G | spiie.tiff | 0 | 25 |
### Future Edit Instructions Here

71
tests/test.scrp Normal file
View File

@ -0,0 +1,71 @@
on run argv
set my_path to (system attribute "PWD") & "/"
set my_test to item 1 of argv
set my_done to item 2 of argv
set my_machine to item 3 of argv
set dsk to item 4 of argv
set loadcmd to item 5 of argv
set my_timeout to item 6 of argv
tell application "Virtual ]["
activate
delay 1.5
-- Close all open machines
close every machine saving no
-- Create a new (AppleIIe, AppleIIPlus, AppleII)
if my_machine = "iie" then
set theMachine to (make new AppleIIe)
end if
if my_machine = "iip" then
set theMachine to (make new AppleIIPlus)
end if
if my_machine = "ii" then
set theMachine to (make new AppleII)
end if
tell theMachine
-- Change to a color screen
-- set monochrome screen to false
set scanlines to true
set speaker volume to 0.25
if dsk = "1" then
insert my_path & my_test into device "S6D1"
end if
-- Now wait for the startup screen
delay 0.5
reset
set my_prompt to "*"
if loadcmd = "LOAD" then
set my_prompt to "]"
end if
repeat until the last line of the compact screen text = my_prompt
delay 0.5
end repeat
type line loadcmd
play my_path & "test.aif" on device "cassette recorder"
set speed to maximum
try
with timeout of my_timeout seconds
waiting until screen equals imagefile POSIX path of (my_path & my_done)
end timeout
on error
return "ERROR: TIMEOUT: Virtual ][ screen != " & my_done
end try
-- short test of image, not necessary, next 3 lines can be removed
-- delay 0.5
-- type line ""
-- delay 3
end tell
delay 1.5
close every machine saving no
quit
end tell
end run

113
tests/test.sh Executable file
View File

@ -0,0 +1,113 @@
#!/bin/bash
# Path to wine binary for testing Windows binary
PATH=~/wine/bin:$PATH
TESTS=$1
IMAGES=images
TIFFS=tiffs
_test()
{
IMAGE=$1
DONE=$2
MACHINE=$3
LOAD="$4"
TIMEOT=$5
FILETYPE=$(echo $IMAGE | tr '[:upper:]' '[:lower:]' | awk -F. '{print $NF}')
DSK=0
if [ "$FILETYPE" = "po" -o "$FILETYPE" = "do" -o "$FILETYPE" = "dsk" ]
then
DSK=1
fi
if [ "$DSK" = "1" ]
then
dd if=/dev/zero of=test.$FILETYPE bs=1k count=140 >/dev/null 2>&1
fi
if ! OUTPUT=$(osascript test.scrp test.${FILETYPE} $DONE $MACHINE $DSK "$LOAD" $TIMEOT)
then
echo
return 1
fi
if echo $OUTPUT | grep ERROR >/dev/null 2>&1
then
echo $OUTPUT
echo
return 1
fi
if [ "$DSK" = "0" ]
then
rm -f test.aif
return 0
fi
S1=$(/usr/bin/shasum ${IMAGE} | awk '{print $1}')
S2=$(/usr/bin/shasum test.$FILETYPE | awk '{print $1}')
echo "$IMAGE $S1 $S2" >>test.log
echo >>test.log
if [ "$S1" = "$S2" ]
then
rm -f test.$FILETYPE test.aif
return 0
fi
return 1
}
>test.log
echo
echo "Tests:"
echo
grep '^|' $TESTS
echo
IFS=$'\n'
for i in $(grep '^| [0-9]' $TESTS | perl -p -e 's/\| +/|/g' | perl -p -e 's/ +\|/|/g' | sed 's/\|/:/g')
do
IFS=:
set -- $i
N=$2
CMD="$3"
INPUT=$4
MACHINE=$5
LOAD="$6"
DONE=$7
OFFSET=$8
TIMEOT=$9
#echo $N : $CMD : $INPUT : $MACHINE : $LOAD : $DONE : $OFFSET : $TIMEOT
if grep "^$N:" passed >/dev/null 2>&1
then
echo "Test $N already passed"
continue
fi
EC=0
echo "Running test $N..."
echo $* >>test.log
echo " $CMD $IMAGES/$INPUT test.aif"
eval "$CMD" $IMAGES/$INPUT test.aif >>test.log 2>&1
echo " _test ${IMAGES}/${INPUT} ${TIFFS}/${DONE} $MACHINE $LOAD $TIMEOT"
if _test ${IMAGES}/${INPUT} ${TIFFS}/${DONE} $MACHINE "$LOAD" $TIMEOT
then
echo " passed"
echo "$N:$(date)" >>passed
else
echo " FAILED"
EC=1
break
fi
done
unset IFS
exit $EC

BIN
tests/tiffs/dskiie.tiff Normal file

Binary file not shown.

BIN
tests/tiffs/dskiip.tiff Normal file

Binary file not shown.

BIN
tests/tiffs/mpii.tiff Normal file

Binary file not shown.

BIN
tests/tiffs/mpiie.tiff Normal file

Binary file not shown.

BIN
tests/tiffs/spiie.tiff Normal file

Binary file not shown.

Binary file not shown.