summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/smartmed.h
blob: 708449cd36ac697b444302c58c1b8affeef9d8b2 (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
// license:BSD-3-Clause
// copyright-holders:Raphael Nabet
/*
    smartmed.h: header file for smartmed.c
*/

#ifndef MAME_MACHINE_SMARTMEDIA_H
#define MAME_MACHINE_SMARTMEDIA_H

#pragma once

#include "formats/imageutl.h"
#include "softlist_dev.h"

//#define SMARTMEDIA_IMAGE_SAVE


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

// ======================> nand_device
class nand_device : public device_t
{
public:
	// "Sequential Row Read is available only on K9F5608U0D_Y,P,V,F or K9F5608D0D_Y,P"
	enum class chip
	{
		K9F5608U0D = 0,   // K9F5608U0D
		K9F5608U0D_J,     // K9F5608U0D-Jxxx
		K9F5608U0B,       // K9F5608U0B
		K9F1G08U0B,       // K9F1G08U0B
		K9LAG08U0M        // K9LAG08U0M
	};

	// construction/destruction
	nand_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	auto rnb_wr_callback() { return m_write_rnb.bind(); }

	void set_nand_type(chip type)
	{
		switch (type)
		{
		case chip::K9F5608U0D:
			m_id_len = 2;
			m_id[0] = 0xec;
			m_id[1] = 0x75;
			m_page_data_size = 512;
			m_page_total_size = 512 + 16;
			m_log2_pages_per_block = compute_log2(32);
			m_num_pages = 32 * 2048;
			m_col_address_cycles = 1;
			m_row_address_cycles = 2;
			m_sequential_row_read = 1;
			break;
		case chip::K9F5608U0D_J:
		case chip::K9F5608U0B:
			m_id_len = 2;
			m_id[0] = 0xec;
			m_id[1] = 0x75;
			m_page_data_size = 512;
			m_page_total_size = 512 + 16;
			m_log2_pages_per_block = compute_log2(32);
			m_num_pages = 32 * 2048;
			m_col_address_cycles = 1;
			m_row_address_cycles = 2;
			m_sequential_row_read = 0;
			break;
		case chip::K9F1G08U0B:
			m_id_len = 5;
			m_id[0] = 0xec;
			m_id[1] = 0xf1;
			m_id[2] = 0x00;
			m_id[3] = 0x95;
			m_id[4] = 0x40;
			m_page_data_size = 2048;
			m_page_total_size = 2048 + 64;
			m_log2_pages_per_block = compute_log2(64);
			m_num_pages = 64 * 1024;
			m_col_address_cycles = 2;
			m_row_address_cycles = 2;
			m_sequential_row_read = 0;
			break;
		case chip::K9LAG08U0M:
			m_id_len = 5;
			m_id[0] = 0xec;
			m_id[1] = 0xd5;
			m_id[2] = 0x55;
			m_id[3] = 0x25;
			m_id[4] = 0x68;
			m_page_data_size = 2048;
			m_page_total_size = 2048 + 64;
			m_log2_pages_per_block = compute_log2(128);
			m_num_pages = 128 * 8192;
			m_col_address_cycles = 2;
			m_row_address_cycles = 3;
			m_sequential_row_read = 0;
			break;
		default:
			printf("Unknown NAND type!\n");
			m_id_len = 0;
			m_page_data_size = 0;
			m_page_total_size = 0;
			m_log2_pages_per_block = 0;
			m_num_pages = 0;
			m_col_address_cycles = 0;
			m_row_address_cycles = 0;
			m_sequential_row_read = 0;
			break;
		}
	}

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

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

	void set_data_ptr(void *ptr);

protected:
	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
	};

	nand_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);

	// device-level overrides
	virtual void device_start() override;
	virtual void device_reset() override;

	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_t* m_data_ptr;  // FEEPROM data area
	std::unique_ptr<uint8_t[]> 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

	std::unique_ptr<uint8_t[]> m_pagereg;   // page register used by program command
	uint8_t m_id[5];      // chip ID
	uint8_t 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_t clock);

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

	virtual bool is_readable()  const noexcept override { return true; }
	virtual bool is_writeable() const noexcept override { return true; }
	virtual bool is_creatable() const noexcept override { return false; }
	virtual bool must_be_loaded() const noexcept override { return false; }
	virtual bool is_reset_on_load() const noexcept override { return false; }
	virtual const char *image_interface() const noexcept override { return "sm_memc"; }
	virtual const char *file_extensions() const noexcept override { return "smc"; }

	virtual image_init_result call_load() override;
	virtual void call_unload() override;

protected:
	virtual const software_list_loader &get_software_list_loader() const override { return image_software_list_loader::instance(); }

	image_init_result smartmedia_format_1();
	image_init_result smartmedia_format_2();
	int detect_geometry(uint8_t id1, uint8_t id2);
};


// device type definition
DECLARE_DEVICE_TYPE(NAND,       nand_device)
DECLARE_DEVICE_TYPE(SMARTMEDIA, smartmedia_image_device)

#endif // MAME_MACHINE_SMARTMEDIA_H