diff options
Diffstat (limited to 'src/mame/tangerine/microtan_m.cpp')
-rw-r--r-- | src/mame/tangerine/microtan_m.cpp | 491 |
1 files changed, 491 insertions, 0 deletions
diff --git a/src/mame/tangerine/microtan_m.cpp b/src/mame/tangerine/microtan_m.cpp new file mode 100644 index 00000000000..e2ae9c57b0f --- /dev/null +++ b/src/mame/tangerine/microtan_m.cpp @@ -0,0 +1,491 @@ +// license:GPL-2.0+ +// copyright-holders:Juergen Buchmueller +/****************************************************************************** + * Microtan 65 + * + * Thanks go to Geoff Macdonald <mail@geoff.org.uk> + * for his site http://www.geoff.org.uk/microtan/index.htm + * and to Fabrice Frances <frances@ensica.fr> + * for his site http://oric.free.fr/microtan.html + * + *****************************************************************************/ + +#include "emu.h" +#include "microtan.h" + +//#define VERBOSE 1 +#include "logmacro.h" + + +uint8_t microtan_state::bffx_r(offs_t offset) +{ + uint8_t data = 0xff; + + if (machine().side_effects_disabled()) return data; + + switch (offset & 3) + { + case 0: /* BFF0: read enables chunky graphics */ + m_chunky_graphics = 1; + LOG("bff0_r: -> %02x (chunky graphics on)\n", data); + break; + case 1: /* BFF1: read undefined (?) */ + LOG("bff1_r: -> %02x\n", data); + break; + case 2: /* BFF2: read undefined (?) */ + LOG("bff2_r: -> %02x\n", data); + break; + case 3: /* BFF3: read keyboard/keypad */ + data = m_keyboard->read() | (m_keyboard_int_flag << 7); + LOG("bff3_r: -> %02x (keyboard ASCII)\n", data); + break; + } + return data; +} + + +/* This callback is called one clock cycle after BFF2 is written (delayed nmi) */ +TIMER_CALLBACK_MEMBER(microtan_state::pulse_nmi) +{ + m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero); +} + +void microtan_state::bffx_w(offs_t offset, uint8_t data) +{ + switch (offset & 3) + { + case 0: /* BFF0: write reset keyboard interrupt flag */ + /* This removes bit 7 from the ASCII value of the last key pressed. */ + LOG("bff0_w: %d <- %02x (keyboard IRQ clear )\n", offset, data); + kbd_int(0); + break; + case 1: /* BFF1: write delayed NMI */ + LOG("bff1_w: %d <- %02x (delayed NMI)\n", offset, data); + m_pulse_nmi_timer->adjust(m_maincpu->cycles_to_attotime(8)); + break; + case 2: /* BFF2: write keypad */ + LOG("bff2_w: %d <- %02x (keypad column)\n", offset, data); + m_keyboard->write(data); + break; + case 3: /* BFF3: write disable chunky graphics */ + LOG("bff3_w: %d <- %02x (chunky graphics off)\n", offset, data); + m_chunky_graphics = 0; + break; + } +} + + +uint8_t mt6809_state::bffx_r(offs_t offset) +{ + uint8_t data = 0xff; + + if (machine().side_effects_disabled()) return data; + + switch (offset & 3) + { + case 3: /* BFF3: read keyboard */ + data = m_keyboard->read(); + LOG("bff3_r: -> %02x (keyboard ASCII)\n", data); + break; + } + return data; +} + +void mt6809_state::bffx_w(offs_t offset, uint8_t data) +{ + switch (offset & 3) + { + case 0: /* BFF0: write reset keyboard interrupt flag */ + LOG("bff0_w: %d <- %02x (keyboard NMI clear )\n", offset, data); + m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE); + break; + } +} + + +void microtan_state::kbd_int(int state) +{ + m_keyboard_int_flag = state; + + m_irq_line->in_w<IRQ_KBD>(state); +} + + +void microtan_state::pgm_chargen_w(offs_t offset, uint8_t data) +{ + switch (offset & 0x200) + { + case 0x000: + /* update char &80-&1F */ + m_gfx1->base()[offset | 0x800] = data; + m_gfxdecode->gfx(0)->mark_dirty(0x80 | (offset >> 4)); + break; + case 0x200: + /* update char &E0-&FF */ + m_gfx1->base()[offset | 0xc00] = data; + m_gfxdecode->gfx(0)->mark_dirty(0xc0 | (offset >> 4)); + break; + } +} + + +void microtan_state::machine_start() +{ + uint8_t *dst = memregion("gfx2")->base(); + + for (int i = 0; i < 256; i++) + { + switch (i & 3) + { + case 0: dst[0] = dst[1] = dst[2] = dst[3] = 0x00; break; + case 1: dst[0] = dst[1] = dst[2] = dst[3] = 0xf0; break; + case 2: dst[0] = dst[1] = dst[2] = dst[3] = 0x0f; break; + case 3: dst[0] = dst[1] = dst[2] = dst[3] = 0xff; break; + } + dst += 4; + switch (BIT(i, 2, 2)) + { + case 0: dst[0] = dst[1] = dst[2] = dst[3] = 0x00; break; + case 1: dst[0] = dst[1] = dst[2] = dst[3] = 0xf0; break; + case 2: dst[0] = dst[1] = dst[2] = dst[3] = 0x0f; break; + case 3: dst[0] = dst[1] = dst[2] = dst[3] = 0xff; break; + } + dst += 4; + switch (BIT(i, 4, 2)) + { + case 0: dst[0] = dst[1] = dst[2] = dst[3] = 0x00; break; + case 1: dst[0] = dst[1] = dst[2] = dst[3] = 0xf0; break; + case 2: dst[0] = dst[1] = dst[2] = dst[3] = 0x0f; break; + case 3: dst[0] = dst[1] = dst[2] = dst[3] = 0xff; break; + } + dst += 4; + switch (BIT(i, 6, 2)) + { + case 0: dst[0] = dst[1] = dst[2] = dst[3] = 0x00; break; + case 1: dst[0] = dst[1] = dst[2] = dst[3] = 0xf0; break; + case 2: dst[0] = dst[1] = dst[2] = dst[3] = 0x0f; break; + case 3: dst[0] = dst[1] = dst[2] = dst[3] = 0xff; break; + } + dst += 4; + } + + m_pulse_nmi_timer = timer_alloc(FUNC(microtan_state::pulse_nmi), this); +} + +void mt6809_state::machine_start() +{ +} + + +std::error_condition microtan_state::verify_snapshot(const uint8_t *data, int size) +{ + if (size == 8263) + { + logerror("snapshot_id: magic size %d found\n", size); + return std::error_condition(); + } + else + { + if (4 + data[2] + 256 * data[3] + 1 + 16 + 16 + 16 + 1 + 1 + 16 + 16 + 64 + 7 == size) + { + logerror("snapshot_id: header RAM size + structures matches filesize %d\n", size); + return std::error_condition(); + } + } + + return image_error::INVALIDIMAGE; +} + +std::error_condition microtan_state::parse_intel_hex(uint8_t *snapshot_buff, const char *src) +{ + char line[128]; + int /*row = 0,*/ column = 0, last_addr = 0, last_size = 0; + + while (*src) + { + if (*src == '\r' || *src == '\n') + { + if (column) + { + unsigned int size, addr, null, b[32], cs, n; + + line[column] = '\0'; + /*row++;*/ + n = sscanf(line, ":%02x%04x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + &size, &addr, &null, + &b[ 0], &b[ 1], &b[ 2], &b[ 3], &b[ 4], &b[ 5], &b[ 6], &b[ 7], + &b[ 8], &b[ 9], &b[10], &b[11], &b[12], &b[13], &b[14], &b[15], + &b[16], &b[17], &b[18], &b[19], &b[20], &b[21], &b[22], &b[23], + &b[24], &b[25], &b[26], &b[27], &b[28], &b[29], &b[30], &b[31], + &cs); + if (n == 0) + logerror("parse_intel_hex: malformed line [%s]\n", line); + else + if (n == 1) + logerror("parse_intel_hex: only size found [%s]\n", line); + else + if (n == 2) + logerror("parse_intel_hex: only size and addr found [%s]\n", line); + else + if (n == 3) + logerror("parse_intel_hex: only size, addr and null found [%s]\n", line); + else + if (null != 0) + logerror("parse_intel_hex: warning null byte is != 0 [%s]\n", line); + else + { + int i, sum; + + n -= 3; + + sum = size + (addr & 0xff) + ((addr >> 8) & 0xff); + if (n != 32 + 1) + cs = b[n-1]; + + last_addr = addr; + last_size = n-1; + logerror("parse_intel_hex: %04X", addr); + for (i = 0; i < n-1; i++) + { + sum += b[i]; + snapshot_buff[addr++] = b[i]; + } + logerror("-%04X checksum %02X+%02X = %02X\n", addr-1, cs, sum & 0xff, (cs + sum) & 0xff); + } + } + column = 0; + } + else + line[column++] = *src; + + src++; + } + /* register preset? */ + if (last_size == 7) + { + logerror("parse_intel_hex: registers (?) at %04X\n", last_addr); + memcpy(&snapshot_buff[8192+64], &snapshot_buff[last_addr], last_size); + } + return std::error_condition(); +} + +std::error_condition microtan_state::parse_zillion_hex(uint8_t *snapshot_buff, const char *src) +{ + char line[128]; + int parsing = 0, /*row = 0,*/ column = 0; + + while (*src) + { + if (parsing) + { + if (*src == '}') + parsing = 0; + else + { + if (*src == '\r' || *src == '\n') + { + if (column) + { + unsigned int addr, b[8], n; + + line[column] = '\0'; + /*row++;*/ + n = sscanf(line, "%x %x %x %x %x %x %x %x %x", &addr, &b[0], &b[1], &b[2], &b[3], &b[4], &b[5], &b[6], &b[7]); + if (n == 0) + logerror("parse_zillion_hex: malformed line [%s]\n", line); + else + if (n == 1) + logerror("parse_zillion_hex: only addr found [%s]\n", line); + else + { + logerror("parse_zillion_hex: %04X", addr); + for (int i = 0; i < n-1; i++) + snapshot_buff[addr++] = b[i]; + logerror("-%04X\n", addr-1); + } + } + column = 0; + } + else + line[column++] = *src; + } + } + else + { + if (*src == '\r' || *src == '\n') + { + if (column) + { + int addr; + + /*row++;*/ + line[column] = '\0'; + int n = sscanf(line, "G%x", (unsigned int *) &addr); + if (n == 1 && !snapshot_buff[8192+64+0] && !snapshot_buff[8192+64+1]) + { + logerror("microtan_hexfile_init: go addr %04X\n", addr); + snapshot_buff[8192+64+0] = addr & 0xff; + snapshot_buff[8192+64+1] = (addr >> 8) & 0xff; + } + } + column = 0; + } + else + line[column++] = *src; + + if (*src == '{') + { + parsing = 1; + column = 0; + } + } + src++; + } + return std::error_condition(); +} + +void microtan_state::set_cpu_regs(const uint8_t *snapshot_buff, int base) +{ + logerror("snapshot_copy: PC:%02X%02X P:%02X A:%02X X:%02X Y:%02X SP:1%02X\n", + snapshot_buff[base+1], snapshot_buff[base+0], snapshot_buff[base+2], snapshot_buff[base+3], + snapshot_buff[base+4], snapshot_buff[base+5], snapshot_buff[base+6]); + m_maincpu->set_state_int(M6502_PC, snapshot_buff[base+0] + (snapshot_buff[base+1] << 8)); + m_maincpu->set_state_int(M6502_P, snapshot_buff[base+2]); + m_maincpu->set_state_int(M6502_A, snapshot_buff[base+3]); + m_maincpu->set_state_int(M6502_X, snapshot_buff[base+4]); + m_maincpu->set_state_int(M6502_Y, snapshot_buff[base+5]); + m_maincpu->set_state_int(M6502_S, snapshot_buff[base+6] + 0x100); +} + +void microtan_state::snapshot_copy(uint8_t *snapshot_buff, int snapshot_size) +{ + address_space &space = m_maincpu->space(AS_PROGRAM); + + /* check for .DMP file format */ + if (snapshot_size == 8263) + { + /********** DMP format + * Lower 8k of RAM (0000 to 1fff) + * 64 bytes of chunky graphics bits (first byte bit is for character at 0200, bit 1=0201, etc) + * 7 bytes of CPU registers (PCL, PCH, PSW, A, IX, IY, SP) + */ + + int base = 0; + /* 8K of RAM from 0000 to 1fff */ + for (int i = 0; i < 0x2000; i++) + space.write_byte(i, snapshot_buff[base + i]); + + base += 8192; + /* 64 bytes of chunky graphics info */ + for (int i = 0; i < 32*16; i++) + m_chunky_buffer[i] = (snapshot_buff[base+i/8] >> (i&7)) & 1; + + base += 64; + set_cpu_regs(snapshot_buff, base); + } + else + { + /********** M65 format ************************************ + * 2 bytes: File version + * 2 bytes: RAM size + * n bytes: RAM (0000 to RAM Size) + * 16 bytes: 1st 6522 (0xbfc0 to 0xbfcf) + * 16 bytes: 2nd 6522 (0xbfe0 to 0xbfef) + * 16 bytes: Microtan IO (0xbff0 to 0xbfff) + * 1 byte : Space Invasion sound (0xbc04) + * 1 byte : Chunky graphics state (0=off, 1=on) + * 16 bytes: 1st AY8910 registers + * 16 bytes: 2nd AY8910 registers + * 64 bytes: Chunky graphics bits (first byte bit 0 is for character at 0200, bit 1=0201, etc) + * 7 bytes: CPU registers (PCL, PCH, PSW, A, IX, IY, SP) + */ + int ramend = snapshot_buff[2] + 256 * snapshot_buff[3]; + if (2 + 2 + ramend + 1 + 16 + 16 + 16 + 1 + 1 + 16 + 16 + 64 + 7 != snapshot_size) + { + logerror("snapshot_copy: size %d doesn't match RAM size %d + structure size\n", snapshot_size, ramend+1); + return; + } + + int base = 4; + for (int i = 0; i < snapshot_buff[2] + 256 * snapshot_buff[3] + 1; i++) + space.write_byte(i, snapshot_buff[base + i]); + base += ramend + 1; + + /* first set of VIA6522 registers */ + for (int i = 0; i < 16; i++ ) + space.write_byte(0xbfc0 + i, snapshot_buff[base++]); + + /* second set of VIA6522 registers */ + for (int i = 0; i < 16; i++ ) + space.write_byte(0xbfe0 + i, snapshot_buff[base++]); + + /* microtan IO bff0-bfff */ + for (int i = 0; i < 16; i++ ) + { + if (i < 4) + bffx_w(i, snapshot_buff[base++]); + } + + space.write_byte(0xbc04, snapshot_buff[base++]); + m_chunky_graphics = snapshot_buff[base++]; + + /* first set of AY8910 registers */ + for (int i = 0; i < 16; i++ ) + { + space.write_byte(0xbc00, i); + space.write_byte(0xbc01, snapshot_buff[base++]); + } + + /* second set of AY8910 registers */ + for (int i = 0; i < 16; i++ ) + { + space.write_byte(0xbc02, i); + space.write_byte(0xbc03, snapshot_buff[base++]); + } + + for (int i = 0; i < 32*16; i++) + m_chunky_buffer[i] = (snapshot_buff[base+i/8] >> (i&7)) & 1; + + base += 64; + + set_cpu_regs(snapshot_buff, base); + } +} + +SNAPSHOT_LOAD_MEMBER(microtan_state::snapshot_cb) +{ + uint64_t snapshot_len = image.length(); + if (snapshot_len < 4 || snapshot_len >= 66000) + return std::make_pair(image_error::INVALIDLENGTH, std::string()); + + auto snapshot_buff = std::make_unique<uint8_t []>(snapshot_len); + if (image.fread(snapshot_buff.get(), snapshot_len) != snapshot_len) + return std::make_pair(image_error::UNSPECIFIED, std::string()); + + std::error_condition err = verify_snapshot(snapshot_buff.get(), snapshot_len); + if (err) + return std::make_pair(err, std::string()); + + snapshot_copy(snapshot_buff.get(), snapshot_len); + return std::make_pair(std::error_condition(), std::string()); +} + +QUICKLOAD_LOAD_MEMBER(microtan_state::quickload_cb) +{ + int snapshot_size = 8263; /* magic size */ + std::vector<uint8_t> snapshot_buff(snapshot_size, 0); + std::vector<char> buff(image.length() + 1); + std::error_condition rc; + + image.fread(&buff[0], image.length()); + + buff[image.length()] = '\0'; + + if (buff[0] == ':') + rc = parse_intel_hex(&snapshot_buff[0], &buff[0]); + else + rc = parse_zillion_hex(&snapshot_buff[0], &buff[0]); + if (!rc) + snapshot_copy(&snapshot_buff[0], snapshot_size); + return std::make_pair(rc, std::string()); +} |