1 // license:BSD-3-Clause
2 // copyright-holders:Tim Schuerewegen
3 /*
4 
5     Atmel Serial DataFlash
6 
7     (c) 2001-2007 Tim Schuerewegen
8 
9     AT45DB041 -  528 KByte
10     AT45DB081 - 1056 KByte
11     AT45DB161 - 2112 KByte
12 
13 */
14 
15 #include "emu.h"
16 #include "at45dbxx.h"
17 
18 #define LOG_LEVEL  1
19 #define _logerror(level,x)  do { if (LOG_LEVEL > level) logerror x; } while (0)
20 
21 #define FLASH_CMD_52  0x52
22 #define FLASH_CMD_57  0x57
23 #define FLASH_CMD_60  0x60
24 #define FLASH_CMD_82  0x82
25 
26 #define FLASH_MODE_XX  0 // unknown
27 #define FLASH_MODE_SI  1 // input
28 #define FLASH_MODE_SO  2 // output
29 
30 
31 //**************************************************************************
32 //  GLOBAL VARIABLES
33 //**************************************************************************
34 
35 // device type definition
36 DEFINE_DEVICE_TYPE(AT45DB041, at45db041_device, "at45db041", "AT45DB041")
37 DEFINE_DEVICE_TYPE(AT45DB081, at45db081_device, "at45db081", "AT45DB081")
38 DEFINE_DEVICE_TYPE(AT45DB161, at45db161_device, "at45db161", "AT45DB161")
39 
40 
41 //**************************************************************************
42 //  LIVE DEVICE
43 //**************************************************************************
44 
45 //-------------------------------------------------
46 //  at45db041_device - constructor
47 //-------------------------------------------------
48 
at45db041_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)49 at45db041_device::at45db041_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
50 	: at45db041_device(mconfig, AT45DB041, tag, owner, clock)
51 {
52 }
53 
54 
at45db041_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)55 at45db041_device::at45db041_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
56 	: device_t(mconfig, type, tag, owner, clock)
57 	, device_nvram_interface(mconfig, *this)
58 	, write_so(*this)
59 {
60 }
61 
62 
at45db081_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)63 at45db081_device::at45db081_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
64 	: at45db041_device(mconfig, AT45DB081, tag, owner, clock)
65 {
66 }
67 
68 
at45db161_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)69 at45db161_device::at45db161_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
70 	: at45db041_device(mconfig, AT45DB161, tag, owner, clock)
71 {
72 }
73 
74 
75 //-------------------------------------------------
76 //  device_start - device-specific startup
77 //-------------------------------------------------
78 
device_start()79 void at45db041_device::device_start()
80 {
81 	m_size = num_pages() * page_size();
82 	m_data.resize(m_size);
83 	m_buffer1.resize(page_size());
84 	//m_buffer2.resize(page_size());
85 
86 	// pins
87 	m_pin.cs    = 0;
88 	m_pin.sck   = 0;
89 	m_pin.si    = 0;
90 	m_pin.wp    = 0;
91 	m_pin.reset = 0;
92 	m_pin.busy  = 0;
93 
94 	// data
95 	save_item(NAME(m_data));
96 	// pins
97 	save_item(NAME(m_pin.cs));
98 	save_item(NAME(m_pin.sck));
99 	save_item(NAME(m_pin.si));
100 	save_item(NAME(m_pin.so));
101 	save_item(NAME(m_pin.wp));
102 	save_item(NAME(m_pin.reset));
103 	save_item(NAME(m_pin.busy));
104 
105 	write_so.resolve_safe();
106 }
107 
108 
109 //-------------------------------------------------
110 //  device_reset - device-specific reset
111 //-------------------------------------------------
112 
device_reset()113 void at45db041_device::device_reset()
114 {
115 	_logerror( 1, ("at45dbxx_reset\n"));
116 	// mode
117 	m_mode = FLASH_MODE_SI;
118 	m_status = 0;
119 	// command
120 	memset(&m_cmd.data[0], 0, sizeof(m_cmd.data));
121 	m_cmd.size = 0;
122 	// input/output
123 	m_io.data = nullptr;
124 	m_io.size = 0;
125 	m_io.pos  = 0;
126 	// pins
127 	m_pin.so  = 0;
128 	// output
129 	m_so_byte = 0;
130 	m_so_bits = 0;
131 	// input
132 	m_si_byte = 0;
133 	m_si_bits = 0;
134 }
135 
136 
137 //-------------------------------------------------
138 //  nvram_default - called to initialize NVRAM to
139 //  its default state
140 //-------------------------------------------------
141 
nvram_default()142 void at45db041_device::nvram_default()
143 {
144 	memset(&m_data[0], 0xff, m_data.size());
145 
146 	memory_region *region = memregion(DEVICE_SELF);
147 	if (region != nullptr)
148 	{
149 		uint32_t bytes = region->bytes();
150 		if (bytes > m_size)
151 			bytes = m_size;
152 
153 		memcpy(&m_data[0], region->base(), bytes);
154 	}
155 }
156 
157 //-------------------------------------------------
158 //  nvram_read - called to read NVRAM from the
159 //  .nv file
160 //-------------------------------------------------
161 
nvram_read(emu_file & file)162 void at45db041_device::nvram_read(emu_file &file)
163 {
164 	file.read(&m_data[0], m_size);
165 }
166 
167 //-------------------------------------------------
168 //  nvram_write - called to write NVRAM to the
169 //  .nv file
170 //-------------------------------------------------
171 
nvram_write(emu_file & file)172 void at45db041_device::nvram_write(emu_file &file)
173 {
174 	file.write(&m_data[0], m_size);
175 }
176 
read_byte()177 uint8_t at45db041_device::read_byte()
178 {
179 	uint8_t data;
180 	// check mode
181 	if ((m_mode != FLASH_MODE_SO) || (!m_io.data)) return 0;
182 	// read byte
183 	data = m_io.data[m_io.pos++];
184 	_logerror( 2, ("at45dbxx_read_byte (%02X) (%03d/%03d)\n", data, m_io.pos, m_io.size));
185 	if (m_io.pos == m_io.size) m_io.pos = 0;
186 	return data;
187 }
188 
flash_set_io(uint8_t * data,uint32_t size,uint32_t pos)189 void at45db041_device::flash_set_io(uint8_t* data, uint32_t size, uint32_t pos)
190 {
191 	m_io.data = data;
192 	m_io.size = size;
193 	m_io.pos  = pos;
194 }
195 
flash_get_page_addr()196 uint32_t at45db041_device::flash_get_page_addr()
197 {
198 	return ((m_cmd.data[1] & 0x0F) << 7) | ((m_cmd.data[2] & 0xFE) >> 1);
199 }
200 
flash_get_byte_addr()201 uint32_t at45db041_device::flash_get_byte_addr()
202 {
203 	return ((m_cmd.data[2] & 0x01) << 8) | ((m_cmd.data[3] & 0xFF) >> 0);
204 }
205 
flash_get_page_addr()206 uint32_t at45db081_device::flash_get_page_addr()
207 {
208 	return ((m_cmd.data[1] & 0x1F) << 7) | ((m_cmd.data[2] & 0xFE) >> 1);
209 }
210 
flash_get_page_addr()211 uint32_t at45db161_device::flash_get_page_addr()
212 {
213 	return ((m_cmd.data[1] & 0x3F) << 6) | ((m_cmd.data[2] & 0xFC) >> 2);
214 }
215 
flash_get_byte_addr()216 uint32_t at45db161_device::flash_get_byte_addr()
217 {
218 	return ((m_cmd.data[2] & 0x03) << 8) | ((m_cmd.data[3] & 0xFF) >> 0);
219 }
220 
write_byte(uint8_t data)221 void at45db041_device::write_byte(uint8_t data)
222 {
223 	// check mode
224 	if (m_mode != FLASH_MODE_SI) return;
225 	// process byte
226 	if (m_cmd.size < 8)
227 	{
228 		uint8_t opcode;
229 		_logerror( 2, ("at45dbxx_write_byte (%02X)\n", data));
230 		// add to command buffer
231 		m_cmd.data[m_cmd.size++] = data;
232 		// check opcode
233 		opcode = m_cmd.data[0];
234 		switch (opcode)
235 		{
236 			// status register read
237 			case FLASH_CMD_57 :
238 			{
239 				// 8 bits command
240 				if (m_cmd.size == 1)
241 				{
242 					_logerror( 1, ("at45dbxx opcode %02X - status register read\n", opcode));
243 					m_status = (m_status & 0xC7) | device_id(); // 80 = busy / 40 = compare fail
244 					flash_set_io(&m_status, 1, 0);
245 					m_mode = FLASH_MODE_SO;
246 					m_cmd.size = 8;
247 				}
248 			}
249 			break;
250 			// main memory page to buffer 1 compare
251 			case FLASH_CMD_60 :
252 			{
253 				// 8 bits command + 4 bits reserved + 11 bits page address + 9 bits don't care
254 				if (m_cmd.size == 4)
255 				{
256 					uint32_t page;
257 					uint8_t comp;
258 					page = flash_get_page_addr();
259 					_logerror( 1, ("at45dbxx opcode %02X - main memory page to buffer 1 compare [%04X]\n", opcode, page));
260 					comp = memcmp( &m_data[page * page_size()], &m_buffer1[0], page_size()) == 0 ? 0 : 1;
261 					if (comp) m_status |= 0x40; else m_status &= ~0x40;
262 					_logerror( 1, ("at45dbxx page compare %s\n", comp ? "failure" : "success"));
263 					m_mode = FLASH_MODE_SI;
264 					m_cmd.size = 8;
265 				}
266 			}
267 			break;
268 			// main memory page read
269 			case FLASH_CMD_52 :
270 			{
271 				// 8 bits command + 4 bits reserved + 11 bits page address + 9 bits buffer address + 32 bits don't care
272 				if (m_cmd.size == 8)
273 				{
274 					uint32_t page, byte;
275 					page = flash_get_page_addr();
276 					byte = flash_get_byte_addr();
277 					_logerror( 1, ("at45dbxx opcode %02X - main memory page read [%04X/%04X]\n", opcode, page, byte));
278 					flash_set_io(&m_data[page * page_size()], page_size(), byte);
279 					m_mode = FLASH_MODE_SO;
280 					m_cmd.size = 8;
281 				}
282 			}
283 			break;
284 			// main memory page program through buffer 1
285 			case FLASH_CMD_82 :
286 			{
287 				// 8 bits command + 4 bits reserved + 11 bits page address + 9 bits buffer address
288 				if (m_cmd.size == 4)
289 				{
290 					uint32_t page, byte;
291 					page = flash_get_page_addr();
292 					byte = flash_get_byte_addr();
293 					_logerror( 1, ("at45dbxx opcode %02X - main memory page program through buffer 1 [%04X/%04X]\n",opcode, page, byte));
294 					flash_set_io(&m_buffer1[0], page_size(), byte);
295 					memset(&m_buffer1[0], 0xff, m_buffer1.size());
296 					m_mode = FLASH_MODE_SI;
297 					m_cmd.size = 8;
298 				}
299 			}
300 			break;
301 			// other
302 			default :
303 			{
304 				_logerror( 1, ("at45dbxx opcode %02X - unknown\n", opcode));
305 				m_cmd.data[0] = 0;
306 				m_cmd.size = 0;
307 			}
308 			break;
309 		}
310 	}
311 	else
312 	{
313 		_logerror( 2, ("at45dbxx_write_byte (%02X) (%03d/%03d)\n", data, m_io.pos + 1, m_io.size));
314 		// store byte
315 		m_io.data[m_io.pos] = data;
316 		m_io.pos++;
317 		if (m_io.pos == m_io.size) m_io.pos = 0;
318 	}
319 }
320 
READ_LINE_MEMBER(at45db041_device::so_r)321 READ_LINE_MEMBER(at45db041_device::so_r)
322 {
323 	if (m_pin.cs == 0) return 0;
324 	return m_pin.so;
325 }
326 
WRITE_LINE_MEMBER(at45db041_device::si_w)327 WRITE_LINE_MEMBER(at45db041_device::si_w)
328 {
329 	if (m_pin.cs == 0) return;
330 	m_pin.si = state;
331 }
332 
WRITE_LINE_MEMBER(at45db041_device::cs_w)333 WRITE_LINE_MEMBER(at45db041_device::cs_w)
334 {
335 	// check if changed
336 	if (m_pin.cs == state) return;
337 	// cs low-to-high
338 	if (state != 0)
339 	{
340 		// complete program command
341 		if ((m_cmd.size >= 4) && (m_cmd.data[0] == FLASH_CMD_82))
342 		{
343 			uint32_t page, byte;
344 			page = flash_get_page_addr();
345 			byte = flash_get_byte_addr();
346 			_logerror( 1, ("at45dbxx - program data stored in buffer 1 into selected page in main memory [%04X/%04X]\n", page, byte));
347 			memcpy( &m_data[page * page_size()], &m_buffer1[0], page_size());
348 		}
349 		// reset
350 		at45db041_device::device_reset();
351 	}
352 	// save cs
353 	m_pin.cs = state;
354 }
355 
WRITE_LINE_MEMBER(at45db041_device::sck_w)356 WRITE_LINE_MEMBER(at45db041_device::sck_w)
357 {
358 	// check if changed
359 	if (m_pin.sck == state) return;
360 	// sck high-to-low
361 	if (state == 0)
362 	{
363 		// output (part 1)
364 		if (m_so_bits == 8)
365 		{
366 			m_so_bits = 0;
367 			m_so_byte = read_byte();
368 		}
369 		// output (part 2)
370 		m_pin.so = (m_so_byte >> m_so_bits) & 1;
371 		write_so(m_pin.so);
372 		m_so_bits++;
373 	}
374 	else
375 	{
376 		// input
377 		if (m_pin.si) m_si_byte = m_si_byte | (1 << m_si_bits);
378 		m_si_bits++;
379 		if (m_si_bits == 8)
380 		{
381 			m_si_bits = 0;
382 			write_byte(m_si_byte);
383 			m_si_byte = 0;
384 		}
385 	}
386 	// save sck
387 	m_pin.sck = state;
388 }
389