http://wiki.kasettilamerit.fi/wiki/api.php?action=feedcontributions&user=Tnt&feedformat=atomKasettilamerit - Käyttäjän muokkaukset [fi]2024-03-28T19:17:24ZKäyttäjän muokkauksetMediaWiki 1.29.2http://wiki.kasettilamerit.fi/wiki/index.php?title=Apple_II&diff=45Apple II2017-12-02T22:56:59Z<p>Tnt: </p>
<hr />
<div>W. Gayler - The Apple II Circuit Description<br />
<br />
p. 87<br />
<br />
== Cassette Tape ==<br />
<br />
The Apple II can store and retrieve digital data using a standard audio cassette tape recorder. The hardware involved is fairly simple; all the intelligence is in the firmware. When you store a program, routines in the monitor ROM cause flip-flop J13-9 (Fig. C-12*) to generate square or rectangular waveforms. Thus, J13-8 then drives the CASSETTE DATA OUT jack. This jack is meant to be connected to the microphone input of the recorder. <br />
<br />
The earphone output of the recorder connects to the CASSETTE DATA IN jack of the Apple. When you load a program, the signals from the tape pass through operational amplifier K13, then appear at an input of data selector H14. The 6502 can read the output of H14 under program control. The program (again in the monitor ROM) then processes the cassette signal to reproduce the data. <br />
<br />
pp. 93-96<br />
<br />
== Detailed Circuit Analysis - Cassette Tape ==<br />
<br />
In this section we will describe the hardware involved in writing and reading cassette tapes. We will also touch on some aspects of the cassette system that are actually determined by the firmware.<br />
<br />
Data to be recorded on tape is formatted into records. Each record consists of several seconds of header tone followed by a sync bit, the actual data, and a check sum. Binary files and machine code are recorded as one record (Fig. 7-6A). BASIC programs are recorded as two records (Fig. 7-6B). The first record contains the BASIC program's length in the record's data field. The second record contains the BASIC program itself.<br />
<br />
[[Tiedosto:ISBN_0-672-21959-X_Fig_7-6.png]]<br />
<br />
Fig. 7-7 shows individual bits or cycles of the tones that make up the format. The times shown are approximate, but they are within 2% of measured values. The header tone consists of half cycles of 650 microseconds each. This is a frequency of 770 Hz. The sync bit contains one-half cycle of 200 microseconds followed by one-half cycle of 250 microseconds. A 0 bit consists of two 250 microsecond half cycles. Data of all 0's would be a tone of 2000 Hz. A 1 bit consists of two half cycles of 500 microseconds each. Data of all 1's would be a 1000-Hz (l-kHz) tone. It takes 500 microseconds to transmit a 0 and 1000 microseconds to transmit a 1. The average transmission rate for random data is therefore 1333 bits per second.<br />
<br />
Data is recorded low byte first. Within each byte the MSB is recorded first.<br />
<br />
[[Tiedosto:ISBN_0-672-21959-X_Fig_7-7.png]]<br />
<br />
Fig. 7-8 shows typical tape cassette waveforms near the time of the sync bit. When the cassette output ($C020-$C02F) is accessed, J13-11 goes low for 489 nS (point A). On J13-11's rising edge, J13-8 is clocked (point B). Since J13-8 connects to JL3-I2 (Fig. C-12*), this flip-flop will toggle when clocked. In Fig. 7-8 we have shown the last two and one-half cycles of the header tone. The sync bit comes next, followed by the first data byte. In this example, the first byte is $B0 or 10110000 (binary).<br />
<br />
Note that on power-up, J13-8 can be either low or high. The processor can neither initialize nor read the state of J13-8. As a result, the J13-8 waveform could be inverted from what is shown in Fig. 7-8. No matter in which state J13-8 starts, it toggles every time J13-11 goes high. That is all that matters.<br />
<br />
Resistors R18 and R19 attenuate J13-8 to about 0.8%, or 32 mV peak-peak open circuit. The attenuated signal appears at the CASSETTE DATA OUT jack of the Apple. It is connected to the microphone input of the recorder when data is stored. This concludes the discussion of the hardware used in the write direction. We now turn our attention to the read process.<br />
<br />
On data retrieval, the earphone jack of the recorder connects to the CASSETTE DATA IN jack of the Apple. There may or may not be a polarity inversion in going through the recorder; it does not matter. The cassette input is ac coupled by C10 and attenuated to 50% by R17 and R30. The signal then connects to the inverting input of operational amplifier K13.<br />
<br />
Operational amplifier K13 is wired to act as a comparator. Ground through R16 provides an average comparator threshold of 0 volt and R15 provides about 100 mV of hysteresis at the input of the comparator. This circuit arrangement is called a zero crossing detector. The minimum cassette input that produces good results is about 1 volt peak-peak. While reading tapes, the output of K13 swings from plus-saturated to minus-saturated, or about ± 4 volts.<br />
<br />
Resistor R29 limits current out of the input of H14 when K13-6 is low. Resistor R29 and the input clamping diode of H14 effectively convert the signal to a TTL level at H14-4. Note that the signal is inverted by K13. Except for an inversion, the TTL signal at J13-8 has been recreated at Hl4-4. To see this, compare the waveforms for J13-8 and H14-4 as shown in Fig. 7-8.<br />
<br />
At this point we must discuss how the cassette signal gets through data selector H14 (Fig. C-12*).If the address is in the range $C060-$C06F, then F13-9 will go low during ϕ2. This enables H14 via pin 7. Data selector H14 selects one of its eight inputs as a function of address lines AD0, AD1, and AD2. When the address is $C060 or $C068 (AD0, ADl, and AD2 all equal 0), H14 is enabled and selects input pin 4 to output on pin 5. Pin H14-5 connects to data bus bit 7. Thus, at either of these addresses, the cassette input is put on data bus bit 7. Bit 7 is used since it is easily tested by various 6502 instructions. Since ADB is not decoded by this part of the circuit, there are two addresses eight locations apart that can access the cassette input. In such cases, we usually use the lower address ($C060).<br />
<br />
[[Tiedosto:ISBN_0-672-21959-X_Fig_7-8.png|800px|thumb|left]]<br />
<br clear=all><br />
<br />
Routines in the monitor scan bit 7 at location $C060 every 12.8 microseconds looking for a transition. By measuring the time between transitions, the routines can distinguish between header, sync, 0, and 1 bits.<br />
<br />
p103<br />
<br />
<br />
[[Tiedosto:ISBN_0-672-21959-X_Fig_C-12.png|800px|thumb|left]]</div>Tnthttp://wiki.kasettilamerit.fi/wiki/index.php?title=Tiedosto:ISBN_0-672-21959-X_Fig_C-12.png&diff=44Tiedosto:ISBN 0-672-21959-X Fig C-12.png2017-12-02T22:45:29Z<p>Tnt: The Apple II Circuit Description, Fig. C-12 - On-board I/O</p>
<hr />
<div>The Apple II Circuit Description, Fig. C-12 - On-board I/O</div>Tnthttp://wiki.kasettilamerit.fi/wiki/index.php?title=Tiedosto:ISBN_0-672-21959-X_Fig_7-8.png&diff=43Tiedosto:ISBN 0-672-21959-X Fig 7-8.png2017-12-02T22:44:16Z<p>Tnt: The Apple II Circuit Description, Fig. 7-8 - Tape cassette waveforms</p>
<hr />
<div>The Apple II Circuit Description, Fig. 7-8 - Tape cassette waveforms</div>Tnthttp://wiki.kasettilamerit.fi/wiki/index.php?title=Tiedosto:ISBN_0-672-21959-X_Fig_7-7.png&diff=42Tiedosto:ISBN 0-672-21959-X Fig 7-7.png2017-12-02T22:43:29Z<p>Tnt: The Apple II Circuit Description, Fig. 7-7 - Cassette bit timing</p>
<hr />
<div>The Apple II Circuit Description, Fig. 7-7 - Cassette bit timing</div>Tnthttp://wiki.kasettilamerit.fi/wiki/index.php?title=Tiedosto:ISBN_0-672-21959-X_Fig_7-6.png&diff=41Tiedosto:ISBN 0-672-21959-X Fig 7-6.png2017-12-02T22:42:39Z<p>Tnt: The Apple II Circuit Description, Fig. 7-6 - Cassette tape formats</p>
<hr />
<div>The Apple II Circuit Description, Fig. 7-6 - Cassette tape formats</div>Tnthttp://wiki.kasettilamerit.fi/wiki/index.php?title=Apple_II&diff=40Apple II2017-12-02T19:49:02Z<p>Tnt: Ak: Uusi sivu: W. Gayler - The Apple II Circuit Description p. 87 == Cassette Tape == The Apple II can store and retrieve digital data using a standard audio cassette tape recorder. The hardwa...</p>
<hr />
<div>W. Gayler - The Apple II Circuit Description<br />
<br />
p. 87<br />
<br />
== Cassette Tape ==<br />
<br />
The Apple II can store and retrieve digital data using a standard audio cassette tape recorder. The hardware involved is fairly simple; all the intelligence is in the firmware. When you store a program, routines in the monitor ROM cause flip-flop J13-9 (Fig. C-12*) to generate square or rectangular waveforms. Thus, J13-8 then drives the CASSETTE DATA OUT jack. This jack is meant to be connected to the microphone input of the recorder. <br />
<br />
The earphone output of the recorder connects to the CASSETTE DATA IN jack of the Apple. When you load a program, the signals from the tape pass through operational amplifier K13, then appear at an input of data selector H14. The 6502 can read the output of H14 under program control. The program (again in the monitor ROM) then processes the cassette signal to reproduce the data. <br />
<br />
pp. 93-96<br />
<br />
== Detailed Circuit Analysis - Cassette Tape ==<br />
<br />
In this section we will describe the hardware involved in writing and reading cassette tapes. We will also touch on some aspects of the cassette system that are actually determined by the firmware.<br />
<br />
Data to be recorded on tape is formatted into records. Each record consists of several seconds of header tone followed by a sync bit, the actual data, and a check sum. Binary files and machine code are recorded as one record (Fig. 7-6A). BASIC programs are recorded as two records (Fig. 7-6B). The first record contains the BASIC program's length in the record's data field. The second record contains the BASIC program itself.<br />
<br />
Fig. 7-7 shows individual bits or cycles of the tones that make up the format. The times shown are approximate, but they are within 2% of measured values. The header tone consists of half cycles of 650 microseconds each. This is a frequency of 770 Hz. The sync bit contains one-half cycle of 200 microseconds followed by one-half cycle of 250 microseconds. A 0 bit consists of two 250 microsecond half cycles. Data of all 0's would be a tone of 2000 Hz. A 1 bit consists of two half cycles of 500 microseconds each. Data of all 1's would be a 1000-Hz (l-kHz) tone. It takes 500 microseconds to transmit a 0 and 1000 microseconds to transmit a 1. The average transmission rate for random data is therefore 1333 bits per second.<br />
<br />
Data is recorded low byte first. Within each byte the MSB is recorded first.<br />
<br />
Fig. 7-8 shows typical tape cassette waveforms near the time of the sync bit. When the cassette output ($C020-$C02F) is accessed, J13-11 goes low for 489 nS (point A). On J13-11's rising edge, J13-8 is clocked (point B). Since J13-8 connects to JL3-I2 (Fig. C-12*), this flip-flop will toggle when clocked. In Fig. 7-8 we have shown the last two and one-half cycles of the header tone. The sync bit comes next, followed by the first data byte. In this example, the first byte is $B0 or 10110000 (binary).<br />
<br />
Note that on power-up, J13-8 can be either low or high. The processor can neither initialize nor read the state of J13-8. As a result, the J13-8 waveform could be inverted from what is shown in Fig. 7-8. No matter in which state J13-8 starts, it toggles every time J13-11 goes high. That is all that matters.<br />
<br />
Resistors R18 and R19 attenuate J13-8 to about 0.8%, or 32 mV peak-peak open circuit. The attenuated signal appears at the CASSETTE DATA OUT jack of the Apple. It is connected to the microphone input of the recorder when data is stored. This concludes the discussion of the hardware used in the write direction. We now turn our attention to the read process.<br />
<br />
On data retrieval, the earphone jack of the recorder connects to the CASSETTE DATA IN jack of the Apple. There may or may not be a polarity inversion in going through the recorder; it does not matter. The cassette input is ac coupled by C10 and attenuated to 50% by R17 and R30. The signal then connects to the inverting input of operational amplifier K13.<br />
<br />
Operational amplifier K13 is wired to act as a comparator. Ground through R16 provides an average comparator threshold of 0 volt and R15 provides about 100 mV of hysteresis at the input of the comparator. This circuit arrangement is called a zero crossing detector. The minimum cassette input that produces good results is about 1 volt peak-peak. While reading tapes, the output of K13 swings from plus-saturated to minus-saturated, or about ± 4 volts.<br />
<br />
Resistor R29 limits current out of the input of H14 when K13-6 is low. Resistor R29 and the input clamping diode of H14 effectively convert the signal to a TTL level at H14-4. Note that the signal is inverted by K13. Except for an inversion, the TTL signal at J13-8 has been recreated at Hl4-4. To see this, compare the waveforms for J13-8 and H14-4 as shown in Fig. 7-8.<br />
<br />
At this point we must discuss how the cassette signal gets through data selector H14 (Fig. C-12*).If the address is in the range $C060-$C06F, then F13-9 will go low during ϕ2. This enables H14 via pin 7. Data selector H14 selects one of its eight inputs as a function of address lines AD0, AD1, and AD2. When the address is $C060 or $C068 (AD0, ADl, and AD2 all equal 0), H14 is enabled and selects input pin 4 to output on pin 5. Pin H14-5 connects to data bus bit 7. Thus, at either of these addresses, the cassette input is put on data bus bit 7. Bit 7 is used since it is easily tested by various 6502 instructions. Since ADB is not decoded by this part of the circuit, there are two addresses eight locations apart that can access the cassette input. In such cases, we usually use the lower address ($C060).<br />
<br />
Routines in the monitor scan bit 7 at location $C060 every 12.8 microseconds looking for a transition. By measuring the time between transitions, the routines can distinguish between header, sync, 0, and 1 bits.<br />
<br />
p103<br />
<br />
<br />
Fig. C-12</div>Tnthttp://wiki.kasettilamerit.fi/wiki/index.php?title=Tiedosto:Wave_svi_3x8_byte_31.svg&diff=31Tiedosto:Wave svi 3x8 byte 31.svg2017-11-27T10:03:01Z<p>Tnt: Tnt tallensi uuden version tiedostosta Tiedosto:Wave svi 3x8 byte 31.svg</p>
<hr />
<div>Byte 0x31 encoded as Spectravideo 3x8 cassette signal</div>Tnthttp://wiki.kasettilamerit.fi/wiki/index.php?title=Tiedosto:Wave_svi_3x8_byte_31.svg&diff=30Tiedosto:Wave svi 3x8 byte 31.svg2017-11-27T10:01:55Z<p>Tnt: Tnt tallensi uuden version tiedostosta Tiedosto:Wave svi 3x8 byte 31.svg</p>
<hr />
<div>Byte 0x31 encoded as Spectravideo 3x8 cassette signal</div>Tnthttp://wiki.kasettilamerit.fi/wiki/index.php?title=Spectravideo&diff=29Spectravideo2017-11-26T13:18:08Z<p>Tnt: </p>
<hr />
<div><br />
== Physical interface and memory mapping==<br />
Spectravideo 3x8 uses [https://en.wikipedia.org/wiki/Intel_8255 Intel 8255 Programmable Peripheral Interface] to read and write cassette data.<br />
<br />
I/O ports used for cassette data:<br />
<br />
;Port A (0x98)<br />
: Bit 7: Cassette: Read data<br />
: Bit 6: Cassette: Ready<br />
;Port C (0x97)<br />
: Bit 5: Cassette: Write data<br />
: Bit 4: Cassette: Motor relay control (0=on, 1=off)<br />
<br />
All ports are in mode 0 - simple I/O.<br />
<br />
[[Tiedosto:Svi_ppi_8255.png]]<br />
<br />
;Official Spectravideo cassette players<br />
: SV-903 Data Cassette (1800 bps, stereo, microphone) <br />
: SV-904 Data Cassette (1800 bps) <br />
;Do-it-yourself interface for any cassette player<br />
: Universal Cassette Interface> by Peter Zevenhoven. Published in C.U.C. magazine #18.<br />
<br />
== Cassette data lead-in and sync==<br />
<br />
Lead-in consists of 3200 alternating short and long pulses.<br />
<br />
=== Normal signal ===<br />
<br />
[[Tiedosto:wave_normal_falling_edge.svg]]<br />
<br />
Time between falling edges is clearly different.<br />
<br />
=== Inverted signal: ===<br />
<br />
[[Tiedosto:Wave_inverted_falling_edge.svg]]<br />
<br />
Time between falling edges is constant because it takes one half of both short pulse and long pulse.<br />
<br />
Spectravideo ROM code checks the polarity of cassette signal with a routine at 0x2117. It does that by measuring 100 pulse pairs and checking whether their lengths are all far enough from each other to be normal signal or close enough to be inverted signal.<br />
If cassette signal is inverted, code sets flag at 0xFD4C to non-zero value. Read_pulse routine at 0x2164 uses this flag to use either falling or rising edge to measure pulse length.<br />
<br />
Once the polarity has been detected, ROM code at 0x2149 waits until it finds bit pattern 01111111. Only then it returns and the actual header starts.<br />
<br />
[[Tiedosto:Wave_svi_3x8_sync.svg]]<br />
<br />
== Stop byte ==<br />
Whenever the tape is stopped, one extra zero byte (with start bit) is written, followed by a short pause before the tape player motor is actually stopped.<br />
<br />
<br />
== Data bytes ==<br />
Everything except the lead-in and sync mark is stored with nine pulses - each data byte has a start bit prepended to it. That is done to give some extra time for inter-byte processing and to ensure that Spectravideo can accurately measure length of the first data bit.<br />
Start bit is always a long pulse (0) but that isn't checked in the loader code.<br />
<br />
For example, byte 0x31 ("1") is coded as<br />
<br />
[[Tiedosto:Wave_svi_3x8_byte_31.svg]]<br />
<br />
The first pulse is the start bit, next eight are bits "00110001" stored the most significant bit first.<br />
<br />
== Header ==<br />
Header consists of 17 bytes:<br />
<br />
;Type<br />
: Header type - repeated 10 times<br />
;File name<br />
: Name in ASCII - six chars, padded with space (0x20)<br />
;Attribute byte<br />
: Extra byte used to tell which screen mode was used when saving screen data. Otherwise unused.<br />
<br />
Cassette is stopped after writing the header. This routine at 0x206C adds one more zero byte which isn't technically part of the header.<br />
<br />
== Different file types==<br />
Spectravideo uses the following standard file types, but nothing stops users from using their own, either by calling ROM functions or rolling their own ones.<br />
Note that the zero byte written by _CTWOFF routine called at STOP is not explicitly shown below.<br />
<br />
;=== CSAVE ... - tokenized BASIC program ===<br />
: SYNC<br />
: HEADER - type=0xD3, attribute=0xFF<br />
: STOP<br />
: SYNC<br />
: DATA[] - tokenized BASIC<br />
: 7 * 0x00<br />
: STOP<br />
<br />
;=== CSAVE ...,S - screen mode 0, text only ===<br />
: SYNC<br />
: HEADER - type=0xD3, attribute=0x00<br />
: STOP<br />
: SYNC<br />
: DATA[] - 0x03C0 bytes, written to VDP[0x0000-0x03BF] (text)<br />
: STOP<br />
<br />
;=== CSAVE ...,S - screen mode 1, hi-res ===<br />
: SYNC<br />
: HEADER - type=0xD3, attribute=0x01<br />
: STOP<br />
: SYNC<br />
: DATA[] - 0x1800 bytes, written to VDP[0x0000-0x17FF] (bitmap)<br />
: DATA[] - 0x1800 bytes, written to VDP[0x2000-0x37FF] (color)<br />
: DATA[] - 0x0080 bytes, written to VDP[0x1B00-0x1B7F] (sprite attributes)<br />
: DATA[] - 0x0800 bytes, written to VDP[0x3800-0x3FFF] (sprite data)<br />
: STOP<br />
<br />
;=== CSAVE ...,S - screen mode 2, lo-res ===<br />
: SYNC<br />
: HEADER - type=0xD3, attribute=0x02<br />
: STOP<br />
: SYNC<br />
: DATA[] - 0x0600 bytes, written to VDP[0x0000-0x05FF] ()<br />
: DATA[] - 0x0080 bytes, written to VDP[0x1B00-0x1B7F] (sprite attributes)<br />
: DATA[] - 0x0800 bytes, written to VDP[0x3800-0x3FFF] (sprite data)<br />
: STOP<br />
<br />
;=== BSAVE ...,start,end,exec - binary data ===<br />
: SYNC<br />
: HEADER - type=0xD0, attribute=0x00<br />
: STOP<br />
: SYNC<br />
: start.w - 16-bit start address, low byte first<br />
: end.w - 16-bit end address<br />
: exec.w - 16-bit execution address (if not given in BSAVE command exec defaults to start)<br />
: DATA[] - from start to end, inclusive<br />
: STOP<br />
<br />
;=== OPEN "CAS..." - Sequential file ===<br />
;=== also used when BASIC program is saved in ASCII format, using command SAVE ...,A<br />
: SYNC<br />
: HEADER - type=0xEA, attribute=0x00<br />
: STOP<br />
: SYNC<br />
: DATA [256] - 256 bytes of data<br />
: STOP<br />
: SYNC + DATA[] + STOP - repeated until the last block<br />
: SYNC<br />
: DATA [256] - last block is padded with 0x1A, no other info about the data length is given<br />
: STOP<br />
<br />
<br />
----<br />
<br />
----<br />
<br />
----<br />
<br />
<br />
; SYNC<br />
: 400 * 55h (raw)<br />
: 1 * 7fh (raw)<br />
<br />
; BYTE<br />
: STARTBIT : - this is not verified to be zero when reading<br />
: DATA : MSB first<br />
<br />
; STOP<br />
: 1 * 00<br />
: pause<br />
: motor off<br />
<br />
; HEADER<br />
: 10 * type<br />
: 6 * name - padded with spaces<br />
: 1 * attribute<br />
<br />
----<br />
<br />
; CSAVE ...<br />
; SAVE "CAS..."<br />
; CLOAD ...<br />
: SYNC<br />
: HEADER D3,FF - CSAVE, not screen<br />
: STOP<br />
: SYNC<br />
: DATA[] - tokenized BASIC<br />
: 7 * 00<br />
: STOP<br />
<br />
;CSAVE ...,S<br />
;SAVE "CAS...",S<br />
;CLOAD ...<br />
<br />
: SYNC<br />
: HEADER D3,00 - CSAVE SCREEN 0<br />
: STOP<br />
: SYNC<br />
: DATA[03C0h] - written to VDP[0000h-03BFh]<br />
: STOP<br />
<br />
<br />
: SYNC<br />
: HEADER D3,01 - CSAVE SCREEN 1<br />
: STOP<br />
: SYNC<br />
: DATA[1800h] - written to VDP[0000h-17FFh] - bitmap<br />
: DATA[1800h] - written to VDP[2000h-37FFh] - color<br />
: DATA[0080h] - written to VDP[1B00h-1B7Fh] - sprite attributes<br />
: DATA[0800h] - written to VDP[3800h-3FFFh] - sprite data<br />
: STOP<br />
<br />
<br />
: SYNC<br />
: HEADER D3,02 - CSAVE SCREEN 2<br />
: STOP<br />
: SYNC<br />
: DATA[0600h] - written to VDP[0000h-05FFh] - color<br />
: DATA[0080h] - written to VDP[1B00h-1B7Fh] - sprite attributes<br />
: DATA[0800h] - written to VDP[3800h-3FFFh] - sprite data<br />
: STOP<br />
<br />
----<br />
<br />
;BSAVE ...,start,end,exec<br />
;BLOAD ...<br />
: SYNC<br />
: HEADER D0,00 - BSAVE<br />
: STOP<br />
: SYNC<br />
: start.w - lo,hi<br />
: end.w - -''-<br />
: exec.w - -''-<br />
: DATA[] - from start to end, inclusive<br />
: STOP<br />
<br />
----<br />
<br />
;OPEN "CAS..." - Sequential file<br />
;SAVE ,A<br />
<br />
: SYNC<br />
: HEADER EA,00 - Sequential file<br />
: STOP<br />
: SYNC<br />
: DATA [256]<br />
: STOP<br />
: ...<br />
: SYNC<br />
: DATA {256] - last block is padded with 1Ah<br />
: STOP</div>Tnthttp://wiki.kasettilamerit.fi/wiki/index.php?title=Spectravideo&diff=28Spectravideo2017-11-26T13:16:13Z<p>Tnt: </p>
<hr />
<div><br />
== Physical interface and memory mapping==<br />
Spectravideo 3x8 uses [https://en.wikipedia.org/wiki/Intel_8255 Intel 8255 Programmable Peripheral Interface] to read and write cassette data.<br />
<br />
I/O ports used for cassette data:<br />
<br />
;Port A (0x98)<br />
: Bit 7: Cassette: Read data<br />
: Bit 6: Cassette: Ready<br />
;Port C (0x97)<br />
: Bit 5: Cassette: Write data<br />
: Bit 4: Cassette: Motor relay control (0=on, 1=off)<br />
<br />
All ports are in mode 0 - simple I/O.<br />
<br />
[[Tiedosto:Svi_ppi_8255.png]]<br />
<br />
;Official Spectravideo cassette players<br />
: SV-903 Data Cassette (1800 bps, stereo, microphone) <br />
: SV-904 Data Cassette (1800 bps) <br />
;Do-it-yourself interface for any cassette player<br />
: Universal Cassette Interface> by Peter Zevenhoven. Published in C.U.C. magazine #18.<br />
<br />
== Cassette data lead-in and sync==<br />
<br />
Lead-in consists of 3200 alternating short and long pulses.<br />
<br />
=== Normal signal ===<br />
<br />
[[Tiedosto:wave_normal_falling_edge.svg]]<br />
<br />
Time between falling edges is clearly different.<br />
<br />
=== Inverted signal: ===<br />
<br />
[[Tiedosto:Wave_inverted_falling_edge.svg]]<br />
<br />
Time between falling edges is constant because it takes one half of both short pulse and long pulse.<br />
<br />
Spectravideo ROM code checks the polarity of cassette signal with a routine at 0x2117. It does that by measuring 100 pulse pairs and checking whether their lengths are all far enough from each other to be normal signal or close enough to be inverted signal.<br />
If cassette signal is inverted, code sets flag at 0xFD4C to non-zero value. Read_pulse routine at 0x2164 uses this flag to use either falling or rising edge to measure pulse length.<br />
<br />
Once the polarity has been detected, ROM code at 0x2149 waits until it finds bit pattern 01111111. Only then it returns and the actual header starts.<br />
<br />
[[Tiedosto:Wave_svi_3x8_sync.svg]]<br />
<br />
=== Stop byte ===<br />
Whenever the tape is stopped, one extra zero byte (with start bit) is written, followed by a short pause before the tape player motor is actually stopped.<br />
<br />
<br />
=== Data bytes ===<br />
Everything except the lead-in and sync mark is stored with nine pulses - each data byte has a start bit prepended to it. That is done to give some extra time for inter-byte processing and to ensure that Spectravideo can accurately measure length of the first data bit.<br />
Start bit is always a long pulse (0) but that isn't checked in the loader code.<br />
<br />
For example, byte 0x31 ("1") is coded as<br />
<br />
[[Tiedosto:Wave_svi_3x8_byte_31.svg]]<br />
<br />
The first pulse is the start bit, next eight are bits "00110001" stored the most significant bit first.<br />
<br />
=== Header ===<br />
Header consists of 17 bytes:<br />
<br />
;Type<br />
: Header type - repeated 10 times<br />
;File name<br />
: Name in ASCII - six chars, padded with space (0x20)<br />
;Attribute byte<br />
: Extra byte used to tell which screen mode was used when saving screen data. Otherwise unused.<br />
<br />
Cassette is stopped after writing the header. This routine at 0x206C adds one more zero byte which isn't technically part of the header.<br />
<br />
== Different file types==<br />
Spectravideo uses the following standard file types, but nothing stops users from using their own, either by calling ROM functions or rolling their own ones.<br />
Note that the zero byte written by _CTWOFF routine called at STOP is not explicitly shown below.<br />
<br />
;=== CSAVE ... - tokenized BASIC program ===<br />
: SYNC<br />
: HEADER - type=0xD3, attribute=0xFF<br />
: STOP<br />
: SYNC<br />
: DATA[] - tokenized BASIC<br />
: 7 * 0x00<br />
: STOP<br />
<br />
;=== CSAVE ...,S - screen mode 0, text only ===<br />
: SYNC<br />
: HEADER - type=0xD3, attribute=0x00<br />
: STOP<br />
: SYNC<br />
: DATA[] - 0x03C0 bytes, written to VDP[0x0000-0x03BF] (text)<br />
: STOP<br />
<br />
;=== CSAVE ...,S - screen mode 1, hi-res ===<br />
: SYNC<br />
: HEADER - type=0xD3, attribute=0x01<br />
: STOP<br />
: SYNC<br />
: DATA[] - 0x1800 bytes, written to VDP[0x0000-0x17FF] (bitmap)<br />
: DATA[] - 0x1800 bytes, written to VDP[0x2000-0x37FF] (color)<br />
: DATA[] - 0x0080 bytes, written to VDP[0x1B00-0x1B7F] (sprite attributes)<br />
: DATA[] - 0x0800 bytes, written to VDP[0x3800-0x3FFF] (sprite data)<br />
: STOP<br />
<br />
;=== CSAVE ...,S - screen mode 2, lo-res ===<br />
: SYNC<br />
: HEADER - type=0xD3, attribute=0x02<br />
: STOP<br />
: SYNC<br />
: DATA[] - 0x0600 bytes, written to VDP[0x0000-0x05FF] ()<br />
: DATA[] - 0x0080 bytes, written to VDP[0x1B00-0x1B7F] (sprite attributes)<br />
: DATA[] - 0x0800 bytes, written to VDP[0x3800-0x3FFF] (sprite data)<br />
: STOP<br />
<br />
;=== BSAVE ...,start,end,exec - binary data ===<br />
: SYNC<br />
: HEADER - type=0xD0, attribute=0x00<br />
: STOP<br />
: SYNC<br />
: start.w - 16-bit start address, low byte first<br />
: end.w - 16-bit end address<br />
: exec.w - 16-bit execution address (if not given in BSAVE command exec defaults to start)<br />
: DATA[] - from start to end, inclusive<br />
: STOP<br />
<br />
;=== OPEN "CAS..." - Sequential file ===<br />
;=== also used when BASIC program is saved in ASCII format, using command SAVE ...,A<br />
: SYNC<br />
: HEADER - type=0xEA, attribute=0x00<br />
: STOP<br />
: SYNC<br />
: DATA [256] - 256 bytes of data<br />
: STOP<br />
: SYNC + DATA[] + STOP - repeated until the last block<br />
: SYNC<br />
: DATA [256] - last block is padded with 0x1A, no other info about the data length is given<br />
: STOP<br />
<br />
<br />
----<br />
<br />
----<br />
<br />
----<br />
<br />
<br />
; SYNC<br />
: 400 * 55h (raw)<br />
: 1 * 7fh (raw)<br />
<br />
; BYTE<br />
: STARTBIT : - this is not verified to be zero when reading<br />
: DATA : MSB first<br />
<br />
; STOP<br />
: 1 * 00<br />
: pause<br />
: motor off<br />
<br />
; HEADER<br />
: 10 * type<br />
: 6 * name - padded with spaces<br />
: 1 * attribute<br />
<br />
----<br />
<br />
; CSAVE ...<br />
; SAVE "CAS..."<br />
; CLOAD ...<br />
: SYNC<br />
: HEADER D3,FF - CSAVE, not screen<br />
: STOP<br />
: SYNC<br />
: DATA[] - tokenized BASIC<br />
: 7 * 00<br />
: STOP<br />
<br />
;CSAVE ...,S<br />
;SAVE "CAS...",S<br />
;CLOAD ...<br />
<br />
: SYNC<br />
: HEADER D3,00 - CSAVE SCREEN 0<br />
: STOP<br />
: SYNC<br />
: DATA[03C0h] - written to VDP[0000h-03BFh]<br />
: STOP<br />
<br />
<br />
: SYNC<br />
: HEADER D3,01 - CSAVE SCREEN 1<br />
: STOP<br />
: SYNC<br />
: DATA[1800h] - written to VDP[0000h-17FFh] - bitmap<br />
: DATA[1800h] - written to VDP[2000h-37FFh] - color<br />
: DATA[0080h] - written to VDP[1B00h-1B7Fh] - sprite attributes<br />
: DATA[0800h] - written to VDP[3800h-3FFFh] - sprite data<br />
: STOP<br />
<br />
<br />
: SYNC<br />
: HEADER D3,02 - CSAVE SCREEN 2<br />
: STOP<br />
: SYNC<br />
: DATA[0600h] - written to VDP[0000h-05FFh] - color<br />
: DATA[0080h] - written to VDP[1B00h-1B7Fh] - sprite attributes<br />
: DATA[0800h] - written to VDP[3800h-3FFFh] - sprite data<br />
: STOP<br />
<br />
----<br />
<br />
;BSAVE ...,start,end,exec<br />
;BLOAD ...<br />
: SYNC<br />
: HEADER D0,00 - BSAVE<br />
: STOP<br />
: SYNC<br />
: start.w - lo,hi<br />
: end.w - -''-<br />
: exec.w - -''-<br />
: DATA[] - from start to end, inclusive<br />
: STOP<br />
<br />
----<br />
<br />
;OPEN "CAS..." - Sequential file<br />
;SAVE ,A<br />
<br />
: SYNC<br />
: HEADER EA,00 - Sequential file<br />
: STOP<br />
: SYNC<br />
: DATA [256]<br />
: STOP<br />
: ...<br />
: SYNC<br />
: DATA {256] - last block is padded with 1Ah<br />
: STOP</div>Tnthttp://wiki.kasettilamerit.fi/wiki/index.php?title=Tiedosto:Wave_svi_3x8_byte_31.svg&diff=27Tiedosto:Wave svi 3x8 byte 31.svg2017-11-26T13:06:12Z<p>Tnt: Byte 0x31 encoded as Spectravideo 3x8 cassette signal</p>
<hr />
<div>Byte 0x31 encoded as Spectravideo 3x8 cassette signal</div>Tnthttp://wiki.kasettilamerit.fi/wiki/index.php?title=Tiedosto:Wave_svi_3x8_sync.svg&diff=26Tiedosto:Wave svi 3x8 sync.svg2017-11-26T13:02:11Z<p>Tnt: Spectravideo 318/328 sync signal</p>
<hr />
<div>Spectravideo 318/328 sync signal</div>Tnthttp://wiki.kasettilamerit.fi/wiki/index.php?title=Tiedosto:Wave_inverted_falling_edge.svg&diff=25Tiedosto:Wave inverted falling edge.svg2017-11-26T12:59:36Z<p>Tnt: Pulse length incorrectly measured between falling edges when the signal is inverted</p>
<hr />
<div>Pulse length incorrectly measured between falling edges when the signal is inverted</div>Tnthttp://wiki.kasettilamerit.fi/wiki/index.php?title=Tiedosto:Wave_normal_falling_edge.svg&diff=24Tiedosto:Wave normal falling edge.svg2017-11-26T12:46:01Z<p>Tnt: Pulse length correctly measured between falling edges</p>
<hr />
<div>Pulse length correctly measured between falling edges</div>Tnthttp://wiki.kasettilamerit.fi/wiki/index.php?title=Tiedosto:Svi_ppi_8255.png&diff=23Tiedosto:Svi ppi 8255.png2017-11-26T12:31:19Z<p>Tnt: Spectravideo 318 cassette interface schematics</p>
<hr />
<div>Spectravideo 318 cassette interface schematics</div>Tnthttp://wiki.kasettilamerit.fi/wiki/index.php?title=Spectravideo&diff=2Spectravideo2017-11-21T08:48:29Z<p>Tnt: Ak: Uusi sivu: ; SYNC : 400 * 55h (raw) : 1 * 7fh (raw) ; BYTE : STARTBIT : - this is not verified to be zero when reading : DATA : MSB first ; STOP : 1 * 00 : pause : motor off ; HEADER : 10...</p>
<hr />
<div>; SYNC<br />
: 400 * 55h (raw)<br />
: 1 * 7fh (raw)<br />
<br />
; BYTE<br />
: STARTBIT : - this is not verified to be zero when reading<br />
: DATA : MSB first<br />
<br />
; STOP<br />
: 1 * 00<br />
: pause<br />
: motor off<br />
<br />
; HEADER<br />
: 10 * type<br />
: 6 * name - padded with spaces<br />
: 1 * attribute<br />
<br />
----<br />
<br />
; CSAVE ...<br />
; SAVE "CAS..."<br />
; CLOAD ...<br />
: SYNC<br />
: HEADER D3,FF - CSAVE, not screen<br />
: STOP<br />
: SYNC<br />
: DATA[] - tokenized BASIC<br />
: 7 * 00<br />
: STOP<br />
<br />
;CSAVE ...,S<br />
;SAVE "CAS...",S<br />
;CLOAD ...<br />
<br />
: SYNC<br />
: HEADER D3,00 - CSAVE SCREEN 0<br />
: STOP<br />
: SYNC<br />
: DATA[03C0h] - written to VDP[0000h-03BFh]<br />
: STOP<br />
<br />
<br />
: SYNC<br />
: HEADER D3,01 - CSAVE SCREEN 1<br />
: STOP<br />
: SYNC<br />
: DATA[1800h] - written to VDP[0000h-17FFh] - bitmap<br />
: DATA[1800h] - written to VDP[2000h-37FFh] - color<br />
: DATA[0080h] - written to VDP[1B00h-1B7Fh] - sprite attributes<br />
: DATA[0800h] - written to VDP[3800h-3FFFh] - sprite data<br />
: STOP<br />
<br />
<br />
: SYNC<br />
: HEADER D3,02 - CSAVE SCREEN 2<br />
: STOP<br />
: SYNC<br />
: DATA[0600h] - written to VDP[0000h-05FFh] - color<br />
: DATA[0080h] - written to VDP[1B00h-1B7Fh] - sprite attributes<br />
: DATA[0800h] - written to VDP[3800h-3FFFh] - sprite data<br />
: STOP<br />
<br />
----<br />
<br />
;BSAVE ...,start,end,exec<br />
;BLOAD ...<br />
: SYNC<br />
: HEADER D0,00 - BSAVE<br />
: STOP<br />
: SYNC<br />
: start.w - lo,hi<br />
: end.w - -''-<br />
: exec.w - -''-<br />
: DATA[] - from start to end, inclusive<br />
: STOP<br />
<br />
----<br />
<br />
;OPEN "CAS..." - Sequential file<br />
;SAVE ,A<br />
<br />
: SYNC<br />
: HEADER EA,00 - Sequential file<br />
: STOP<br />
: SYNC<br />
: DATA [256]<br />
: STOP<br />
: ...<br />
: SYNC<br />
: DATA {256] - last block is padded with 1Ah<br />
: STOP</div>Tnt