Jump to content
IGNORED

Interesting little piece of history


Bryan

Recommended Posts

I was looking through some old stuff and I found a circuit board I designed during the short time I worked with Tom Harker at ICD.

 

It's a programmer for custom Jaguar and Lynx Flash cartridges we designed. Tom lost almost everything when he abandoned the ICD offices, so this is probably the only remaining board. I'm trying to decide if I should sell it or auction it off. I don't have any of the documentation on it (or cartridges, for that matter) so I don't think I'd try to build it up or anything.

 

The only things I remember are that it was parallel port based, it used a power pack Tom was already using for hard disk interfaces, and I seem to recall it was pretty fast.

post-3606-0-46853600-1435099197_thumb.jpg

  • Like 4
Link to comment
Share on other sites

Interesting...

 

On a side note, what was the deal with abandoning the ICD offices? Did ICD hit Dire Straits or something and that's why he just walked?

 

I talk a little bit about it here:

 

http://atariage.com/forums/topic/229656-interview-questions-for-bill-wilkinson/page-2?do=findComment&comment=3139701

 

Basically, he was focusing more and more on an ISP business and needed to move into a more centralized location. He didn't have space to take the ICD stuff so he left it in the old factory location imagining they'd never rent that space to anyone else. I don't know if he ever really planned to go back for it but the place has been completely looted now. There was so much cool stuff in there.... :(

 

Anyway, I know money was very tight when I was there. I didn't know much about the Catbox situation at first, but eventually people started contacting me trying to reach Tom.

  • Like 1
Link to comment
Share on other sites

 

I talk a little bit about it here:

 

http://atariage.com/forums/topic/229656-interview-questions-for-bill-wilkinson/page-2?do=findComment&comment=3139701

 

Basically, he was focusing more and more on an ISP business and needed to move into a more centralized location. He didn't have space to take the ICD stuff so he left it in the old factory location imagining they'd never rent that space to anyone else. I don't know if he ever really planned to go back for it but the place has been completely looted now. There was so much cool stuff in there.... :(

 

Anyway, I know money was very tight when I was there. I didn't know much about the Catbox situation at first, but eventually people started contacting me trying to reach Tom.

 

That's incredibly fascinating and kind of sad all the same. Thanks for sharing the information and shedding some background light on the whole situation. I guess it makes more sense now that my past inquiries regarding PCB layout and schematics, etc for the CatBox went completely unanswered. I don't imagine it would have been something someone went through and just trashed everything but I guess that's probably more likely than not.

Link to comment
Share on other sites

Yeah, it was sad. First Mike Hohman bought all that ICD stuff and ended up not being able to pay his storage fees (so I heard...) and then Tom let everything else go. There's not much left of ICD today.

 

I know Tom had a lot of Catbox parts in various states of completion but the stainless boxes were the expensive part. He told me he was planning to ship them out as soon as he could afford the boxes. Tom had always been a big supporter of the Atari community and I think he really planned to make good on the orders. He later told me he'd lost all his records regarding the pre-sales. This was around the time I left.

 

There are two things I wish I had from that office. One is a prototype 800XL with 128K. Apparently this was the machine the Tramiels used as the basis for the 130XE. It's interesting that much of the XE line was actually unreleased Warner stuff. The other is a collection of Atari disk drive firmware source code on fanfold paper complete with the original comments.

 

-Bry

  • Like 1
Link to comment
Share on other sites

  • 4 weeks later...

Source code!

// JagFlash Programmer v1.0
// Flash Utility
// Updated Nov 18, 1998
// (c) 1998 Bryan Edewaard for ICD, Inc.
 
#include <dos.h>
#include <stdio.h>
#include <fcntl.h>
// Include Primitive library
#include "jflib.h"
 
#define TRUE 1
#define FALSE 0
 
int Erase();
int GetID();
int Program();
int Verify();
int CheckStatus();
 
main()
{
 
int i,flag=0;
 
// Initialize the programmer...
 
printf("Initializing programmer...\n");
jf_Init(); // Initialize Programmer
// temp=jf_Status(); // Get Device Status
 
jf_PowerOn(); // 12v on
jf_SetLED(RED);
 
delay(500); // Let voltages settle
 
// Set D to $50 (clear Status) for all 4 chips
for (i=0; i<4; i++)
jf_SetD(i,0x50);
 
jf_CE_lo(); // Write sequence
jf_WE_lo(); // Once data has been set
jf_WE_hi();
jf_CE_hi();
 
while(TRUE)
{
// Get device ID's
 
printf("Checking Flash ID's\n");
if (GetID()==FALSE)
break;
 
// Erase all blocks...
 
printf("Erasing all blocks...\n");
if (Erase()==FALSE)
break;
 
if (CheckStatus()==FALSE)
break;
 
// Begin programming...
jf_SetLED(GREEN); // Change LED color (cause we can)
 
printf("Programming...\n");
if (Program()==FALSE)
break;
 
if (CheckStatus()==FALSE)
break;
 
// Verify();
flag=1;
break;
}
 
jf_PowerOff();
 
if (flag==0)  // Flash the light RED for an error
{
printf("Program terminated.\n");
for (i=0; i<6; i++)
{
jf_SetLED(OFF);
delay(250);
jf_SetLED(RED);
delay(250);
}
}
else
printf("Operation completed.\n");
 
jf_SetLED(OFF);
 
}
 
// Check cartridge ID
// Works only for the JagFlash 4 stuffed
// with Intel 28F008's
int GetID()
{
 
unsigned char data[4];
int i;
 
// Set D to $90 (read DeviceID) for all 4 chips
for (i=0; i<4; i++)
jf_SetD(i,0x90);
 
jf_CE_lo(); // Write sequence
jf_WE_lo(); // Once data has been set
jf_WE_hi();
jf_CE_hi();
 
 
jf_CE_lo(); // Read sequence
jf_OE_lo();
 
for (i=0; i<4; i++) // Read once CE and OE are low
data[i]=jf_ReadD(i);
 
jf_OE_hi();
jf_CE_hi();
 
printf("Mfg: %X %X %X %X\n",data[0],data[1],data[2],data[3]);
 
for (i=0; i<4; i++) // Make sure all 4 chips are okay (Mfg Check)
{
if (data[i]!=0x89)
{
printf("ID Error!\n");
return FALSE;
}
}
 
jf_SetA(0,0x07); // Change bit 0 to 1 (programmer's bit 2)
 
jf_CE_lo(); // Read sequence
jf_OE_lo();
 
for (i=0; i<4; i++)
data[i]=jf_ReadD(i);
 
jf_OE_hi();
jf_CE_hi();
 
printf("ID: %X %X %X %X\n",data[0],data[1],data[2],data[3]);
 
for (i=0; i<4; i++) // Make sure all 4 chips are okay (ID check)
{
if (data[i]!=0xA2)
{
printf("ID Error!\n");
return FALSE;
}
}
 
return TRUE; // Everything's okay
}
 
// Erases all 4 28F008's
int Erase()
{
 
int i,j;
char status;
 
// There are 16 blocks to be erased.
// We will check status after the entire erase
// instead of after each block.
 
jf_SetA(0,0); // Block selected on Flash's top 4 bits,
jf_SetA(1,0); // so lower bits don't matter.
 
for (i=0; i<16; i++)
{
 
// First set the block to be erased
// 00000, 10000 ... F0000 - shifted up 2
// (the programmers A0 & A1 lines aren't used
// in a 32-bit cartridge.)
 
jf_SetA(2,i<<2);
 
// Issue the pre-erase command (0x20)
 
for (j=0; j<4; j++)
jf_SetD(j,0x20);
 
jf_CE_lo(); // Write sequence
jf_WE_lo();
jf_WE_hi();
jf_CE_hi();
 
// Issue the Block-Erase command
 
for (j=0; j<4; j++)
jf_SetD(j,0xD0);
 
jf_CE_lo(); // Write sequence
jf_WE_lo();
jf_WE_hi();
jf_CE_hi();
 
// Wait for all 4 chips to finish
// For this we need to watch the READY bits
 
printf("%X",(char)i);
 
for (j=0; j<20; j++) // Give it 10 ticks to finish
{
 
delay(350); // Wait a bit
printf("."); // Print dots while we wait
 
status=jf_Status(); // Check READY bits
 
if ((status&0x0F)==0x00)
break;   // Erase done... continue
 
}
 
printf("\n"); // End the "dot line"
 
if (j==20) // Did we time-out?
{
printf("Erase failed!\n");
return FALSE;   // Problem!
}
}
return TRUE;   // Cart erased.
}
 
// Program the contents of JF.IMG into the cart
int Program()
{
 
int file,i,j,k,l;
char status, buffer[256];
unsigned count;
 
if (_dos_open("JF.IMG", O_RDONLY, &file)!=0)
return FALSE;
 
// three loops, one for each Address register
// 64x256x64x4(bytes per location)=4MB
for (i=0; i<64; i++)
{
printf(".");
jf_SetA(2,i); // Set the address top bits
 
for (j=0; j<256; j++)
{
jf_SetA(1,j);    // Set the address middle bits
 
// Get data for the inner loop
// (doing fewer, larger reads would speed this up)
_dos_read(file, buffer, 256, &count);
 
for (k=0; k<64; k++)
{
// inner loop
 
jf_SetA(0,k<<2); // Set the address low bits
 
for (l=0; l<4; l++)
jf_SetD(l,0x40); // write command
 
jf_CE_lo(); // Write sequence
jf_WE_lo();
jf_WE_hi();
// leave CE lo jf_CE_hi();
 
for (l=0; l<4; l++)
jf_SetD(l, buffer[(k<<2)+l]);  // actual write
 
// jf_CE_lo(); // Write sequence
jf_WE_lo();
jf_WE_hi();
jf_CE_hi();
 
while((jf_Status()&0x0F)!=0x00); // Check READY bits
 
}
}
}
printf("\n");
_dos_close(file);
return TRUE;
}
 
// Diagnostic code
// This increases programming time,
// And the Jag can test carts faster.
int Verify()
{
 
int file,i,j,k,l;
char status, buffer[256];
unsigned count;
 
if (_dos_open("JF.IMG", O_RDONLY, &file)!=0)
return FALSE;
 
for (i=0; i<4; i++) // Set all chips to read array mode
jf_SetD(i,0xFF);
 
jf_CE_lo(); // Write sequence
jf_WE_lo();
jf_WE_hi();
jf_CE_hi();
 
 
// three loops, one for each Address register
// 64x256x64x4(bytes per location)=4MB
for (i=0; i<64; i++)
{
printf(".");
jf_SetA(2,i); // Set the address top bits
 
for (j=0; j<256; j++)
{
jf_SetA(1,j);    // Set the address middle bits
 
// Get data for the inner loop
// (doing fewer, larger reads would speed this up)
_dos_read(file, buffer, 256, &count);
 
for (k=0; k<64; k++)
{
// inner loop
 
jf_SetA(0,k<<2); // Set the address low bits
 
jf_CE_lo();
jf_OE_lo();
 
 
if (buffer[(k<<2)]!=jf_ReadD(0))
printf("Error U1\n");
 
if (buffer[(k<<2)+1]!=jf_ReadD(1))
printf("Error U2\n");
 
if (buffer[(k<<2)+2]!=jf_ReadD(2))
printf("Error U3\n");
 
if (buffer[(k<<2)+3]!=jf_ReadD(3))
printf("Error U4\n");
 
jf_OE_hi();
jf_CE_hi();
 
 
}
}
}
printf("\n");
_dos_close(file);
return TRUE;
}
 
// Make sure all Flash chips are happy
int CheckStatus()
{
 
char data[4];
int i;
 
// for (i=0; i<3; i++)
// jf_SetA(i,0); // Set addr to 0 (doesn't matter, really)
 
// Set D to $70 (read Status) for all 4 chips
for (i=0; i<4; i++)
jf_SetD(i,0x70);
 
jf_CE_lo(); // Write sequence
jf_WE_lo(); // Once data has been set
jf_WE_hi();
jf_CE_hi();
 
 
jf_CE_lo(); // Read sequence
jf_OE_lo();
 
for (i=0; i<4; i++) // Read once CE and OE are low
data[i]=jf_ReadD(i);// read Status register
 
jf_OE_hi();
jf_CE_hi();
 
for (i=0; i<4; i++) // Make sure everything is cool
{
if ((data[i]&0x30)!=0)
{
printf("Flash Error in U%d.\n",i+1);
return FALSE;
}
}
 
printf("Flash Status OK!\n");
return TRUE;
}
And the IO library (jflib.c)

// JagFlash Programmer v1.0
// Primitive Library
// Updated Nov 18, 1998
// (c) 1998 Bryan Edewaard for ICD, Inc.
 
#include "jflib.h"
 
void SetCR(); // Private function
 
unsigned char CR; // global to hold the current CR.
 
// ***********
 
// Private routine
// Updates CR to match the CR variable.
void SetCR()
{
asm{
// Set up the Parallel Control Register
mov dx,0x37A // Select Parallel Control Register
mov al,0x0E // 00001110 = Select CR, No Strobe, Output Mode
out dx,al
 
mov dx,0x378 // Select Parallel Data Register
mov al,CR // Get initial CR data
out dx,al
 
mov dx,0x37A // Select Parallel Control Register
mov al,0x0F // 00001111 = Select CR, Strobe
out dx,al
 
mov al,0x0E // 00001110 = Release Strobe
out dx,al  // CR is now updated
}
}
 
// returns the value returned by Status();
void jf_Init()
{
 
//The device should be initialized to the proper start-up state.
//This is done by writing $7E to CR, and $00 to all other registers.
 
CR = 0x7E; // 01111110 = WR Mode; No Pwr, LED, Rst, CE, OE, WE
SetCR(); // Update CR
jf_SetD(0,0); // Clear D registers
jf_SetD(1,0);
jf_SetD(2,0);
jf_SetD(3,0);
jf_SetA(0,0); // Clear A registers
jf_SetA(1,0);
jf_SetA(2,0);
 
}
 
// Updates a D register.
void jf_SetD(int reg, char data)
{
 
// First, is "reg" in range?
if((reg<0)||(reg>3))
return; // Not a valid register!
 
// 2nd, is the programmer in Read or Write mode?
// Look at CR variable.
 
if(CR&0x01!=0) // Are we in read mode?
{
CR=CR&0xFE; // Write mode
SetCR();
}
 
// Select the requested register
asm{
mov dx,0x37A // Select Parallel Control Register
mov ax,reg // Get register number
shl ax,1 // Shift up 1 place
mov ah,al // Make a copy of AL for later
out dx,al // Programmer is now on correct register
 
mov dx,0x378 // Select Parallel Data Register
mov al,data // Get the data
out dx,al // Put the data on the port
 
mov dx,0x37A // Select Parallel Control Register
mov al,0x01
or al,ah // Turn strobe on
out dx,al
 
mov al,ah
out dx,al // Turn strobe off
}
 
}
 
// Pass a D reg, get the data back!
char jf_ReadD(int reg)
{
 
char retval;
 
// First, is "reg" in range?
if((reg<0)||(reg>3))
return 0; // Not a valid register!
 
// 2nd, is the programmer in Read or Write mode?
// Look at CR variable.
 
if((CR&0x01)!=1) // Are we in write mode?
{
CR=CR|0x01; // Read mode
SetCR();
}
 
// Select the requested register
asm{
mov dx,0x37A // Select Parallel Control Register
mov ax,reg // Get register number
shl ax,1 // Shift up 1 place
mov ah,al // Make a copy of AL for later
or  al,0x20     // Put port in input mode
out dx,al
or al,0x01 // Turn on Strobe
out dx,al // Programmer D reg is now selected
 
mov dx,0x378 // Select Parallel Data Register
in  al,dx // Get data from the programmer
mov retval,al // Save the data
 
mov al,ah
out dx,al // Turn strobe off (Turns off input mode)
}
 
return retval; // All done!
}
 
// Set an Address register
void jf_SetA(int reg, char addr)
{
 
// First, is "reg" in range?
if((reg<0)||(reg>2))
return; // Not a valid register!
 
reg+=4; // Address registers are 4-6
 
// Select the requested register
asm{
mov dx,0x37A // Select Parallel Control Register
mov ax,reg // Get register number
shl al,1 // Shift up 1 place
mov ah,al // Make a copy of AL for later
out dx,al // Programmer is now on correct register
 
mov dx,0x378 // Select Parallel Data Register
mov al,addr // Get the address data
out dx,al // Put the data on the port
 
mov dx,0x37A // Select Parallel Control Register
mov al,0x01
or al,ah // Turn strobe on
out dx,al
 
mov al,ah
out dx,al // Turn strobe off
}
}
 
// Turn on programmer power
void jf_PowerOn()
{
 
CR=CR|0x80; // Set power bit
SetCR();
}
 
// Turn off programmer power
void jf_PowerOff()
{
 
CR=CR&0x7F; // Clear power bit
SetCR();
}
 
// Set LED color
// 0=off 1=green 2=red
void jf_SetLED(int color)
{
 
if((color<0)||(color>2))
return; // Not a valid color
 
color=color<<5;     // Move color bits into place
CR=(CR&0x9F)|(char)color; // Put color bits in CR
 
SetCR();
}
 
// Get device status
// returns JDET in bit 7 and LDET in bit 6 (1=present)
// returns RDY in bits 0-3
char jf_Status()
{
 
char retval;
 
asm{
mov dx,0x37A // Select Parallel Control Register
mov al,0x02 // Pick any register where S0 is 1, No Strobe
out dx,al
 
mov dx,0x379 // Select Parallel Status Register
in  al,dx // Get status from programmer
mov ah,al // copy status for formatting
and al,0x80 // keep only JDET bit in al
shr ah,3 // move RDY bits down
and ah,0x0F // keep only RDY bits in ah
or ah,al // move JDET back in
 
// Now do the Lynx port
mov dx,0x37A // Select Parallel Control Register
mov al,0x00 // Pick any register where S0 is 0, No Strobe
out dx,al
 
mov dx,0x379 // Select Parallel Status Register
in  al,dx // Get status again.
and al,0x80 // keep only LDET
shr al,1 // mov LDET bit down
or ah,al // update ah
mov retval,ah // put bl into status variable
}
 
return retval;
}
 
// Bring WE low
void jf_WE_lo()
{
CR=CR&0xFD; // Clear WE
SetCR();
}
 
// Bring WE high
void jf_WE_hi()
{
CR=CR|0x02; // Set WE
SetCR();
}
 
// Bring OE low
void jf_OE_lo()
{
CR=CR&0xFB; // Clear OE
SetCR();
}
 
// Bring OE high
void jf_OE_hi()
{
CR=CR|0x04; // Set OE
SetCR();
}
 
// Bring CE low
void jf_CE_lo()
{
CR=CR&0xF7; // Clear CE
SetCR();
}
 
// Bring CE high
void jf_CE_hi()
{
CR=CR|0x08; // Set CE
SetCR();
}
 
// Bring RST low - Reset the Flash chips
void jf_Rst_lo()
{
CR=CR&0xEF; // Clear Reset
SetCR();
}
 
// Bring RST high
void jf_Rst_hi()
{
CR=CR|0x10; // Set Reset
SetCR();
}
// Get the current value of CR
char jf_GetCR()
{
return CR;
}
...and jflib.h

// JagFlash Primitive Library
// Header File
// Nov 18, 1998
 
#define OFF 0
#define GREEN 1
#define RED 2
 
void jf_Init();
void jf_SetD(int, char);
char jf_ReadD(int);
void jf_SetA(int, char);
void jf_PowerOn();
void jf_PowerOff();
void jf_SetLED(int);
char jf_Status();
void jf_WE_lo();
void jf_WE_hi();
void jf_OE_lo();
void jf_OE_hi();
void jf_CE_lo();
void jf_CE_hi();
void jf_Rst_lo();
void jf_Rst_hi();
char jf_GetCR();
  • Like 4
Link to comment
Share on other sites

"// Begin programming...

jf_SetLED(GREEN); // Change LED color (cause we can)"

 

 

 

LOL.

:) I like putting jokes in source code, even if no one else ever sees it.

 

When I've gone through all my backups, I'll put everything in a single zip file. I'd love to find the cartridge board Gerbers.

  • Like 2
Link to comment
Share on other sites

  • 1 month later...

 

L00K! R4R3! Jaguar stuff! With a reasonable starting price? You do realize that is against the rules?

I'm willing to let it go for whatever it turns out to be worth. I'm not going to use it but a collector might get a kick out it. I'm traveling back to the States in less than a week so it'll be a good time to sell & ship it.

  • Like 1
Link to comment
Share on other sites

  • 2 months later...

Found a letter from us (Damien Jones and I) to Atari when things were going south on the Jaguar front. It was really painful to write. This is just prior to us joining ICD.

 

(Of course, they never did reply, and we never did return the development system)

post-3606-0-13104400-1449677551_thumb.jpg

  • Like 8
Link to comment
Share on other sites

Found a letter from us (Damien Jones and I) to Atari when things were going south on the Jaguar front. It was really painful to write. This is just prior to us joining ICD.

 

(Of course, they never did reply, and we never did return the development system)

 

Thanks for sharing that.

Link to comment
Share on other sites

Nice bit of Info. Shows how Atari treated Devs. A shame.

 

Not really. Atari gets a lot of negative feedback, and often times it is warranted. But that is not warranted in this particular case.

 

This is just a gamedev business as usual.

 

Atari, as a publisher, rightfully, expected the brand new developer to prove themselves by, creating the game for free, in exchange for an opportunity, and potentially / maybe / perhaps, a revenue or an upfront license cash payment.

 

The timing of this business endeavor was unfortunate, that's for sure, but there is definitely nothing unexpected when you consider the reality of gamedev lottery.

Link to comment
Share on other sites

The letter was a bit heartbreaking to read but understandable.

 

I would have liked to the Atari 2600 emulator in action. Cracks me up how people berated such projects like this and games like Raiden because they were not a "challenge for a 64 bit system".

 

That might be true, but I know someone would have bought the 2600 game pack.

 

Do you remember how functional that emulator was? I have heard of two in various stages. One ran at like 40% speed, and one ran at better speeds but had no player/missile going on.

 

I still think getting an emulator and making a way to burn it with a collection of rom images on a Jaguar CD would be fun. I know I've had fun doing that for the Dreamcast and the emulators that system can run.

  • Like 1
Link to comment
Share on other sites

I'll have to look and see if I have any of the game documents from Atari. The deal was that we'd get $330K in advance as we met contract milestones. All we had to do was sign the contract, which never came (we knew another developer who got his signing check right before Atari started collapsing and never had to produce a thing!). We spent a lot of time on the phone with Bill Rehbock. I'd like to say it was a collaboration, but mostly we listened to him talk about this go-cart game where people had to shoot cables into things to make turns and knock things over to make obstacles. I wasn't sure if it was going to be fun or not.

 

Eventually, we sold our development stuff and code to Carl Forhan. The trick with the 2600 emulator was to figure out the most efficient way to get the job done in a parallel fashion. I ended up using the GPU almost exclusively for 6507 emulation with local RAM look-up tables for the instructions that were the hardest to emulate quickly. Reading from the bus can stall the GPU quite a bit so we re-packaged the cartridge data so that each 32-bit word in DRAM contained the next 3 bytes: B4B3B2B1, B5B4B3B2, B6B5B4B3, etc... This way we could keep shifting down instead of hitting the bus, and we'd continually pre-fetch every 4th word as long as the code didn't jump. When it did, we would grab the word which had the desired byte in the low 8 bits and continue from there. It wasted RAM, but we had plenty and it was very efficient to fetch this way. The GPU would then make a table of TIA changes made by the code which were passed to the DSP which rendered scan lines and was going to process the sound. I think we could have made it run pretty well.

 

We later heard that Dave Staugas was working on an emulator in house, and that's why they weren't going to use ours. I had a chance to ask Dave about it years later and he said his was never fast enough to be useful. I think we were probably being a bit more clever about it. I used to have a demo tape of everything we did on the jag. I gave it to someone I was interviewing with for a job and he lost it.

 

I was interviewed for the Antic podcast and I talked a bit about the Jaguar and ICD stuff:

 

http://ataripodcast.libsyn.com/webpage/2015/11

  • Like 8
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...