Page 1 of 1
Possible DIY USB Genesis/MD Reader/writer
Posted: Wed Oct 15, 2014 4:19 am
by Jazzmarazz
I eventually want to make a fully capable reader/writer supporting many mappers, roms and rams, but for now I spent the night working on this.
It is a Gen/MD cart reader and writer based on the Arduino MEGA using the EXTernal MEMory interface. I have used the exmem interface for normal external RAM expansion, but I think it would be nice to use as a reader and writer for both 16-bit Mask ROMs/EEPROMs and 8-bit SRAM/serial eeprom.
Does anyone think this would not work? Can I use three latches in this fashion to emulate a 16-bit data bus?
Obviously I would have to tie the second and third latch enable pins to an IO on the arduino and a few other miscellaneous pins such as !TIME, but I like the way it looks so far.
Posted: Wed Oct 15, 2014 12:23 pm
by HardWareMan
Posted: Wed Oct 15, 2014 12:56 pm
by Jazzmarazz
Hey, that is wonderful! Where can I get some more info? Does your board allow for writing to any address as well?
Posted: Wed Oct 15, 2014 1:43 pm
by HardWareMan
Here:
Code: Select all
// Cold reset
void DoColdReset()
// MRES/VRES --______--
{
PORTB = 0xFF;
PORTD = 0x00;
delay(1000);
PORTD = 0x03;
}
// Warm reset
void DoWarmReset()
// VRES --______--
{
PORTB = 0xFF;
PORTD = 0x02;
delay(100);
PORTD = 0x03;
}
// Read word
word DoReadWord(long Adr)
// ASEL - $000000..$7FFFFF
// CE0 - $000000..$3FFFFF
// TIME - $A13000..$A130FF
// AS --________--
// CTRL --________--
// CAS0 --________--
// CAS2 ------____--
{
byte Cmd, Adm, Adh;
word Result;
Adm = (Adr >> 8) & 0xFF; Adh = (Adr >> 16) & 0xFF;
PORTF = Adr & 0xFF; PORTK = Adm; PORTL = Adh;
Cmd = 0xEE; PORTB = 0xFF;
if ((Adh & 0x80) == 0x00) { Cmd = Cmd & 0xDF; }
if ((Adh & 0xC0) == 0x00) { Cmd = Cmd & 0xBF; }
if ((Adh == 0xA1) & (Adm == 0x30)) { Cmd = Cmd & 0x7F; }
PORTB = Cmd; Cmd = Cmd & 0xFD; Result = PINC; PORTB = Cmd;
// Three times for required delay
Result = (PINA << 8) | PINC;
Result = (PINA << 8) | PINC;
Result = (PINA << 8) | PINC;
PORTB = 0xFF;
return (Result);
}
// Write word
void DoWriteWord(long Adr, word Data)
// ASEL - $000000..$7FFFFF
// CE0 - $000000..$3FFFFF
// TIME - $A13000..$A130FF
// AS --____________--
// CTRL --____________--
// LWR -------_______--
// UWR -------_______--
{
byte Cmd, Adm, Adh;
Adm = (Adr >> 8) & 0xFF; Adh = (Adr >> 16) & 0xFF;
PORTF = Adr & 0xFF; PORTK = Adm; PORTL = Adh;
Cmd = 0xEF; PORTB = 0xFF;
if ((Adh & 0x80) == 0x00) { Cmd = Cmd & 0xDF; }
if ((Adh & 0xC0) == 0x00) { Cmd = Cmd & 0xBF; }
if ((Adh == 0xA1) & (Adm == 0x30)) { Cmd = Cmd & 0x7F; }
PORTB = Cmd;
DDRA = 0xFF; PORTA = lowByte(Data); DDRC = 0xFF; PORTC = highByte(Data);
PORTB = Cmd; Cmd = Cmd & 0xF3; PORTB = Cmd;
PORTB = 0xFF; DDRA = 0x00; PORTA = 0xFF; DDRC = 0x00; PORTC = 0xFF;
}
// Write low byte (D0-D7)
void DoWriteLow(long Adr, byte Data)
// ASEL - $000000..$7FFFFF
// CE0 - $000000..$3FFFFF
// TIME - $A13000..$A130FF
// AS --____________--
// CTRL --____________--
// LWR -------_______--
// UWR ----------------
{
byte Cmd, Adm, Adh;
Adm = (Adr >> 8) & 0xFF; Adh = (Adr >> 16) & 0xFF;
PORTF = Adr & 0xFF; PORTK = Adm; PORTL = Adh;
Cmd = 0xEF; PORTB = 0xFF;
if ((Adh & 0x80) == 0x00) { Cmd = Cmd & 0xDF; }
if ((Adh & 0xC0) == 0x00) { Cmd = Cmd & 0xBF; }
if ((Adh == 0xA1) & (Adm == 0x30)) { Cmd = Cmd & 0x7F; }
PORTB = Cmd;
DDRA = 0xFF; PORTA = Data; DDRC = 0x00; PORTC = 0xFF;
PORTB = Cmd; Cmd = Cmd & 0xFB; PORTB = Cmd;
PORTB = 0xFF; DDRA = 0x00; PORTA = 0xFF;
}
// Write high byte (D8-D15)
void DoWriteHigh(long Adr, byte Data)
// ASEL - $000000..$7FFFFF
// CE0 - $000000..$3FFFFF
// TIME - $A13000..$A130FF
// AS --____________--
// CTRL --____________--
// LWR ----------------
// UWR -------_______--
{
byte Cmd, Adm, Adh;
Adm = (Adr >> 8) & 0xFF; Adh = (Adr >> 16) & 0xFF;
PORTF = Adr & 0xFF; PORTK = Adm; PORTL = Adh;
Cmd = 0xEF; PORTB = 0xFF;
if ((Adh & 0x80) == 0x00) { Cmd = Cmd & 0xDF; }
if ((Adh & 0xC0) == 0x00) { Cmd = Cmd & 0xBF; }
if ((Adh == 0xA1) & (Adm == 0x30)) { Cmd = Cmd & 0x7F; }
PORTB = Cmd;
DDRA = 0x00; PORTA = 0xFF; DDRC = 0xFF; PORTC = Data;
PORTB = Cmd; Cmd = Cmd & 0xF7; PORTB = Cmd;
PORTB = 0xFF; DDRC = 0x00; PORTC = 0xFF;
}
Full range 3 bytes addres used. A0 is not used, A1 connected to VA1 and so thru A23->VA23.
Posted: Wed Oct 15, 2014 3:06 pm
by Eke
You might also be interested ArDUMPino and SGCExplorer from Bruno Freitas.
www.brunofreitas.com/node/31
www.brunofreitas.com/node/42
I have the latter and the firmware is easily modifiable to poke & dump heavily protected cartridges.
Posted: Wed Oct 15, 2014 10:01 pm
by Jazzmarazz
HardWareMan wrote:Here:
Code: Select all
// Cold reset
void DoColdReset()
// MRES/VRES --______--
{
PORTB = 0xFF;
PORTD = 0x00;
delay(1000);
PORTD = 0x03;
}
// Warm reset
void DoWarmReset()
// VRES --______--
{
PORTB = 0xFF;
PORTD = 0x02;
delay(100);
PORTD = 0x03;
}
// Read word
word DoReadWord(long Adr)
// ASEL - $000000..$7FFFFF
// CE0 - $000000..$3FFFFF
// TIME - $A13000..$A130FF
// AS --________--
// CTRL --________--
// CAS0 --________--
// CAS2 ------____--
{
byte Cmd, Adm, Adh;
word Result;
Adm = (Adr >> 8) & 0xFF; Adh = (Adr >> 16) & 0xFF;
PORTF = Adr & 0xFF; PORTK = Adm; PORTL = Adh;
Cmd = 0xEE; PORTB = 0xFF;
if ((Adh & 0x80) == 0x00) { Cmd = Cmd & 0xDF; }
if ((Adh & 0xC0) == 0x00) { Cmd = Cmd & 0xBF; }
if ((Adh == 0xA1) & (Adm == 0x30)) { Cmd = Cmd & 0x7F; }
PORTB = Cmd; Cmd = Cmd & 0xFD; Result = PINC; PORTB = Cmd;
// Three times for required delay
Result = (PINA << 8) | PINC;
Result = (PINA << 8) | PINC;
Result = (PINA << 8) | PINC;
PORTB = 0xFF;
return (Result);
}
// Write word
void DoWriteWord(long Adr, word Data)
// ASEL - $000000..$7FFFFF
// CE0 - $000000..$3FFFFF
// TIME - $A13000..$A130FF
// AS --____________--
// CTRL --____________--
// LWR -------_______--
// UWR -------_______--
{
byte Cmd, Adm, Adh;
Adm = (Adr >> 8) & 0xFF; Adh = (Adr >> 16) & 0xFF;
PORTF = Adr & 0xFF; PORTK = Adm; PORTL = Adh;
Cmd = 0xEF; PORTB = 0xFF;
if ((Adh & 0x80) == 0x00) { Cmd = Cmd & 0xDF; }
if ((Adh & 0xC0) == 0x00) { Cmd = Cmd & 0xBF; }
if ((Adh == 0xA1) & (Adm == 0x30)) { Cmd = Cmd & 0x7F; }
PORTB = Cmd;
DDRA = 0xFF; PORTA = lowByte(Data); DDRC = 0xFF; PORTC = highByte(Data);
PORTB = Cmd; Cmd = Cmd & 0xF3; PORTB = Cmd;
PORTB = 0xFF; DDRA = 0x00; PORTA = 0xFF; DDRC = 0x00; PORTC = 0xFF;
}
// Write low byte (D0-D7)
void DoWriteLow(long Adr, byte Data)
// ASEL - $000000..$7FFFFF
// CE0 - $000000..$3FFFFF
// TIME - $A13000..$A130FF
// AS --____________--
// CTRL --____________--
// LWR -------_______--
// UWR ----------------
{
byte Cmd, Adm, Adh;
Adm = (Adr >> 8) & 0xFF; Adh = (Adr >> 16) & 0xFF;
PORTF = Adr & 0xFF; PORTK = Adm; PORTL = Adh;
Cmd = 0xEF; PORTB = 0xFF;
if ((Adh & 0x80) == 0x00) { Cmd = Cmd & 0xDF; }
if ((Adh & 0xC0) == 0x00) { Cmd = Cmd & 0xBF; }
if ((Adh == 0xA1) & (Adm == 0x30)) { Cmd = Cmd & 0x7F; }
PORTB = Cmd;
DDRA = 0xFF; PORTA = Data; DDRC = 0x00; PORTC = 0xFF;
PORTB = Cmd; Cmd = Cmd & 0xFB; PORTB = Cmd;
PORTB = 0xFF; DDRA = 0x00; PORTA = 0xFF;
}
// Write high byte (D8-D15)
void DoWriteHigh(long Adr, byte Data)
// ASEL - $000000..$7FFFFF
// CE0 - $000000..$3FFFFF
// TIME - $A13000..$A130FF
// AS --____________--
// CTRL --____________--
// LWR ----------------
// UWR -------_______--
{
byte Cmd, Adm, Adh;
Adm = (Adr >> 8) & 0xFF; Adh = (Adr >> 16) & 0xFF;
PORTF = Adr & 0xFF; PORTK = Adm; PORTL = Adh;
Cmd = 0xEF; PORTB = 0xFF;
if ((Adh & 0x80) == 0x00) { Cmd = Cmd & 0xDF; }
if ((Adh & 0xC0) == 0x00) { Cmd = Cmd & 0xBF; }
if ((Adh == 0xA1) & (Adm == 0x30)) { Cmd = Cmd & 0x7F; }
PORTB = Cmd;
DDRA = 0x00; PORTA = 0xFF; DDRC = 0xFF; PORTC = Data;
PORTB = Cmd; Cmd = Cmd & 0xF7; PORTB = Cmd;
PORTB = 0xFF; DDRC = 0x00; PORTC = 0xFF;
}
Full range 3 bytes addres used. A0 is not used, A1 connected to VA1 and so thru A23->VA23.
Thanks a load! I am definitely going to look at this code and see if I want to go that path. Having no extra IC's would be a great goal. My main concern was the speed, and that is why I went with the EXMEM direction. 32k/s is fast enough for me though!
Yes, I have seen both of those and the first one has too many components for what i would like to make. The second one uses a teensy ++ which are very expensive compared to the MEGA. I just bought three Teensy 2.0 for another project, but they are too limited.
Thanks for the links though.
Posted: Thu Oct 16, 2014 12:24 pm
by KanedaFr
If you use expander, you'll won't need a lot of pin (i2c ones)
I tried this one myself
http://gendev.spritesmind.net/wip/2011/ ... perwriter/
(and yes, it's a teensy, but anything with the i2c pins we'll do it)
Posted: Mon Nov 17, 2014 4:15 am
by Jazzmarazz
Posted: Tue Nov 18, 2014 12:50 am
by sega16
SPI io expander are faster than i2c generally. Remember to consult with the datasheet instead of just assuming however.
Posted: Tue Nov 18, 2014 1:01 am
by Jazzmarazz
Speed is not my concern, just functionality. I still have time for changes though, since this is just a prototype (obviously).
Posted: Mon Dec 01, 2014 9:51 pm
by Jazzmarazz
Small update. I can now read the content of carts directly to the PC!
I am simply using bit manipulation within loops and pin arrays. I need to clean up the code first and write some intelligent functions (read header first, check for cart/backwards cart, etc) and then I can write a simple GUI and make it capable of writing to carts.
Thanks again for all of the help folks.
Posted: Tue Dec 02, 2014 12:51 am
by KanedaFr
while cleaning the forum, I also found this post which could help you :
viewtopic.php?p=20062#20062