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?

Image
Image

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
I've already done this before. Using Funduino Mega2560 it don't require any additional ICs.
Image
ImageImage
Image
Image
It can generate full set of MD M68K bus signals. It even can dump some protected cartridges. :3 The dumping speed is about 32KBytes/s. Packet protocol with CRC check.

Anyway, continue with DIY.

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!
Eke wrote: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.
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
Thanks for all the great links guys. I went ahead and decided to remove the IC's and wire up my own board based on the MEGA. I am going to start on the code now.

Image
Image
Image
Image

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). :P

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