(MESS) microbee : added support for TAP and BEE formats (used in ubee512 emulator) [Robbbert]

This commit is contained in:
Robbbert 2014-02-27 13:01:33 +00:00
parent b474c7dcb1
commit f273d09bd5
7 changed files with 317 additions and 6 deletions

2
.gitattributes vendored
View File

@ -2887,6 +2887,8 @@ src/lib/formats/m20_dsk.c svneol=native#text/plain
src/lib/formats/m20_dsk.h svneol=native#text/plain
src/lib/formats/m5_dsk.c svneol=native#text/plain
src/lib/formats/m5_dsk.h svneol=native#text/plain
src/lib/formats/mbee_cas.c svneol=native#text/plain
src/lib/formats/mbee_cas.h svneol=native#text/plain
src/lib/formats/mbee_dsk.c svneol=native#text/plain
src/lib/formats/mbee_dsk.h svneol=native#text/plain
src/lib/formats/mfi_dsk.c svneol=native#text/plain

259
src/lib/formats/mbee_cas.c Normal file
View File

@ -0,0 +1,259 @@
// 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 "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 *buffer, int sample_pos, int count, int level)
{
if (buffer)
{
for (int i=0; i<count; i++)
buffer[sample_pos + i] = level;
}
return count;
}
static int mbee_output_bit(INT16 *buffer, int sample_pos, bool bit)
{
int samples = 0;
if (mbee_speed)
{
if (bit)
{
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_LOW);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_HIGH);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_LOW);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_HIGH);
}
else
{
samples += mbee_put_samples(buffer, sample_pos + samples, 4, WAVEENTRY_LOW);
samples += mbee_put_samples(buffer, sample_pos + samples, 4, WAVEENTRY_HIGH);
}
}
else
{
if (bit)
{
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_LOW);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_HIGH);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_LOW);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_HIGH);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_LOW);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_HIGH);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_LOW);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_HIGH);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_LOW);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_HIGH);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_LOW);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_HIGH);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_LOW);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_HIGH);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_LOW);
samples += mbee_put_samples(buffer, sample_pos + samples, 2, WAVEENTRY_HIGH);
}
else
{
samples += mbee_put_samples(buffer, sample_pos + samples, 4, WAVEENTRY_LOW);
samples += mbee_put_samples(buffer, sample_pos + samples, 4, WAVEENTRY_HIGH);
samples += mbee_put_samples(buffer, sample_pos + samples, 4, WAVEENTRY_LOW);
samples += mbee_put_samples(buffer, sample_pos + samples, 4, WAVEENTRY_HIGH);
samples += mbee_put_samples(buffer, sample_pos + samples, 4, WAVEENTRY_LOW);
samples += mbee_put_samples(buffer, sample_pos + samples, 4, WAVEENTRY_HIGH);
samples += mbee_put_samples(buffer, sample_pos + samples, 4, WAVEENTRY_LOW);
samples += mbee_put_samples(buffer, sample_pos + samples, 4, WAVEENTRY_HIGH);
}
}
return samples;
}
static int mbee_output_byte(INT16 *buffer, int sample_pos, UINT8 byte)
{
int samples = 0;
UINT8 i;
/* start */
samples += mbee_output_bit (buffer, sample_pos + samples, 0);
/* data */
for (i = 0; i<8; i++)
samples += mbee_output_bit (buffer, sample_pos + samples, (byte >> 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 *buffer, const UINT8 *bytes)
{
UINT32 sample_count = 0;
UINT32 byte_count = 0;
UINT32 i = 0;
bool temp_speed = 0;
UINT8 temp_blocks = 0;
UINT16 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<temp_size; i++)
sample_count += mbee_output_byte(buffer, sample_count, bytes[byte_count++]);
}
return sample_count;
}
/*******************************************************************
Generate samples for the tape image
********************************************************************/
static int mbee_tap_fill_wave(INT16 *buffer, int length, UINT8 *bytes)
{
return mbee_handle_tap(buffer, bytes);
}
/*******************************************************************
Calculate the number of samples needed for this tape image
********************************************************************/
static int mbee_tap_calculate_size_in_samples(const UINT8 *bytes, int length)
{
mbee_image_size = length;
return mbee_handle_tap(NULL, bytes);
}
static const struct CassetteLegacyWaveFiller mbee_tap_config =
{
mbee_tap_fill_wave, /* fill_wave */
-1, /* chunk_size */
0, /* chunk_samples */
mbee_tap_calculate_size_in_samples, /* chunk_sample_calc */
MBEE_WAV_FREQUENCY, /* sample_frequency */
0, /* header_samples */
0 /* trailer_samples */
};
static casserr_t mbee_tap_identify(cassette_image *cassette, struct CassetteOptions *opts)
{
return cassette_legacy_identify(cassette, opts, &mbee_tap_config);
}
static casserr_t mbee_tap_load(cassette_image *cassette)
{
return cassette_legacy_construct(cassette, &mbee_tap_config);
}
static const struct CassetteFormat mbee_tap_image_format =
{
"tap",
mbee_tap_identify,
mbee_tap_load,
NULL
};
CASSETTE_FORMATLIST_START(mbee_cassette_formats)
CASSETTE_FORMAT(mbee_tap_image_format)
CASSETTE_FORMATLIST_END

View File

@ -0,0 +1,15 @@
// license:BSD-3-Clause
// copyright-holders:Robbbert
/*********************************************************************
mbee_cas.h
Format code for Microbee cassette images
*********************************************************************/
#include "cassimg.h"
CASSETTE_FORMATLIST_EXTERN(mbee_cassette_formats);

View File

@ -156,6 +156,7 @@ FORMATSOBJS = \
$(LIBOBJ)/formats/lviv_lvt.o \
$(LIBOBJ)/formats/m20_dsk.o \
$(LIBOBJ)/formats/m5_dsk.o \
$(LIBOBJ)/formats/mbee_cas.o \
$(LIBOBJ)/formats/mbee_dsk.o \
$(LIBOBJ)/formats/mm_dsk.o \
$(LIBOBJ)/formats/msx_dsk.o \

View File

@ -125,6 +125,7 @@
#include "includes/mbee.h"
#include "formats/dsk_dsk.h"
#include "formats/mbee_dsk.h"
#include "formats/mbee_cas.h"
#define XTAL_13_5MHz 13500000
@ -720,6 +721,15 @@ static MC6845_INTERFACE( mbee256_crtc )
mbee256_update_addr /* handler to process transparent mode */
};
static const cassette_interface mbee_cassette_interface =
{
mbee_cassette_formats,
NULL,
(cassette_state)(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED),
NULL,
NULL
};
static MACHINE_CONFIG_START( mbee, mbee_state )
/* basic machine hardware */
MCFG_CPU_ADD("maincpu", Z80, XTAL_12MHz / 6) /* 2 MHz */
@ -753,14 +763,14 @@ static MACHINE_CONFIG_START( mbee, mbee_state )
/* devices */
MCFG_MC6845_ADD("crtc", SY6545_1, "screen", XTAL_12MHz / 8, mbee_crtc)
MCFG_QUICKLOAD_ADD("quickload", mbee_state, mbee, "mwb,com", 2)
MCFG_QUICKLOAD_ADD("quickload", mbee_state, mbee, "mwb,com,bee", 2)
MCFG_QUICKLOAD_ADD("quickload2", mbee_state, mbee_z80bin, "bin", 2)
MCFG_CENTRONICS_ADD("centronics", centronics_printers, "image")
MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", "centronics")
MCFG_CASSETTE_ADD( "cassette", default_cassette_interface )
MCFG_CASSETTE_ADD( "cassette", mbee_cassette_interface )
MACHINE_CONFIG_END
@ -798,14 +808,14 @@ static MACHINE_CONFIG_START( mbeeic, mbee_state )
/* devices */
MCFG_MC6845_ADD("crtc", SY6545_1, "screen", XTAL_13_5MHz / 8, mbeeic_crtc)
MCFG_QUICKLOAD_ADD("quickload", mbee_state, mbee, "mwb,com", 2)
MCFG_QUICKLOAD_ADD("quickload", mbee_state, mbee, "mwb,com,bee", 2)
MCFG_QUICKLOAD_ADD("quickload2", mbee_state, mbee_z80bin, "bin", 2)
MCFG_CENTRONICS_ADD("centronics", centronics_printers, "image")
MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", "centronics")
MCFG_CASSETTE_ADD( "cassette", default_cassette_interface )
MCFG_CASSETTE_ADD( "cassette", mbee_cassette_interface )
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( mbeepc, mbeeic )

View File

@ -309,7 +309,7 @@ static const cassette_interface spc1000_cassette_interface =
// irq is inverted in emulation, so we need this trampoline
WRITE_LINE_MEMBER( spc1000_state::irq_w )
{
m_maincpu->set_input_line(0, state ? CLEAR_LINE : ASSERT_LINE);
m_maincpu->set_input_line(0, state ? CLEAR_LINE : HOLD_LINE);
}
static const mc6847_interface spc1000_mc6847_intf =

View File

@ -776,7 +776,7 @@ DRIVER_INIT_MEMBER(mbee_state,mbeett)
Quickload
These load the standard BIN format, as well
as COM and MWB files.
as BEE, COM and MWB files.
************************************************************/
@ -840,6 +840,30 @@ QUICKLOAD_LOAD_MEMBER( mbee_state, mbee )
if (sw) m_maincpu->set_pc(0x100);
}
else if (!mame_stricmp(image.filetype(), "bee"))
{
/* bee files - machine-language games that start at 0900 */
for (i = 0; i < quickload_size; i++)
{
j = 0x900 + i;
if (image.fread(&data, 1) != 1)
{
image.message("Unexpected EOF");
return IMAGE_INIT_FAIL;
}
if ((j < m_size) || (j > 0xefff))
space.write_byte(j, data);
else
{
image.message("Not enough memory in this microbee");
return IMAGE_INIT_FAIL;
}
}
if (sw) m_maincpu->set_pc(0x900);
}
return IMAGE_INIT_PASS;
}