/* * ===================================================================================== * * ________ .__ __ ________ ____ ________ * \_____ \ __ __|__| ____ | | __\______ \ _______ _/_ |/ _____/ * / / \ \| | \ |/ ___\| |/ / | | \_/ __ \ \/ /| / __ \ * / \_/. \ | / \ \___| < | ` \ ___/\ / | \ |__\ \ * \_____\ \_/____/|__|\___ >__|_ \/_______ /\___ >\_/ |___|\_____ / * \__> \/ \/ \/ \/ \/ * * www.optixx.org * * * Version: 1.0 * Created: 07/21/2009 03:32:16 PM * Author: david@optixx.org * * ===================================================================================== */ #include #include #include #include #include #include #include #include #include "pwm.h" #include "debug.h" #include "info.h" #include "sram.h" #include "util.h" #include "uart.h" #include "dump.h" #include "irq.h" #include "config.h" #include "crc.h" #include "command.h" #include "shared_memory.h" #include "system.h" extern system_t my_system; const char STR_ROM[] PROGMEM = "Rom"; const char STR_RAM[] PROGMEM = "Sram"; const char STR_BAT[] PROGMEM = "Battery"; const char STR_SUPERFX[] PROGMEM = "SuperFX"; const char STR_SA[] PROGMEM = "SA-1"; uint8_t command_buf[RECEIVE_BUF_LEN]; uint8_t recv_buf[RECEIVE_BUF_LEN]; volatile uint8_t recv_counter = 0; volatile uint8_t cr = 0; uint8_t *token_ptr; #if DO_SHELL uint8_t *get_token(void) { uint8_t *p = token_ptr; while (*p == ' ') p++; if (*p == '\0') return NULL; token_ptr = p; do { token_ptr++; if (*token_ptr == ' ' || *token_ptr == '\n' || *token_ptr == '\r') { *token_ptr++ = '\0'; break; } } while (*token_ptr != ' ' && *token_ptr != '\n' && *token_ptr != '\r'); return p; } uint8_t get_dec(uint32_t * decval) { const uint8_t *t; t = get_token(); if (t != NULL) { int x = util_sscandec(t); if (x < 0) return 0; *decval = x; return 1; } return 0; } uint8_t parse_hex(const uint8_t * s, uint32_t * hexval) { uint32_t x = util_sscanhex(s); *hexval = (uint32_t) x; return 1; } uint8_t get_hex(uint32_t * hexval) { const uint8_t *t; t = get_token(); if (t != NULL) return parse_hex(t, hexval); return 0; } uint8_t get_hex_arg2(uint32_t * hexval1, uint32_t * hexval2) { return get_hex(hexval1) && get_hex(hexval2); } uint8_t get_hex_arg3(uint32_t * hexval1, uint32_t * hexval2, uint32_t * hexval3) { return get_hex(hexval1) && get_hex(hexval2) && get_hex(hexval3); } #if 0 static uint8_t get_int32(uint32_t * val) { if (!get_hex(val)) { info_P(PSTR("Invalid argument!\n")); return 0; } else { return 1; } } static uint8_t get_int8(uint8_t * val) { uint32_t ret; if (!get_hex(&ret) || ret > 0xff) { info_P(PSTR("Invalid argument!\n")); return 0; } else { *val = (uint8_t) ret; return 1; } } #endif static int get_bool(void) { const uint8_t *t; t = get_token(); if (t != NULL) { int result = util_sscanbool(t); if (result >= 0) return result; } info_P(PSTR("Invalid argument (should be 0 or 1)!\n")); return -1; } void prompt(void) { uart_putc('\r'); uart_putc('\n'); uart_putc('>'); } ISR(USART0_RX_vect) { UCSR0B &= (255 - (1 << RXCIE0)); // Interrupts disable for RxD sei(); if (recv_counter == (sizeof(recv_buf) - 1)) { cr = 1; recv_buf[recv_counter] = '\0'; recv_counter = 0; prompt(); } recv_buf[recv_counter] = UDR0; uart_putc(recv_buf[recv_counter]); if (recv_buf[recv_counter] == 0x0d) { /* * recv_buf[recv_counter] = 0; */ cr = 1; recv_buf[++recv_counter] = '\0'; recv_counter = 0; prompt(); } else { // we accept backspace or delete if ((recv_buf[recv_counter] == 0x08 || recv_buf[recv_counter] == 0x7f) && recv_counter > 0) { recv_counter--; } else { recv_counter++; } } UCSR0B |= (1 << RXCIE0); } enum cmds { CMD_DUMP, CMD_DUMPVEC, CMD_DUMPHEADER, #if DO_CRC_CHECK CMD_CRC, #endif CMD_EXIT, CMD_RESET, CMD_RESETSNIFF, CMD_IRQ, CMD_AVR, CMD_SNES, CMD_LOROM, CMD_HIROM, CMD_WR, CMD_SHMWR, CMD_SHMSAVE, CMD_SHMRESTORE, CMD_LOADER, CMD_RECONNECT, CMD_STATUS, CMD_SYS, CMD_HELP }; const uint8_t cmdlist[][CMD_HELP] PROGMEM = { {"DUMP"}, {"DUMPVEC"}, {"DUMPHEADER"}, #if DO_CRC_CHECK {"CRC"}, #endif {"EXIT"}, {"RESET"}, {"RESETSNIFF"}, {"IRQ"}, {"AVR"}, {"SNES"}, {"LOROM"}, {"HIROM"}, {"WR"}, {"SHMWR"}, {"SHMSAVE"}, {"SHMRESTORE"}, {"LOADER"}, {"RECONNECT"}, {"STATUS"}, {"SYS"}, {"HELP"}, }; void shell_help(void) { uint8_t i; info_P(PSTR("\n")); for (i = CMD_DUMP; i < CMD_HELP; i++) { info_P((PGM_P) cmdlist[i]); info_P(PSTR("\n")); } } void shell_run(void) { uint8_t *t; uint32_t arg1; uint32_t arg2; uint16_t crc; uint16_t offset; uint8_t c; if (!cr) return; cr = 0; strcpy((char *) command_buf, (char *) recv_buf); token_ptr = command_buf; t = get_token(); if (t == NULL) shell_help(); util_strupper(t); if (strcmp_P((const char *) t, (PGM_P) cmdlist[CMD_DUMP]) == 0) { if (get_hex_arg2(&arg1, &arg2)) dump_memory(arg1, arg2); else info_P(PSTR("DUMP \n")); #if DO_CRC_CHECK } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_CRC]) == 0) { if (get_hex_arg2(&arg1, &arg2)) { crc = crc_check_bulk_memory(arg1, arg2, 0x8000); info_P(PSTR("0x%06lx - 0x%06lx crc=0x%04x\n"), arg1, arg2, crc); } else info_P(PSTR("CRC \n")); #endif } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_EXIT]) == 0) { leave_application(); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_RESET]) == 0) { system_send_snes_reset(); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_IRQ]) == 0) { info_P(PSTR("Send IRQ\n")); snes_irq_on(); snes_irq_lo(); _delay_us(20); snes_irq_hi(); snes_irq_off(); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_AVR]) == 0) { system_set_bus_avr(); snes_irq_lo(); system_snes_irq_off(); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_SNES]) == 0) { snes_irq_lo(); system_snes_irq_off(); system_set_wr_disable(); system_set_bus_snes(); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_LOROM]) == 0) { system_set_rom_lorom(); system_set_wr_disable(); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_HIROM]) == 0) { system_set_rom_hirom(); system_set_wr_disable(); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_WR]) == 0) { arg1 = get_bool(); if (arg1 == 1) { info_P(PSTR("Set WR enable")); snes_wr_enable(); } else if (arg1 == 0) { info_P(PSTR("Set WR disable")); snes_wr_disable(); } } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_RESETSNIFF]) == 0) { arg1 = get_bool(); if (arg1 == 1) { info_P(PSTR("Start Reset sniffer")); irq_init(); } else if (arg1 == 0) { info_P(PSTR("Stop Reset sniffer")); irq_stop(); } } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_DUMPVEC]) == 0) { uint16_t offset; if (my_system.rom_mode == LOROM) offset = 0x8000; else offset = 0x0000; info_P(PSTR("ABORT 0x%04x 0x%04x\n"), (0xFFE8 - offset), sram_read16_be(0xFFE8 - offset)); info_P(PSTR("BRK 0x%04x 0x%04x\n"), (0xFFE6 - offset), sram_read16_be(0xFFE6 - offset)); info_P(PSTR("COP 0x%04x 0x%04x\n"), (0xFFE4 - offset), sram_read16_be(0xFFE4 - offset)); info_P(PSTR("IRQ 0x%04x 0x%04x\n"), (0xFFEE - offset), sram_read16_be(0xFFEE - offset)); info_P(PSTR("NMI 0x%04x 0x%04x\n"), (0xFFEA - offset), sram_read16_be(0xFFEA - offset)); info_P(PSTR("RES 0x%04x 0x%04x\n"), (0xFFFC - offset), sram_read16_be(0xFFFC - offset)); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_DUMPHEADER]) == 0) { if (my_system.rom_mode == LOROM) offset = 0x8000; else offset = 0x0000; /* * # $ffc0..$ffd4 => Name of the ROM, typically in ASCII, using spaces to pad the name to 21 bytes. # $ffd5 => ROM layout, * typically $20 for LoROM, or $21 for HiROM. Add $10 for FastROM. # $ffd6 => Cartridge type, typically $00 for ROM only, or $02 * for ROM with save-RAM. # $ffd7 => ROM size byte. # $ffd8 => RAM size byte. # $ffd9 => Country code, which selects the video in * the emulator. Values $00, $01, $0d use NTSC. Values in range $02..$0c use PAL. Other values are invalid. # $ffda => Licensee * code. If this value is $33, then the ROM has an extended header with ID at $ffb2..$ffb5. # $ffdb => Version number, typically * $00. # $ffdc..$ffdd => Checksum complement, which is the bitwise-xor of the checksum and $ffff. # $ffde..$ffdf => SNES checksum, * an unsigned 16-bit checksum of bytes. # $ffe0..$ffe3 => Unknown. */ info_P(PSTR("NAME 0x%04x "), (0xffc0 - offset)); for (arg1 = (0xffc0 - offset); arg1 < (0xffc0 - offset + 21); arg1++) { c = sram_read(arg1); if (c > 0x1f && c < 0x7f) printf("%c", c); } printf("\n"); c = sram_read(0xffd5 - offset); info_P(PSTR("LAYOUT 0x%04x "), (0xffd5 - offset)); switch (c) { case 0x20: info_P(PSTR("LoROM, not fast\n")); break; case 0x21: info_P(PSTR("HiRom, not fast\n")); break; case 0x30: info_P(PSTR("LoROM, fast\n")); break; case 0x31: info_P(PSTR("HiRom, fast\n")); break; default: info_P(PSTR("Unkown 0x%02x\n"), c); break; } c = sram_read(0xffd6 - offset); info_P(PSTR("TYPE 0x%04xc"), (0xffd6 - offset), c); switch (c) { case 0x00: info_P(PSTR("Rom\n")); break; case 0x01: info_P(PSTR("Rom + Sram\n")); break; case 0x02: info_P(PSTR("Rom + Sram + Battery\n")); break; case 0x13: info_P(PSTR("SuperFX\n")); break; case 0x14: info_P(PSTR("SuperFX\n")); break; case 0x15: info_P(PSTR("SuperFX + Sram\n")); break; case 0x1a: info_P(PSTR("SuperFX + Sram\n")); break; case 0x34: info_P(PSTR("SA-1")); break; case 0x35: info_P(PSTR("SA-1")); break; default: info_P(PSTR("Unkown 0x%02x\n"), c); break; } arg1 = (2 << (sram_read(0xffd7 - offset) - 1)); info_P(PSTR("ROM 0x%04x %li MBit ( %li KiB)\n"), (0xffd7 - offset), (arg1 / 128), arg1); arg1 = (2 << (sram_read(0xffd8 - offset) - 1)); info_P(PSTR("RAM 0x%04x %li KiB\n"), (0xffd8 - offset), arg1); info_P(PSTR("CCODE 0x%04x "), (0xffd9 - offset)); c = sram_read(0xffd9 - offset); if (c == 0x00 || c == 0x01 || 0x0d) info_P(PSTR("NTSC\n")); else if (c >= 0x02 || c <= 0x0c) info_P(PSTR("PAL\n")); else info_P(PSTR("Unkown 0x%02x\n"), c); info_P(PSTR("LIC 0x%04x 0x%02x\n"), (0xffda - offset), sram_read(0xffda - offset)); info_P(PSTR("VER 0x%04x 0x%02x\n"), (0xffdb - offset), sram_read(0xffdb - offset)); info_P(PSTR("SUM1 0x%04x 0x%04x\n"), (0xffdc - offset), sram_read16_be(0xffdc - offset)); info_P(PSTR("SUM2 0x%04x 0x%04x\n"), (0xffde - offset), sram_read16_be(0xffde - offset)); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_SHMWR]) == 0) { if (get_hex_arg2(&arg1, &arg2)) shared_memory_write((uint8_t) arg1, (uint8_t) arg1); else info_P(PSTR("SHMWR \n")); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_SHMSAVE]) == 0) { shared_memory_scratchpad_region_tx_save(); shared_memory_scratchpad_region_rx_save(); info_P(PSTR("Save scratchpad\n")); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_SHMRESTORE]) == 0) { shared_memory_scratchpad_region_tx_restore(); shared_memory_scratchpad_region_rx_restore(); info_P(PSTR("Restore scratchpad\n")); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_LOADER]) == 0) { boot_startup_rom(500); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_RECONNECT]) == 0) { usb_connect(); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_STATUS]) == 0) { transaction_status(); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_SYS]) == 0) { system_status(); } else if (strcmp_P((char *) t, (PGM_P) cmdlist[CMD_HELP]) == 0) { shell_help(); } prompt(); } #endif