mirror of
https://github.com/holub/mame
synced 2025-04-21 07:52:35 +03:00
(MESS) microbee : added support for TAP and BEE formats (used in ubee512 emulator) [Robbbert]
This commit is contained in:
parent
b474c7dcb1
commit
f273d09bd5
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -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
259
src/lib/formats/mbee_cas.c
Normal 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
|
15
src/lib/formats/mbee_cas.h
Normal file
15
src/lib/formats/mbee_cas.h
Normal 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);
|
||||
|
@ -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 \
|
||||
|
@ -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 )
|
||||
|
@ -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 =
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user