eeprom93xx.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*
  2. * QEMU EEPROM 93xx emulation
  3. *
  4. * Copyright (c) 2006-2007 Stefan Weil
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. /* Emulation for serial EEPROMs:
  21. * NMC93C06 256-Bit (16 x 16)
  22. * NMC93C46 1024-Bit (64 x 16)
  23. * NMC93C56 2028 Bit (128 x 16)
  24. * NMC93C66 4096 Bit (256 x 16)
  25. * Compatible devices include FM93C46 and others.
  26. *
  27. * Other drivers use these interface functions:
  28. * eeprom93xx_new - add a new EEPROM (with 16, 64 or 256 words)
  29. * eeprom93xx_free - destroy EEPROM
  30. * eeprom93xx_read - read data from the EEPROM
  31. * eeprom93xx_write - write data to the EEPROM
  32. * eeprom93xx_data - get EEPROM data array for external manipulation
  33. *
  34. * Todo list:
  35. * - No emulation of EEPROM timings.
  36. */
  37. #include <assert.h>
  38. #include "hw.h"
  39. #include "eeprom93xx.h"
  40. /* Debug EEPROM emulation. */
  41. //~ #define DEBUG_EEPROM
  42. #ifdef DEBUG_EEPROM
  43. #define logout(fmt, args...) fprintf(stderr, "EEPROM\t%-24s" fmt, __func__, ##args)
  44. #else
  45. #define logout(fmt, args...) ((void)0)
  46. #endif
  47. static int eeprom_instance = 0;
  48. static const int eeprom_version = 20061112;
  49. #if 0
  50. typedef enum {
  51. eeprom_read = 0x80, /* read register xx */
  52. eeprom_write = 0x40, /* write register xx */
  53. eeprom_erase = 0xc0, /* erase register xx */
  54. eeprom_ewen = 0x30, /* erase / write enable */
  55. eeprom_ewds = 0x00, /* erase / write disable */
  56. eeprom_eral = 0x20, /* erase all registers */
  57. eeprom_wral = 0x10, /* write all registers */
  58. eeprom_amask = 0x0f,
  59. eeprom_imask = 0xf0
  60. } eeprom_instruction_t;
  61. #endif
  62. #ifdef DEBUG_EEPROM
  63. static const char *opstring[] = {
  64. "extended", "write", "read", "erase"
  65. };
  66. #endif
  67. struct _eeprom_t {
  68. uint8_t tick;
  69. uint8_t address;
  70. uint8_t command;
  71. uint8_t writeable;
  72. uint8_t eecs;
  73. uint8_t eesk;
  74. uint8_t eedo;
  75. uint8_t addrbits;
  76. uint8_t size;
  77. uint16_t data;
  78. uint16_t contents[0];
  79. };
  80. /* Code for saving and restoring of EEPROM state. */
  81. static void eeprom_save(QEMUFile *f, void *opaque)
  82. {
  83. /* Save EEPROM data. */
  84. unsigned address;
  85. eeprom_t *eeprom = (eeprom_t *)opaque;
  86. qemu_put_buffer(f, (uint8_t *)eeprom, sizeof(*eeprom) - 2);
  87. qemu_put_be16(f, eeprom->data);
  88. for (address = 0; address < eeprom->size; address++) {
  89. qemu_put_be16(f, eeprom->contents[address]);
  90. }
  91. }
  92. static int eeprom_load(QEMUFile *f, void *opaque, int version_id)
  93. {
  94. /* Load EEPROM data from saved data if version and EEPROM size
  95. of data and current EEPROM are identical. */
  96. eeprom_t *eeprom = (eeprom_t *)opaque;
  97. int result = -EINVAL;
  98. if (version_id == eeprom_version) {
  99. unsigned address;
  100. uint8_t size = eeprom->size;
  101. qemu_get_buffer(f, (uint8_t *)eeprom, sizeof(*eeprom) - 2);
  102. if (eeprom->size == size) {
  103. eeprom->data = qemu_get_be16(f);
  104. for (address = 0; address < eeprom->size; address++) {
  105. eeprom->contents[address] = qemu_get_be16(f);
  106. }
  107. result = 0;
  108. }
  109. }
  110. return result;
  111. }
  112. void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi)
  113. {
  114. uint8_t tick = eeprom->tick;
  115. uint8_t eedo = eeprom->eedo;
  116. uint16_t address = eeprom->address;
  117. uint8_t command = eeprom->command;
  118. logout("CS=%u SK=%u DI=%u DO=%u, tick = %u\n",
  119. eecs, eesk, eedi, eedo, tick);
  120. if (! eeprom->eecs && eecs) {
  121. /* Start chip select cycle. */
  122. logout("Cycle start, waiting for 1st start bit (0)\n");
  123. tick = 0;
  124. command = 0x0;
  125. address = 0x0;
  126. } else if (eeprom->eecs && ! eecs) {
  127. /* End chip select cycle. This triggers write / erase. */
  128. if (eeprom->writeable) {
  129. uint8_t subcommand = address >> (eeprom->addrbits - 2);
  130. if (command == 0 && subcommand == 2) {
  131. /* Erase all. */
  132. for (address = 0; address < eeprom->size; address++) {
  133. eeprom->contents[address] = 0xffff;
  134. }
  135. } else if (command == 3) {
  136. /* Erase word. */
  137. eeprom->contents[address] = 0xffff;
  138. } else if (tick >= 2 + 2 + eeprom->addrbits + 16) {
  139. if (command == 1) {
  140. /* Write word. */
  141. eeprom->contents[address] &= eeprom->data;
  142. } else if (command == 0 && subcommand == 1) {
  143. /* Write all. */
  144. for (address = 0; address < eeprom->size; address++) {
  145. eeprom->contents[address] &= eeprom->data;
  146. }
  147. }
  148. }
  149. }
  150. /* Output DO is tristate, read results in 1. */
  151. eedo = 1;
  152. } else if (eecs && ! eeprom->eesk && eesk) {
  153. /* Raising edge of clock shifts data in. */
  154. if (tick == 0) {
  155. /* Wait for 1st start bit. */
  156. if (eedi == 0) {
  157. logout("Got correct 1st start bit, waiting for 2nd start bit (1)\n");
  158. tick++;
  159. } else {
  160. logout("wrong 1st start bit (is 1, should be 0)\n");
  161. tick = 2;
  162. //~ assert(!"wrong start bit");
  163. }
  164. } else if (tick == 1) {
  165. /* Wait for 2nd start bit. */
  166. if (eedi != 0) {
  167. logout("Got correct 2nd start bit, getting command + address\n");
  168. tick++;
  169. } else {
  170. logout("1st start bit is longer than needed\n");
  171. }
  172. } else if (tick < 2 + 2) {
  173. /* Got 2 start bits, transfer 2 opcode bits. */
  174. tick++;
  175. command <<= 1;
  176. if (eedi) {
  177. command += 1;
  178. }
  179. } else if (tick < 2 + 2 + eeprom->addrbits) {
  180. /* Got 2 start bits and 2 opcode bits, transfer all address bits. */
  181. tick++;
  182. address = ((address << 1) | eedi);
  183. if (tick == 2 + 2 + eeprom->addrbits) {
  184. logout("%s command, address = 0x%02x (value 0x%04x)\n",
  185. opstring[command], address, eeprom->contents[address]);
  186. if (command == 2) {
  187. eedo = 0;
  188. }
  189. address = address % eeprom->size;
  190. if (command == 0) {
  191. /* Command code in upper 2 bits of address. */
  192. switch (address >> (eeprom->addrbits - 2)) {
  193. case 0:
  194. logout("write disable command\n");
  195. eeprom->writeable = 0;
  196. break;
  197. case 1:
  198. logout("write all command\n");
  199. break;
  200. case 2:
  201. logout("erase all command\n");
  202. break;
  203. case 3:
  204. logout("write enable command\n");
  205. eeprom->writeable = 1;
  206. break;
  207. }
  208. } else {
  209. /* Read, write or erase word. */
  210. eeprom->data = eeprom->contents[address];
  211. }
  212. }
  213. } else if (tick < 2 + 2 + eeprom->addrbits + 16) {
  214. /* Transfer 16 data bits. */
  215. tick++;
  216. if (command == 2) {
  217. /* Read word. */
  218. eedo = ((eeprom->data & 0x8000) != 0);
  219. }
  220. eeprom->data <<= 1;
  221. eeprom->data += eedi;
  222. } else {
  223. logout("additional unneeded tick, not processed\n");
  224. }
  225. }
  226. /* Save status of EEPROM. */
  227. eeprom->tick = tick;
  228. eeprom->eecs = eecs;
  229. eeprom->eesk = eesk;
  230. eeprom->eedo = eedo;
  231. eeprom->address = address;
  232. eeprom->command = command;
  233. }
  234. uint16_t eeprom93xx_read(eeprom_t *eeprom)
  235. {
  236. /* Return status of pin DO (0 or 1). */
  237. logout("CS=%u DO=%u\n", eeprom->eecs, eeprom->eedo);
  238. return (eeprom->eedo);
  239. }
  240. #if 0
  241. void eeprom93xx_reset(eeprom_t *eeprom)
  242. {
  243. /* prepare eeprom */
  244. logout("eeprom = 0x%p\n", eeprom);
  245. eeprom->tick = 0;
  246. eeprom->command = 0;
  247. }
  248. #endif
  249. eeprom_t *eeprom93xx_new(uint16_t nwords)
  250. {
  251. /* Add a new EEPROM (with 16, 64 or 256 words). */
  252. eeprom_t *eeprom;
  253. uint8_t addrbits;
  254. switch (nwords) {
  255. case 16:
  256. case 64:
  257. addrbits = 6;
  258. break;
  259. case 128:
  260. case 256:
  261. addrbits = 8;
  262. break;
  263. default:
  264. assert(!"Unsupported EEPROM size, fallback to 64 words!");
  265. nwords = 64;
  266. addrbits = 6;
  267. }
  268. eeprom = (eeprom_t *)qemu_mallocz(sizeof(*eeprom) + nwords * 2);
  269. eeprom->size = nwords;
  270. eeprom->addrbits = addrbits;
  271. /* Output DO is tristate, read results in 1. */
  272. eeprom->eedo = 1;
  273. logout("eeprom = 0x%p, nwords = %u\n", eeprom, nwords);
  274. register_savevm("eeprom", eeprom_instance, eeprom_version,
  275. eeprom_save, eeprom_load, eeprom);
  276. return eeprom;
  277. }
  278. void eeprom93xx_free(eeprom_t *eeprom)
  279. {
  280. /* Destroy EEPROM. */
  281. logout("eeprom = 0x%p\n", eeprom);
  282. unregister_savevm("eeprom", eeprom);
  283. qemu_free(eeprom);
  284. }
  285. uint16_t *eeprom93xx_data(eeprom_t *eeprom)
  286. {
  287. /* Get EEPROM data array. */
  288. return &eeprom->contents[0];
  289. }
  290. /* eof */