c2t-96h minor updates, doc updates, article added/updated, windows 96h binary

This commit is contained in:
Egan Ford 2015-12-31 12:19:07 -07:00
parent dc09517573
commit c96332b204
16 changed files with 2268 additions and 4 deletions

View File

@ -1,13 +1,16 @@
all: c2t
all: c2t c2t-96h
clean:
rm c2t.h c2t
rm c2t.h c2t c2t-96h
cd asm; make clean
c2t: c2t.c c2t.h
gcc -Wall -O3 -o c2t c2t.c
gcc -Wall -Wno-unused-value -Wno-unused-function -O3 -o c2t c2t.c
c2t-96h: c2t-96h.c c2t.h
gcc -Wall -Wno-unused-value -Wno-unused-function -O3 -o c2t-96h 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

View File

@ -28,7 +28,8 @@ You clearly do not understand the awesomeness of the Apple II, move along.
## Version
0.996 (Nov 29 2014)
c2t 0.996 (Nov 29 2014)
c2t-96h 0.997 (Dec 31 2015)
## Installation
@ -63,6 +64,22 @@ gcc -Wall -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/doku.php?id=compiling_for_win32>, then type:
```
cd windows
cp ../c2t.*
cp ../fake6502.h
/usr/local/gcc-4.8.0-qt-4.8.4-for-mingw32/win32-gcc/bin/i586-mingw32-gcc -Wall -Wno-unused-value -Wno-unused-function -O3 -static -o c2t.exe c2t.c
```
## c2t-96h Version
`c2t-96h` is a hacked up version of `c2t` that fixes a few bugs (e.g. `.po` files) and adds working 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.
## Tested Configurations:

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')

BIN
c2t

Binary file not shown.

BIN
c2t-96h Executable file

Binary file not shown.

1855
c2t-96h.c Normal file

File diff suppressed because it is too large Load Diff

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.

BIN
windows/c2t-96h.exe Executable file

Binary file not shown.