summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/vcs/harmony_melody.cpp
blob: 04c78933d1c52963d5a677badfa95eb411ba347f (plain) (blame)
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
// license:BSD-3-Clause
// copyright-holders:David Haywood
/***************************************************************************

Harmony / Melody cart for the A2600

The Harmony cart is a 'modern' A2600 cartridge, used for homebrew etc. It has
an SD slot and can be connected to a PC, roms can be transferred to it with
software on the PC side.  It uses an ARM7TDMI-S LPC2103 @ 70 Mhz to emulate
the mapper behavior of other cartridges.  It has an SD card slot for storing
game data.

The Melody version of the cartridge has been used for several recent A2600
commercial releases as well as some reproductions due to it's ability to be
programmed as any other cartridge type.  This lacks the SD slot?

The 'DPC+' games by SpiceWare run on a Harmony / Melody cart, DPC+ seems to
be a virtual 'software mapper' programmed on the ARM rather than a real mapper.


There is also a 'Harmony Encore' cartridge which adds support for some of the
games the original couldn't handle due to them having larger ROMs and more
complex banking schemes (Stella's Stocking etc.)

some Harmony cart details can be found at
http://atariage.com/forums/topic/156500-latest-harmony-cart-software/


DPC+ notes
----------

Some info on the Harmony / Melody when configured as DPC+ hardware can be found on Darrell Spice Jr's guides:
http://atariage.com/forums/blog/148/entry-11811-dpcarm-part-6-dpc-cartridge-layout/
http://atariage.com/forums/blog/148/entry-11883-dpcarm-part-7-6507arm-exchange-of-information/
http://atariage.com/forums/blog/148/entry-11903-dpcarm-part-8-multiple-functions/
http://atariage.com/forums/blog/148/entry-11935-dpcarm-part-9-functional-menu/
http://atariage.com/forums/blog/148/entry-11964-dpcarm-part-10-score-timer-display/
http://atariage.com/forums/blog/148/entry-11988-dpcarm-part-12-gamepad-support/

map:
    Bankswitching uses addresses $FFF6-$FFFB

    * ARM RAM mapped at $40000000 in this area
    $0000-$0BFF: HARMONY/MELODY driver (not accessible by 2600 itself) (copied to $40000000 - $40000bff on startup by ARM)
    $0C00-$1BFF: Bank 0 (each bank can map to 0x1000 - 0x1fff in 6507 space, like other carts)
    $1C00-$2BFF: Bank 1
    $2C00-$3BFF: Bank 2
    $3C00-$4BFF: Bank 3
    $4C00-$5BFF: Bank 4
    $5C00-$6BFF: Bank 5 (default bank is bank 5)
    $6C00-$7BFF: Display Data (indirect access) (copied to $40000C00 - $40001bff on startup by ARM)
    $7C00-$7FFF: Synth Frequency Data (not accessible by 2600 itself) (copied to $40001C00 - $40001fff on startup by ARM)

***************************************************************************/


#include "emu.h"
#include "harmony_melody.h"



// cart device

DEFINE_DEVICE_TYPE(A26_ROM_HARMONY, a26_rom_harmony_device, "a2600_harmony", "Atari 2600 ROM Cart HARMONY/MELODY")


a26_rom_harmony_device::a26_rom_harmony_device(const machine_config &mconfig, const char *tag, device_t *owner, const XTAL &clock)
	: a26_rom_base_device(mconfig, A26_ROM_HARMONY, tag, owner, clock)
	, m_cpu(*this, "arm")
	, m_base_bank(0)
{
}

//-------------------------------------------------
//  mapper specific start/reset
//-------------------------------------------------

void a26_rom_harmony_device::harmony_arm7_map(address_map &map)
{
}

void a26_rom_harmony_device::device_add_mconfig(machine_config &config)
{
	LPC2103(config, m_cpu, XTAL::u(70000000));
	m_cpu->set_addrmap(AS_PROGRAM, &a26_rom_harmony_device::harmony_arm7_map);
}


void a26_rom_harmony_device::device_start()
{
	save_item(NAME(m_base_bank));
}

// actually if the ARM code is doing this and providing every opcode to the main CPU based
// on bus activity then we shouldn't be doing and of this here (if the ROM is actually
// the internal Flash rom of the ARM CPU then the A2600 CPU won't be able to see it directly
// at all?)
//
// instead we need the ARM monitoring the bus at all times and supplying the code on
// demand transparent to the main CPU? is this theory correct?

void a26_rom_harmony_device::device_reset()
{
	m_base_bank = 5;

	memcpy(m_cpu->m_flash, m_rom, 0x8000);
	m_cpu->reset();
}

uint8_t a26_rom_harmony_device::read8_r(offs_t offset)
{
	return m_rom[offset + (m_base_bank * 0x1000)];
}


void a26_rom_harmony_device::check_bankswitch(offs_t offset)
{
	switch (offset)
	{
	case 0x0ff6: m_base_bank = 0; break;
	case 0x0ff7: m_base_bank = 1; break;
	case 0x0ff8: m_base_bank = 2; break;
	case 0x0ff9: m_base_bank = 3; break;
	case 0x0ffa: m_base_bank = 4; break;
	case 0x0ffb: m_base_bank = 5; break;
	default: break;
	}
}

void a26_rom_harmony_device::install_memory_handlers(address_space *space)
{
	space->install_read_handler(0x1000, 0x1fff, read8sm_delegate(*this, FUNC(a26_rom_harmony_device::read)));
	space->install_write_handler(0x1000, 0x1fff, write8sm_delegate(*this, FUNC(a26_rom_harmony_device::write)));
}

uint8_t a26_rom_harmony_device::read(offs_t offset)
{
	uint8_t retvalue = read8_r(offset + 0xc00); // banks start at 0xc00

	check_bankswitch(offset);

	return retvalue;
}

void a26_rom_harmony_device::write(offs_t offset, uint8_t data)
{
	check_bankswitch(offset);
}