mirror of
https://github.com/UzixLS/famicom-dumper.git
synced 2025-07-19 07:21:16 +03:00
972 lines
21 KiB
C
972 lines
21 KiB
C
/* Famicom Dumper/Programmer
|
|
*
|
|
* Copyright notice for this file:
|
|
* Copyright (C) 2016 Cluster
|
|
* http://clusterrr.com
|
|
* clusterrr@clusterrr.com
|
|
*
|
|
* 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; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
#include "defines.h"
|
|
#include <avr/io.h>
|
|
#include <avr/interrupt.h>
|
|
#include <avr/wdt.h>
|
|
#include <util/delay.h>
|
|
#include <inttypes.h>
|
|
#include "usart.h"
|
|
#include "comm.h"
|
|
#include "jtag.h"
|
|
|
|
#define LED_RED_ON PORTB |= (1<<7)
|
|
#define LED_RED_OFF PORTB &= ~(1<<7)
|
|
#define LED_GREEN_ON PORTB |= (1<<6)
|
|
#define LED_GREEN_OFF PORTB &= ~(1<<6)
|
|
#define ROMSEL_HI PORTF |= (1<<1)
|
|
#define ROMSEL_LOW PORTF &= ~(1<<1)
|
|
#define PHI2_HI PORTF |= (1<<0)
|
|
#define PHI2_LOW PORTF &= ~(1<<0)
|
|
#define MODE_READ { PORTD = 0xFF; DDRD = 0; }
|
|
#define MODE_WRITE DDRD = 0xFF
|
|
#define PRG_READ PORTF |= (1<<7)
|
|
#define PRG_WRITE PORTF &= ~(1<<7)
|
|
#define CHR_READ_HI PORTF |= (1<<5)
|
|
#define CHR_READ_LOW PORTF &= ~(1<<5)
|
|
#define CHR_WRITE_HI PORTF |= (1<<2)
|
|
#define CHR_WRITE_LOW PORTF &= ~(1<<2)
|
|
|
|
static void (*jump_to_bootloader)(void) = (void*)0xF800;
|
|
|
|
ISR(USART0_RX_vect)
|
|
{
|
|
unsigned char b;
|
|
while (UCSR0A & (1<<RXC0))
|
|
{
|
|
b = UDR0;
|
|
comm_proceed(b);
|
|
}
|
|
}
|
|
|
|
static void phi2_init()
|
|
{
|
|
int i = 0x80;
|
|
unsigned char h = PORTF |= (1<<0);
|
|
unsigned char l = PORTF &= ~(1<<0);
|
|
while(i != 0){
|
|
PORTA = l;
|
|
PORTA = h;
|
|
i--;
|
|
}
|
|
}
|
|
|
|
static void set_address(unsigned int address)
|
|
{
|
|
unsigned char l = address & 0xFF;
|
|
unsigned char h = address>>8;
|
|
|
|
PORTA = l;
|
|
PORTC = h;
|
|
|
|
// PPU /A13
|
|
if ((address >> 13) & 1)
|
|
PORTF &= ~(1<<4);
|
|
else
|
|
PORTF |= 1<<4;
|
|
}
|
|
|
|
static void set_romsel(unsigned int address)
|
|
{
|
|
if (address & 0x8000)
|
|
{
|
|
ROMSEL_LOW;
|
|
} else {
|
|
ROMSEL_HI;
|
|
}
|
|
}
|
|
|
|
static unsigned char read_prg_byte(unsigned int address)
|
|
{
|
|
MODE_READ;
|
|
PRG_READ;
|
|
set_address(address);
|
|
PHI2_HI;
|
|
set_romsel(address);
|
|
_delay_us(1);
|
|
return PIND;
|
|
}
|
|
|
|
static unsigned char read_chr_byte(unsigned int address)
|
|
{
|
|
MODE_READ;
|
|
PHI2_HI;
|
|
ROMSEL_HI;
|
|
set_address(address);
|
|
CHR_READ_LOW;
|
|
|
|
_delay_us(1);
|
|
|
|
uint8_t result = PIND;
|
|
|
|
CHR_READ_HI;
|
|
return result;
|
|
}
|
|
|
|
static unsigned char read_coolboy_byte(unsigned int address)
|
|
{
|
|
MODE_READ;
|
|
PRG_READ;
|
|
set_address(address);
|
|
PHI2_HI;
|
|
ROMSEL_LOW;
|
|
PORTB |= 1<<TDO_PIN;
|
|
PORTB &= ~(1<<TCK_PIN);
|
|
_delay_us(1);
|
|
return PIND;
|
|
}
|
|
|
|
static void read_prg_send(unsigned int address, unsigned int len)
|
|
{
|
|
LED_GREEN_ON;
|
|
comm_start(COMMAND_PRG_READ_RESULT, len);
|
|
while (len > 0)
|
|
{
|
|
comm_send_byte(read_prg_byte(address));
|
|
len--;
|
|
address++;
|
|
}
|
|
set_address(0);
|
|
PHI2_HI;
|
|
ROMSEL_HI;
|
|
LED_GREEN_OFF;
|
|
}
|
|
|
|
static void read_chr_send(unsigned int address, unsigned int len)
|
|
{
|
|
LED_GREEN_ON;
|
|
comm_start(COMMAND_CHR_READ_RESULT, len);
|
|
while (len > 0)
|
|
{
|
|
comm_send_byte(read_chr_byte(address));
|
|
len--;
|
|
address++;
|
|
}
|
|
set_address(0);
|
|
PHI2_HI;
|
|
ROMSEL_HI;
|
|
LED_GREEN_OFF;
|
|
}
|
|
|
|
static uint16_t crc16_update(uint16_t crc, uint8_t a)
|
|
{
|
|
int i;
|
|
crc ^= a;
|
|
for (i = 0; i < 8; ++i)
|
|
{
|
|
if (crc & 1)
|
|
crc = (crc >> 1) ^ 0xA001;
|
|
else
|
|
crc = (crc >> 1);
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
static void read_prg_crc_send(unsigned int address, unsigned int len)
|
|
{
|
|
LED_GREEN_ON;
|
|
uint16_t crc = 0;
|
|
read_prg_byte(address);
|
|
while (len > 0)
|
|
{
|
|
unsigned char l = address & 0xFF;
|
|
unsigned char h = address>>8;
|
|
PORTA = l;
|
|
PORTC = h;
|
|
_delay_us(1);
|
|
crc = crc16_update(crc, PIND);
|
|
len--;
|
|
address++;
|
|
}
|
|
set_address(0);
|
|
PHI2_HI;
|
|
ROMSEL_HI;
|
|
comm_start(COMMAND_PRG_READ_RESULT, 2);
|
|
comm_send_byte(crc & 0xFF);
|
|
comm_send_byte((crc >> 8) & 0xFF);
|
|
LED_GREEN_OFF;
|
|
}
|
|
|
|
static void read_chr_crc_send(unsigned int address, unsigned int len)
|
|
{
|
|
LED_GREEN_ON;
|
|
uint16_t crc = 0;
|
|
while (len > 0)
|
|
{
|
|
crc = crc16_update(crc, read_chr_byte(address));
|
|
len--;
|
|
address++;
|
|
}
|
|
set_address(0);
|
|
PHI2_HI;
|
|
ROMSEL_HI;
|
|
comm_start(COMMAND_CHR_READ_RESULT, 2);
|
|
comm_send_byte(crc & 0xFF);
|
|
comm_send_byte((crc >> 8) & 0xFF);
|
|
LED_GREEN_OFF;
|
|
}
|
|
|
|
static void read_coolboy_send(unsigned int address, unsigned int len)
|
|
{
|
|
LED_GREEN_ON;
|
|
PORTB |= 1<<TCK_PIN;
|
|
PORTB |= 1<<TDO_PIN;
|
|
DDRB |= 1<<TCK_PIN;
|
|
DDRB |= 1<<TDO_PIN;
|
|
comm_start(COMMAND_PRG_READ_RESULT, len);
|
|
while (len > 0)
|
|
{
|
|
comm_send_byte(read_coolboy_byte(address));
|
|
len--;
|
|
address++;
|
|
}
|
|
set_address(0);
|
|
ROMSEL_HI;
|
|
PORTB |= 1<<TCK_PIN;
|
|
PORTB |= 1<<TDO_PIN;
|
|
|
|
jtag_shutdown();
|
|
LED_GREEN_OFF;
|
|
}
|
|
|
|
static void write_prg_byte(unsigned int address, uint8_t data)
|
|
{
|
|
PHI2_LOW;
|
|
ROMSEL_HI;
|
|
MODE_WRITE;
|
|
PRG_WRITE;
|
|
PORTD = data;
|
|
set_address(address); // PHI2 low, ROMSEL always HIGH
|
|
// _delay_us(1);
|
|
|
|
PHI2_HI;
|
|
//_delay_us(10);
|
|
set_romsel(address); // ROMSEL is low if need, PHI2 high
|
|
|
|
_delay_us(1); // WRITING
|
|
//_delay_ms(1); // WRITING
|
|
|
|
// PHI2 low, ROMSEL high
|
|
PHI2_LOW;
|
|
_delay_us(1);
|
|
ROMSEL_HI;
|
|
|
|
// Back to read mode
|
|
// _delay_us(1);
|
|
PRG_READ;
|
|
MODE_READ;
|
|
set_address(0);
|
|
|
|
// Set phi2 to high state to keep cartridge unreseted
|
|
// _delay_us(1);
|
|
PHI2_HI;
|
|
|
|
// _delay_us(1);
|
|
}
|
|
|
|
static void write_chr_byte(unsigned int address, uint8_t data)
|
|
{
|
|
PHI2_LOW;
|
|
ROMSEL_HI;
|
|
MODE_WRITE;
|
|
PORTD = data;
|
|
set_address(address); // PHI2 low, ROMSEL always HIGH
|
|
//_delay_us(10);
|
|
|
|
CHR_WRITE_LOW;
|
|
|
|
_delay_us(1); // WRITING
|
|
//_delay_ms(1); // WRITING
|
|
|
|
CHR_WRITE_HI;
|
|
|
|
//_delay_us(1);
|
|
|
|
MODE_READ;
|
|
set_address(0);
|
|
PHI2_HI;
|
|
|
|
//_delay_us(1);
|
|
}
|
|
|
|
static void write_prg(unsigned int address, unsigned int len, uint8_t* data)
|
|
{
|
|
LED_RED_ON;
|
|
while (len > 0)
|
|
{
|
|
write_prg_byte(address, *data);
|
|
address++;
|
|
len--;
|
|
data++;
|
|
}
|
|
//_delay_ms(1);
|
|
LED_RED_OFF;
|
|
}
|
|
|
|
static void write_chr(unsigned int address, unsigned int len, uint8_t* data)
|
|
{
|
|
LED_RED_ON;
|
|
while (len > 0)
|
|
{
|
|
write_chr_byte(address, *data);
|
|
address++;
|
|
len--;
|
|
data++;
|
|
}
|
|
//_delay_ms(1);
|
|
LED_RED_OFF;
|
|
}
|
|
|
|
static void write_prg_flash_command(unsigned int address, uint8_t data)
|
|
{
|
|
write_prg_byte(address | 0x8000, data);
|
|
}
|
|
|
|
static void write_coolboy_flash_command(unsigned int address, uint8_t data)
|
|
{
|
|
PORTB |= 1<<TCK_PIN;
|
|
PORTB |= 1<<TDO_PIN;
|
|
ROMSEL_HI;
|
|
PRG_READ;
|
|
set_address(address);
|
|
MODE_WRITE;
|
|
PORTD = data;
|
|
PHI2_HI;
|
|
ROMSEL_LOW;
|
|
_delay_us(1);
|
|
|
|
PORTB &= ~(1<<TDO_PIN);
|
|
|
|
_delay_us(1);
|
|
|
|
PORTB |= 1<<TDO_PIN;
|
|
set_address(0);
|
|
ROMSEL_HI;
|
|
MODE_READ;
|
|
}
|
|
|
|
static void write_chr_flash_command(unsigned int address, uint8_t data)
|
|
{
|
|
write_chr_byte(address, data);
|
|
}
|
|
|
|
static int write_prg_flash_byte(unsigned int address, uint8_t data)
|
|
{
|
|
write_prg_flash_command(0x0000, 0xF0);
|
|
write_prg_flash_command(0x0555, 0xAA);
|
|
write_prg_flash_command(0x02AA, 0x55);
|
|
write_prg_flash_command(0x0555, 0xA0);
|
|
|
|
write_prg_flash_command(address, data);
|
|
_delay_us(50);
|
|
|
|
int timeout = 0;
|
|
uint8_t res, last_res = 0;
|
|
while (timeout < 200)
|
|
{
|
|
res = read_prg_byte(address | 0x8000);
|
|
ROMSEL_HI;
|
|
if (res == last_res && last_res == data) break;
|
|
last_res = res;
|
|
_delay_us(50);
|
|
timeout++;
|
|
}
|
|
//PHI2_LOW;
|
|
ROMSEL_HI;
|
|
set_address(0);
|
|
|
|
return timeout < 10;
|
|
}
|
|
|
|
|
|
static int write_chr_flash_byte(unsigned int address, uint8_t data)
|
|
{
|
|
write_chr_flash_command(0x0000, 0xF0);
|
|
write_chr_flash_command(0x0555, 0xAA);
|
|
write_chr_flash_command(0x02AA, 0x55);
|
|
write_chr_flash_command(0x0555, 0xA0);
|
|
write_chr_flash_command(address, data);
|
|
|
|
int timeout = 0;
|
|
while (read_chr_byte(address | 0x8000) != data && timeout < 10)
|
|
{
|
|
_delay_us(100);
|
|
timeout++;
|
|
}
|
|
set_address(0);
|
|
PHI2_LOW;
|
|
ROMSEL_HI;
|
|
|
|
return timeout < 10;
|
|
}
|
|
|
|
static int erase_prg_flash()
|
|
{
|
|
LED_RED_ON;
|
|
write_prg_flash_command(0x0000, 0xF0);
|
|
write_prg_flash_command(0x0AAA, 0xAA);
|
|
write_prg_flash_command(0x0555, 0x55);
|
|
write_prg_flash_command(0x0AAA, 0x80);
|
|
write_prg_flash_command(0x0AAA, 0xAA);
|
|
write_prg_flash_command(0x0555, 0x55);
|
|
write_prg_flash_command(0x0AAA, 0x10);
|
|
|
|
int timeout = 0;
|
|
while ((read_prg_byte(0x8000) != 0xFF) && (timeout < 300000))
|
|
{
|
|
_delay_ms(1);
|
|
timeout++;
|
|
}
|
|
set_address(0);
|
|
PHI2_HI;
|
|
ROMSEL_HI;
|
|
|
|
LED_RED_OFF;
|
|
return timeout < 300000;
|
|
}
|
|
|
|
static int erase_coolboy_sector()
|
|
{
|
|
LED_RED_ON;
|
|
PORTB |= 1<<TCK_PIN;
|
|
PORTB |= 1<<TDO_PIN;
|
|
DDRB |= 1<<TCK_PIN;
|
|
DDRB |= 1<<TDO_PIN;
|
|
ROMSEL_HI;
|
|
|
|
write_coolboy_flash_command(0x0000, 0xF0);
|
|
write_coolboy_flash_command(0x0AAA, 0xAA);
|
|
write_coolboy_flash_command(0x0555, 0x55);
|
|
write_coolboy_flash_command(0x0AAA, 0x80);
|
|
write_coolboy_flash_command(0x0AAA, 0xAA);
|
|
write_coolboy_flash_command(0x0555, 0x55);
|
|
write_coolboy_flash_command(0x0000, 0x30);
|
|
|
|
int timeout = 0;
|
|
uint8_t debug;
|
|
while (((debug = read_coolboy_byte(0x8000)) != 0xFF) && (timeout < 3000))
|
|
{
|
|
//comm_start(0xFF, 1);
|
|
//comm_send_byte(debug);
|
|
_delay_ms(1);
|
|
timeout++;
|
|
}
|
|
|
|
set_address(0);
|
|
ROMSEL_HI;
|
|
|
|
jtag_shutdown();
|
|
LED_RED_OFF;
|
|
return timeout < 3000;
|
|
}
|
|
|
|
static int erase_coolgirl_sector()
|
|
{
|
|
LED_RED_ON;
|
|
write_prg_flash_command(0x0000, 0xF0);
|
|
write_prg_flash_command(0x0AAA, 0xAA);
|
|
write_prg_flash_command(0x0555, 0x55);
|
|
write_prg_flash_command(0x0AAA, 0x80);
|
|
write_prg_flash_command(0x0AAA, 0xAA);
|
|
write_prg_flash_command(0x0555, 0x55);
|
|
write_prg_flash_command(0x0000, 0x30);
|
|
|
|
int timeout = 0;
|
|
uint8_t debug;
|
|
while (((debug = read_prg_byte(0x8000)) != 0xFF) && (timeout < 3000))
|
|
{
|
|
//comm_start(0xFF, 1);
|
|
//comm_send_byte(debug);
|
|
_delay_ms(1);
|
|
timeout++;
|
|
}
|
|
set_address(0);
|
|
PHI2_HI;
|
|
ROMSEL_HI;
|
|
|
|
LED_RED_OFF;
|
|
return timeout < 3000;
|
|
}
|
|
|
|
static int erase_chr_flash()
|
|
{
|
|
LED_RED_ON;
|
|
write_chr_flash_command(0x0000, 0xF0);
|
|
write_chr_flash_command(0x0555, 0xAA);
|
|
write_chr_flash_command(0x02AA, 0x55);
|
|
write_chr_flash_command(0x0555, 0x80);
|
|
write_chr_flash_command(0x0555, 0xAA);
|
|
write_chr_flash_command(0x02AA, 0x55);
|
|
write_chr_flash_command(0x0555, 0x10);
|
|
|
|
int timeout = 0;
|
|
while ((read_chr_byte(0) != 0xFF) && (timeout < 10000))
|
|
{
|
|
_delay_ms(1);
|
|
timeout++;
|
|
}
|
|
set_address(0);
|
|
PHI2_HI;
|
|
ROMSEL_HI;
|
|
|
|
LED_RED_OFF;
|
|
return timeout < 10000;
|
|
}
|
|
|
|
static int write_prg_flash(unsigned int address, unsigned int len, uint8_t* data)
|
|
{
|
|
LED_RED_ON;
|
|
int ok = 1;
|
|
while (len > 0)
|
|
{
|
|
if (!write_prg_flash_byte(address, *data))
|
|
{
|
|
ok = 0;
|
|
break;
|
|
}
|
|
address++;
|
|
len--;
|
|
data++;
|
|
}
|
|
LED_RED_OFF;
|
|
return ok;
|
|
}
|
|
|
|
static int write_coolboy(unsigned int address, unsigned int len, uint8_t* data)
|
|
{
|
|
LED_RED_ON;
|
|
PORTB |= 1<<TCK_PIN;
|
|
PORTB |= 1<<TDO_PIN;
|
|
DDRB |= 1<<TCK_PIN;
|
|
DDRB |= 1<<TDO_PIN;
|
|
ROMSEL_HI;
|
|
uint8_t ok = 1;
|
|
while (len > 0)
|
|
{
|
|
|
|
//uint8_t count = len > 16 ? 16 : len;
|
|
uint8_t count = 0;
|
|
uint8_t* d = data;
|
|
unsigned int a = address;
|
|
unsigned int address_base = a & 0xFFE0;
|
|
while (len > 0 && ((a & 0xFFE0) == address_base))
|
|
{
|
|
if (*d != 0xFF) count++;
|
|
a++;
|
|
len--;
|
|
d++;
|
|
}
|
|
|
|
if (count)
|
|
{
|
|
//write_prg_flash_command(0x0000, 0xF0);
|
|
write_coolboy_flash_command(0x0AAA, 0xAA);
|
|
write_coolboy_flash_command(0x0555, 0x55);
|
|
write_coolboy_flash_command(0x0000, 0x25);
|
|
write_coolboy_flash_command(0x0000, count-1);
|
|
|
|
while (count > 0)
|
|
{
|
|
if (*data != 0xFF)
|
|
{
|
|
write_coolboy_flash_command(address, *data);
|
|
count--;
|
|
}
|
|
address++;
|
|
data++;
|
|
}
|
|
|
|
write_coolboy_flash_command(0x0000, 0x29);
|
|
_delay_us(10);
|
|
|
|
long int timeout = 0;
|
|
uint8_t res, last_res = 0;
|
|
while (timeout < 100000)
|
|
{
|
|
res = read_coolboy_byte((address-1) | 0x8000);
|
|
ROMSEL_HI;
|
|
if (res == last_res && last_res == *(data-1)) break;
|
|
last_res = res;
|
|
_delay_us(10);
|
|
timeout++;
|
|
}
|
|
if (timeout >= 100000)
|
|
{
|
|
ok = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
address = a;
|
|
data = d;
|
|
}
|
|
ROMSEL_HI;
|
|
jtag_shutdown();
|
|
LED_RED_OFF;
|
|
return ok;
|
|
}
|
|
|
|
static int write_coolgirl(unsigned int address, unsigned int len, uint8_t* data)
|
|
{
|
|
LED_RED_ON;
|
|
ROMSEL_HI;
|
|
uint8_t ok = 1;
|
|
while (len > 0)
|
|
{
|
|
|
|
//uint8_t count = len > 16 ? 16 : len;
|
|
uint8_t count = 0;
|
|
uint8_t* d = data;
|
|
unsigned int a = address;
|
|
unsigned int address_base = a & 0xFFE0;
|
|
while (len > 0 && ((a & 0xFFE0) == address_base))
|
|
{
|
|
if (*d != 0xFF) count++;
|
|
a++;
|
|
len--;
|
|
d++;
|
|
}
|
|
|
|
if (count)
|
|
{
|
|
//write_prg_flash_command(0x0000, 0xF0);
|
|
write_prg_flash_command(0x0AAA, 0xAA);
|
|
write_prg_flash_command(0x0555, 0x55);
|
|
write_prg_flash_command(0x0000, 0x25);
|
|
write_prg_flash_command(0x0000, count-1);
|
|
|
|
while (count > 0)
|
|
{
|
|
if (*data != 0xFF)
|
|
{
|
|
write_prg_flash_command(address, *data);
|
|
count--;
|
|
}
|
|
address++;
|
|
data++;
|
|
}
|
|
|
|
write_prg_flash_command(0x0000, 0x29);
|
|
_delay_us(10);
|
|
|
|
long int timeout = 0;
|
|
uint8_t res, last_res = 0;
|
|
while (timeout < 100000)
|
|
{
|
|
res = read_prg_byte((address-1) | 0x8000);
|
|
ROMSEL_HI;
|
|
if (res == last_res && last_res == *(data-1)) break;
|
|
last_res = res;
|
|
_delay_us(10);
|
|
timeout++;
|
|
}
|
|
if (timeout >= 100000)
|
|
{
|
|
ok = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
address = a;
|
|
data = d;
|
|
}
|
|
ROMSEL_HI;
|
|
LED_RED_OFF;
|
|
return ok;
|
|
}
|
|
|
|
static int write_chr_flash(unsigned int address, unsigned int len, uint8_t* data)
|
|
{
|
|
LED_RED_ON;
|
|
if (address >= 0x8000) address -= 0x8000;
|
|
int ok = 1;
|
|
while (len > 0)
|
|
{
|
|
if (!write_chr_flash_byte(address, *data))
|
|
{
|
|
ok = 0;
|
|
break;
|
|
}
|
|
address++;
|
|
len--;
|
|
data++;
|
|
}
|
|
LED_RED_OFF;
|
|
return ok;
|
|
}
|
|
|
|
void get_mirroring()
|
|
{
|
|
comm_start(COMMAND_MIRRORING_RESULT, 4);
|
|
LED_GREEN_ON;
|
|
set_address(0);
|
|
_delay_us(1);
|
|
comm_send_byte((PINE >> 2) & 1);
|
|
set_address(1<<10);
|
|
_delay_us(1);
|
|
comm_send_byte((PINE >> 2) & 1);
|
|
set_address(1<<11);
|
|
_delay_us(1);
|
|
comm_send_byte((PINE >> 2) & 1);
|
|
set_address((1<<10) | (1<<11));
|
|
_delay_us(1);
|
|
comm_send_byte((PINE >> 2) & 1);
|
|
set_address(0);
|
|
}
|
|
|
|
static void init_ports()
|
|
{
|
|
DDRB |= (1 << 6) | (1 << 7); // LEDS
|
|
DDRF = 0b10110111; // CPU R/W, IRQ, PPU /RD, PPU /A13, CIRAM /CE, PPU /WR, /ROMSEL, PHI2
|
|
PORTF = 0b11111111; // CPU R/W, IRQ, PPU /RD, PPU /A13, CIRAM /CE, PPU /WR, /ROMSEL, PHI2
|
|
DDRE &= ~(1<<2); // CIRAM A10
|
|
PORTE |= 1<<2; // CIRAM A10
|
|
MODE_READ;
|
|
set_address(0);
|
|
DDRA = 0xFF; // Address low
|
|
DDRC = 0xFF; // Address high
|
|
}
|
|
|
|
static void reset_phi2()
|
|
{
|
|
LED_RED_ON;
|
|
LED_GREEN_ON;
|
|
PHI2_LOW;
|
|
ROMSEL_HI;
|
|
_delay_ms(100);
|
|
PHI2_HI;
|
|
LED_RED_OFF;
|
|
LED_GREEN_OFF;
|
|
}
|
|
|
|
int main (void)
|
|
{
|
|
sei();
|
|
USART_init();
|
|
init_ports();
|
|
jtag_shutdown();
|
|
|
|
LED_RED_OFF;
|
|
LED_GREEN_OFF;
|
|
|
|
comm_init();
|
|
comm_start(COMMAND_PRG_STARTED, 0);
|
|
|
|
uint16_t address;
|
|
uint16_t length;
|
|
|
|
unsigned long int t = 0;
|
|
char led_down = 0;
|
|
int led_bright = 0;
|
|
|
|
while (1)
|
|
{
|
|
TCCR1A |= (1<<COM1C1) | (1<<COM1B1) | (1<<WGM10);
|
|
TCCR1B |= (1<<CS10);
|
|
if (t++ >= 10000)
|
|
{
|
|
if (!led_down)
|
|
{
|
|
led_bright++;
|
|
if (led_bright >= 110) led_down = 1;
|
|
} else {
|
|
led_bright--;
|
|
if (!led_bright) led_down = 0;
|
|
}
|
|
if (led_bright >= 100) OCR1B = led_bright - 100;
|
|
if (led_down)
|
|
{
|
|
int led_bright2 = 110-led_bright;
|
|
if (led_bright2 <= 20)
|
|
{
|
|
if (led_bright2 > 10) led_bright2 = 20 - led_bright2;
|
|
OCR1C = led_bright2*2;
|
|
}
|
|
}
|
|
t = 0;
|
|
}
|
|
|
|
if (comm_recv_done)
|
|
{
|
|
comm_recv_done = 0;
|
|
t = led_down = led_bright = 0;
|
|
TCCR1A = OCR1B = OCR1C = 0;
|
|
|
|
switch (comm_recv_command)
|
|
{
|
|
case COMMAND_PRG_INIT:
|
|
comm_start(COMMAND_PRG_STARTED, 0);
|
|
break;
|
|
|
|
case COMMAND_PRG_READ_REQUEST:
|
|
address = recv_buffer[0] | ((uint16_t)recv_buffer[1]<<8);
|
|
length = recv_buffer[2] | ((uint16_t)recv_buffer[3]<<8);
|
|
read_prg_send(address, length);
|
|
break;
|
|
|
|
case COMMAND_PRG_CRC_READ_REQUEST:
|
|
address = recv_buffer[0] | ((uint16_t)recv_buffer[1]<<8);
|
|
length = recv_buffer[2] | ((uint16_t)recv_buffer[3]<<8);
|
|
read_prg_crc_send(address, length);
|
|
break;
|
|
|
|
case COMMAND_PRG_WRITE_REQUEST:
|
|
address = recv_buffer[0] | ((uint16_t)recv_buffer[1]<<8);
|
|
length = recv_buffer[2] | ((uint16_t)recv_buffer[3]<<8);
|
|
write_prg(address, length, (uint8_t*)&recv_buffer[4]);
|
|
comm_start(COMMAND_PRG_WRITE_DONE, 0);
|
|
break;
|
|
|
|
case COMMAND_COOLBOY_READ_REQUEST:
|
|
address = recv_buffer[0] | ((uint16_t)recv_buffer[1]<<8);
|
|
length = recv_buffer[2] | ((uint16_t)recv_buffer[3]<<8);
|
|
read_coolboy_send(address, length);
|
|
break;
|
|
|
|
case COMMAND_PHI2_INIT:
|
|
phi2_init();
|
|
comm_start(COMMAND_PHI2_INIT_DONE, 0);
|
|
break;
|
|
|
|
case COMMAND_RESET:
|
|
reset_phi2();
|
|
comm_start(COMMAND_RESET_ACK, 0);
|
|
break;
|
|
|
|
case COMMAND_PRG_FLASH_ERASE_REQUEST:
|
|
if (erase_prg_flash())
|
|
comm_start(COMMAND_PRG_WRITE_DONE, 0);
|
|
break;
|
|
|
|
case COMMAND_PRG_FLASH_WRITE_REQUEST:
|
|
address = recv_buffer[0] | ((uint16_t)recv_buffer[1]<<8);
|
|
length = recv_buffer[2] | ((uint16_t)recv_buffer[3]<<8);
|
|
if (write_prg_flash(address, length, (uint8_t*)&recv_buffer[4]))
|
|
comm_start(COMMAND_PRG_WRITE_DONE, 0);
|
|
break;
|
|
|
|
case COMMAND_COOLBOY_ERASE_REQUEST:
|
|
if (erase_coolboy_sector())
|
|
comm_start(COMMAND_PRG_WRITE_DONE, 0);
|
|
break;
|
|
|
|
case COMMAND_COOLBOY_WRITE_REQUEST:
|
|
address = recv_buffer[0] | ((uint16_t)recv_buffer[1]<<8);
|
|
length = recv_buffer[2] | ((uint16_t)recv_buffer[3]<<8);
|
|
if (write_coolboy(address, length, (uint8_t*)&recv_buffer[4]))
|
|
comm_start(COMMAND_PRG_WRITE_DONE, 0);
|
|
break;
|
|
|
|
case COMMAND_COOLGIRL_ERASE_SECTOR_REQUEST:
|
|
if (erase_coolgirl_sector())
|
|
comm_start(COMMAND_PRG_WRITE_DONE, 0);
|
|
break;
|
|
|
|
case COMMAND_COOLGIRL_WRITE_REQUEST:
|
|
address = recv_buffer[0] | ((uint16_t)recv_buffer[1]<<8);
|
|
length = recv_buffer[2] | ((uint16_t)recv_buffer[3]<<8);
|
|
if (write_coolgirl(address, length, (uint8_t*)&recv_buffer[4]))
|
|
comm_start(COMMAND_PRG_WRITE_DONE, 0);
|
|
break;
|
|
|
|
case COMMAND_CHR_INIT:
|
|
comm_start(COMMAND_CHR_STARTED, 0);
|
|
break;
|
|
|
|
case COMMAND_CHR_READ_REQUEST:
|
|
address = recv_buffer[0] | ((uint16_t)recv_buffer[1]<<8);
|
|
length = recv_buffer[2] | ((uint16_t)recv_buffer[3]<<8);
|
|
read_chr_send(address, length);
|
|
break;
|
|
|
|
case COMMAND_CHR_CRC_READ_REQUEST:
|
|
address = recv_buffer[0] | ((uint16_t)recv_buffer[1]<<8);
|
|
length = recv_buffer[2] | ((uint16_t)recv_buffer[3]<<8);
|
|
read_chr_crc_send(address, length);
|
|
break;
|
|
|
|
case COMMAND_CHR_WRITE_REQUEST:
|
|
address = recv_buffer[0] | ((uint16_t)recv_buffer[1]<<8);
|
|
length = recv_buffer[2] | ((uint16_t)recv_buffer[3]<<8);
|
|
write_chr(address, length, (uint8_t*)&recv_buffer[4]);
|
|
comm_start(COMMAND_CHR_WRITE_DONE, 0);
|
|
break;
|
|
|
|
case COMMAND_MIRRORING_REQUEST:
|
|
get_mirroring();
|
|
break;
|
|
|
|
/*
|
|
case COMMAND_EPROM_PREPARE:
|
|
write_eprom_prepare();
|
|
break;
|
|
|
|
case COMMAND_CHR_EPROM_WRITE_REQUEST:
|
|
address = recv_buffer[0] | ((uint16_t)recv_buffer[1]<<8);
|
|
length = recv_buffer[2] | ((uint16_t)recv_buffer[3]<<8);
|
|
write_eprom(address, length, (uint8_t*)&recv_buffer[4]);
|
|
comm_start(COMMAND_CHR_WRITE_DONE, 0);
|
|
break;
|
|
*/
|
|
|
|
case COMMAND_CHR_FLASH_ERASE_REQUEST:
|
|
if (erase_chr_flash())
|
|
comm_start(COMMAND_CHR_WRITE_DONE, 0);
|
|
break;
|
|
|
|
case COMMAND_CHR_FLASH_WRITE_REQUEST:
|
|
address = recv_buffer[0] | ((uint16_t)recv_buffer[1]<<8);
|
|
length = recv_buffer[2] | ((uint16_t)recv_buffer[3]<<8);
|
|
if (write_chr_flash(address, length, (uint8_t*)&recv_buffer[4]))
|
|
comm_start(COMMAND_CHR_WRITE_DONE, 0);
|
|
break;
|
|
|
|
case COMMAND_JTAG_SETUP:
|
|
jtag_setup();
|
|
comm_start(COMMAND_JTAG_RESULT, 1);
|
|
comm_send_byte(1);
|
|
break;
|
|
|
|
case COMMAND_JTAG_SHUTDOWN:
|
|
jtag_shutdown();
|
|
comm_start(COMMAND_JTAG_RESULT, 1);
|
|
comm_send_byte(1);
|
|
break;
|
|
|
|
case COMMAND_JTAG_EXECUTE:
|
|
address = recv_buffer[0] | ((uint16_t)recv_buffer[1]<<8);
|
|
comm_start(COMMAND_JTAG_RESULT, 1);
|
|
LED_RED_ON;
|
|
comm_send_byte(jtag_execute(address, (uint8_t*) &recv_buffer[2]));
|
|
LED_RED_OFF;
|
|
break;
|
|
case COMMAND_BOOTLOADER:
|
|
cli();
|
|
MCUCSR = 0;
|
|
jump_to_bootloader();
|
|
}
|
|
}
|
|
}
|
|
}
|