1 // license:BSD-3-Clause
2 // copyright-holders:Nigel Barnes
3 /**********************************************************************
4 
5     Morley Electronics RAM Disc
6 
7     Notes:
8     - 1MB model has 4096 sectors &0000 to &0fff
9     - 2MB model has 8192 sectors &0000 to &1fff
10 
11 **********************************************************************/
12 
13 
14 #include "emu.h"
15 #include "ramdisc.h"
16 
17 
18 //**************************************************************************
19 //  DEVICE DEFINITIONS
20 //**************************************************************************
21 
22 DEFINE_DEVICE_TYPE(BBC_RAMDISC, bbc_ramdisc_device, "bbc_ramdisc", "Morley Electronics RAM Disc");
23 
24 
25 //-------------------------------------------------
26 //  INPUT_PORTS( ramdisc )
27 //-------------------------------------------------
28 
29 static INPUT_PORTS_START(ramdisc)
30 	PORT_START("POWER")
31 	PORT_CONFNAME(0x01, 0x01, "Power") PORT_CHANGED_MEMBER(DEVICE_SELF, bbc_ramdisc_device, power_changed, 0)
DEF_STR(Off)32 	PORT_CONFSETTING(0x00, DEF_STR(Off))
33 	PORT_CONFSETTING(0x01, DEF_STR(On))
34 	PORT_START("SIZE")
35 	PORT_CONFNAME(0x03, 0x02, "RAM Disk Capacity")
36 	PORT_CONFSETTING(0x01, "1MB")
37 	PORT_CONFSETTING(0x02, "2MB")
38 INPUT_PORTS_END
39 
40 //-------------------------------------------------
41 //  input_ports - device-specific input ports
42 //-------------------------------------------------
43 
44 ioport_constructor bbc_ramdisc_device::device_input_ports() const
45 {
46 	return INPUT_PORTS_NAME(ramdisc);
47 }
48 
49 //-------------------------------------------------
50 //  ROM( ramdisc )
51 //-------------------------------------------------
52 
53 ROM_START(ramdisc)
54 	ROM_REGION(0x4000, "exp_rom", 0)
55 	ROM_LOAD("ramdisc101.rom", 0x0000, 0x4000, CRC(627568c2) SHA1(17e727998756fe35ff451fd2ce1d4b5977be24fc))
56 ROM_END
57 
58 //-------------------------------------------------
59 //  device_add_mconfig - add device configuration
60 //-------------------------------------------------
61 
device_add_mconfig(machine_config & config)62 void bbc_ramdisc_device::device_add_mconfig(machine_config &config)
63 {
64 	/* ram disk */
65 	NVRAM(config, "nvram", nvram_device::DEFAULT_NONE);
66 
67 	BBC_1MHZBUS_SLOT(config, m_1mhzbus, DERIVED_CLOCK(1, 1), bbc_1mhzbus_devices, nullptr);
68 	m_1mhzbus->irq_handler().set(DEVICE_SELF_OWNER, FUNC(bbc_1mhzbus_slot_device::irq_w));
69 	m_1mhzbus->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(bbc_1mhzbus_slot_device::nmi_w));
70 }
71 
72 //-------------------------------------------------
73 //  rom_region - device-specific ROM region
74 //-------------------------------------------------
75 
device_rom_region() const76 const tiny_rom_entry *bbc_ramdisc_device::device_rom_region() const
77 {
78 	return ROM_NAME(ramdisc);
79 }
80 
81 //**************************************************************************
82 //  LIVE DEVICE
83 //**************************************************************************
84 
85 //-------------------------------------------------
86 //  bbc_ramdisc_device - constructor
87 //-------------------------------------------------
88 
bbc_ramdisc_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)89 bbc_ramdisc_device::bbc_ramdisc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
90 	: device_t(mconfig, BBC_RAMDISC, tag, owner, clock)
91 	, device_bbc_1mhzbus_interface(mconfig, *this)
92 	, m_1mhzbus(*this, "1mhzbus")
93 	, m_nvram(*this, "nvram")
94 	, m_ram_size(*this, "SIZE")
95 	, m_power(*this, "POWER")
96 	, m_sector(0)
97 {
98 }
99 
100 //-------------------------------------------------
101 //  device_start - device-specific startup
102 //-------------------------------------------------
103 
device_start()104 void bbc_ramdisc_device::device_start()
105 {
106 	/* define 2mb ram */
107 	m_ram = std::make_unique<uint8_t[]>(0x200000);
108 	m_nvram->set_base(m_ram.get(), 0x200000);
109 
110 	/* register for save states */
111 	save_pointer(NAME(m_ram), 0x200000);
112 	save_item(NAME(m_sector));
113 }
114 
115 
116 //**************************************************************************
117 //  IMPLEMENTATION
118 //**************************************************************************
119 
INPUT_CHANGED_MEMBER(bbc_ramdisc_device::power_changed)120 INPUT_CHANGED_MEMBER(bbc_ramdisc_device::power_changed)
121 {
122 	/* clear RAM on power off */
123 	if (!newval)
124 	{
125 		memset(m_ram.get(), 0xff, 0x200000);
126 	}
127 }
128 
fred_r(offs_t offset)129 uint8_t bbc_ramdisc_device::fred_r(offs_t offset)
130 {
131 	uint8_t data = 0xff;
132 
133 	if (m_power->read())
134 	{
135 		switch (offset)
136 		{
137 		case 0xc0:
138 			/* sector LSB */
139 			data = m_sector & 0x00ff;
140 			break;
141 		case 0xc2:
142 			/* sector MSB */
143 			data = (m_sector & 0xff00) >> 8;
144 			break;
145 		case 0xc1:
146 		case 0xc3:
147 			/* TODO: unknown purpose, must return 0x3f or 0x5f */
148 			data = 0x3f;
149 			logerror("Read %04x -> %02x\n", offset | 0xfcc0, data);
150 			break;
151 		}
152 	}
153 
154 	data &= m_1mhzbus->fred_r(offset);
155 
156 	return data;
157 }
158 
fred_w(offs_t offset,uint8_t data)159 void bbc_ramdisc_device::fred_w(offs_t offset, uint8_t data)
160 {
161 	if (m_power->read())
162 	{
163 		switch (offset)
164 		{
165 		case 0xc0:
166 			/* sector LSB */
167 			m_sector = (m_sector & 0xff00) | data;
168 			break;
169 		case 0xc2:
170 			/* sector MSB */
171 			m_sector = (m_sector & 0x00ff) | (data << 8);
172 			break;
173 		case 0xc1:
174 		case 0xc3:
175 			/* TODO: unknown purpose, always writes 0x00 or 0xff */
176 			logerror("Write %04x <- %02x\n", offset | 0xfcc0, data);
177 			break;
178 		}
179 	}
180 
181 	m_1mhzbus->fred_w(offset, data);
182 }
183 
jim_r(offs_t offset)184 uint8_t bbc_ramdisc_device::jim_r(offs_t offset)
185 {
186 	uint8_t data = 0xff;
187 
188 	/* power on and sector < 2mb */
189 	if (m_power->read() && m_sector < (m_ram_size->read() << 8))
190 	{
191 		data &= m_ram[(m_sector << 8) | offset];
192 	}
193 
194 	data &= m_1mhzbus->jim_r(offset);
195 
196 	return data;
197 }
198 
jim_w(offs_t offset,uint8_t data)199 void bbc_ramdisc_device::jim_w(offs_t offset, uint8_t data)
200 {
201 	/* power on and sector < 2mb */
202 	if (m_power->read() && m_sector < (m_ram_size->read() << 8))
203 	{
204 		m_ram[(m_sector << 8) | offset] = data;
205 	}
206 
207 	m_1mhzbus->jim_w(offset, data);
208 }
209