586 lines
16 KiB
C
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
|