|
|
@ -65,11 +65,62 @@ |
|
|
|
|
|
|
|
#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 { |
|
|
|
uint8_t address_mask; |
|
|
|
uint8_t reset_polarity; |
|
|
|
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 }; |
|
|
|
|
|
|
|
|
|
|
@ -100,10 +151,14 @@ static void shift_data(uint8_t data) |
|
|
|
{ |
|
|
|
uint8_t mask; |
|
|
|
|
|
|
|
for (mask = 0x01; mask != 0; mask <<= 1) { |
|
|
|
if (data & mask) { |
|
|
|
for (mask = 0x01; mask != 0; mask <<= 1) |
|
|
|
{ |
|
|
|
if (data & mask) |
|
|
|
{ |
|
|
|
PORTB |= (1<<SREG_DAT); |
|
|
|
} else { |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
PORTB &= ~(1<<SREG_DAT); |
|
|
|
} |
|
|
|
|
|
|
@ -126,32 +181,69 @@ static void store_pulse(void) |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* write pulse for SRAM and increment counter |
|
|
|
* write pulse for SRAM |
|
|
|
* ************************************************************************* */ |
|
|
|
static void write_inc_pulse(void) |
|
|
|
static void write_pulse(void) |
|
|
|
{ |
|
|
|
/* positive edge clocks in data */ |
|
|
|
PORTB &= ~(1<<nRAM_WR); |
|
|
|
PORTB |= (1<<nRAM_WR); |
|
|
|
} /* write_pulse */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* reset address counter |
|
|
|
* ************************************************************************* */ |
|
|
|
static void address_reset(void) |
|
|
|
{ |
|
|
|
PORTD &= ~(1<<nTARGET_EN); |
|
|
|
PORTD |= (1<<nTARGET_EN); |
|
|
|
} /* address_reset */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* increment address counter |
|
|
|
* ************************************************************************* */ |
|
|
|
static void address_inc_pulse(void) |
|
|
|
{ |
|
|
|
/* positive edge increments counter */ |
|
|
|
PORTB |= (1<<CNT_CLK); |
|
|
|
PORTB &= ~(1<<CNT_CLK); |
|
|
|
} /* write_inc_pulse */ |
|
|
|
} /* address_inc_pulse */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* controls A16 line |
|
|
|
* ************************************************************************* */ |
|
|
|
static void address_set_a16(uint8_t enable) |
|
|
|
{ |
|
|
|
if (enable) |
|
|
|
{ |
|
|
|
PORTD |= (1<<EMU_A16); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
PORTD &= ~(1<<EMU_A16); |
|
|
|
} |
|
|
|
} /* address_set_a16 */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* switch access to RAM between emulator and target |
|
|
|
* ************************************************************************* */ |
|
|
|
static void do_reset(uint8_t enable) |
|
|
|
static void set_progmode(uint8_t progmode) |
|
|
|
{ |
|
|
|
if (enable) { |
|
|
|
gdata.progmode = progmode; |
|
|
|
|
|
|
|
if (progmode) |
|
|
|
{ |
|
|
|
/* switch RAM access to EMU */ |
|
|
|
PORTD |= (1<<nTARGET_EN); |
|
|
|
PORTD &= ~(1<<nLED_RT); |
|
|
|
PORTB &= ~(1<<nEMU_EN); |
|
|
|
|
|
|
|
} else { |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
/* set eprom address line mask */ |
|
|
|
shift_data(gdata.address_mask); |
|
|
|
shift_data(0x00); |
|
|
@ -161,109 +253,136 @@ static void do_reset(uint8_t enable) |
|
|
|
PORTB |= (1<<nEMU_EN); |
|
|
|
PORTD &= ~(1<<nTARGET_EN); |
|
|
|
PORTD |= (1<<nLED_RT); |
|
|
|
|
|
|
|
/* address counter is reset */ |
|
|
|
gdata.address = 0x00; |
|
|
|
} |
|
|
|
|
|
|
|
/* set RESET_OUT */ |
|
|
|
if (enable ^ gdata.reset_polarity) { |
|
|
|
if (progmode ^ gdata.reset_polarity) |
|
|
|
{ |
|
|
|
PORTB &= ~(1<<RESET_OUT); |
|
|
|
} else { |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
PORTB |= (1<<RESET_OUT); |
|
|
|
} |
|
|
|
} /* do_reset */ |
|
|
|
} /* set_progmode */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* configures number of addresslines and loads data from UART into RAM |
|
|
|
* set_address |
|
|
|
* ************************************************************************* */ |
|
|
|
static void do_load(uint8_t type, uint32_t length) |
|
|
|
static void set_address(uint32_t address) |
|
|
|
{ |
|
|
|
uint32_t size; |
|
|
|
switch (type) { |
|
|
|
case 0x02: /* 2716 - 2kB */ |
|
|
|
size = 0x0800; |
|
|
|
gdata.address_mask = 0x00; |
|
|
|
break; |
|
|
|
|
|
|
|
case 0x04: /* 2732 - 4kB */ |
|
|
|
size = 0x1000; |
|
|
|
gdata.address_mask = 0x80; |
|
|
|
break; |
|
|
|
|
|
|
|
case 0x08: /* 2764 - 8kB */ |
|
|
|
size = 0x2000; |
|
|
|
gdata.address_mask = 0xC0; |
|
|
|
break; |
|
|
|
|
|
|
|
case 0x10: /* 27128 - 16kB */ |
|
|
|
size = 0x4000; |
|
|
|
gdata.address_mask = 0xE0; |
|
|
|
break; |
|
|
|
|
|
|
|
case 0x20: /* 27256 - 32kB */ |
|
|
|
size = 0x8000; |
|
|
|
gdata.address_mask = 0xF0; |
|
|
|
break; |
|
|
|
/* reset address counter */ |
|
|
|
if (address < gdata.address) |
|
|
|
{ |
|
|
|
address_reset(); |
|
|
|
gdata.address = 0; |
|
|
|
} |
|
|
|
|
|
|
|
case 0x40: /* 27512 - 64kB */ |
|
|
|
size = 0x10000; |
|
|
|
gdata.address_mask = 0xF8; |
|
|
|
break; |
|
|
|
// TODO: A16 is not controlled by counter |
|
|
|
|
|
|
|
default: |
|
|
|
case 0x80: /* 27010 - 128kB */ |
|
|
|
size = 0x20000; |
|
|
|
gdata.address_mask = 0xFC; |
|
|
|
break; |
|
|
|
while (gdata.address++ < address) |
|
|
|
{ |
|
|
|
address_inc_pulse(); |
|
|
|
} |
|
|
|
} /* set_address */ |
|
|
|
|
|
|
|
do_reset(1); |
|
|
|
|
|
|
|
uint32_t i; |
|
|
|
uint8_t data; |
|
|
|
for (i = 0; i < size; i++) { |
|
|
|
if (i > 0xFFFF) { |
|
|
|
PORTD |= (1<<EMU_A16); |
|
|
|
} else { |
|
|
|
PORTD &= ~(1<<EMU_A16); |
|
|
|
} |
|
|
|
/* ************************************************************************* |
|
|
|
* write_data |
|
|
|
* ************************************************************************* */ |
|
|
|
static void write_data(uint8_t length) |
|
|
|
{ |
|
|
|
while (length--) |
|
|
|
{ |
|
|
|
address_set_a16(gdata.address++ > 0xFFFF); |
|
|
|
|
|
|
|
data = (i < length) ? ser_recv() : 0xFF; |
|
|
|
shift_data(data); |
|
|
|
shift_data(ser_recv()); |
|
|
|
store_pulse(); |
|
|
|
write_inc_pulse(); |
|
|
|
write_pulse(); |
|
|
|
address_inc_pulse(); |
|
|
|
} |
|
|
|
|
|
|
|
do_reset(0); |
|
|
|
} /* do_load */ |
|
|
|
} /* write_data */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* clears whole RAM (writes 0xFF) |
|
|
|
* fill RAM with 0xFF |
|
|
|
* ************************************************************************* */ |
|
|
|
static void do_clear(void) |
|
|
|
{ |
|
|
|
do_reset(1); |
|
|
|
uint16_t i = 0xFFFF; |
|
|
|
|
|
|
|
shift_data(0xFF); |
|
|
|
|
|
|
|
uint16_t i = 0xFFFF; |
|
|
|
|
|
|
|
PORTD &= ~(1<<EMU_A16); |
|
|
|
do { |
|
|
|
store_pulse(); |
|
|
|
write_inc_pulse(); |
|
|
|
write_pulse(); |
|
|
|
address_inc_pulse(); |
|
|
|
} while (i--); |
|
|
|
|
|
|
|
PORTD |= (1<<EMU_A16); |
|
|
|
do { |
|
|
|
store_pulse(); |
|
|
|
write_inc_pulse(); |
|
|
|
write_pulse(); |
|
|
|
address_inc_pulse(); |
|
|
|
} while (i--); |
|
|
|
|
|
|
|
do_reset(0); |
|
|
|
} /* do_clear */ |
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* |
|
|
|
* configures number of addresslines |
|
|
|
* ************************************************************************* */ |
|
|
|
static uint8_t set_eprom_type(uint8_t type) |
|
|
|
{ |
|
|
|
switch (type) |
|
|
|
{ |
|
|
|
case EPROM_TYPE_2K: |
|
|
|
gdata.address_max = 0x0800; |
|
|
|
gdata.address_mask = 0x00; |
|
|
|
break; |
|
|
|
|
|
|
|
case EPROM_TYPE_4K: |
|
|
|
gdata.address_max = 0x1000; |
|
|
|
gdata.address_mask = 0x80; |
|
|
|
break; |
|
|
|
|
|
|
|
case EPROM_TYPE_8K: |
|
|
|
gdata.address_max = 0x2000; |
|
|
|
gdata.address_mask = 0xC0; |
|
|
|
break; |
|
|
|
|
|
|
|
case EPROM_TYPE_16K: |
|
|
|
gdata.address_max = 0x4000; |
|
|
|
gdata.address_mask = 0xE0; |
|
|
|
break; |
|
|
|
|
|
|
|
case EPROM_TYPE_32K: |
|
|
|
gdata.address_max = 0x8000; |
|
|
|
gdata.address_mask = 0xF0; |
|
|
|
break; |
|
|
|
|
|
|
|
case EPROM_TYPE_64K: |
|
|
|
gdata.address_max = 0x10000; |
|
|
|
gdata.address_mask = 0xF8; |
|
|
|
break; |
|
|
|
|
|
|
|
case EPROM_TYPE_128K: |
|
|
|
gdata.address_max = 0x20000; |
|
|
|
gdata.address_mask = 0xFC; |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
return ERROR_INVALID_PARAMETER; |
|
|
|
} |
|
|
|
|
|
|
|
return SUCCESS; |
|
|
|
} /* set_eprom_type */ |
|
|
|
|
|
|
|
|
|
|
|
#if 0 |
|
|
|
/* Powerfail / Wakeup */ |
|
|
|
ISR(INT0_vect) |
|
|
@ -325,44 +444,164 @@ int main(void) |
|
|
|
PORTD &= ~((1<<nLED_GN) | (1<<nTARGET_EN)); |
|
|
|
|
|
|
|
/* init RAM */ |
|
|
|
gdata.address_mask = 0x3F; |
|
|
|
set_eprom_type(EPROM_TYPE_128K); |
|
|
|
set_progmode(PROGMODE_ENABLED); |
|
|
|
do_clear(); |
|
|
|
set_progmode(PROGMODE_DISABLED); |
|
|
|
|
|
|
|
while (1) |
|
|
|
{ |
|
|
|
uint8_t msgtype = ser_recv(); |
|
|
|
uint8_t length = ser_recv(); |
|
|
|
uint8_t error_code = ERROR_INVALID_PARAMETER; |
|
|
|
|
|
|
|
switch (msgtype) |
|
|
|
{ |
|
|
|
case MSGTYPE_VERSION_REQ: |
|
|
|
if (length == 0x00) |
|
|
|
{ |
|
|
|
ser_send(MSGTYPE_VERSION_RSP); |
|
|
|
ser_send(sizeof(version_str) -1); |
|
|
|
|
|
|
|
while (1) { |
|
|
|
uint8_t cmd = ser_recv(); |
|
|
|
const uint8_t * p_data = version_str; |
|
|
|
while (*p_data) |
|
|
|
{ |
|
|
|
ser_send(*p_data++); |
|
|
|
} |
|
|
|
|
|
|
|
switch (cmd) { |
|
|
|
case 'p': /* low active reset */ |
|
|
|
gdata.reset_polarity = 0; |
|
|
|
ser_send('\n'); |
|
|
|
error_code = SUCCESS; |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case 'P': /* high active reset */ |
|
|
|
gdata.reset_polarity = 1; |
|
|
|
ser_send('\n'); |
|
|
|
case MSGTYPE_PAGESIZE_REQ: |
|
|
|
if (length == 0x00) |
|
|
|
{ |
|
|
|
ser_send(MSGTYPE_PAGESIZE_RSP); |
|
|
|
ser_send(0x01); |
|
|
|
ser_send(PAGESIZE_MAX); |
|
|
|
|
|
|
|
error_code = SUCCESS; |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case 'r': /* reset pulse */ |
|
|
|
do_reset(1); |
|
|
|
_delay_ms(10); |
|
|
|
do_reset(0); |
|
|
|
ser_send('\n'); |
|
|
|
case MSGTYPE_CONFIG_REQ: |
|
|
|
if (length == 0x03) |
|
|
|
{ |
|
|
|
uint8_t eprom_type = ser_recv(); |
|
|
|
uint8_t pagesize = ser_recv(); |
|
|
|
uint8_t reset_polarity = ser_recv(); |
|
|
|
|
|
|
|
if (gdata.progmode == PROGMODE_ENABLED) |
|
|
|
{ |
|
|
|
error_code = ERROR_INVALID_MODE; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if ((reset_polarity <= RESET_POLARITY_HIGH) && |
|
|
|
(pagesize <= PAGESIZE_MAX) && |
|
|
|
(set_eprom_type(eprom_type) == SUCCESS) |
|
|
|
) |
|
|
|
{ |
|
|
|
gdata.pagesize = pagesize; |
|
|
|
gdata.reset_polarity = reset_polarity; |
|
|
|
|
|
|
|
ser_send(MSGTYPE_CONFIG_RSP); |
|
|
|
ser_send(0x00); |
|
|
|
error_code = SUCCESS; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case 'l': /* load eprom content */ |
|
|
|
case MSGTYPE_PROGMODE_REQ: |
|
|
|
if (length == 0x01) |
|
|
|
{ |
|
|
|
uint8_t type = ser_recv(); |
|
|
|
uint32_t length = (uint32_t)ser_recv() << 16; |
|
|
|
length |= ser_recv() << 8; |
|
|
|
length |= ser_recv(); |
|
|
|
uint8_t progmode = ser_recv(); |
|
|
|
|
|
|
|
do_load(type, length); |
|
|
|
if (progmode <= PROGMODE_ENABLED) |
|
|
|
{ |
|
|
|
set_progmode(progmode); |
|
|
|
|
|
|
|
ser_send(MSGTYPE_PROGMODE_RSP); |
|
|
|
ser_send(0x00); |
|
|
|
error_code = SUCCESS; |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case MSGTYPE_SETADDRESS_REQ: |
|
|
|
if (length == 0x03) |
|
|
|
{ |
|
|
|
uint32_t address; |
|
|
|
|
|
|
|
address = ser_recv(); |
|
|
|
address = (address << 8) | ser_recv(); |
|
|
|
address = (address << 8) | ser_recv(); |
|
|
|
|
|
|
|
if (address < gdata.address_max) |
|
|
|
{ |
|
|
|
if (gdata.progmode == PROGMODE_DISABLED) |
|
|
|
{ |
|
|
|
error_code = ERROR_INVALID_MODE; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
set_address(address); |
|
|
|
|
|
|
|
ser_send(MSGTYPE_SETADDRESS_RSP); |
|
|
|
ser_send(0x00); |
|
|
|
error_code = SUCCESS; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case MSGTYPE_WRITE_REQ: |
|
|
|
if ((length > 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: |
|
|
|
ser_send('?'); |
|
|
|
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 */ |