openMSX
EEPROM_93C46.cc
Go to the documentation of this file.
1#include "EEPROM_93C46.hh"
2
3#include "serialize.hh"
4
5namespace openmsx {
6
8 : sram(NUM_ADDRESSES, xml, SRAM::DontLoadTag{})
9{
10}
11
12EEPROM_93C46::EEPROM_93C46(const std::string& name, const DeviceConfig& config)
13 : sram(name + " EEPROM", NUM_ADDRESSES, config)
14{
15}
16
18{
19 completionTime = EmuTime::zero();
20 state = IN_RESET;
21 writeProtected = true;
22 bits = 0;
23 address = 0;
24 shiftRegister = 0;
25}
26
27uint8_t EEPROM_93C46::read(unsigned addr) const
28{
29 return sram[addr];
30}
31
32void EEPROM_93C46::write(unsigned addr, uint8_t value, EmuTime::param time)
33{
34 // The ST M93C46 datasheet documents that erase before write is not
35 // needed.
36 sram.write(addr, value); // not: sram[addr] & value
37 completionTime = time + EmuDuration::usec(1750);
38}
39
40void EEPROM_93C46::writeAll(uint8_t value, EmuTime::param time)
41{
42 sram.memset(0, value, NUM_ADDRESSES);
43 //for (auto addr : xrange(NUM_ADDRESSES)) {
44 // sram.write(addr, sram[addr] & value);
45 //}
46 completionTime = time + EmuDuration::usec(8000);
47}
48
49void EEPROM_93C46::erase(unsigned addr, EmuTime::param time)
50{
51 sram.write(addr, 255);
52 completionTime = time + EmuDuration::usec(1000);
53}
54
55void EEPROM_93C46::eraseAll(EmuTime::param time)
56{
57 sram.memset(0, 255, NUM_ADDRESSES);
58 completionTime = time + EmuDuration::usec(8000);
59}
60
61bool EEPROM_93C46::ready(EmuTime::param time) const
62{
63 return time >= completionTime;
64}
65
66bool EEPROM_93C46::read_DO(EmuTime::param time) const
67{
68 if (state == READING_DATA) {
69 return shiftRegister & (1 << (SHIFT_REG_BITS - 1));
70 } else if (state == WAIT_FOR_START_BIT) {
71 return ready(time);
72 } else {
73 return true;
74 }
75}
76
77void EEPROM_93C46::write_CS(bool value, EmuTime::param time)
78{
79 if (pinCS == value) return;
80 pinCS = value;
81
82 if (pinCS) {
83 csTime = time; // see clockEvent()
84
85 assert(state == IN_RESET);
86 state = WAIT_FOR_START_BIT;
87 } else {
88 state = IN_RESET;
89 }
90}
91
92void EEPROM_93C46::write_CLK(bool value, EmuTime::param time)
93{
94 if (pinCLK == value) return;
95 pinCLK = value;
96
97 if (pinCLK) {
98 clockEvent(time);
99 }
100}
101
102void EEPROM_93C46::write_DI(bool value, EmuTime::param /*time*/)
103{
104 pinDI = value;
105}
106
107void EEPROM_93C46::clockEvent(EmuTime::param time)
108{
109 switch (state) {
110 case IN_RESET:
111 // nothing
112 break;
113
115 // Ignore simultaneous rising CLK and CS edge.
116 if (pinDI && ready(time) && (time > csTime)) {
117 shiftRegister = 0;
118 bits = 0;
119 state = WAIT_FOR_COMMAND;
120 }
121 break;
122
123 case WAIT_FOR_COMMAND:
124 shiftRegister = narrow_cast<uint16_t>((shiftRegister << 1) | int(pinDI));
125 ++bits;
126 if (bits == (2 + ADDRESS_BITS)) {
127 execute_command(time);
128 }
129 break;
130
131 case READING_DATA:
132 if ((bits % DATA_BITS) == 0) {
133 uint8_t value = read(address);
134 shiftRegister = uint16_t(value << (SHIFT_REG_BITS - DATA_BITS));
135 address = (address + 1) & ADDRESS_MASK;
136 } else {
137 shiftRegister <<= 1;
138 }
139 ++bits;
140 break;
141
142 case WAIT_FOR_WRITE:
143 shiftRegister = narrow_cast<uint16_t>((shiftRegister << 1) | int(pinDI));
144 ++bits;
145 if (bits == DATA_BITS) {
146 if (writeProtected) {
147 state = IN_RESET;
148 break;
149 }
150 write(address, narrow_cast<uint8_t>(shiftRegister), time);
151 state = IN_RESET;
152 }
153 break;
154
156 shiftRegister = narrow_cast<uint16_t>((shiftRegister << 1) | int(pinDI));
157 ++bits;
158 if (bits == DATA_BITS) {
159 if (writeProtected) {
160 state = IN_RESET;
161 break;
162 }
163 writeAll(narrow_cast<uint8_t>(shiftRegister), time);
164 state = IN_RESET;
165 }
166 break;
167 }
168}
169
170void EEPROM_93C46::execute_command(EmuTime::param time)
171{
172 bits = 0;
173 address = shiftRegister & ADDRESS_MASK;
174
175 switch ((shiftRegister >> ADDRESS_BITS) & 3) {
176 case 0:
177 switch (address >> (ADDRESS_BITS - 2)) {
178 case 0: // LOCK
179 writeProtected = true;
180 state = IN_RESET;
181 break;
182
183 case 1: // WRITE ALL
184 shiftRegister = 0;
185 state = WAIT_FOR_WRITE_ALL;
186 break;
187
188 case 2: // ERASE ALL
189 if (writeProtected) {
190 state = IN_RESET;
191 break;
192 }
193 eraseAll(time);
194 state = IN_RESET;
195 break;
196
197 case 3: // UNLOCK
198 writeProtected = false;
199 state = IN_RESET;
200 break;
201 }
202 break;
203
204 case 1: // WRITE
205 shiftRegister = 0;
206 state = WAIT_FOR_WRITE;
207 break;
208
209 case 2: // READ
210 // Data is fetched after first CLK. Reset the shift register to
211 // 0 to simulate the dummy 0 bit that happens prior to the
212 // first clock
213 shiftRegister = 0;
214 state = READING_DATA;
215 break;
216
217 case 3: // ERASE
218 if (writeProtected) {
219 state = IN_RESET;
220 break;
221 }
222 erase(address, time);
223 state = IN_RESET;
224 break;
225 }
226}
227
228static constexpr std::initializer_list<enum_string<EEPROM_93C46::State>> stateInfo = {
229 { "IN_RESET", EEPROM_93C46::IN_RESET },
230 { "WAIT_FOR_START_BIT", EEPROM_93C46::WAIT_FOR_START_BIT },
231 { "WAIT_FOR_COMMAND", EEPROM_93C46::WAIT_FOR_COMMAND },
232 { "READING_DATA", EEPROM_93C46::READING_DATA },
233 { "WAIT_FOR_WRITE", EEPROM_93C46::WAIT_FOR_WRITE },
234 { "WAIT_FOR_WRITEALL", EEPROM_93C46::WAIT_FOR_WRITE_ALL },
235};
237
238template<typename Archive>
239void EEPROM_93C46::serialize(Archive& ar, unsigned /*version*/)
240{
241 ar.serialize("sram", sram,
242 "completionTime", completionTime,
243 "csTime", csTime,
244 "state", state,
245 "shiftRegister", shiftRegister,
246 "bits", bits,
247 "address", address,
248 "pinCS", pinCS,
249 "pinCLK", pinCLK,
250 "pinDI", pinDI,
251 "writeProtected", writeProtected);
252}
254
255} // namespace openmsx
static constexpr uint32_t ADDRESS_MASK
static constexpr uint8_t ADDRESS_BITS
void write_CS(bool value, EmuTime::param time)
static constexpr uint32_t NUM_ADDRESSES
static constexpr uint8_t DATA_BITS
void serialize(Archive &ar, unsigned version)
EEPROM_93C46(const XMLElement &xml)
void write_CLK(bool value, EmuTime::param time)
bool read_DO(EmuTime::param time) const
void write_DI(bool value, EmuTime::param time)
static constexpr EmuDuration usec(unsigned x)
void write(size_t addr, byte value)
Definition SRAM.cc:65
void memset(size_t addr, byte c, size_t size)
Definition SRAM.cc:74
This file implemented 3 utility functions:
Definition Autofire.cc:11
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
#define SERIALIZE_ENUM(TYPE, INFO)