/src/emu/machine/x76f100.c

https://github.com/groovybits/groovymame · C · 328 lines · 265 code · 39 blank · 24 comment · 46 complexity · abdd50b6c2df6897cbcd02738d19c153 MD5 · raw file

  1. /*
  2. * x76f100.c
  3. *
  4. * Secure SerialFlash
  5. *
  6. * The X76F100 is a Password Access Security Supervisor, containing one 896-bit Secure SerialFlash array.
  7. * Access to the memory array can be controlled by two 64-bit passwords. These passwords protect read and
  8. * write operations of the memory array.
  9. *
  10. */
  11. #include "emu.h"
  12. #include "machine/x76f100.h"
  13. #define VERBOSE_LEVEL 0
  14. inline void ATTR_PRINTF(3,4) x76f100_device::verboselog(int n_level, const char *s_fmt, ...)
  15. {
  16. if(VERBOSE_LEVEL >= n_level)
  17. {
  18. va_list v;
  19. char buf[32768];
  20. va_start(v, s_fmt);
  21. vsprintf(buf, s_fmt, v);
  22. va_end(v);
  23. logerror("x76f100 %s %s: %s", tag(), machine().describe_context(), buf);
  24. }
  25. }
  26. // device type definition
  27. const device_type X76F100 = &device_creator<x76f100_device>;
  28. x76f100_device::x76f100_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
  29. : device_secure_serial_flash(mconfig, X76F100, "X76F100", tag, owner, clock)
  30. {
  31. }
  32. void x76f100_device::device_start()
  33. {
  34. device_secure_serial_flash::device_start();
  35. save_item(NAME(state));
  36. save_item(NAME(shift));
  37. save_item(NAME(bit));
  38. save_item(NAME(byte));
  39. save_item(NAME(command));
  40. save_item(NAME(write_buffer));
  41. save_item(NAME(response_to_reset));
  42. save_item(NAME(write_password));
  43. save_item(NAME(read_password));
  44. save_item(NAME(data));
  45. }
  46. void x76f100_device::device_reset()
  47. {
  48. device_secure_serial_flash::device_reset();
  49. state = STATE_STOP;
  50. shift = 0;
  51. bit = 0;
  52. byte = 0;
  53. command = 0;
  54. memset(write_buffer, 0, SIZE_WRITE_BUFFER);
  55. }
  56. void x76f100_device::nvram_default()
  57. {
  58. // region always wins
  59. if(m_region)
  60. {
  61. // Ensure the size is correct though
  62. if(m_region->bytes() != SIZE_RESPONSE_TO_RESET+SIZE_WRITE_PASSWORD+SIZE_READ_PASSWORD+SIZE_DATA)
  63. logerror("x76f100 %s: Wrong region length for initialization data, expected 0x%x, got 0x%x\n",
  64. tag(),
  65. SIZE_RESPONSE_TO_RESET+SIZE_WRITE_PASSWORD+SIZE_READ_PASSWORD+SIZE_DATA,
  66. m_region->bytes());
  67. else {
  68. UINT8 *rb = m_region->base();
  69. int offset = 0;
  70. memcpy(response_to_reset, rb + offset, SIZE_RESPONSE_TO_RESET); offset += SIZE_RESPONSE_TO_RESET;
  71. memcpy(write_password, rb + offset, SIZE_WRITE_PASSWORD); offset += SIZE_WRITE_PASSWORD;
  72. memcpy(read_password, rb + offset, SIZE_READ_PASSWORD); offset += SIZE_READ_PASSWORD;
  73. memcpy(data, rb + offset, SIZE_DATA); offset += SIZE_DATA;
  74. return;
  75. }
  76. }
  77. // That chip isn't really usable without the passwords, so bitch
  78. // if there's no region
  79. logerror("x76f100 %s: Warning, no default data provided, chip is unusable.\n", tag());
  80. memset(response_to_reset, 0, SIZE_RESPONSE_TO_RESET);
  81. memset(write_password, 0, SIZE_WRITE_PASSWORD);
  82. memset(read_password, 0, SIZE_READ_PASSWORD);
  83. memset(data, 0, SIZE_DATA);
  84. }
  85. void x76f100_device::cs_0()
  86. {
  87. /* enable chip */
  88. state = STATE_STOP;
  89. }
  90. void x76f100_device::cs_1()
  91. {
  92. /* disable chip */
  93. state = STATE_STOP;
  94. /* high impendence? */
  95. sdar = 0;
  96. }
  97. void x76f100_device::rst_0()
  98. {
  99. }
  100. void x76f100_device::rst_1()
  101. {
  102. if(!cs) {
  103. verboselog(1, "goto response to reset\n");
  104. state = STATE_RESPONSE_TO_RESET;
  105. bit = 0;
  106. byte = 0;
  107. }
  108. }
  109. UINT8 *x76f100_device::password()
  110. {
  111. if((command & 0xe1) == COMMAND_READ)
  112. {
  113. return read_password;
  114. }
  115. return write_password;
  116. }
  117. void x76f100_device::password_ok()
  118. {
  119. if((command & 0xe1) == COMMAND_READ)
  120. {
  121. state = STATE_READ_DATA;
  122. }
  123. else if((command & 0xe1) == COMMAND_WRITE)
  124. {
  125. state = STATE_WRITE_DATA;
  126. }
  127. else
  128. {
  129. /* TODO: */
  130. }
  131. }
  132. int x76f100_device::data_offset()
  133. {
  134. int block_offset = (command >> 1) & 0x0f;
  135. return block_offset * SIZE_WRITE_BUFFER + byte;
  136. }
  137. void x76f100_device::scl_0()
  138. {
  139. if(cs)
  140. return;
  141. switch(state) {
  142. case STATE_RESPONSE_TO_RESET:
  143. if(bit == 0) {
  144. shift = response_to_reset[byte];
  145. verboselog(1, "<- response_to_reset[%d]: %02x\n", byte, shift);
  146. }
  147. sdar = shift & 1;
  148. shift >>= 1;
  149. bit++;
  150. if(bit == 8) {
  151. bit = 0;
  152. byte++;
  153. if(byte == 4)
  154. byte = 0;
  155. }
  156. break;
  157. }
  158. }
  159. void x76f100_device::scl_1()
  160. {
  161. if(cs)
  162. return;
  163. switch(state) {
  164. case STATE_RESPONSE_TO_RESET:
  165. break;
  166. case STATE_LOAD_COMMAND:
  167. case STATE_LOAD_PASSWORD:
  168. case STATE_VERIFY_PASSWORD:
  169. case STATE_WRITE_DATA:
  170. if(bit < 8) {
  171. verboselog(2, "clock\n");
  172. shift <<= 1;
  173. if(sdaw)
  174. shift |= 1;
  175. bit++;
  176. } else {
  177. switch(state) {
  178. case STATE_LOAD_COMMAND:
  179. verboselog(1, "-> command: %02x\n", command);
  180. sdar = false;
  181. command = shift;
  182. /* todo: verify command is valid? */
  183. state = STATE_LOAD_PASSWORD;
  184. bit = 0;
  185. shift = 0;
  186. break;
  187. case STATE_LOAD_PASSWORD:
  188. verboselog(1, "-> password: %02x\n", shift);
  189. sdar = false;
  190. write_buffer[byte++] = shift;
  191. if(byte == SIZE_WRITE_BUFFER)
  192. state = STATE_VERIFY_PASSWORD;
  193. bit = 0;
  194. shift = 0;
  195. break;
  196. case STATE_VERIFY_PASSWORD:
  197. verboselog(1, "-> verify password: %02x\n", shift);
  198. sdar = false;
  199. /* todo: this should probably be handled as a command */
  200. if(shift == COMMAND_ACK_PASSWORD) {
  201. /* todo: this should take 10ms before it returns ok. */
  202. if(!memcmp(password(), write_buffer, SIZE_WRITE_BUFFER))
  203. password_ok();
  204. else
  205. sdar = true;
  206. }
  207. bit = 0;
  208. shift = 0;
  209. break;
  210. case STATE_WRITE_DATA:
  211. verboselog(1, "-> data: %02x\n", shift );
  212. sdar = false;
  213. write_buffer[byte++] = shift;
  214. if(byte == SIZE_WRITE_BUFFER) {
  215. for(byte = 0; byte < SIZE_WRITE_BUFFER; byte++)
  216. data[data_offset()] = write_buffer[byte];
  217. byte = 0;
  218. }
  219. bit = 0;
  220. shift = 0;
  221. break;
  222. }
  223. }
  224. break;
  225. case STATE_READ_DATA:
  226. if(bit < 8) {
  227. if(bit == 0) {
  228. shift = data[data_offset()];
  229. verboselog(1, "<- data: %02x\n", shift );
  230. }
  231. sdar = (shift >> 7) & 1;
  232. shift <<= 1;
  233. bit++;
  234. } else {
  235. bit = 0;
  236. sdar = false;
  237. if(!sdaw) {
  238. verboselog(2, "ack <-\n");
  239. byte++;
  240. } else {
  241. verboselog(2, "nak <-\n");
  242. }
  243. }
  244. break;
  245. }
  246. }
  247. void x76f100_device::sda_0()
  248. {
  249. if(cs || !scl)
  250. return;
  251. switch(state) {
  252. case STATE_STOP:
  253. state = STATE_LOAD_COMMAND;
  254. break;
  255. case STATE_LOAD_PASSWORD:
  256. /* todo: this will be the 0xc0 command, but it's not handled as a command yet. */
  257. break;
  258. case STATE_READ_DATA:
  259. // c->state = STATE_LOAD_ADDRESS;
  260. break;
  261. default:
  262. break;
  263. }
  264. bit = 0;
  265. byte = 0;
  266. shift = 0;
  267. sdar = false;
  268. }
  269. void x76f100_device::sda_1()
  270. {
  271. if(cs || !scl)
  272. return;
  273. state = STATE_STOP;
  274. sdar = false;
  275. }
  276. void x76f100_device::nvram_read(emu_file &file)
  277. {
  278. file.read(response_to_reset, SIZE_RESPONSE_TO_RESET);
  279. file.read(write_password, SIZE_WRITE_PASSWORD);
  280. file.read(read_password, SIZE_READ_PASSWORD);
  281. file.read(data, SIZE_DATA);
  282. }
  283. void x76f100_device::nvram_write(emu_file &file)
  284. {
  285. file.write(response_to_reset, SIZE_RESPONSE_TO_RESET);
  286. file.write(write_password, SIZE_WRITE_PASSWORD);
  287. file.write(read_password, SIZE_READ_PASSWORD);
  288. file.write(data, SIZE_DATA);
  289. }