2016-02-09 12:29:30 +01:00

586 lines
16 KiB
C

/*
doctor64jr.c - Bung Doctor V64 Junior support for uCON64
Copyright (c) 1999 - 2002 NoisyB
Copyright (c) 2004, 2015 dbjh
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
drjr transfer protocol
DB25 pin name
p2~p9 pd[7:0] XXXXXXXXXXX ai XXXXX data XXXX
p1 nwrite ~~~~~~~~~|_____________________|~~
p14 ndstb ~~~~~~~~~~~~~~~~~~~~~~~~~|_|~~~~~~
p17 nastb ~~~~~~~~~~~~~|_|~~~~~~~~~~~~~~~~~~
ai[]=0 r/w a[7..0]
ai[]=1 r/w a[15..8]
ai[]=2 r/w a[23..16]
ai[]=3 w a[28..24]
ai[]=3 r (rst,wdf,wcf,a[28..24])
ai[]=4 r/w data
ai[]=5 w mode
ai[]=6 w en_1
ai[]=7 w en_0
*remark
a[8..1] support page count up
ai[3]d7:0=N64 power off, 1=N64 power on
d6:0=no dram data written, 1=dram data written
d5:0=no data write in b4000000~b7ffffff, 1=some data written in b4000000~b7ffffff
mode d0:0=dram read only and clear wdf, 1=dram write enable
d1:0=disable cartridge read and clear wcf flag,
1=enable cartridge read(write b4000000~b7ffffff will switch off dram and cartridge will present at b0000000~b3ffffff)
en_0=05 and en_1=0a is enable port control
mode:q0 0 1 0 1
mode:q1 0 0 1 1
b7ff ffff
b400 0000 dram read only dram r/w cartridge read cartridge read(* write this area will switch off dram)
b3ff ffff
b000 0000 dram read only dram r/w dram read only dram r/w
eg:enable port control
DB25 pin name
p2~p9 pd[7:0] XXXXXXXXXXX 07 XX 05 XXXX 06 XX 0a XXXXXXXXXXXX
p1 nwrite ~~~~~~~~~|_____________________________|~~~~~~~
p14 ndstb ~~~~~~~~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~~
p17 nastb ~~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~~~~~~~~
en_0=05 en_1=0a
eg:write adr $b0123456, data $a55a,$1234..
DB25 pin name
p2~p9 pd[7:0] XXXXXXXXXXX 00 XX 56 XXXX 01 XX 34 XXXX 02 XX 12 XXXX 03 XX b0 XXXXXX 04 XX 5a XX a5 XX 34 XX 12 XXXXXXXXXXX
p1 nwrite ~~~~~~~~~|_______________________________________________________________________________________|~~~~~~~~~~
p14 ndstb ~~~~~~~~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~~~|_|~~~|_|~~~|_|~~~|_|~~~~~~~~~~~
p17 nastb ~~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~~~|_|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
set adr word low set adr word high wdata a55a wdata 1234 (after write adr=b012345a)
eg:read adr $b0123400~$b01235ff, 512 data
DB25 pin name
p2~p9 pd[7:0] XXXXXXXXXXX 00 XX 00 XXXX 01 XX 34 XXXX 02 XX 12 XXXX 03 XX b0 XXXXXX 04 XX data0 XX data1 X ... X data510 XX data511 XXXXX
p1 nwrite ~~~~~~~~~|________________________________________________________________~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
p14 ndstb ~~~~~~~~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~~~~|_|~~~~~~|_|~~~ ~~~ ~~~~|_|~~~~~~~~|_|~~~~~~~~
p17 nastb ~~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~~~|_|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
set adr word low set adr word high (after 512 read adr=b0123400)
eg:dram write protect, disable N64 access to cartridge and disable port control
DB25 pin name
p2~p9 pd[7:0] XXXXXXXXXXX 05 XX 00 XXXX 07 XX 00 XXXX 06 XX 00 XXXXXXXXXXXX
p1 nwrite ~~~~~~~~~|________________________________________|~~~~~~~~~~
p14 ndstb ~~~~~~~~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~~
p17 nastb ~~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~|_|~~~~~~~~~~~~~~~~~~
mode=00 en_0=00 en_1=00
simple backup rountine for N64
void writePI(unsigned long addr, unsigned long value)
{
do {} while (*(volatile unsigned long *) (0xa4600010) & 3); // check parallel interface not busy
addr &=0xbffffffc;
*(unsigned long *)(addr)=value;
}
unsigned long readPI(unsigned long addr)
{
do {} while (*(volatile unsigned long *) (0xa4600010) & 3); // check parallel interface not busy
addr &=0xbffffffc;
return *(unsigned long *)(addr);
}
// MAIN -- START OF USER CODE
void mainproc(void *arg) {
u32 base_adr;
for (base_adr=0;base_adr<0x1000000;base_adr++){ // backup 128Mbits
writePI(0xb0000000+base_adr,readPI(0xb4000000 + base_adr)); // write data
}
}
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include "misc/archive.h"
#include "misc/parallel.h"
#include "ucon64.h"
#include "ucon64_misc.h"
#include "backup/doctor64jr.h"
#ifdef USE_PARALLEL
static st_ucon64_obj_t doctor64jr_obj[] =
{
{UCON64_N64, WF_DEFAULT | WF_STOP | WF_NO_ROM}
};
#endif
const st_getopt2_t doctor64jr_usage[] =
{
{
NULL, 0, 0, 0,
NULL, "Doctor V64 Junior"/*"19XX Bung Enterprises Ltd http://www.bung.com.hk"*/,
NULL
},
#ifdef USE_PARALLEL
{
"xdjr", 0, 0, UCON64_XDJR,
NULL, "send ROM to Doctor V64 Junior; " OPTION_LONG_S "port=PORT",
&doctor64jr_obj[0]
},
#if 0
{
"xdjrs", 0, 0, UCON64_XDJRS,
NULL, "send/receive SRAM to/from Doctor V64 Junior; " OPTION_LONG_S "port=PORT\n"
"receives automatically when SRAM does not exist",
&doctor64jr_obj[0]
},
#endif
#endif // USE_PARALLEL
{NULL, 0, 0, 0, NULL, NULL, NULL}
};
#ifdef USE_PARALLEL
#define BUFFERSIZE 32768
//#define set_ai_write outportb (port_a, 5); // ninit=1, nwrite=0
#define set_data_write outportb (port_a, 1); // ninit=0, nwrite=0
#define set_data_read outportb (port_a, 0); // ninit=0, nwrite=1
//#define set_normal outportb (port_a, 4); // ninit=1, nwrite=1
static unsigned short int port_8, port_9, port_a, port_b, port_c,
*buffer;
static int wv_mode;
static void
set_ai (unsigned char ai)
{
outportb (port_a, 5); // ninit=1, nwrite=0
outportb (port_b, ai);
}
static void
set_ai_data (unsigned char ai, unsigned char data)
{
set_ai (ai);
set_data_write // ninit=0, nwrite=0
outportb (port_c, data);
}
static void
init_port (int enable_write)
{
#ifndef USE_PPDEV
outportb (port_9, 1); // clear EPP time flag
#endif
set_ai_data (6, 0x0a);
set_ai_data (7, 0x05); // 6==0x0a, 7==0x05 is pc_control mode
// set_ai (5);
// set_data_read
// enable_write = inportb (port_c);
set_ai_data (5, (unsigned char) enable_write); // d0=0 is write protect mode
}
static void
end_port (int enable_write)
{
set_ai_data (5, (unsigned char) enable_write); // d0=0 is write protect mode
set_ai_data (7, 0); // release pc mode
set_ai_data (6, 0); // 6==0x0a, 7==0x05 is pc_control mode
outportb (port_a, 4); // ninit=1, nwrite=1
}
static int
check_card (void)
{
set_ai_data (3, 0x12);
set_ai_data (2, 0x34);
set_ai_data (1, 0x56);
set_ai_data (0, 0x78);
set_ai (3);
set_data_read // ninit=0, nwrite=1
if ((inportb (port_c) & 0x1f) != 0x12)
return 1;
set_ai (2);
set_data_read
if (inportb (port_c) != 0x34)
return 1;
set_ai (1);
set_data_read
if (inportb (port_c) != 0x56)
return 1;
set_ai (0);
set_data_read
if (inportb (port_c) != 0x78)
return 1;
return 0;
}
static int
write_32k (unsigned short int hi_word, unsigned short int lo_word)
{
unsigned char unpass, pass1;
unsigned short int i, j, fix;
set_ai_data (3, (unsigned char) (0x10 | (hi_word >> 8)));
set_ai_data (2, (unsigned char) hi_word);
for (i = 0; i < 0x40; i++)
{
unpass = 3;
while (unpass)
{
set_ai_data (1, (unsigned char) ((i << 1) | lo_word));
set_ai_data (0, 0);
set_ai (4); // set address index=4
set_data_write // ninit=0, nwrite=0
fix = i << 8;
for (j = 0; j < 256; j++)
outportw (port_c, buffer[j + fix]);
set_data_read // ninit=0, nwrite=1
if (wv_mode)
{
for (j = 0; j < 256; j++)
if (inportw (port_c) != buffer[j + fix])
break;
}
else
{
pass1 = 1;
for (j = 0; j < 4; j++)
if (inportw (port_c) != buffer[j + fix])
{
pass1 = 0;
break;
}
if (pass1)
{
set_ai_data (1, (unsigned char) ((i << 1) | lo_word | 1));
set_ai_data (0, 0xf8);
set_ai (4);
set_data_read // ninit=0, nwrite=1
for (j = 252; j < 256; j++)
if (inportw (port_c) != buffer[j + fix])
break;
}
}
set_ai (0);
set_data_read // ninit=0, nwrite=1
if (inportb (port_c) != 0)
{
unpass--;
outportb (port_a, 0x0b); // set all pin=0 for debug
set_ai_data (3, (unsigned char) (0x10 | (hi_word >> 8)));
set_ai_data (2, (unsigned char) hi_word);
if (unpass == 0)
return 1;
}
else
unpass = 0;
}
}
/*
outportb (ai, 0);
printf ("\na[7..0]=%02x\n", inportb (data));
outportb (ai, 1);
printf ("a[15..8]=%02x\n", inportb (data));
*/
return 0;
}
#if 0 // not used
static int
verify_32k (unsigned short int hi_word, unsigned short int lo_word)
{
char unpass;
unsigned short int i, j, fix;
set_ai_data (3, (unsigned char) (0x10 | (hi_word >> 8)));
set_ai_data (2, (unsigned char) hi_word);
for (i = 0; i < 0x40; i++)
{
unpass = 3;
while (unpass)
{
set_ai_data (1, (unsigned char) ((i << 1) | lo_word));
set_ai_data (0, 0);
set_ai (4);
set_data_read // ninit=0, nwrite=1
fix = i << 8;
for (j = 0; j < 256; j++)
{
if (inportw (port_c) != buffer[j + fix])
{
outportb (port_a, 0x0b); // all pin=0 for debug
set_ai_data (3, (unsigned char) (0x10 | (hi_word >> 8)));
set_ai_data (2, (unsigned char) hi_word);
unpass--;
if (unpass == 0)
return 1;
else
break;
}
}
if (j == 256)
break;
}
}
/*
outportb (ai,0);
printf ("\na[7..0]=%02x\n", inportb (data));
outportb (ai, 1);
printf ("a[15..8]=%02x\n", inportb (data));
*/
return 0;
}
static void
gen_pat_32k (unsigned short int offset)
{
int i;
for (i = 0; i < 0x4000; i++)
buffer[i] = i + offset;
}
static unsigned short int
test_dram (void)
{
int n_pages = 0, page;
gen_pat_32k (0x0000);
write_32k (0, 0);
gen_pat_32k (0x8000);
write_32k (0x100, 0);
gen_pat_32k (0x0000);
if (verify_32k (0, 0) == 0) // find lower 128 Mbits
n_pages = 0x100;
gen_pat_32k (0x8000);
if (verify_32k (0x100, 0) == 0) // find upper 128 Mbits
n_pages = 0x200;
printf ("Testing DRAM...\n");
for (page = 0; page < n_pages; page++)
{
gen_pat_32k ((unsigned short int) (page * 2));
if (write_32k (page, 0))
return 0;
else
{
fputc ('w', stdout);
fflush (stdout);
}
gen_pat_32k ((unsigned short int) (page * 2 + 1));
if (write_32k (page, 0x80))
return 0;
else
{
fputc ('w', stdout);
fflush (stdout);
}
}
fputc ('\n', stdout);
for (page = 0; page < n_pages; page++)
{
gen_pat_32k ((unsigned short int) (page * 2));
if (verify_32k (page, 0))
return 0;
else
{
fputc ('v', stdout);
fflush (stdout);
}
gen_pat_32k ((unsigned short int) (page * 2 + 1));
if (verify_32k (page, 0x80))
return 0;
else
{
fputc ('v', stdout);
fflush (stdout);
}
}
return n_pages;
}
#endif
static unsigned long int
get_address (void)
{
unsigned long int address;
set_ai_data (6, 0x0a); // enable pc mode
set_ai_data (7, 0x05); // enable pc mode
set_ai (3);
set_data_read // ninit=0, nwrite=1
address = inportb (port_c) << 24;
set_ai (2);
set_data_read
address |= inportb (port_c) << 16;
set_ai (1);
set_data_read
address |= inportb (port_c) << 8;
set_ai (0);
set_data_read
address |= inportb (port_c);
return address;
}
int
doctor64jr_read (const char *filename, unsigned short parport)
{
(void) filename;
(void) parport;
return fprintf (stderr, "ERROR: The function for dumping a cartridge is not yet implemented for the\n"
" Doctor V64 Junior\n");
}
int
doctor64jr_write (const char *filename, unsigned short parport)
{
unsigned int enable_write = 0, size, bytesread, bytessent = 0, n_pages;
time_t init_time;
unsigned short int page;
FILE *file;
parport_print_info ();
port_8 = parport;
port_9 = parport + 1;
port_a = parport + 2;
port_b = parport + 3;
port_c = parport + 4;
init_port (enable_write);
if (check_card () != 0)
{
fprintf (stderr, "ERROR: No Doctor V64 Junior card present\n");
end_port (enable_write);
exit (1);
}
wv_mode = 0;
if ((file = fopen (filename, "rb")) == NULL)
{
fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], filename);
exit (1);
}
if ((buffer = (unsigned short int *) malloc (BUFFERSIZE)) == NULL)
{
fprintf (stderr, ucon64_msg[FILE_BUFFER_ERROR], BUFFERSIZE);
exit (1);
}
size = ucon64.file_size;
printf ("Send: %d Bytes (%.4f Mb)\n\n", size, (float) size / MBIT);
#if 0
if (dram_test)
{
dram_size = test_dram ();
if (dram_size)
printf ("\nDRAM size=%dMbits\n", (dram_size / 2));
else
fprintf (stderr, "\nERROR: DRAM test failed\n");
return 0;
}
#endif
n_pages = (size + (64 * 1024 - 1)) / (64 * 1024); // "+ (64 * 1024 - 1)" to round up
init_time = time (0);
for (page = 0; page < n_pages; page++)
{
bytesread = fread ((unsigned char *) buffer, 1, BUFFERSIZE, file);
if (write_32k (page, 0))
{
fprintf (stderr, "ERROR: Transfer failed at address 0x%8lx", get_address ());
break;
}
bytesread += fread ((unsigned char *) buffer, 1, BUFFERSIZE, file);
if (write_32k (page, 0x80))
{
fprintf (stderr, "ERROR: Transfer failed at address 0x%8lx", get_address ());
break;
}
bytessent += bytesread;
ucon64_gauge (init_time, bytessent, size);
}
fputc ('\n', stdout);
if (enable_write) // 1 or 3
printf ("DRAM write protect disabled\n");
if (enable_write & 2) // 3
printf ("Run cartridge enabled\n");
// set_ai_data(5, enable_write); // d0=0 is write protect mode
end_port (enable_write);
return 0;
}
#endif // USE_PARALLEL