home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <dos.h>
- #include <timer.h>
- #include <conio.h>
- #include <stdlib.h>
-
- #define N 1000
-
-
- //************************************************************************
- //** Cable specifications: **
- //** **
- //** Pinouts: **
- //** IBM Parallel Port Atari SIO name **
- //** **
- //** 1 -----------------> 7 command/ **
- //** 14 <---------------- 5 dataout **
- //** 16 -----------------> 10 vcc/rdy **
- //** 17 -----------------> 3 datain **
- //** 24 ----------------- 4 gnd **
- //** 25 ----------------- 6 gnd **
- //** **
- //** **
- //** Connector Specs: **
- //** IBM Parallel Port DB25M 25 pin male d-shell **
- //** (view as if you were plugging the connector into your face) **
- //** 1 2 3 4 5 6 7 8 9 10 11 12 13 **
- //** 14 15 16 17 18 19 20 21 22 23 24 25 **
- //** **
- //** **
- //** **
- //** Atari SIO Molex 13 pin **
- //** (view as if you were plugging the connector into your face) **
- //** **
- //** 1 3 5 7 9 11 13 **
- //** 2 4 6 8 10 12 **
- //** **
- //** **
- //** Notes: **
- //** (1) Keep the wire length less than 3 feet. **
- //** **
- //************************************************************************
-
-
- //*****************This is the structure of the xf551 configuration record.
- //This is here for information only, the struct is not used in this program.
- struct DRVCONFIG
- {
- char DRVTRC; // number of tracks (0x28)
- int DRVSTP; // drive step rate (0)
- char DRVSEC; // number of sectors on a track (0x12, 0x1a)
- char DRVSID; // number of disk sides (0=single 1=double)
- char DRVDEN; // drive density 0 = sd, 4 = dd
- int DRVBYT; // bytes per sector 0x80 = 128, 0x100 = 256
- char DRVSEL; // drive address (d1: = 1)
- char DRVSER; // drive serial rate (0x41 = 19200bps)
- int DRVMSC; // ???
- char CHKSUM; // checksum for above data
- };
-
- //********Below are the configuration records for the various drive types
- //single sided single density
- char d810[13] = {0x28,00,00,0x12,0x00,0x00,0x00,80,0x01,0x41,00,00,0xfc};
- //single sided enhanced density
- char d1050[13] ={0x28,00,00,0x1a,0x00,0x04,0x00,80,0x01,0x41,00,00,0x09};
- //single sided double density
- char xf551[13] ={0x28,00,00,0x12,0x00,0x04,0x01,00,0x01,0x41,00,00,0x82};
-
- char data[512];
- unsigned data_valid, data_xmit;
-
- //************************************************************************
- //** calibration(freq) **
- //** This routine estimates the number of loop counts **
- //** in 25uS. This count is used to synchronize this **
- //** program with the sio data rate expected by the **
- //** atari disk drive. **
- //** **
- //** Inputs: **
- //** freq - The atari sio data rate (ideally ~19034 bits per **
- //** second) however, 18350bps seems to be more reliable. **
- //** Outputs: **
- //** none. **
- //** **
- //** Routines called: **
- //** none. **
- //** **
- //** History: **
- //** 07/11/94 Created M.S.M. **
- //** **
- //** **
- //************************************************************************
- void calibrate(double freq)
- {
- double tim, rate = (0.5/freq); // get 1/2 the period
- double clock_period = 1.0/1193180.0;
- unsigned temp, inc= 0x80; // start off with msb set
- data_valid = 0x80;
- long t;
- outportb(97,1); // enable timer 2
- //*******use successive approximation method to estimate the loop count
- for (int sa=0;sa<8;sa++)
- {
- t = 0L;
- for (int i=0;i<N;i++) // repeat inner loop N times
- {
- outportb(67,0xb4); // set up counter 2 mode 2
- asm {mov si,data_valid;} // disable interrupts
- outportb(66,0); // reset timer
- outportb(66,0);
- // asm cli; // For some reason disabling
- // interrupt messes up timing
- Loop:
- asm { dec si; jne Loop} // decrement counter
- // asm sti // reenable interrupts
- outportb(67,0x80); // latch count
- temp = inportb(66);
- temp += (inportb(66)<<8); // get count
- t += long(-temp);
- }
- tim = double(t)*clock_period/N; // get average loop time
- if (tim>rate) data_valid -= inc; // if the loop time is too
- inc = inc>>1; // long, set current bit to zero.
- data_valid |= inc; // try next lower bit
-
- // for debug
- // printf("tim = %lg, data_valid = %x\n", tim, data_valid);
- }
-
- //Account for the instruction just before and just after the timing loop
- data_valid = unsigned(double(data_valid)*0.98);
-
-
- printf("\ncount error = %lg nS loop count = %d\n", (tim-rate)*1e9, data_valid);
- if (data_valid <75) puts(
- "The cpu clock is probably too slow for this program to work properly."
- );
- }
-
-
- //************************************************************************
- //** get_bytes(data,len,timeout) **
- //** This routine expects to receive len bytes of data **
- //** over the atari SIO. **
- //** The received data is stored in char near *data. **
- //** If the data is not received before timeout, then **
- //** the data buffer is filled with 0xff. **
- //** **
- //** Inputs: **
- //** data - A near pointer to the data buffer memory. **
- //** len - The nember of bytes to be received, including **
- //** the checksum byte. **
- //** timeout - The routine waits timeout*8mS for a response. **
- //** Outputs: **
- //** data - The data read from the serial bus is stored **
- //** in this memory space. The first two bytes **
- //** are the acknowledge and complete bytes. **
- //** This is so that the calling routine can **
- //** can determine if the transfer was successful. **
- //** **
- //** Routines called: **
- //** none. **
- //** **
- //** History: **
- //** 07/11/94 Created M.S.M. **
- //** **
- //** Notes: **
- //** 1. The timing in this routine is critical. Changes **
- //** should be made with extreme care. **
- //** **
- //** 2. The numbers in parenthesis are the 286 clock cycles **
- //** per instruction. **
- //************************************************************************
- void get_bytes(char near *data, int len, int timeout)
- {
- // data - is the data buffer
- // len - is the number of bytes to send
- // timeout - is multiples of 8mS
- asm {
- cli // I need exact timing (2)
- mov dx,37ah // parallel control port (4)
- mov di,data // get offset of data (21)
- mov bx,len // initialize data counter (21)
- mov si,0 // set up time out timer (4)
- mov cx,timeout // intialize timeout counter (21)
- }
- Data_Len_Loop:
- asm {
- dec si // dec timeout LSW counter (3)
- jne Wait_For_Data // LSW timeout loop (4,16)
- dec cx // dec timeout MSW counter (3)
- je P_DV_1 // jmp for time out error (4,16)
- }
- Wait_For_Data:
- asm {
- in al,dx // read PIO control port (8)
- test al,8 // isolate dataout bit (4)
- je Data_Len_Loop // wait for start bit (4,16)
- mov cl,0 // cl holds received data (4)
- mov ch,9d // data + start bit (4)
- }
- P_DV_1:
- asm mov ax,data_valid // start 26uS delay (21)
- DV_1:
- asm {
- dec ax // (4) clock delay
- jne DV_1 // (4,16) total delay = 20*delay_valid
- shr cl,1 // get ready for next bit (2)
- in al,dx // read start bit (8)
- shl al,4 // make msb (11)
- and al,80h // isolate dataout bit (4)
- or cl,al // add bit to cl (3)
- mov ax,data_valid // start 26uS delay (21)
- }
- DV_2:
- asm {
- dec ax // (4) clock delay
- jne DV_2 // (4,16) total delay = 20*delay_valid
- dec ch // 10 bits (3)
- jne P_DV_1 // read next bit (4,16)
- not cl // invert bits (3)
- mov ds:[di],cl // save data (20)
- inc di // data++ (3)
- mov ax,data_valid // sync up to next bit (21)
- }
- DV_3:
- asm {
- dec ax // ~25uS counter (3)
- jne DV_3 // 25uS conunter loop (4,16)
- dec bx // len-- (3)
- mov si,0 // setup timeout counter (4)
- mov cx,timeout // (21)
- jne Data_Len_Loop // loop back to get more bytes (4,16)
- sti // enable interrupts
- // maximum time interrupts disabled <200ms
- }
- }
- //************************************************************************
- //** send_data(data,len) **
- //** This routine sends len bytes of data over the atari SIO.**
- //** The data is sent from the buffer pointed to by 'data'. **
- //** The command line is not toggled. **
- //** **
- //** Inputs: **
- //** data - A near pointer to the data buffer memory. **
- //** len - The nember of bytes to be sent, including **
- //** the checksum byte. The checksum byte must **
- //** be computed by the caller. **
- //** Outputs: **
- //** data - The data read from the serial bus is stored **
- //** in this memory space. These two bytes **
- //** are the 'acknowledge' and 'complete' bytes. **
- //** This is so that the calling routine can **
- //** can determine if the transfer was successful. **
- //** **
- //** Routines called: **
- //** none. **
- //** **
- //** History: **
- //** 07/11/94 Created M.S.M. **
- //** **
- //** Notes: **
- //** 1. The timing in this routine is critical. Changes **
- //** should be made with extreme care. **
- //** **
- //** 2. The numbers in parenthesis are the 286 clock cycles **
- //** per instruction. **
- //************************************************************************
- void send_data(char *data, int len)
- {
- asm {
- cli // I need exact timing (2)
- mov dx,37ah // parallel control port (4)
- mov di,data // get offset of data (21)
- mov si,len // number of byte to send (21)
- xor bh,bh // clear bh (3)
- }
- Data_Len_Loop:
- asm {
- mov bl,[di] // get send data from memory (21)
- not bl // invert the data (3)
- stc // set start bit (2)
- rcl bx,2 // align data with proper pin (7)
- mov cx,10d // data + start and stop bits (4)
- }
- Read_Next_Bit:
- asm {
- mov ax,data_valid // 26uS delay (21)
- }
- DV_1:
- asm {
- dec ax // (4) clock delay
- jne DV_1 // (4,16) jmp to finish delay
- mov al,bl // get data (3)
- and al,2 // get data bit (4)
- or al,4 // rdy set (4)
- out dx,al // send it out (10)
- shr bx,1 // get next bit (2)
- mov ax,data_xmit // 26uS delay
- }
- DV_2:
- asm {
- dec ax // (4) clock delay
- jne DV_2 // (4,16) jmp to finish delay
- dec cx // 10 bits (3)
- jne Read_Next_Bit // read next bit (4,16)
- mov ax,data_valid // 26uS delay (21)
- }
- DV_3:
- asm {
- dec ax // (4) clock delay
- jne DV_3 // (4,16) jmp to finish delay
- inc di // data++
- dec si // len-- (3)
- jne Data_Len_Loop // get bytes (4,16)
- sti // enable interrupts
- // maximum time interrupts disabled <200ms
- }
- get_bytes(data,2,5);
-
- }
- //************************************************************************
- //** send_frame(data) **
- //** This routine sends 5 bytes of data over the atari SIO. **
- //** The data is sent from the buffer pointed to by 'data'. **
- //** The command line is toggled. **
- //** --- **
- //** Inputs: **
- //** data - A near pointer to the data buffer memory. **
- //** **
- //** Outputs: **
- //** data - The data read from the serial bus is stored **
- //** in this memory space. These two bytes **
- //** are the 'acknowledge' and 'complete' bytes. **
- //** This is so that the calling routine can **
- //** can determine if the transfer was successful. **
- //** **
- //** Routines called: **
- //** none. **
- //** **
- //** History: **
- //** 07/11/94 Created M.S.M. **
- //** **
- //** Notes: **
- //** 1. The timing in this routine is critical. Changes **
- //** should be made with extreme care. **
- //** **
- //** 2. The numbers in parenthesis are the 286 clock cycles **
- //** per instruction. **
- //************************************************************************
- void send_frame(char *data)
- {
- asm {
- cli // I need exact timing (2)
- mov dx,37ah // parallel control port (4)
- mov di,data // get offset of data (21)
- mov si,5 // number of byte to send (21)
- xor bh,bh // clear bh (3)
- }
- Data_Len_Loop:
- asm {
- mov bl,[di] // get send data from memory (21)
- not bl // invert the data (3)
- stc // set start bit (2)
- rcl bx,2 // align data with proper pin (7)
- mov cx,10d // data + start and stop bits (4)
- }
- Read_Next_Bit:
- asm {
- mov ax,data_valid // 26uS delay (21)
- }
- DV_1:
- asm {
- dec ax // (4) clock delay
- jne DV_1 // (4,16) jmp to finish delay
- mov al,bl // get data (3)
- and al,2 // get data bit (4)
- or al,5 // rdy and command set (4)
- out dx,al // send it out (10)
- shr bx,1 // get next bit (2)
- mov ax,data_xmit // 26uS delay
- }
- DV_2:
- asm {
- dec ax // (4) clock delay
- jne DV_2 // (4,16) jmp to finish delay
- dec cx // 10 bits (3)
- jne Read_Next_Bit // read next bit (4,16)
- mov ax,data_valid // 26uS delay (21)
- }
- DV_3:
- asm {
- dec ax // (4) clock delay
- jne DV_3 // (4,16) jmp to finish delay
- inc di // data++
- dec si // len-- (3)
- jne Data_Len_Loop // get bytes (4,16)
- sti // enable interrupts
- // maximum time interrupts disabled <200ms
- }
- }
-
- //************************************************************************
- //** frame_getdata(drive,command,aux1,aux2,timeout,data,len) **
- //** This routine sends a command frame over the atari SIO **
- //** and expects to 'len' bytes of receive data back. **
- //** **
- //** Inputs: **
- //** drive - Atari disk drive # 1 through 8. (usually 1) **
- //** command - One of the atari SIO commands: **
- //** Read 0x52 **
- //** Write 0x57 **
- //** Status 0x53 **
- //** Put 0x50 **
- //** Format 0x21 **
- //** etc. **
- //** aux1, aux2 - Same as SIO: value depends on command sent **
- //** timeout - Wait for response 'timeout'*8mS **
- //** data - A near pointer to the data buffer memory. **
- //** len - The nember of bytes to be received, including **
- //** the checksum byte. **
- //** **
- //** Outputs: **
- //** data - The data read from the serial bus is stored **
- //** in this memory space. The first two bytes **
- //** are the 'acknowledge' and 'complete' bytes. **
- //** This is so that the calling routine can **
- //** can determine if the transfer was successful. **
- //** **
- //** Routines called: **
- //** send_frame() **
- //** get_bytes() **
- //** **
- //** History: **
- //** 07/11/94 Created M.S.M. **
- //** **
- //************************************************************************
- int frame_getdata(char drive, char command, char aux1, char aux2, int timeout,
- char *data, int len)
- {
- int check = 0;
- outportb(0x37a,4);
- data[0] = 0x30+drive; // drive 1
- data[1] = command; // command
- data[2] = aux1; // aux1
- data[3] = aux2; // aux2
- for (int i=0;i<4;i++)
- {
- check += data[i];
- if (check>255) check -= 255;
- }
- data[4] = check;
-
- // puts("sending command frame");
- outportb(0x37a,0x05);
- asm {mov ax,200;}
- loop1:
- asm {dec ax; jne loop1}
-
- send_frame(data); // send command frame
- asm {mov ax,100;}
- loop2:
- asm {dec ax; jne loop2}
-
- outportb(0x37a,0x04);
- get_bytes(data,len+2,timeout);
- // for (i=0;i<len+2;i++) printf("%x ", data[i]);
- // puts("");
-
- return (data[0]==0x41);
- }
-
- //************************************************************************
- //** frame_senddata(drive,command,aux1,aux2,timeout,data, **
- //** buff, bufflen) **
- //** This routine sends a command frame over the atari SIO **
- //** and then sends 'len' bytes of data. **
- //** **
- //** Inputs: **
- //** drive - Atari disk drive # 1 through 8. (usually 1) **
- //** command - One of the atari SIO commands: **
- //** Read 0x52 **
- //** Write 0x57 **
- //** Status 0x53 **
- //** Put 0x50 **
- //** Format 0x21 **
- //** etc. **
- //** aux1, aux2 - Same as SIO: value depends on command sent **
- //** timeout - Wait for response 'timeout'*8mS **
- //** data - A near pointer to the command buffer memory. **
- //** buff - A near pointer to the data buffer memory. **
- //** len - The number of data bytes to be sent, including **
- //** the checksum byte. **
- //** **
- //** Outputs: **
- //** data - The data read from the serial bus is stored **
- //** in this memory space. These two bytes **
- //** are the 'acknowledge' and 'complete' bytes. **
- //** This is so that the calling routine can **
- //** can determine if the transfer was successful. **
- //** **
- //** Routines called: **
- //** send_frame() **
- //** send_data() **
- //** **
- //** History: **
- //** 07/11/94 Created M.S.M. **
- //** **
- //************************************************************************
- int frame_senddata(char drive, char command, char aux1, char aux2, char timeout,
- char *data, char *buf, int lenbuf)
- {
- int check = 0;
- outportb(0x37a,4);
- data[0] = 0x30+drive; // drive 1
- data[1] = command; // command
- data[2] = aux1; // aux1
- data[3] = aux2; // aux2
- for (int i=0;i<4;i++)
- {
- check+=data[i];
- if (check>255) check -= 255;
- }
- data[4] = check;
- // puts("sending command frame");
- outportb(0x37a,0x05);
- asm {mov ax,200;}
- loop1:
- asm {dec ax; jne loop1}
-
- send_frame(data); // send command frame
- asm {mov ax,100;}
- loop2:
- asm {dec ax; jne loop2}
-
- outportb(0x37a,0x04);
- get_bytes(data,1,timeout);
-
- send_data(buf,lenbuf);
-
- // printf("%x %x\n",data[0],data[1]);
- return (data[0]==0x41);
- }
-
- //************************************************************************
- //** Main routine to copy an atari disk to the IBM harddrive. **
- //** **
- //** **
- //** **
- //** **
- //************************************************************************
- void main(int argc, char **argv)
- {
-
- //**************Check for required command line inputs*************
- if (argc<2) {
- puts("**This program copy and entire atari disk to an ibm image file.**");
- puts("usage:siocopy out_filename < -s, -e -d, or -2> <sio rate>");
- puts("-s single sided single density");
- puts("-e single sided enhanced density");
- puts("-d double sided double density");
- puts("If sio rate not given, 19200 bits per second is used");
- exit(0);
- }
-
- // genreal purpose variables
- unsigned i, check;
-
- // conatins the sio data rate
- double siorate;
-
- //******* The data rate is adjustable to account for slightly ********
- //******* different data rates on different atari disk drives.********
- // get sio rate from command line or use default
- if (argc>3) siorate = _atold(argv[3]);
- else siorate = 19200.0;
-
- // Estimate the number of loop counts in 1/2 the period of the sio
- // data rate.
- printf("--- calibrating SIO data rate to %lg hz---\n", siorate);
- calibrate(siorate);
-
- data_xmit = data_valid; // used for debug
- outportb(0x37a,4); // initialize PIO lines
-
- // Try to read the disk drive status
- if (frame_getdata(1,0x53,0,0,10,data, 5)==0) // get four byte of status
- { // plus one checksum byte
- puts("Disk drive not responding: be sure the drive is connected and turned on.");
- exit(0);
- }
-
- // open IBM file
- FILE *fout = fopen(argv[1],"wb");
-
- // Determine the atari disk drive type
- int num_sect = 720, num_bytes = 128, read = 'R';
- puts("reading atari disk drive #1");
-
- // if no drive specification is given, assume SSSD
- if (argc>2)
- {
- argv[2]++;
- switch(*argv[2])
- {
- // The user thinks it is an enhanced density disk. Test it to
- // be sure.
- case 'e':
- case 'E':
- // Try to configure the disk drive
- if (frame_senddata(1,0x4f,0,0,40,data,d1050,13)==0)
- {
- // disk is not configurable, maybe its a true 1050.
- // Use the 1050 read command (I think this is correct).
- read = 0x24;
- num_sect = 1040;
- break;
- }
-
- // Read sector 1 from the disk
- frame_getdata(1,'R',1,0,40,data,129);
- delay(500); // wait for rest of data if 256 byte/sector
-
- //Read confiuration record
- frame_getdata(1,0x4e,0,0,40,data,13);
- // Did it set up properly?
- if (data[7]!=0x04)
- {
- puts("Not an enhanced density disk.");
- num_sect = 720;
- }
- else num_sect = 1040;
- break;
- // Double density double sided case.
- //*************************************************************
- //*** This does not work. I do not know the proper format ****
- //*** for the double density case. ****
- //*************************************************************
- case 'd':
- case 'D':
- if (frame_senddata(1,0x4f,0,0,40,data,xf551,13)==0)
- {puts("This disk drive is not configurable."); exit(0);}
-
- //Read sector 1 to test data
- frame_getdata(1,'R',1,0,40,data,129);
- delay(500); // wait for rest of data if 256 byte/sector
-
- // get configuration record.
- frame_getdata(1,0x4e,0,0,40,data,13);
- // for (i=0;i<13;i++) printf("%x ",data[i+2]);
- // puts("");
-
- // Check if we have 256 byte sectors
- if (data[8] == 1)
- num_bytes = 256;
- else
- {
- puts("not double density");
- num_bytes = 128;
- }
- // Check if we have a two sided disk drive
- if (data[6] == 1)
- num_sect = 1040;
- else
- {
- puts("not double sided");
- num_sect = (data[7]==0)?720:1040;
- }
- break;
- // Single sided single density case (atari 810)
- case 's':
- case 'S':
- num_sect = 720;
- frame_senddata(1,0x4f,0,0,10,data,d810,13);
- break;
- default:
- puts("Drive type must be one of the following: <-s, -e, or -d>");
- exit(0);
- }
- }
-
-
- //read all the sectors
- for (int sect=1;sect<=num_sect;sect++)
- {
- printf("reading sector %d\r", sect);
- if (frame_getdata(1,read,sect&0xff,sect>>8,2,data,num_bytes+1)==0)
- puts("sector not read");
-
- // verify checksum
- check = 0;
- for (int k=0;k<num_bytes;k++)
- {
- check += data[k+2];
- if (check>255) check -=255;
- }
- if (check!=data[num_bytes+2])
- {printf("checksum error at sector %d.\n",sect);
- puts("Bad disk, copy protected disk or wrong disk type");
- exit(0);
- }
- // write the atari disk data to the ibm file
- fwrite(&data[2],num_bytes,1,fout);
- }
- fclose(fout);
- }