summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/machine/smartmed.h
blob: e913870bdca7a87032a7fc22d7ffd7b75ed2b1d6 (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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/*
    smartmed.h: header file for smartmed.c
*/

#ifndef __SMARTMEDIA_H__
#define __SMARTMEDIA_H__

#include "formats/imageutl.h"

//#define SMARTMEDIA_IMAGE_SAVE

#define MCFG_NAND_TYPE(_type)                           \
	nand_device::set_nand_type(*device, _type);

#define MCFG_NAND_RNB_CALLBACK(_write) \
	devcb = &nand_device::set_rnb_wr_callback(*device, DEVCB_##_write);

/***************************************************************************
    TYPE DEFINITIONS
***************************************************************************/

enum sm_mode_t
{
	SM_M_INIT,      // initial state
	SM_M_READ,      // read page data
	SM_M_PROGRAM,   // program page data
	SM_M_ERASE,     // erase block data
	SM_M_READSTATUS,// read status
	SM_M_READID,        // read ID
	SM_M_30,
	SM_M_RANDOM_DATA_INPUT,
	SM_M_RANDOM_DATA_OUTPUT
};

enum pointer_sm_mode_t
{
	SM_PM_A,        // accessing first 256-byte half of 512-byte data field
	SM_PM_B,        // accessing second 256-byte half of 512-byte data field
	SM_PM_C         // accessing spare field
};


// "Sequential Row Read is available only on K9F5608U0D_Y,P,V,F or K9F5608D0D_Y,P"
enum
{
	NAND_CHIP_K9F5608U0D = 0,   // K9F5608U0D
	NAND_CHIP_K9F5608U0D_J,     // K9F5608U0D-Jxxx
	NAND_CHIP_K9F5608U0B,       // K9F5608U0B
	NAND_CHIP_K9F1G08U0B,       // K9F1G08U0B
	NAND_CHIP_K9LAG08U0M        // K9LAG08U0M
};

// ======================> nand_device
class nand_device : public device_t
{
public:
	// construction/destruction
	nand_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
	nand_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);

	template<class _Object> static devcb_base &set_rnb_wr_callback(device_t &device, _Object object) { return downcast<nand_device &>(device).m_write_rnb.set_callback(object); }

	static void set_nand_type(device_t &device, int type)
	{
		nand_device &dev = downcast<nand_device &>(device);
		switch (type)
		{
			case NAND_CHIP_K9F5608U0D:
				dev.m_id_len = 2;
				dev.m_id[0] = 0xec;
				dev.m_id[1] = 0x75;
				dev.m_page_data_size = 512;
				dev.m_page_total_size = 512 + 16;
				dev.m_log2_pages_per_block = compute_log2(32);
				dev.m_num_pages = 32 * 2048;
				dev.m_col_address_cycles = 1;
				dev.m_row_address_cycles = 2;
				dev.m_sequential_row_read = 1;
				break;
			case NAND_CHIP_K9F5608U0D_J:
			case NAND_CHIP_K9F5608U0B:
				dev.m_id_len = 2;
				dev.m_id[0] = 0xec;
				dev.m_id[1] = 0x75;
				dev.m_page_data_size = 512;
				dev.m_page_total_size = 512 + 16;
				dev.m_log2_pages_per_block = compute_log2(32);
				dev.m_num_pages = 32 * 2048;
				dev.m_col_address_cycles = 1;
				dev.m_row_address_cycles = 2;
				dev.m_sequential_row_read = 0;
				break;
			case NAND_CHIP_K9F1G08U0B:
				dev.m_id_len = 5;
				dev.m_id[0] = 0xec;
				dev.m_id[1] = 0xf1;
				dev.m_id[2] = 0x00;
				dev.m_id[3] = 0x95;
				dev.m_id[4] = 0x40;
				dev.m_page_data_size = 2048;
				dev.m_page_total_size = 2048 + 64;
				dev.m_log2_pages_per_block = compute_log2(64);
				dev.m_num_pages = 64 * 1024;
				dev.m_col_address_cycles = 2;
				dev.m_row_address_cycles = 2;
				dev.m_sequential_row_read = 0;
				break;
			case NAND_CHIP_K9LAG08U0M:
				dev.m_id_len = 5;
				dev.m_id[0] = 0xec;
				dev.m_id[1] = 0xd5;
				dev.m_id[2] = 0x55;
				dev.m_id[3] = 0x25;
				dev.m_id[4] = 0x68;
				dev.m_page_data_size = 2048;
				dev.m_page_total_size = 2048 + 64;
				dev.m_log2_pages_per_block = compute_log2(128);
				dev.m_num_pages = 128 * 8192;
				dev.m_col_address_cycles = 2;
				dev.m_row_address_cycles = 3;
				dev.m_sequential_row_read = 0;
				break;
			default:
				printf("Unknown NAND type!\n");
				dev.m_id_len = 0;
				dev.m_page_data_size = 0;
				dev.m_page_total_size = 0;
				dev.m_log2_pages_per_block = 0;
				dev.m_num_pages = 0;
				dev.m_col_address_cycles = 0;
				dev.m_row_address_cycles = 0;
				dev.m_sequential_row_read = 0;
				break;
		}
	}

	int is_present();
	int is_protected();
	int is_busy();

	UINT8 data_r();
	void command_w(UINT8 data);
	void address_w(UINT8 data);
	void data_w(UINT8 data);

	void read(int offset, void *data, int size);

	void set_data_ptr(void *ptr);
protected:
	// device-level overrides
	virtual void device_start();
	virtual void device_reset();

	int m_page_data_size;   // 256 for a 2MB card, 512 otherwise
	int m_page_total_size;// 264 for a 2MB card, 528 otherwise
	int m_num_pages;        // 8192 for a 4MB card, 16184 for 8MB, 32768 for 16MB,
						// 65536 for 32MB, 131072 for 64MB, 262144 for 128MB...
						// 0 means no card loaded
	int m_log2_pages_per_block; // log2 of number of pages per erase block (usually 4 or 5)

	UINT8 *m_data_ptr;  // FEEPROM data area
	UINT8 *m_data_uid_ptr;

	sm_mode_t m_mode;               // current operation mode
	pointer_sm_mode_t m_pointer_mode;       // pointer mode

	unsigned int m_page_addr;       // page address pointer
	int m_byte_addr;        // byte address pointer
	int m_addr_load_ptr;    // address load pointer

	int m_status;           // current status
	int m_accumulated_status;   // accumulated status

	UINT8 *m_pagereg;   // page register used by program command
	UINT8 m_id[5];      // chip ID
	UINT8 m_mp_opcode;  // multi-plane operation code

	int m_mode_3065;

	// Palm Z22 NAND has 512 + 16 byte pages but, for some reason, Palm OS writes 512 + 64 bytes when
	// programming a page, so we need to keep track of the number of bytes written so we can ignore the
	// last 48 (64 - 16) bytes or else the first 48 bytes get overwritten
	int m_program_byte_count;

	int m_id_len;
	int m_col_address_cycles;
	int m_row_address_cycles;
	int m_sequential_row_read;

	devcb_write_line m_write_rnb;

	#ifdef SMARTMEDIA_IMAGE_SAVE
	int m_image_format;
	#endif
};



class smartmedia_image_device : public nand_device,
								public device_image_interface
{
public:
	// construction/destruction
	smartmedia_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);

	// image-level overrides
	virtual iodevice_t image_type() const { return IO_MEMCARD; }

	virtual bool is_readable()  const { return 1; }
	virtual bool is_writeable() const { return 1; }
	virtual bool is_creatable() const { return 0; }
	virtual bool must_be_loaded() const { return 0; }
	virtual bool is_reset_on_load() const { return 0; }
	virtual const char *image_interface() const { return "sm_memc"; }
	virtual const char *file_extensions() const { return "smc"; }
	virtual const option_guide *create_option_guide() const { return NULL; }

	virtual bool call_load();
	virtual void call_unload();
	virtual bool call_softlist_load(software_list_device &swlist, const char *swname, const rom_entry *start_entry) { return load_software(swlist, swname, start_entry); }

protected:
	// device-level overrides
	virtual void device_config_complete();

	bool smartmedia_format_1();
	bool smartmedia_format_2();
	int detect_geometry( UINT8 id1, UINT8 id2);
};


// device type definition
extern const device_type NAND;
extern const device_type SMARTMEDIA;


#endif /* __SMARTMEDIA_H__ */