You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

608 lines
18 KiB

  1. /***************************************************************************
  2. * Copyright (C) 04/2013 by Olaf Rempel *
  3. * razzor@kopf-tisch.de *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; version 2 of the License, *
  8. * *
  9. * This program is distributed in the hope that it will be useful, *
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  12. * GNU General Public License for more details. *
  13. * *
  14. * You should have received a copy of the GNU General Public License *
  15. * along with this program; if not, write to the *
  16. * Free Software Foundation, Inc., *
  17. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  18. ***************************************************************************/
  19. #include <avr/io.h>
  20. #include <avr/interrupt.h>
  21. #define F_CPU 11059200
  22. #include <util/delay.h>
  23. /*
  24. * attiny2313
  25. * lfuse: 0xff (ext. crystal, slow rising power, max startup time)
  26. * hfuse: 0xdb (2.7V BOD)
  27. * efuse: 0xff (self Prog enabled)
  28. *
  29. * PB0 -> NC
  30. * PB1 -> reset-out
  31. * PB2 -> /WR SRAM
  32. * PB3 -> SRCK (shift register clock)
  33. * PB4 -> SER (shift register input)
  34. * PB5 -> CCK (counter clock)
  35. * PB6 -> RCK (counter and shift register store clock)
  36. * PB7 -> /OE (output enable counter, shift register, reset-out, A16)
  37. * PD0 <- RXD
  38. * PD1 -> TXD
  39. * PD2 <- /PowerFail
  40. * PD3 -> A16
  41. * PD4 -> /LED_GN
  42. * PD5 -> /LED_RT
  43. * PD6 -> /OE (output enable RAM and address buffer, counter clear)
  44. */
  45. #define RESET_OUT PORTB1
  46. #define nRAM_WR PORTB2
  47. #define SREG_CLK PORTB3
  48. #define SREG_DAT PORTB4
  49. #define CNT_CLK PORTB5
  50. #define REG_STORE PORTB6
  51. #define nEMU_EN PORTB7
  52. #define RXD PORTD0
  53. #define TXD PORTD1
  54. #define nPOWERFAIL PORTD2
  55. #define EMU_A16 PORTD3
  56. #define nLED_GN PORTD4
  57. #define nLED_RT PORTD5
  58. #define nTARGET_EN PORTD6
  59. #define BAUDRATE 115200
  60. #define UART_CALC_BAUDRATE(baudRate) (((uint32_t)F_CPU) / (((uint32_t)baudRate)*16) -1)
  61. /* ************************************************************************* */
  62. #define MSGTYPE_VERSION_REQ 0x01 /* no payload */
  63. #define MSGTYPE_PAGESIZE_REQ 0x02 /* no payload */
  64. #define MSGTYPE_CONFIG_REQ 0x03 /* eprom_type(1), pagesize(1), reset_polarity(1) */
  65. #define MSGTYPE_PROGMODE_REQ 0x04 /* progmode(1) */
  66. #define MSGTYPE_SETADDRESS_REQ 0x05 /* address(3) msb first */
  67. #define MSGTYPE_WRITE_REQ 0x06 /* data(0-pagesize) */
  68. #define MSGTYPE_READ_REQ 0x07 /* length(1) */
  69. #define MSGTYPE_ERROR_RSP 0x80 /* error_code(1) */
  70. #define MSGTYPE_VERSION_RSP 0x81 /* version(?) */
  71. #define MSGTYPE_PAGESIZE_RSP 0x82 /* pagesize(1) */
  72. #define MSGTYPE_CONFIG_RSP 0x83 /* no payload */
  73. #define MSGTYPE_PROGMODE_RSP 0x84 /* no payload */
  74. #define MSGTYPE_SETADDRESS_RSP 0x85 /* no payload */
  75. #define MSGTYPE_WRITE_RSP 0x86 /* no payload */
  76. #define MSGTYPE_READ_RSP 0x87 /* data(0-pagesize) */
  77. #define SUCCESS 0x00
  78. #define ERROR_UNKNOWN_COMMAND 0x01 /* unknown message type */
  79. #define ERROR_NOT_SUPPORTED 0x02 /* command not supported */
  80. #define ERROR_INVALID_MODE 0x03 /* invalid progmode */
  81. #define ERROR_INVALID_PARAMETER 0x04 /* invalid parameter in request */
  82. #define ERROR_INVALID_ADDRESS 0x05 /* write outside of configured region */
  83. #define RESET_POLARITY_LOW 0x00 /* low active reset */
  84. #define RESET_POLARITY_HIGH 0x01 /* high active reset */
  85. #define EPROM_TYPE_2K 0x02 /* 2716 */
  86. #define EPROM_TYPE_4K 0x04 /* 2732 */
  87. #define EPROM_TYPE_8K 0x08 /* 2764 */
  88. #define EPROM_TYPE_16K 0x10 /* 27128 */
  89. #define EPROM_TYPE_32K 0x20 /* 27256 */
  90. #define EPROM_TYPE_64K 0x40 /* 27512 */
  91. #define EPROM_TYPE_128K 0x80 /* 27010 */
  92. #define PROGMODE_DISABLED 0x00 /* target running, no write access to RAM */
  93. #define PROGMODE_ENABLED 0x01 /* target reset, write access to RAM */
  94. #define PAGESIZE_MAX 128
  95. /* ************************************************************************* */
  96. struct _globdata {
  97. uint32_t address_max;
  98. uint32_t address;
  99. uint8_t progmode;
  100. uint8_t reset_polarity;
  101. uint8_t pagesize;
  102. uint8_t address_mask;
  103. };
  104. static const uint8_t version_str[] = "epromsim v1.00";
  105. static struct _globdata gdata = { 0 };
  106. /* *************************************************************************
  107. * send one byte to UART
  108. * ************************************************************************* */
  109. static void ser_send(uint8_t data)
  110. {
  111. loop_until_bit_is_set(UCSRA, UDRIE);
  112. UDR = data;
  113. } /* ser_send */
  114. /* *************************************************************************
  115. * receive one byte from UART
  116. * ************************************************************************* */
  117. static uint8_t ser_recv(void)
  118. {
  119. loop_until_bit_is_set(UCSRA, RXC);
  120. return UDR;
  121. } /* ser_recv */
  122. /* *************************************************************************
  123. * shift one byte out to register (LSB first)
  124. * ************************************************************************* */
  125. static void shift_data(uint8_t data)
  126. {
  127. uint8_t mask;
  128. for (mask = 0x01; mask != 0; mask <<= 1)
  129. {
  130. if (data & mask)
  131. {
  132. PORTB |= (1<<SREG_DAT);
  133. }
  134. else
  135. {
  136. PORTB &= ~(1<<SREG_DAT);
  137. }
  138. /* positive edge clocks in data */
  139. PORTB |= (1<<SREG_CLK);
  140. PORTB &= ~(1<<SREG_CLK);
  141. }
  142. } /* shift_data */
  143. /* *************************************************************************
  144. * store pulse for register and counter
  145. * ************************************************************************* */
  146. static void store_pulse(void)
  147. {
  148. /* positive edge transfers data to output buffer */
  149. PORTB |= (1<<REG_STORE);
  150. PORTB &= ~(1<<REG_STORE);
  151. } /* store_pulse */
  152. /* *************************************************************************
  153. * write pulse for SRAM
  154. * ************************************************************************* */
  155. static void write_pulse(void)
  156. {
  157. /* positive edge clocks in data */
  158. PORTB &= ~(1<<nRAM_WR);
  159. PORTB |= (1<<nRAM_WR);
  160. } /* write_pulse */
  161. /* *************************************************************************
  162. * reset address counter
  163. * ************************************************************************* */
  164. static void address_reset(void)
  165. {
  166. PORTD &= ~(1<<nTARGET_EN);
  167. PORTD |= (1<<nTARGET_EN);
  168. } /* address_reset */
  169. /* *************************************************************************
  170. * increment address counter
  171. * ************************************************************************* */
  172. static void address_inc_pulse(void)
  173. {
  174. /* positive edge increments counter */
  175. PORTB |= (1<<CNT_CLK);
  176. PORTB &= ~(1<<CNT_CLK);
  177. } /* address_inc_pulse */
  178. /* *************************************************************************
  179. * controls A16 line
  180. * ************************************************************************* */
  181. static void address_set_a16(uint8_t enable)
  182. {
  183. if (enable)
  184. {
  185. PORTD |= (1<<EMU_A16);
  186. }
  187. else
  188. {
  189. PORTD &= ~(1<<EMU_A16);
  190. }
  191. } /* address_set_a16 */
  192. /* *************************************************************************
  193. * switch access to RAM between emulator and target
  194. * ************************************************************************* */
  195. static void set_progmode(uint8_t progmode)
  196. {
  197. gdata.progmode = progmode;
  198. if (progmode)
  199. {
  200. /* switch RAM access to EMU */
  201. PORTD |= (1<<nTARGET_EN);
  202. PORTD &= ~(1<<nLED_RT);
  203. PORTB &= ~(1<<nEMU_EN);
  204. }
  205. else
  206. {
  207. /* set eprom address line mask */
  208. shift_data(gdata.address_mask);
  209. shift_data(0x00);
  210. store_pulse();
  211. /* switch RAM access to TARGET */
  212. PORTB |= (1<<nEMU_EN);
  213. PORTD &= ~(1<<nTARGET_EN);
  214. PORTD |= (1<<nLED_RT);
  215. /* address counter is reset */
  216. gdata.address = 0x00;
  217. }
  218. /* set RESET_OUT */
  219. if (progmode ^ gdata.reset_polarity)
  220. {
  221. PORTB &= ~(1<<RESET_OUT);
  222. }
  223. else
  224. {
  225. PORTB |= (1<<RESET_OUT);
  226. }
  227. } /* set_progmode */
  228. /* *************************************************************************
  229. * set_address
  230. * ************************************************************************* */
  231. static void set_address(uint32_t address)
  232. {
  233. /* reset address counter */
  234. if (address < gdata.address)
  235. {
  236. address_reset();
  237. gdata.address = 0;
  238. }
  239. // TODO: A16 is not controlled by counter
  240. while (gdata.address++ < address)
  241. {
  242. address_inc_pulse();
  243. }
  244. } /* set_address */
  245. /* *************************************************************************
  246. * write_data
  247. * ************************************************************************* */
  248. static void write_data(uint8_t length)
  249. {
  250. while (length--)
  251. {
  252. address_set_a16(gdata.address++ > 0xFFFF);
  253. shift_data(ser_recv());
  254. store_pulse();
  255. write_pulse();
  256. address_inc_pulse();
  257. }
  258. } /* write_data */
  259. /* *************************************************************************
  260. * fill RAM with 0xFF
  261. * ************************************************************************* */
  262. static void do_clear(void)
  263. {
  264. uint16_t i = 0xFFFF;
  265. shift_data(0xFF);
  266. PORTD &= ~(1<<EMU_A16);
  267. do {
  268. store_pulse();
  269. write_pulse();
  270. address_inc_pulse();
  271. } while (i--);
  272. PORTD |= (1<<EMU_A16);
  273. do {
  274. store_pulse();
  275. write_pulse();
  276. address_inc_pulse();
  277. } while (i--);
  278. } /* do_clear */
  279. /* *************************************************************************
  280. * configures number of addresslines
  281. * ************************************************************************* */
  282. static uint8_t set_eprom_type(uint8_t type)
  283. {
  284. switch (type)
  285. {
  286. case EPROM_TYPE_2K:
  287. gdata.address_max = 0x0800;
  288. gdata.address_mask = 0x00;
  289. break;
  290. case EPROM_TYPE_4K:
  291. gdata.address_max = 0x1000;
  292. gdata.address_mask = 0x80;
  293. break;
  294. case EPROM_TYPE_8K:
  295. gdata.address_max = 0x2000;
  296. gdata.address_mask = 0xC0;
  297. break;
  298. case EPROM_TYPE_16K:
  299. gdata.address_max = 0x4000;
  300. gdata.address_mask = 0xE0;
  301. break;
  302. case EPROM_TYPE_32K:
  303. gdata.address_max = 0x8000;
  304. gdata.address_mask = 0xF0;
  305. break;
  306. case EPROM_TYPE_64K:
  307. gdata.address_max = 0x10000;
  308. gdata.address_mask = 0xF8;
  309. break;
  310. case EPROM_TYPE_128K:
  311. gdata.address_max = 0x20000;
  312. gdata.address_mask = 0xFC;
  313. break;
  314. default:
  315. return ERROR_INVALID_PARAMETER;
  316. }
  317. return SUCCESS;
  318. } /* set_eprom_type */
  319. #if 0
  320. /* Powerfail / Wakeup */
  321. ISR(INT0_vect)
  322. {
  323. if (1) {
  324. /*
  325. * Power Fail:
  326. * - enable RESET_OUT
  327. * - disable nTARGET_EN
  328. * - enable rising edge INT0 (nPOWERFAIL)
  329. * - disable pullups
  330. * - put MCU in standby
  331. */
  332. do_reset(1);
  333. /* disable green LED */
  334. PORTD |= (1<<nLED_GN);
  335. } else {
  336. /*
  337. * Power Restore:
  338. * - enable pullups
  339. * - enable falling edge INT0 (nPOWERFAIL)
  340. * - enable nTARGET_EN again
  341. * - disable RESET_OUT
  342. */
  343. /* enable green LED */
  344. PORTD &= ~(1<<nLED_GN);
  345. do_reset(0);
  346. }
  347. }
  348. #endif
  349. int main(void) __attribute__ ((noreturn));
  350. int main(void)
  351. {
  352. DDRB = 0xFF;
  353. PORTB = (1<<nRAM_WR) | (1<<nEMU_EN);
  354. DDRD = ~((1<<RXD) | (1<<nPOWERFAIL));
  355. PORTD = (1<<RXD) | (1<<nPOWERFAIL) | (1<<nLED_GN) | (1<<nLED_RT) | (1<<nTARGET_EN);
  356. /* enable UART 115200,8n1 */
  357. UBRRH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF;
  358. UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF);
  359. UCSRC = (1<<UCSZ1) | (1<<UCSZ0);
  360. UCSRB = (1<<RXEN) | (1<<TXEN);
  361. #if 0
  362. /* powerfail: detect falling edge on INT0 */
  363. MCUCR = (1<<ISC01);
  364. GIMSK = (1<<INT0);
  365. sei();
  366. #endif
  367. /* enable LED and reset Counter */
  368. PORTD &= ~((1<<nLED_GN) | (1<<nTARGET_EN));
  369. /* init RAM */
  370. set_eprom_type(EPROM_TYPE_128K);
  371. set_progmode(PROGMODE_ENABLED);
  372. do_clear();
  373. set_progmode(PROGMODE_DISABLED);
  374. while (1)
  375. {
  376. uint8_t msgtype = ser_recv();
  377. uint8_t length = ser_recv();
  378. uint8_t error_code = ERROR_INVALID_PARAMETER;
  379. switch (msgtype)
  380. {
  381. case MSGTYPE_VERSION_REQ:
  382. if (length == 0x00)
  383. {
  384. ser_send(MSGTYPE_VERSION_RSP);
  385. ser_send(sizeof(version_str) -1);
  386. const uint8_t * p_data = version_str;
  387. while (*p_data)
  388. {
  389. ser_send(*p_data++);
  390. }
  391. error_code = SUCCESS;
  392. }
  393. break;
  394. case MSGTYPE_PAGESIZE_REQ:
  395. if (length == 0x00)
  396. {
  397. ser_send(MSGTYPE_PAGESIZE_RSP);
  398. ser_send(0x01);
  399. ser_send(PAGESIZE_MAX);
  400. error_code = SUCCESS;
  401. }
  402. break;
  403. case MSGTYPE_CONFIG_REQ:
  404. if (length == 0x03)
  405. {
  406. uint8_t eprom_type = ser_recv();
  407. uint8_t pagesize = ser_recv();
  408. uint8_t reset_polarity = ser_recv();
  409. if (gdata.progmode == PROGMODE_ENABLED)
  410. {
  411. error_code = ERROR_INVALID_MODE;
  412. }
  413. else
  414. {
  415. if ((reset_polarity <= RESET_POLARITY_HIGH) &&
  416. (pagesize <= PAGESIZE_MAX) &&
  417. (set_eprom_type(eprom_type) == SUCCESS)
  418. )
  419. {
  420. gdata.pagesize = pagesize;
  421. gdata.reset_polarity = reset_polarity;
  422. ser_send(MSGTYPE_CONFIG_RSP);
  423. ser_send(0x00);
  424. error_code = SUCCESS;
  425. }
  426. }
  427. }
  428. break;
  429. case MSGTYPE_PROGMODE_REQ:
  430. if (length == 0x01)
  431. {
  432. uint8_t progmode = ser_recv();
  433. if (progmode <= PROGMODE_ENABLED)
  434. {
  435. set_progmode(progmode);
  436. ser_send(MSGTYPE_PROGMODE_RSP);
  437. ser_send(0x00);
  438. error_code = SUCCESS;
  439. }
  440. }
  441. break;
  442. case MSGTYPE_SETADDRESS_REQ:
  443. if (length == 0x03)
  444. {
  445. uint32_t address;
  446. address = ser_recv();
  447. address = (address << 8) | ser_recv();
  448. address = (address << 8) | ser_recv();
  449. if (address < gdata.address_max)
  450. {
  451. if (gdata.progmode == PROGMODE_DISABLED)
  452. {
  453. error_code = ERROR_INVALID_MODE;
  454. }
  455. else
  456. {
  457. set_address(address);
  458. ser_send(MSGTYPE_SETADDRESS_RSP);
  459. ser_send(0x00);
  460. error_code = SUCCESS;
  461. }
  462. }
  463. }
  464. break;
  465. case MSGTYPE_WRITE_REQ:
  466. if ((length > 0) &&
  467. (length <= gdata.pagesize)
  468. )
  469. {
  470. if ((gdata.address >= gdata.address_max) ||
  471. ((gdata.address + length) > gdata.address_max)
  472. )
  473. {
  474. error_code = ERROR_INVALID_ADDRESS;
  475. }
  476. else if (gdata.progmode == PROGMODE_DISABLED)
  477. {
  478. error_code = ERROR_INVALID_MODE;
  479. }
  480. else
  481. {
  482. write_data(length);
  483. ser_send(MSGTYPE_WRITE_RSP);
  484. ser_send(0x00);
  485. error_code = SUCCESS;
  486. }
  487. }
  488. break;
  489. case MSGTYPE_READ_REQ:
  490. error_code = ERROR_NOT_SUPPORTED;
  491. break;
  492. default:
  493. error_code = ERROR_UNKNOWN_COMMAND;
  494. break;
  495. }
  496. if (error_code != SUCCESS)
  497. {
  498. /* read remaining request */
  499. while (length--)
  500. {
  501. (void)ser_recv();
  502. }
  503. ser_send(MSGTYPE_ERROR_RSP);
  504. ser_send(0x01);
  505. ser_send(error_code);
  506. }
  507. }
  508. } /* main */