// license:BSD-3-Clause // copyright-holders:Robbbert /******************************************************************** Support for Microbee cassette images Microbee tapes consist of 3 sections 1. A leader of 63 zeroes 2. A header which contains the program name and other info 3. The main program Each byte after conversion becomes a start bit, bit 0,1,etc to 7, then 2 stop bits. At 1200 baud, a high = 2 cycles of 2400Hz and a low = 1 cycle of 1200Hz At 300 baud, a high = 8 cycles of 2400Hz and a low = 4 cycles of 1200Hz The header bytes are arranged thus: 1 (SOH) 0x01 6 File name 1 file type (M=machine language, B=Basic) 2 length 2 load address 2 exec address 1 tape speed (0 = 300 baud; other = 1200 baud) 1 auto-start (0 = no) 1 unassigned byte 1 CRC byte The header is always at 300 baud; the program will be at the speed indicated by the speed byte. By coincidence (or not), the header is the same format as that of the Sorcerer and SOL-20. In these, the speed and auto-start bytes are unassigned. The CRC uses the same algorithm. The main program is broken into blocks of 256, with each block having its own CRC byte. Microbee tape and quickload formats: BEE - straight binary dump to address 0900, no header. For Machine Language programs. BIN - the standard z80bin format. COM - straight binary dump to address 0100, no header. For Machine Language programs. MWB - straight binary dump to address 08C0, no header. For BASIC programs. TAP - has an ID header of TAP_DGOS_BEE or MBEE, null terminated. This is followed by the binary dump with the leader and CRC bytes included. ********************************************************************/ #include #include "mbee_cas.h" #define WAVEENTRY_LOW -32768 #define WAVEENTRY_HIGH 32767 #define MBEE_WAV_FREQUENCY 9600 // image size static int mbee_image_size; static bool mbee_speed; static int mbee_put_samples(int16_t *buffer, int sample_pos, int count, int level) { if (buffer) { for (int i=0; i> i) & 1); /* stop */ for (i = 0; i<2; i++) samples += mbee_output_bit (buffer, sample_pos + samples, 1); return samples; } static int mbee_handle_tap(int16_t *buffer, const uint8_t *bytes) { uint32_t sample_count = 0; uint32_t byte_count = 0; uint32_t i = 0; bool temp_speed = 0; uint8_t temp_blocks = 0; uint16_t temp_size = 0; // TAP file starts with a null-terminate ID string. We just skip this. while (bytes[byte_count]) byte_count++; // there can be a library of files, loop through them all while (byte_count < mbee_image_size) { mbee_speed = 0; // now output the leader while ( (!bytes[byte_count]) && (byte_count < mbee_image_size) ) sample_count += mbee_output_byte(buffer, sample_count, bytes[byte_count++]); // make sure SOH is where we expect if (bytes[byte_count] != 1 ) break; // store the size for later temp_blocks = bytes[byte_count + 9]; temp_size = bytes[byte_count + 8] + temp_blocks*256; // store the speed for later temp_speed = (bytes[byte_count + 15]) ? 1 : 0; /* header */ for (i=0; i<18; i++) sample_count += mbee_output_byte(buffer, sample_count, bytes[byte_count++]); // change speed mbee_speed = temp_speed; // calculate size of program including CRC bytes temp_size = temp_size + temp_blocks + 1; /* data */ for (i=0; i