/*************************************************************************** * Copyright (C) 04/2013 by Olaf Rempel * * razzor@kopf-tisch.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; version 2 of the License, * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #define F_CPU 11059200 #include /* * attiny2313 * lfuse: 0xff (ext. crystal, slow rising power, max startup time) * hfuse: 0xdb (2.7V BOD) * efuse: 0xff (self Prog enabled) * * PB0 -> NC * PB1 -> reset-out * PB2 -> /WR SRAM * PB3 -> SRCK (shift register clock) * PB4 -> SER (shift register input) * PB5 -> CCK (counter clock) * PB6 -> RCK (counter and shift register store clock) * PB7 -> /OE (output enable counter, shift register, reset-out, A16) * PD0 <- RXD * PD1 -> TXD * PD2 <- /PowerFail * PD3 -> A16 * PD4 -> /LED_GN * PD5 -> /LED_RT * PD6 -> /OE (output enable RAM and address buffer, counter clear) */ #define RESET_OUT PORTB1 #define nRAM_WR PORTB2 #define SREG_CLK PORTB3 #define SREG_DAT PORTB4 #define CNT_CLK PORTB5 #define REG_STORE PORTB6 #define nEMU_EN PORTB7 #define RXD PORTD0 #define TXD PORTD1 #define nPOWERFAIL PORTD2 #define EMU_A16 PORTD3 #define nLED_GN PORTD4 #define nLED_RT PORTD5 #define nTARGET_EN PORTD6 #define BAUDRATE 115200 #define UART_CALC_BAUDRATE(baudRate) (((uint32_t)F_CPU) / (((uint32_t)baudRate)*16) -1) /* ************************************************************************* */ #define MSGTYPE_VERSION_REQ 0x01 /* no payload */ #define MSGTYPE_PAGESIZE_REQ 0x02 /* no payload */ #define MSGTYPE_CONFIG_REQ 0x03 /* eprom_type(1), pagesize(1), reset_polarity(1) */ #define MSGTYPE_PROGMODE_REQ 0x04 /* progmode(1) */ #define MSGTYPE_SETADDRESS_REQ 0x05 /* address(3) msb first */ #define MSGTYPE_WRITE_REQ 0x06 /* data(0-pagesize) */ #define MSGTYPE_READ_REQ 0x07 /* length(1) */ #define MSGTYPE_ERROR_RSP 0x80 /* error_code(1) */ #define MSGTYPE_VERSION_RSP 0x81 /* version(?) */ #define MSGTYPE_PAGESIZE_RSP 0x82 /* pagesize(1) */ #define MSGTYPE_CONFIG_RSP 0x83 /* no payload */ #define MSGTYPE_PROGMODE_RSP 0x84 /* no payload */ #define MSGTYPE_SETADDRESS_RSP 0x85 /* no payload */ #define MSGTYPE_WRITE_RSP 0x86 /* no payload */ #define MSGTYPE_READ_RSP 0x87 /* data(0-pagesize) */ #define SUCCESS 0x00 #define ERROR_UNKNOWN_COMMAND 0x01 /* unknown message type */ #define ERROR_NOT_SUPPORTED 0x02 /* command not supported */ #define ERROR_INVALID_MODE 0x03 /* invalid progmode */ #define ERROR_INVALID_PARAMETER 0x04 /* invalid parameter in request */ #define ERROR_INVALID_ADDRESS 0x05 /* write outside of configured region */ #define RESET_POLARITY_LOW 0x00 /* low active reset */ #define RESET_POLARITY_HIGH 0x01 /* high active reset */ #define EPROM_TYPE_2K 0x02 /* 2716 */ #define EPROM_TYPE_4K 0x04 /* 2732 */ #define EPROM_TYPE_8K 0x08 /* 2764 */ #define EPROM_TYPE_16K 0x10 /* 27128 */ #define EPROM_TYPE_32K 0x20 /* 27256 */ #define EPROM_TYPE_64K 0x40 /* 27512 */ #define EPROM_TYPE_128K 0x80 /* 27010 */ #define PROGMODE_DISABLED 0x00 /* target running, no write access to RAM */ #define PROGMODE_ENABLED 0x01 /* target reset, write access to RAM */ #define PAGESIZE_MAX 128 /* ************************************************************************* */ struct _globdata { uint32_t address_max; uint32_t address; uint8_t progmode; uint8_t reset_polarity; uint8_t pagesize; uint8_t address_mask; }; static const uint8_t version_str[] = "epromsim v1.00"; static struct _globdata gdata = { 0 }; /* ************************************************************************* * send one byte to UART * ************************************************************************* */ static void ser_send(uint8_t data) { loop_until_bit_is_set(UCSRA, UDRIE); UDR = data; } /* ser_send */ /* ************************************************************************* * receive one byte from UART * ************************************************************************* */ static uint8_t ser_recv(void) { loop_until_bit_is_set(UCSRA, RXC); return UDR; } /* ser_recv */ /* ************************************************************************* * shift one byte out to register (LSB first) * ************************************************************************* */ static void shift_data(uint8_t data) { uint8_t mask; for (mask = 0x01; mask != 0; mask <<= 1) { if (data & mask) { PORTB |= (1< 0xFFFF); shift_data(ser_recv()); store_pulse(); write_pulse(); address_inc_pulse(); } } /* write_data */ /* ************************************************************************* * fill RAM with 0xFF * ************************************************************************* */ static void do_clear(void) { uint16_t i = 0xFFFF; shift_data(0xFF); PORTD &= ~(1<>8) & 0xFF; UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF); UCSRC = (1< 0) && (length <= gdata.pagesize) ) { if ((gdata.address >= gdata.address_max) || ((gdata.address + length) > gdata.address_max) ) { error_code = ERROR_INVALID_ADDRESS; } else if (gdata.progmode == PROGMODE_DISABLED) { error_code = ERROR_INVALID_MODE; } else { write_data(length); ser_send(MSGTYPE_WRITE_RSP); ser_send(0x00); error_code = SUCCESS; } } break; case MSGTYPE_READ_REQ: error_code = ERROR_NOT_SUPPORTED; break; default: error_code = ERROR_UNKNOWN_COMMAND; break; } if (error_code != SUCCESS) { /* read remaining request */ while (length--) { (void)ser_recv(); } ser_send(MSGTYPE_ERROR_RSP); ser_send(0x01); ser_send(error_code); } } } /* main */