uchar ret = request_cpu_program.offset == request_cpu_program.length;
if(ret){
if(request_cpu_program.request == REQUEST_FLASH_CONFIG_SET){
- flash_cpu_config(cpu_buffer);
+ flash_cpu_config(cpu_buffer, request_cpu_program.length);
}else{
flash_cpu_program(request_cpu_program.address, request_cpu_program.length, cpu_buffer);
}
uchar ret = request_ppu_program.offset == request_ppu_program.length;
if(ret){
if(request_ppu_program.request == REQUEST_FLASH_CONFIG_SET){
- flash_ppu_config(ppu_buffer);
+ flash_ppu_config(ppu_buffer, request_cpu_program.length);
}else{
flash_ppu_program(request_ppu_program.address, request_ppu_program.length, ppu_buffer);
}
return 1;
case REQUEST_FIRMWARE_VERSION:{
__attribute__ ((section(".firmware.version")))
- static const /*PROGMEM*/ char date[VERSION_STRING_SIZE] = "kazzo16 0.1.2 / " __DATE__;
+ static const /*PROGMEM*/ char date[VERSION_STRING_SIZE] = "kazzo16 0.1.3 / " __DATE__;
memcpy_P(readbuffer, date, rq->wLength.word);
goto xxx_read;}
case REQUEST_FIRMWARE_PROGRAM:{
if(address >= 0x3800){
return 0;
}
+ if(((address & 0x3f00) == 0) && (length < 0x1800)){
+ return 0;
+ }
if(length + address > 0x3800){
return 0;
}
};
//when cpu_write_flash, phi2 must be low. when phi2 is high, mmc3 and vrc4 changes bank.
enum {
- BUS_CLOSE = 0xff
+ BUS_CLOSE = 0xff,
+ ADDRESS_CLOSE = 0x3fff //CPU and PPU are mapped internal registers, cartridge closes buses
};
/*PDx: use input, empty pin is output*/
#define USB_MISC_DIR IO_DIRECTION(D)
return ~ret;
}
+/*
+address high databus assignment
+D0-D5: CPU and PPU A8-A13
+D6: CPU A14
+D7: PPU /A13
+*/
+static void address_set(uint16_t address)
+{
+ ADDRESSBUS_A0_A7_OUT = address & 0xff;
+ uint8_t high = (address & 0x7fff) >> 8; //mask A0-A14
+ if((address & (1 << 13)) == 0){ //if A13 == 0
+ high |= 0x80; //set /A13
+ }
+ DATABUS_OUT = high;
+ BUS_CONTROL_OUT = bit_get_negative(ADDRESS_HIGH_LATCH);
+ BUS_CONTROL_OUT = BUS_CLOSE;
+}
+
void bus_init(void)
{
ADDRESSBUS_A0_A7_DIR = 0xff;
BUS_CONTROL_OUT = BUS_CLOSE;
USB_MISC_DIR = (0b1100 << 4) | 0b0011; //empty pin use OUT
USB_MISC_PULLUP = (1 << CPU_IRQ) | (1 << VRAM_A10);
+
+ address_set(ADDRESS_CLOSE);
}
/*
BUS_CONTROL_OUT = c;
i += 1;
}
-/*
-address high databus assignment
-D0-D5: CPU and PPU A8-A13
-D6: CPU A14
-D7: PPU /A13
-*/
-static void address_set(uint16_t address)
-{
- ADDRESSBUS_A0_A7_OUT = address & 0xff;
- uint8_t high = (address & 0x7fff) >> 8; //mask A0-A14
- if((address & (1 << 13)) == 0){ //if A13 == 0
- high |= 0x80; //set /A13
- }
- DATABUS_OUT = high;
- BUS_CONTROL_OUT = bit_get_negative(ADDRESS_HIGH_LATCH);
- BUS_CONTROL_OUT = BUS_CLOSE;
-}
static inline void direction_write(void)
{
DATABUS_DIR = DATABUS_DIR_OUT;
address += 1;
length--;
}
- direction_write();
+ address_set(ADDRESS_CLOSE);
}
void ppu_read(uint16_t address, uint16_t length, uint8_t *data)
address += 1;
length--;
}
+ address_set(ADDRESS_CLOSE);
}
/*
address += 1;
length--;
}
+ address_set(ADDRESS_CLOSE);
}
void cpu_write_flash_order(const struct flash_order *t)
t++;
length--;
}
+ address_set(ADDRESS_CLOSE);
}
/*
NTSC hardware timing
address += 1;
length--;
}
+ address_set(ADDRESS_CLOSE);
}
static inline void ppu_write_waveform(uint16_t address, uint8_t data)
address += 1;
length--;
}
- direction_write();
+ boot_address_set(ADDRESS_CLOSE);
}
r |= t[1] << 8;
return r;
}
-static void config_set(const uint8_t *data, struct flash_seqence *t)
+static void config_set(const uint8_t *data, uint16_t length, struct flash_seqence *t)
{
t->command_000x = unpack_short_le(data);
- data += 2;
+ data += sizeof(uint16_t);
t->command_2aaa = unpack_short_le(data);
- data += 2;
+ data += sizeof(uint16_t);
t->command_5555 = unpack_short_le(data);
- data += 2;
+ data += sizeof(uint16_t);
t->program_unit = unpack_short_le(data);
- data += 2;
- t->retry_enable = *data;
+ data += sizeof(uint16_t);
+ if(length < 9){ //support client 0.6.0
+ t->retry_enable = 0;
+ }else{
+ t->retry_enable = *data;
+ }
t->program_command[0].address = t->command_5555;
t->program_command[0].data = 0xaa;
t->program_command[2].address = t->command_5555;
t->program_command[2].data = 0xa0;
};
-void flash_cpu_config(const uint8_t *data)
+void flash_cpu_config(const uint8_t *data, uint16_t length)
{
- config_set(data, &seqence_cpu);
+ config_set(data, length, &seqence_cpu);
}
-void flash_ppu_config(const uint8_t *data)
+void flash_ppu_config(const uint8_t *data, uint16_t length)
{
- config_set(data, &seqence_ppu);
+ config_set(data, length, &seqence_ppu);
}
static void program_assign(enum status status, uint16_t address, uint16_t length, const uint8_t *data, struct flash_seqence *t)
void flash_both_idle(void);
//cpu
uint8_t flash_cpu_status(void);
-void flash_cpu_config(const uint8_t *data);
+void flash_cpu_config(const uint8_t *data, uint16_t length);
void flash_cpu_program(uint16_t address, uint16_t length, uint8_t *data);
void flash_cpu_erase(uint16_t address);
void flash_cpu_device_get(uint8_t d[2]);
uint8_t flash_ppu_status(void);
//ppu
-void flash_ppu_config(const uint8_t *data);
+void flash_ppu_config(const uint8_t *data, uint16_t length);
void flash_ppu_program(uint16_t address, uint16_t length, uint8_t *data);
void flash_ppu_erase(uint16_t address);
void flash_ppu_device_get(uint8_t d[2]);
CC = gcc
CFLAG = -I$(LIBUSB)/include -I$(KAZZO) -Wall -Werror
-CFLAG += -O2
-#CFLAG += -O0 -g
+CFLAG += -O2 -DDEBUG=0
+#CFLAG += -O0 -g -DDEBUG=1
LIB = -L$(LIBUSB)/lib/gcc -lusb
PROGRAM = ../kazzo_test.exe
ihex_destory(t);
return ret;
}
-static void snrom_ramopen(usb_dev_handle *handle)
+static void snrom_wram_open(usb_dev_handle *handle)
{
uint8_t t[5];
t[0] = 0x80;
write_memory(handle, REQUEST_CPU_WRITE_6502, INDEX_IMPLIED, 0x8000, 1, t);
t[0] = 0, t[1] = 0, t[2] = 0, t[3] = 1, t[4] = 0;
- write_memory(handle, REQUEST_CPU_WRITE_6502, INDEX_IMPLIED, 0x8000, 5, t);
+ write_memory(handle, REQUEST_CPU_WRITE_6502, INDEX_IMPLIED, 0x8000, sizeof(t), t);
t[0] = 0, t[1] = 0, t[2] = 0, t[3] = 0, t[4] = 0;
- write_memory(handle, REQUEST_CPU_WRITE_6502, INDEX_IMPLIED, 0xe000, 5, t);
- write_memory(handle, REQUEST_CPU_WRITE_6502, INDEX_IMPLIED, 0xa000, 5, t);
+ write_memory(handle, REQUEST_CPU_WRITE_6502, INDEX_IMPLIED, 0xe000, sizeof(t), t);
+ write_memory(handle, REQUEST_CPU_WRITE_6502, INDEX_IMPLIED, 0xa000, sizeof(t), t);
}
-static int cartridge_ram_transform(usb_dev_handle *handle, const uint8_t *firmware, enum request w, enum request r, long address, long length)
+static void snrom_wram_close(usb_dev_handle *handle)
+{
+ const uint8_t t[5] = {0, 0, 0, 0, 1}; //lsb -> msb
+ write_memory(handle, REQUEST_CPU_WRITE_6502, INDEX_IMPLIED, 0xe000, sizeof(t), t);
+ write_memory(handle, REQUEST_CPU_WRITE_6502, INDEX_IMPLIED, 0xa000, sizeof(t), t);
+}
+
+static int cartridge_ram_transform(usb_dev_handle *handle, const uint8_t *firmware, enum request w, enum request r, long address, long length, bool dump)
{
uint8_t *compare;
compare = malloc(length);
write_memory(handle, w, INDEX_IMPLIED, address, length, firmware);
read_memory(handle, r, INDEX_IMPLIED, address, length, compare);
int ret = memcmp(firmware, compare, length);
+ if(dump == true){
+ int i;
+ uint8_t *t = compare;
+ for(i = 0; i < length; i += 0x10){
+ int j;
+ printf("%06x:", i);
+ for(j = 0; j < 0x10; j++){
+ const char *safix;
+ switch(j){
+ case 7:
+ safix = "-";
+ break;
+ case 0x0f:
+ safix = "\n";
+ break;
+ default:
+ safix = " ";
+ break;
+ }
+ printf("%02x%s", *t, safix);
+ t++;
+ }
+ }
+ }
free(compare);
return ret;
}
puts("image open error!");
goto end;
}
- snrom_ramopen(handle);
+ snrom_wram_open(handle);
int ppu, cpu = 0;
- ppu = cartridge_ram_transform(handle, firmware, REQUEST_PPU_WRITE, REQUEST_PPU_READ, 0x0000, 0x2000);
+ ppu = cartridge_ram_transform(handle, firmware, REQUEST_PPU_WRITE, REQUEST_PPU_READ, 0x0000, 0x2000, false);
if(firmsize >= 0x2000){
- cpu = cartridge_ram_transform(handle, firmware + 0x2000, REQUEST_CPU_WRITE_6502, REQUEST_CPU_READ, 0x6000, firmsize - 0x2000);
+ cpu = cartridge_ram_transform(handle, firmware + 0x2000, REQUEST_CPU_WRITE_6502, REQUEST_CPU_READ, 0x6000, firmsize - 0x2000, false);
}
if((ppu == 0) && (cpu == 0)){
// write_memory(handle, REQUEST_FIRMWARE_PROGRAM, firmsize, 0x2000, 0, firmware);
- write_memory(handle, REQUEST_FIRMWARE_PROGRAM, firmsize, 0x0000, 0, firmware);
puts("USB connection will be disconnteced. This is normally.");
- puts("Re-turn on kazzo power.");
+ puts("Re-turn on kazzo's power.");
+ write_memory(handle, REQUEST_FIRMWARE_PROGRAM, firmsize, 0x0000, 0, firmware);
}else{
puts("firmware transform error!");
+ snrom_wram_close(handle);
}
end:
free(firmware);
puts(version);
}
+static bool ppu_read(usb_dev_handle *handle, int seed)
+{
+ int i;
+ int ret = 0;
+ const int bufsize = 0x80;
+ uint8_t *t, *buf = malloc(bufsize);
+/* t = buf;
+ for(i = 0; i < bufsize; i++){
+ *t = i;
+ t++;
+ }
+ ret |= cartridge_ram_transform(handle, buf, REQUEST_PPU_WRITE, REQUEST_PPU_READ, 0x0000, bufsize, false);*/
+/* if(ret == 0){
+ puts("increment ok");
+ }else{
+ puts("increment ng");
+ }*/
+
+ t = buf;
+ srand(5555 * seed);
+ for(i = 0; i < bufsize; i++){
+ *t = rand() & 0xff;
+ t++;
+ }
+ ret |= cartridge_ram_transform(handle, buf, REQUEST_PPU_WRITE, REQUEST_PPU_READ, 0x0000, bufsize, false);
+/* if(ret == 0){
+ puts("ramdom ok");
+ }else{
+ puts("ramdom ng");
+ }*/
+ t = buf;
+ free(buf);
+ return ret == 0;
+}
int main(int c, char **v)
{
usb_init();
case 'v':
firmware_verify(handle, v[2]);
break;
+ case 'p':{
+ if(DEBUG == 0){
+ break;
+ }
+ int i = 0x1000;
+ const char *ret = "test ok";
+ while(i != 0){
+ if(ppu_read(handle, i) == false){
+ ret = "test ng";
+ break;
+ }
+ if((i+1) % 100 == 0){
+ fprintf(stderr, "\r%05d", i+1);
+ fflush(stderr);
+ }
+ i--;
+ }
+ puts(ret);
+ }break;
+ case 'd':
+ if(DEBUG == 1){
+ write_memory(handle, REQUEST_FIRMWARE_PROGRAM, 0x200, 0x0000, 0, NULL);
+ }
+ break;
}
break;
}
w, address,
index, d, length, TIMEOUT
);
- if(cnt != length){
+ if(0 && cnt != length){
puts(__FUNCTION__);
puts(usb_strerror());
- //exit(1);
+ exit(1);
}
free(d);
}
famicom cartridge bus simulator 'kazzo'
unagi development team / 2009.10.08
-firmware version 0.1.1 / 2010.01.02
+firmware version 0.1.2 / 2010.01.10
----features----
-- USB communication to PC
-- read and write access for ROM cartridge
-- program access for flash memory cartridge
-- composed of few parts
+- USB-to-PC communication
+- ROM cartridge read and write access
+- programming access for flash memory cartridge
+- composed of few, mostly off-the-shelf parts
- firmware is powered by V-USB
http://www.obdev.at/products/vusb/index.html
-- firmware and host software are opensource, licenced by GPL v2
+- firmware and host software are open source, licenced by GPL v2
-kazzo was named from Japanese traditional fish '鰹'.
+kazzo was named after the Japanese traditional fish '鰹'.
----files----
firmware/
- firmware source code and Makefile. To complile, required WinAVR
- enviroment.
+ firmware source code and Makefile. In order to complile, WinAVR
+ environment is required.
hostecho/
source codes for kazzo_test.exe
hostmodule/
kazzo_test.exe
loop back test client binary for Windows
kazzo_mega16.hex kazzo_mega164p.hex
- firmware hex file written in Intel-Hex Record
+ firmware hex file written in Intel-Hex Record format
kazzo_schematics.png
- schematics graphic data
- notice! U1 pin number is assigned ATmega16 QFP.
+ schematics graphic file
+ (note: U1 pin number is assigned as ATmega16 QFP.)
readme.txt
this file
usbrequest.txt
- It is written how to request to kazzo.
+ directions on how to send USB request commands to kazzo.
COPYING
GPL v2 licencing document
-Host software 'unagi' is not included in this package. 'unagi's binary
-and source codes are available from official project page.
+Host software 'unagi' is not included in this package. unagi's binary
+and source codes are available from the official project page.
http://unagi.sourceforge.jp/
----AVR fusebit configuration----
U2 |74HC574
CN1 |type B female USB socket
CN2 |3x2 pin header, 2.54 mm spacing
-CN3 |30x2 pin cardedge connecter, 2.54 mm spacing
+CN3 |30x2 pin cartridge connector, 2.54 mm spacing
R1,R2|68 ohm register
R3 |1.5 kohm register
R4 |30 kohm register
JP2 |push switch
----pin assignment----
-See schematics for switch, register, diode and capacitor connection.
+See the schematics file for switch, register, diode and capacitor connection.
CN3: cartridge connector CN1: USB socket type B
+-----+ +---+ U1: ATmega164P (DIP)
GND| 1 31|+5V +5V|1 4|GND +--v--+
CPU A11| 2 32|CPU PHI2 D-|2 3|D+ D0| 1 40|A0
CPU A10| 3 33|CPU A12 +---+ D1| 2 39|A1
- CPU A9| 4 34|CPU A13 CN2: ISP conncetor D2| 3 38|A2
+ CPU A9| 4 34|CPU A13 CN2: ISP connector D2| 3 38|A2
CPU A8| 5 35|CPU A14 +---+ D3| 4 37|A3
CPU A7| 6 36|CPU D7 MISO|1 2|Vcc D4| 5 36|A4
CPU A6| 7 37|CPU D6 SCK|3 4|MOSI MOSI/D5| 6 35|A5
- AHL is Address High Latch.
- NC is No Connection.
- # is negative logic signal.
-- D0-D7 are databus.
+- D0-D7 are data buses.
-- shared by U1, U2, CN3(CPU and PPU).
-- D5-D7 are shared by ISP signal.
-- A0-A13 are addressbus.
+- A0-A13 are address buses.
-- A0-A7 are shared by U1, CN3(CPU and PPU)
-- A8-A13 are shared by U2, CN3(CPU and PPU)
-- CPU A14 and PPU A13# are uniq address buses.
+- CPU A14 and PPU A13# are unique address buses.
- U1 can substitute ATmega16.
-- SOUND IN and SOUND OUT has no connection.
-- If you don't need power switch, short JP1.
-- If you don't need reset switch, open JP2.
+- SOUND IN and SOUND OUT have no connection.
+- If a power switch is unnecessary, short JP1.
+- If a reset switch is unnecessary, open JP2.
Famicom Cartridge Bus Simulator: 'kazzo'
-Firmware USB Request Reference version 0.1.1
+Firmware USB Request Reference version 0.1.3
----Word Definitions----
* CPU Memory Region
REQUEST_FLASH_CONFIG_SET
R/W: write (immediate)
Arguments:
- wLength: must be set as a value of 8
+ wLength: must be set as a value of 9 or 8
wValue: not used
wIndex: target memory region. INDEX_CPU or INDEX_PPU
bData: programmed data for current memory region
bData[5] bit8-15 for command address 0x5555 (c5555)
bData[6] bit0-7 for programming unit length
bData[7] bit8-15 for programming unit length
+ bData[8] programming retry flag (0:disable, 1: enable / if wLength is
+ 8, firmware set 0)
Returns: nothing
Description:
This request defines flash memory command addresses for the target