1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
// license:BSD-3-Clause
// copyright-holders:Curt Coder
/*********************************************************************
formats/atom_tap.c
Cassette code for Acorn Atom tap files (Kansas City Standard)
*********************************************************************/
/*
http://beebwiki.jonripley.com/Acorn_cassette_format#Atom
The Atom supports the System series format (as a 'nameless file') and its own format. The data consists of files separated
by carrier breaks and the appropriate leaders and trailers, and further subdivided into blocks separated by inter-block gaps.
An Atom block consists of the following sequence of bytes:
Four synchronisation bytes (&2A).
File name (one to thirteen characters).
One end of file name marker byte (&0D).
Block flag, one byte.
Block number, two bytes, high byte first.
Data block length ? 1, one byte.
Execution address, two bytes, high byte first.
Load address, two bytes, high byte first.
Data, 0 to 256 bytes.
Checksum, one byte.
The block flag is set as follows:
Bit 7 is set if this block is not the last block of a file.
Bit 6 is set if the block contains data. If clear then the 'data block length' field is invalid.
Bit 5 is set if this block is not the first block of a file.
Bits 4 to 0 are undefined. Normally their contents are:
in the first block, bits 15 to 11 of the end address (=1 + the last address saved in the file);
in subsequent blocks, bits 6 to 2 of the previous block flag.
The checksum is a simple sum (modulo 256) of all bytes from the start of the filename to the end of the data.
*/
#include <assert.h>
#include "atom_tap.h"
#include "csw_cas.h"
#include "uef_cas.h"
/***************************************************************************
PARAMETERS
***************************************************************************/
#define LOG 1
/***************************************************************************
IMPLEMENTATION
***************************************************************************/
/*-------------------------------------------------
CassetteModulation atom_tap_modulation
-------------------------------------------------*/
static const struct CassetteModulation atom_tap_modulation =
{
CASSETTE_MODULATION_SINEWAVE,
1200.0 - 300, 1200.0, 1200.0 + 300,
2400.0 - 600, 2400.0, 2400.0 + 600
};
/*-------------------------------------------------
cassette_image_read_uint8 - read tape data
-------------------------------------------------*/
static uint8_t cassette_image_read_uint8(cassette_image *cassette, uint64_t offset)
{
uint8_t data;
cassette_image_read(cassette, &data, offset, 1);
return data;
}
/*-------------------------------------------------
atom_tap_identify - identify cassette
-------------------------------------------------*/
static cassette_image::error atom_tap_identify(cassette_image *cassette, struct CassetteOptions *opts)
{
return cassette_modulation_identify( cassette, &atom_tap_modulation, opts);
}
/*-------------------------------------------------
atom_tap_load - load cassette
-------------------------------------------------*/
#define MODULATE(_value) \
for (int i = 0; i < (_value ? 8 : 4); i++) { \
err = cassette_put_modulated_data_bit(cassette, 0, time_index, _value, &atom_tap_modulation, &time_displacement);\
if (err != cassette_image::error::SUCCESS) return err;\
time_index += time_displacement;\
}
#define BIT(x,n) (((x)>>(n))&1)
static cassette_image::error atom_tap_load(cassette_image *cassette)
{
cassette_image::error err;
uint64_t image_size = cassette_image_size(cassette);
uint64_t image_pos = 0;
double time_index = 0.0;
double time_displacement;
while (image_pos < image_size)
{
uint8_t data = cassette_image_read_uint8(cassette, image_pos);
/* start bit */
MODULATE(0);
/* data bits */
for (int bit = 0; bit < 8; bit++)
{
MODULATE(BIT(data, bit));
}
/* stop bits */
MODULATE(1);
MODULATE(1);
image_pos++;
}
return cassette_image::error::SUCCESS;
}
/*-------------------------------------------------
CassetteFormat atom_tap_cassette_format
-------------------------------------------------*/
const struct CassetteFormat atom_tap_format =
{
"tap",
atom_tap_identify,
atom_tap_load,
nullptr
};
CASSETTE_FORMATLIST_START( atom_cassette_formats )
CASSETTE_FORMAT(atom_tap_format)
CASSETTE_FORMAT(csw_cassette_format)
CASSETTE_FORMAT(uef_cassette_format)
CASSETTE_FORMATLIST_END
|