testing disk generator

This commit is contained in:
Greg Gauthier 2023-07-06 19:23:21 +01:00
parent 9e412b248b
commit 852d3a1b67
20 changed files with 3276 additions and 0 deletions

BIN
FDISK/BOOTDISK2.atr Normal file

Binary file not shown.

BIN
FDISK/test.atr Normal file

Binary file not shown.

362
SRC/atr2unix-1.3.c Normal file
View File

@ -0,0 +1,362 @@
/************************************************************************/
/* atr2unix.c */
/* */
/* Preston Crow */
/* Public Domain */
/* */
/* Extract files from an Atari DOS or MyDOS .ATR file */
/* */
/* Version History */
/* 5 Jun 95 Version 1.0 Preston Crow <crow@cs.dartmouth.edu> */
/* Initial public release */
/* 20 Dec 95 Version 1.1 Chad Wagner <cmwagner@gate.net> */
/* Ported to MS-DOS machines */
/* 10 Feb 98 Version 1.2 Preston Crow <crow@cs.dartmouth.edu> */
/* Expanded 256-byte sector support */
/* 2 Jan 22 Version 1.3 Preston Crow */
/* Enhanced debugging */
/************************************************************************/
/************************************************************************/
/* Portability macros */
/* 1 Jun 95 crow@cs.dartmouth.edu (Preston Crow) */
/************************************************************************/
#if defined(__MSDOS) || defined(__MSDOS__) || defined(_MSDOS) || \
defined(_MSDOS_)
#define MSDOS /* icky, icky, icky! */
#endif
/************************************************************************/
/* Include files */
/************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#ifdef MSDOS
#include <dir.h>
#include <io.h>
#else
#include <unistd.h>
#endif
/************************************************************************/
/* Macros and Constants */
/************************************************************************/
#define ATRHEAD 16
#define USAGE "atr2unix [-dlmr-] atarifile.atr\n" \
" Flags:\n" \
"\t-l Convert filenames to lower case\n" \
"\t-m MyDOS format disk image\n" \
"\t-- Next argument is not a flag\n" \
"\t-d debugging\n" \
"\t-r={sector} Use non-standard root directory number\n" \
"\t-f Fake run; do not create any files\n"
#ifndef SEEK_SET
#define SEEK_SET 0 /* May be missing from stdio.h */
#endif
#define SEEK(n) (ddshortinit?SEEK1(n):SEEK2(n))
#define SEEK1(n) (ATRHEAD + ((n<4)?((n-1)*128):(3*128+(n-4)*secsize)))
#define SEEK2(n) (ATRHEAD + ((n-1)*secsize))
/************************************************************************/
/* Data types */
/************************************************************************/
struct atari_dirent {
unsigned char flag; /* set bits: 7->deleted 6->in use 5->locked 0->write open */
unsigned char countlo; /* Number of sectors in file */
unsigned char counthi;
unsigned char startlo; /* First sector in file */
unsigned char starthi;
char namelo[8];
char namehi[3];
};
struct atr_head {
unsigned char h0; /* 0x96 */
unsigned char h1; /* 0x02 */
unsigned char seccountlo;
unsigned char seccounthi;
unsigned char secsizelo;
unsigned char secsizehi;
unsigned char hiseccountlo;
unsigned char hiseccounthi;
unsigned char unused[8];
};
/************************************************************************/
/* Function Prototypes */
/************************************************************************/
void read_dir(FILE *in,int sector);
void read_file(char *name,FILE *in,FILE *out,int sector,int count,int filenum);
/************************************************************************/
/* Global variables */
/************************************************************************/
int ddshortinit=0; /* True indicates double density with first 3 sectors 128 bytes */
int secsize,seccount;
int mydos=0;
int lowcase=0;
int debug=0;
int fake=0;
/************************************************************************/
/* main() */
/* Process command line */
/* Open input .ATR file */
/* Interpret .ATR header */
/************************************************************************/
int main(int argc,char *argv[])
{
FILE *in;
struct atr_head head;
int root=361;
--argc; ++argv; /* Skip program name */
/* Process flags */
while (argc) {
int done=0;
if (**argv=='-') {
++*argv;
while(**argv) {
switch(**argv) {
case 'm': /* MyDos disk */
mydos=1;
break;
case '-': /* Last option */
done=1;
break;
case 'l': /* strlwr names */
lowcase=1;
break;
case 'f': /* fake */
fake=1;
break;
case 'd': /* debugging */
debug=1;
break;
case 'r': /* root directory sector */
++*argv;
while ( **argv && !isdigit(**argv) ) ++*argv;
root=atoi(*argv);
while ( argv[0][1] ) ++*argv;
break;
default:
fprintf(stderr,USAGE);
exit(1);
}
++*argv;
}
--argc; ++argv;
}
else break;
if (done) break;
}
if (!argc) {
fprintf(stderr,USAGE);
exit(1);
}
in=fopen(*argv,"rb");
if (!in) {
fprintf(stderr,"Unable to open %s\n%s",*argv,USAGE);
exit(1);
}
--argc; ++argv;
if (argc) {
if (chdir(*argv)) {
fprintf(stderr,"Unable to change to directory: %s\n%s",*argv,USAGE);
exit(1);
}
}
fread(&head,sizeof(head),1,in);
if ( head.h0 != 0x96 || head.h1 != 0x02 )
{
if ( debug ) printf("File does not have ATR signature\n");
return 1;
}
secsize=head.secsizelo+256*head.secsizehi;
seccount=head.seccountlo+256*head.seccounthi;
if ( debug ) printf("ATR image: %d sectors, %d bytes each\n",seccount,secsize);
{
struct stat buf;
size_t expected;
fstat(fileno(in),&buf);
if (((buf.st_size-ATRHEAD)%256)==128) ddshortinit=1;
if (debug) {
if (ddshortinit && secsize==256) printf("DD, but first 3 sectors SD\n");
else if (secsize==256) printf("DD, including first 3 sectors\n");
}
expected = sizeof(head) + seccount * secsize - ((secsize - 128) * 3 * ddshortinit);
if ( (size_t)buf.st_size != expected ) {
if ( debug ) {
int seccount_real;
printf("File size wrong; expected %u bytes, observed %u bytes\n",(unsigned int)expected,(unsigned int)buf.st_size);
seccount_real = (buf.st_size - sizeof(head)) / secsize;
if ( ddshortinit )
{
if ( (size_t)buf.st_size <= sizeof(head) + 3 * 128 ) seccount_real = (buf.st_size - sizeof(head)) / 128;
else seccount_real = 3 + (buf.st_size - sizeof(head) - 3*128)/secsize;
}
printf("Sectors expected: %d, observed: %d\n",seccount,seccount_real);
}
}
}
read_dir(in,root);
return(0);
}
/************************************************************************/
/* display_entry() */
/* Display the contents of one directory entry for debugging */
/************************************************************************/
void display_entry(int i,struct atari_dirent *f)
{
struct atari_dirent empty;
memset(&empty,0,sizeof(empty));
if ( memcmp(&empty,f,sizeof(empty)) == 0 )
{
printf("%2d: [entry is all zeros]\n",i);
return;
}
unsigned count = f->countlo + 256 * f->counthi;
unsigned start = f->startlo + 256 * f->starthi;
printf("%2d: %4d %4d %c%c%c%c%c%c%c%c.%c%c%c\n",i,count,start,
f->namelo[0],f->namelo[1],f->namelo[2],f->namelo[3],f->namelo[4],f->namelo[5],f->namelo[6],f->namelo[7],
f->namehi[0],f->namehi[1],f->namehi[2]);
}
/************************************************************************/
/* read_dir() */
/* Read the entries in a directory */
/* Call read_file() for files, read_dir() for subdirectories */
/************************************************************************/
void read_dir(FILE *in,int sector)
{
int i,j,k;
struct atari_dirent f;
FILE *out;
char name[13];
if ( debug ) printf("Parsing directory sector %d\n",sector);
for(i=0;i<64;++i) {
fseek(in,(long)SEEK(sector)+i*sizeof(f)+(secsize-128)*(i/8),SEEK_SET);
fread(&f,sizeof(f),1,in);
if ( debug ) display_entry(i,&f);
if ( fake ) continue;
if (!f.flag) /* No more entries */
{
if ( debug ) printf("Directory entry %d: zero indicates end of entries\n",i);
return;
}
if (f.flag&128) /* Deleted file */
{
if ( debug ) printf("Directory entry %d: deleted flag\n",i);
continue;
}
for(j=0;j<8;++j) {
name[j]=f.namelo[j];
if (name[j]==' ') break;
}
name[j]='.';
++j;
for(k=0;k<3;++k,++j) {
name[j]=f.namehi[k];
if (name[j]==' ') break;
}
name[j]=0;
if (name[j-1]=='.') name[j-1]=0;
if(lowcase) for(j=0;name[j];++j) name[j]=tolower(name[j]);
if (f.flag ==0x47 ) { /* Seems to work */
printf("Warning: File %s has flag bit 1 set--file ignored\n",name);
continue;
}
if (mydos && f.flag&16) { /* Subdirectory */
if (debug) printf("subdir %s (sec %d);\n",name,f.startlo+256*f.starthi);
#ifdef MSDOS
mkdir(name);
#else
mkdir(name,0777);
#endif
chdir(name);
read_dir(in,f.startlo+256*f.starthi);
chdir("..");
}
else {
out=fopen(name,"wb");
if (!out) {
fprintf(stderr,"Unable to create file: %s\n",name);
exit(2);
}
if (debug) printf("readfile %s (sec %d,count %d,flags %x);\n",name,f.startlo+256*f.starthi,f.countlo+256*f.counthi,f.flag);
read_file(name,in,out,f.startlo+256*f.starthi,f.countlo+256*f.counthi,i);
if (f.flag&32) { /* Make locked files read-only */
#ifdef MSDOS
chmod(name,S_IREAD);
#else
mode_t um;
um=umask(022);
umask(um);
chmod(name,0444 & ~um);
#endif
}
}
}
}
/************************************************************************/
/* read_file() */
/* Trace through the sector chain. */
/* Complications: Are the file numbers or high bits on the sector */
/* number? */
/* What about the last block code for 256-byte sectors? */
/************************************************************************/
void read_file(char *name,FILE *in,FILE *out,int sector,int count,int filenum)
{
unsigned char buf[256];
buf[secsize-1]=0;
while(count) {
if (sector<1) {
fprintf(stderr,"Corrupted file (invalid sector %d): %s\n",sector,name);
return;
}
if (buf[secsize-1]&128 && secsize==128) {
fprintf(stderr,"Corrupted file (unexpected EOF): %s\n",name);
return;
}
if (fseek(in,(long)SEEK(sector),SEEK_SET)) {
fprintf(stderr,"Corrupted file (next sector %d): %s\n",sector,name);
return;
}
fread(buf,secsize,1,in);
fwrite(buf,buf[secsize-1],1,out);
if (mydos) {
sector=buf[secsize-2]+buf[secsize-3]*256;
}
else { /* DOS 2.0 */
sector=buf[secsize-2]+(3&buf[secsize-3])*256;
if (buf[secsize-3]>>2 != filenum) {
fprintf(stderr,"Corrupted file (167: file number mismatch): %s\n",name);
return;
}
}
--count;
}
if (!(buf[secsize-1]&128) && secsize==128 && sector) {
fprintf(stderr,"Corrupted file (expected EOF, code %d, next sector %d): %s\n",buf[secsize-1],sector,name);
return;
}
fclose(out);
}

476
SRC/dcmtoatr-1.4.c Normal file
View File

@ -0,0 +1,476 @@
/*
** dcmtoatr.c -- written by Chad Wagner
**
** I just wanted to throw in some personal comments, I wanted to thank
** Preston Crow, for his work on portability issues, as well as some of
** the ideas he put into this program, Bob Puff, for his hard work on
** The Disk Communicator, an excellent means for transferring disk images,
** and I feel it is the de facto standard, and should remain as such, and
** Jason Duerstock, for writing DCMTODSK and his documents on the DCM
** format, which did help me resolve some of the things I wasn't aware of.
** I am sure there is a few others. Unfortunately I only got one response
** from Bob Puff, he was attempting to help, but I believe he is very busy
** person, and just didn't have the time.
**
** Revision History:
** 31 May 95 cmwagner@gate.net
** 1 Jun 95 cmwagner@gate.net
** added in some portability macros from dcm.c
** added in read_atari16() function from dcm.c
** wrote write_atari16() function
** did a general clean-up of the code
** 1 Jun 95 crow@cs.dartmouth.edu
** did a clean-up of the code, hopefully resolving any
** portability issues
** 2 Jun 95 cmwagner@gate.net and crow@cs.dartmouth.edu
** Allow for multi-file DCM files, after they've been
** combined into a single file
** 5 Jun 95 cmwagner@gate.net
** Fixed decoding routines to handle double density diskettes
** 26 Jun 95 cmwagner@gate.net
** Added in support for creating DCMTOXFD, default compile is
** for DCMTOATR
** 3 Sep 95 cmwagner@gate.net
** Added in -x switch, which creates an XFD image, instead of the
** default ATR image.
** added in soffset() routine, changed around the SOFFSET define,
** so that xfd images could be created, without compiling a
** different version.
** 26 Jun 95 modification is no longer relevant because of this
** modification.
** wrote some more comments, about what certain functions are doing,
** when they were created, and who wrote them.
** 28 Sep 95 lovegrov@student.umass.edu
** Fixed bug in soffset() function, apparently sector 4 would return
** an offset of 16 for ATR images or 0 for XFD images, which is not
** correct.
*/
/* Include files */
#include <stdio.h>
#include <string.h>
/* prototypes */
void decode_C1(void);
void decode_C3(void);
void decode_C4(void);
void decode_C6(void);
void decode_C7(void);
void decode_FA(void);
int read_atari16(FILE *);
void write_atari16(FILE *,int);
int read_offset(FILE *);
void read_sector(FILE *);
void write_sector(FILE *);
long soffset(void);
/*
** Portability macros
** 1 Jun 95 crow@cs.dartmouth.edu (Preston Crow)
*/
#if defined(__MSDOS) || defined(__MSDOS__) || defined(_MSDOS) || defined(_MSDOS_)
#define MSDOS /* icky, icky, icky! */
#endif
#ifndef SEEK_SET
#define SEEK_SET 0 /* May be missing from stdio.h */
#endif
/* version of this program, as seen in usage message */
#define VERSION "1.4"
/* Global variables */
FILE *fin,*fout;
unsigned int secsize;
unsigned short cursec=0,maxsec=0;
unsigned char createdisk=0,working=0,last=0,density,buf[256],atr=16;
int doprint=1; /* True for diagnostic output */
/*
** main()
*/
int main(int argc,char **argv)
{
unsigned char archivetype; /* Block type for first block */
unsigned char blocktype; /* Current block type */
unsigned char tmp; /* Temporary for read without clobber on eof */
unsigned char imgin[256],imgout[256]; /* file names */
unsigned char done=0; /* completion flag */
char *self; /* program name from argv[0] */
#ifdef MSDOS
if ((self = strrchr(argv[0],'\\')) == NULL)
#else
if ((self = strrchr(argv[0],'/')) == NULL)
#endif
{
self = argv[0];
}
else
self++; /* Skip the slash */
--argc;++argv; /* Don't look at the filename anymore */
/* Process switches */
if (argc) while (*argv[0]=='-') {
int nomore=0;
++argv[0]; /* skip the '-' */
while(*argv[0]) {
switch(*argv[0]) {
case '-':
nomore=1;
break;
case 'q':
case 'Q':
doprint = !doprint;
break;
case 'x':
case 'X':
atr = 16 - atr;
break;
default:
fprintf(stderr,"Unsupported switch: %c\n",*argv[0]);
fprintf(stderr,"%s "VERSION" by cmwagner@gate.net\n",self);
fprintf(stderr,"%s [-qx] input[.dcm] [output[.atr]]\n",self);
exit(1);
}
++argv[0]; /* We've processed this flag */
}
--argc;++argv; /* Done processing these flags */
if(nomore) break; /* Filename may begin with '-' */
}
if (argc<1 || argc>2) {
fprintf(stderr,"%s "VERSION" by cmwagner@gate.net\n",self);
fprintf(stderr,"%s [-qx] input[.dcm] [output[.atr]]\n",self);
exit(1);
}
strcpy(imgin,argv[0]);
if (strrchr(imgin,'.') == NULL)
strcat(imgin,".dcm");
if (argc==2)
strcpy(imgout,argv[1]);
else {
char *p;
strcpy(imgout,imgin);
if ((p = strrchr(imgout,'.')) != NULL)
*p = 0;
}
if (strrchr(imgout,'.') == NULL)
if (atr) {
strcat(imgout,".atr");
} else {
strcat(imgout,".xfd");
}
if ((fin = fopen(imgin,"rb")) == NULL) {
fprintf(stderr,"I couldn't open \"%s\" for reading.\n",imgin);
exit(1);
}
archivetype = blocktype = fgetc(fin);
switch(blocktype) {
case 0xF9:
case 0xFA:
break;
default:
fprintf(stderr,"0x%02X is an unknown header block.\n",blocktype);
exit(1);
}
if ((fout = fopen(imgout,"rb")) != NULL) {
fprintf(stderr,"I can't use \"%s\" for output, it already exists.\n",imgout);
exit(1);
} else {
fout = fopen(imgout,"wb");
}
rewind(fin);
do {
if(doprint) printf("\rCurrent sector: %4u",cursec);
#ifdef MSDOS
if (kbhit()) {
if (getch() == 27) {
fprintf(stderr,"\nProcessing terminated by user.\n");
exit(1);
}
}
#endif
if (feof(fin)) {
fflush(stdout); /* Possible buffered I/O confusion fix */
if ((!last) && (blocktype == 0x45) && (archivetype == 0xF9)) {
fprintf(stderr,"\nMulti-part archive error.\n");
fprintf(stderr,"To process these files, you must first combine the files into a single file.\n");
#ifdef MSDOS
fprintf(stderr,"\tCOPY /B file1.dcm+file2.dcm+file3.dcm newfile.dcm\n");
#else
fprintf(stderr,"\tcat file1.dcm file2.dcm file3.dcm > newfile.dcm\n");
#endif
}
else {
fprintf(stderr,"\nEOF before end block.\n");
}
exit(1);
}
tmp = fgetc(fin); /* blocktype is needed on EOF error--don't corrupt it */
if (feof(fin)) continue; /* Will abort on the check at the top of the loop */
blocktype = tmp;
switch(blocktype) {
case 0xF9:
case 0xFA:
/* New block */
decode_FA();
break;
case 0x45:
/* End block */
working=0;
if (last) {
if (doprint) printf("\r%s has been successfully decompressed.\n",imgout);
fclose(fin);
fclose(fout);
done=1; /* Normal exit */
}
break;
case 0x41:
case 0xC1:
decode_C1();
break;
case 0x43:
case 0xC3:
decode_C3();
break;
case 0x44:
case 0xC4:
decode_C4();
break;
case 0x46:
case 0xC6:
decode_C6();
break;
case 0x47:
case 0xC7:
decode_C7();
break;
default:
fprintf(stderr,"\n0x%02X is an unknown block type. File may be "
"corrupt.\n",blocktype);
exit(1);
} /* end case */
if ((blocktype != 0x45) && (blocktype != 0xFA) &&
(blocktype != 0xF9)) {
if (!(blocktype & 0x80)) {
cursec=read_atari16(fin);
fseek(fout,soffset(),SEEK_SET);
} else {
cursec++;
}
}
} while(!done); /* end do */
return(0); /* Should never be executed */
}
void decode_C1(void)
{
int secoff,tmpoff,c;
tmpoff=read_offset(fin);
c=fgetc(fin);
for (secoff=0; secoff<secsize; secoff++) {
buf[secoff]=c;
}
c=tmpoff;
for (secoff=0; secoff<tmpoff; secoff++) {
c--;
buf[c]=fgetc(fin);
}
write_sector(fout);
}
void decode_C3(void)
{
int secoff,tmpoff,c;
secoff=0;
do {
if (secoff)
tmpoff=read_offset(fin);
else
tmpoff=fgetc(fin);
for (; secoff<tmpoff; secoff++) {
buf[secoff]=fgetc(fin);
}
if (secoff == secsize)
break;
tmpoff=read_offset(fin);
c=fgetc(fin);
for (; secoff<tmpoff; secoff++) {
buf[secoff] = c;
}
} while(secoff < secsize);
write_sector(fout);
}
void decode_C4(void)
{
int secoff,tmpoff;
tmpoff=read_offset(fin);
for (secoff=tmpoff; secoff<secsize; secoff++) {
buf[secoff]=fgetc(fin);
}
write_sector(fout);
}
void decode_C6(void)
{
write_sector(fout);
}
void decode_C7(void)
{
read_sector(fin);
write_sector(fout);
}
void decode_FA(void)
{
unsigned char c;
if (working) {
fprintf(stderr,"\nTrying to start section but last section never had "
"an end section block.\n");
exit(1);
}
c=fgetc(fin);
density=((c & 0x70) >> 4);
last=((c & 0x80) >> 7);
switch(density) {
case 0:
maxsec=720;
secsize=128;
break;
case 2:
maxsec=720;
secsize=256;
break;
case 4:
maxsec=1040;
secsize=128;
break;
default:
fprintf(stderr,"\nDensity type is unknown, density type=%u\n",density);
exit(1);
}
if (createdisk == 0) {
createdisk = 1;
if (atr) {
/* write out atr header */
/* special code, 0x0296 */
write_atari16(fout,0x296);
/* image size (low) */
write_atari16(fout,(short)(((long)maxsec * secsize) >> 4));
/* sector size */
write_atari16(fout,secsize);
/* image size (high) */
write_atari16(fout,(short)(((long)maxsec * secsize) >> 20));
/* 8 bytes unused */
write_atari16(fout,0);
write_atari16(fout,0);
write_atari16(fout,0);
write_atari16(fout,0);
}
memset(buf,0,256);
for (cursec=0; cursec<maxsec; cursec++) {
fwrite(buf,secsize,1,fout);
}
}
cursec=read_atari16(fin);
fseek(fout,soffset(),SEEK_SET);
working=1;
}
/*
** read_atari16()
** Read a 16-bit integer with Atari byte-ordering.
** 1 Jun 95 crow@cs.dartmouth.edu (Preston Crow)
*/
int read_atari16(FILE *fin)
{
int ch_low,ch_high; /* fgetc() is type int, not char */
ch_low = fgetc(fin);
ch_high = fgetc(fin);
return(ch_low + 256*ch_high);
}
/*
** write_atari16()
** Write a 16-bit integer with Atari byte-ordering
** 1 Jun 95 cmwagner@gate.net (Chad Wagner)
*/
void write_atari16(FILE *fout,int n)
{
unsigned char ch_low,ch_high;
ch_low = (unsigned char)(n&0xff);
ch_high = (unsigned char)(n/256);
fputc(ch_low,fout);
fputc(ch_high,fout);
}
/*
** read_offset()
** Simple routine that 'reads' the offset from an RLE encoded block, if the
** offset is 0, then it returns it as 256.
** 5 Jun 95 cmwagner@gate.net (Chad Wagner)
*/
int read_offset(FILE *fin)
{
int ch; /* fgetc() is type int, not char */
ch = fgetc(fin);
if (ch == 0)
ch = 256;
return(ch);
}
/*
** read_sector()
** Simple routine that reads in a sector, based on it's location, and the
** sector size. Sectors 1-3, are 128 bytes, all other sectors are secsize.
** 5 Jun 95 cmwagner@gate.net (Chad Wagner)
*/
void read_sector(FILE *fin)
{
fread(buf,(cursec < 4 ? 128 : secsize),1,fin);
}
/*
** write_sector()
** Simple routine that writes in a sector, based on it's location, and the
** sector size. Sectors 1-3, are 128 bytes, all other sectors are secsize.
** 5 Jun 95 cmwagner@gate.net (Chad Wagner)
*/
void write_sector(FILE *fout)
{
fwrite(buf,(cursec < 4 ? 128 : secsize),1,fout);
}
/*
** soffset()
** calculates offsets within ATR or XFD images, for seeking.
** 28 Sep 95 lovegrov@student.umass.edu (Mike White)
*/
long soffset()
{
return (long)atr + (cursec < 4 ? ((long)cursec - 1) * 128 :
((long)cursec - 4) * secsize + 384);
}

1347
SRC/sio2linux-3.1.0.c Normal file

File diff suppressed because it is too large Load Diff

925
SRC/unix2atr-0.9.c Normal file
View File

@ -0,0 +1,925 @@
/************************************************************************/
/* unix2atr.c */
/* */
/* Preston Crow */
/* Public Domain */
/* */
/* Extract files from a Unix directory tree and create a MyDOS */
/* ATR-format disk image file. */
/* */
/* To-do for version 1.0: */
/* Eliminate any bugs */
/* Fix up the DOS 2.5 boot sectors. */
/* * Adjust for DOS.SYS if it is there for DOS2.0/2.5. */
/* */
/* To-do after 1.0: */
/* Support for DOS2.0D?? (256-byte sectors without MyDOS) */
/* * Is it any different from 2.0S? */
/* Support for SpartaDOS */
/* * This will probably have to be coded by someone else, */
/* as I'm not terribly interested in it. */
/* Support for more MyDOS versions */
/* * Simply a matter of detecting the version and writing */
/* out the right boot sectors. */
/* */
/* Version History */
/* */
/* 14 Mar 98 Version 0.9 Preston Crow <crow@cs.dartmouth.edu> */
/* */
/* Auto detect MyDOS version and use correct boot sectors. */
/* This needs to be updated for additional versions; */
/* currently only 4.50 and 4.53 are supported. */
/* */
/* Fixed segfault with directories with > 64 files. */
/* */
/* Fixed a bug in the writing of file data--it's right now */
/* */
/* Cleaned up the MyDOS boot sector data. It may still */
/* be sensitive to different versions of MyDOS. */
/* */
/* 24 Feb 98 Version 0.8 Preston Crow <crow@cs.dartmouth.edu> */
/* Add '-s' option to skip the first 720 sectors. */
/* This is useful to protect against corruption from */
/* files that do raw sector I/O, and to save room to write */
/* the DOS files. */
/* Even with this flag, DOS.SYS will be written at sector 4 */
/* */
/* VTOC is now generated for DOS2.5 enhanced density images. */
/* */
/* Boot sectors are correct for MyDOS and DOS2.0/2.5, */
/* except that they aren't adjusted to reflect the disk */
/* parameters or the existence of DOS.SYS. */
/* */
/* DOS.SYS, DUP.SYS, and AUTORUN.SYS will be the first */
/* files written if they are found. */
/* */
/* Directory sorting is case-insensitive if '-u' is */
/* specified, so the resulting image has a sorted directory. */
/* */
/* 21 Feb 98 Version 0.7 Preston Crow <crow@cs.dartmouth.edu> */
/* Bug fix: ATR "sector" count is now correct. */
/* (Why did they use such a strange formula?) */
/* Initial writing of boot sector and VTOC. */
/* */
/* Still no support for extended DOS 2.5 VTOC. */
/* */
/* Should include file numbers for non-MyDOS disks. */
/* */
/* 7 Feb 98 Version 0.6 Preston Crow <crow@cs.dartmouth.edu> */
/* Bug fixes */
/* */
/* 7 Jun 95 Version 0.5 Preston Crow <crow@cs.dartmouth.edu> */
/* Mostly works except: */
/* MyDos format is the only one that works. */
/* bitmaps aren't written to the image */
/* boot sectors aren't created */
/* */
/************************************************************************/
/************************************************************************/
/* Include files */
/************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <string.h>
#include <unistd.h>
/************************************************************************/
/* Macros and Constants */
/************************************************************************/
#define ATRHEAD 16
#define USAGE "unix2atr [-dumps] #sectors atarifile.atr [directory]\n Flags:\n\t-d Double density sectors\n\t-u Convert filenames to upper case\n\t-m MyDOS format disk image\n\t-s skip the first 720 sectors\n\t-p print debugging stuff\n"
/* SEEK: seek offset in the disk image file for a given sector number */
#define SEEK(n) (ATRHEAD + ((n<4)?((n-1)*128):(3*128+(n-4)*secsize)))
/************************************************************************/
/* Data types */
/************************************************************************/
struct atari_dirent {
unsigned char flag; /* set bits:
7->deleted
6->normal file
5->locked
4->MyDOS subdirectory
3->???
2->??? \ one for >720, one for >1024 ?
1->??? / all for MyDOS?
0->write open */
unsigned char countlo; /* Number of sectors in file */
unsigned char counthi;
unsigned char startlo; /* First sector in file */
unsigned char starthi;
char namelo[8];
char namehi[3];
};
struct atr_head {
unsigned char h0; /* 0x96 */
unsigned char h1; /* 0x02 */
unsigned char seccountlo;
unsigned char seccounthi;
unsigned char secsizelo;
unsigned char secsizehi;
unsigned char hiseccountlo;
unsigned char hiseccounthi;
unsigned char unused[8];
};
/************************************************************************/
/* Function Prototypes */
/************************************************************************/
void write_file(FILE *fin,int sector,int fileno); /* Write a file starting at the specified sector */
void write_dir(int sector); /* Write a directory */
void set_dos_version(char *fname); /* Determine which version of DOS.SYS it is */
int use_sector(void); /* Return a sector number that is free to use after marking it */
int use_8_sector(void); /* Get 8 sectors for a directory */
void write_boot(void); /* Write first 3 sectors */
void write_bitmaps(void); /* Write out the free bitmap */
int afnamecpy(char *an,const char *n);
/************************************************************************/
/* Global variables */
/************************************************************************/
int secsize;
int mydos=0;
int upcase=0;
int debug=0;
int seccount;
char bitmap[64*1024]; /* Free "bit" map */
int lastfree=4;
FILE *fout;
int rootdir; /* flag for sorting routine */
int dos=0; /* true if DOS.SYS is written */
int dosver=0; /* DOS.SYS version code */
/************************************************************************/
/* main() */
/* Process command line */
/* Open input .ATR file */
/* Interpret .ATR header */
/************************************************************************/
int main(int argc,char *argv[])
{
struct atr_head head;
int i;
unsigned char buf[256];
--argc; ++argv; /* Skip program name */
secsize=128;
/* Process flags */
while (argc) {
int done=0;
if (**argv=='-') {
++*argv;
while(**argv) {
switch(**argv) {
case 'd': /* DD */
secsize=256;
break;
case 'm': /* MyDos disk */
mydos=1;
break;
case '-': /* Last option */
done=1;
break;
case 'u': /* strupr names */
upcase=1;
break;
case 'p': /* debugging */
debug=1;
break;
case 's': /* skip early sectors */
lastfree=721;
break;
default:
fprintf(stderr,USAGE);
exit(1);
}
++*argv;
}
--argc; ++argv;
}
else break;
if (done) break;
}
if (argc<2) {
fprintf(stderr,USAGE);
exit(1);
}
/* Number of sectors */
seccount=atoi(*argv);
++argv;--argc;
if (seccount<368) {
fprintf(stderr,USAGE);
exit(1);
}
if ((seccount>1040||(seccount>720&&secsize==256))&&!mydos) {
fprintf(stderr,"Must use MyDos format if more than 1040 SD or 720 DD sectors\n");
exit(1);
}
/* Open output file */
fout=fopen(*argv,"wb");
if (!fout) {
fprintf(stderr,"Unable to open %s\n%s",*argv,USAGE);
exit(1);
}
--argc; ++argv;
/* Change directories? */
if (argc) {
if (chdir(*argv)) {
fprintf(stderr,"Unable to change to directory: %s\n%s",*argv,USAGE);
exit(1);
}
}
/* Initialize free sectors */
for(i=1;i<=seccount;++i) bitmap[i]=0;
for(i=seccount+1;i<64*1024;++i) bitmap[i]=1;
for(i=360;i<=368;++i) bitmap[i]=1;
for(i=0;i<=3;++i) bitmap[i]=1;
if (mydos) {
if (seccount>943+(secsize-128)*8) {
for(i=360-((seccount-943+(secsize*8-1))/(secsize*8));i<360;++i) bitmap[i]=1;
}
}
else {
for(i=1024;i<=seccount;++i) {
bitmap[i]=0; /* Don't use sectors 1024 or above */
}
}
if (!mydos) bitmap[720]=1;
/* Initialize ATR header */
head.h0=0x96;
head.h1=0x02;
head.secsizelo=secsize&0xff;
head.secsizehi=secsize/0x100;
{
unsigned long paragraphs;
paragraphs=(seccount-3)*(secsize/16) + 3*128/16;
head.seccountlo=paragraphs&0xff;
head.seccounthi=(paragraphs>>8)&0xff;
head.hiseccountlo=(paragraphs>>16)&0xff;
head.hiseccounthi=(paragraphs>>24)&0xff;
}
bzero(head.unused,sizeof(head.unused));
fwrite(&head,sizeof(head),1,fout);
/* Initialize sectors */
if (debug)printf("Creating %d %d-byte sectors (%d byte file)\n",seccount,secsize,SEEK(seccount)+secsize);
for(i=0;i<256;++i)buf[i]=0;
fseek(fout,SEEK(1),SEEK_SET);
for(i=1;i<=3;++i) fwrite(buf,128,1,fout);
for(i=4;i<=seccount;++i) fwrite(buf,secsize,1,fout);
write_dir(361);
write_boot();
write_bitmaps();
return(0);
}
/************************************************************************/
/* write_file() */
/* Write a file starting at the specified sector */
/************************************************************************/
void write_file(FILE *fin,int sector,int fileno)
{
unsigned char buf[256];
int i;
int sc=1;
unsigned char c;
c=fgetc(fin);
while (!feof(fin)) {
int nsec=0;
bzero(buf,secsize);
if (!mydos) buf[secsize-3]=(fileno<<2);
for(i=0;i<secsize-3;++i) {
buf[i]=c;
++buf[secsize-1];
c=fgetc(fin);
if (feof(fin)) break;
}
/* Write the sector */
if (!feof(fin)) {
nsec=use_sector();
++sc;
buf[secsize-2]=nsec%256;
buf[secsize-3]+=nsec/256; /* add to fileno */
}
fseek(fout,SEEK(sector),SEEK_SET);
fwrite(buf,secsize,1,fout);
if (nsec && buf[secsize-1]!=secsize-3) {
printf("Something is very wrong!\n");
printf("sector: %d\n",sector);
printf("nsec: %d\n",nsec);
printf("bytes: %d\n",buf[secsize-1]);
exit(1);
}
if (debug && 0) printf("\t\t\tsector %d -> %d\n",sector,nsec);
sector=nsec;
}
if (debug) printf("\t\tFile written, %d sectors\n",sc);
}
/************************************************************************/
/* mydirsort() */
/* */
/* Compare two directory entries for use in sorting. */
/* Essentially alphabetical ordering, except for special files that */
/* go first: DOS.SYS, DUP.SYS, and AUTORUN.SYS. */
/* */
/* Note that MyDOS 4.53 seems to use '*AR0' instead of 'AUTORUN.SYS' */
/* as the auto-loaded menu program. I don't know why. */
/************************************************************************/
int mydirsort(const struct dirent *const*a,const struct dirent *const*b)
{
char an[12],bn[12];
/* If the filename isn't valid for Atari, it's order doesn't matter */
if (!afnamecpy(an,(*a)->d_name)) return(0);
if (!afnamecpy(bn,(*b)->d_name)) return(0);
/* Place certain files first in the root directory */
if (rootdir) {
if (strcmp(an,"DOS SYS")==0) return(-1);
if (strcmp(bn,"DOS SYS")==0) return( 1);
if (strcmp(an,"DUP SYS")==0) return(-1);
if (strcmp(bn,"DUP SYS")==0) return( 1);
if (strcmp(an,"AUTORUN SYS")==0) return(-1);
if (strcmp(bn,"AUTORUN SYS")==0) return( 1);
if (strcmp(an,"AUTORUN AR0")==0) return(-1);
if (strcmp(bn,"AUTORUN AR0")==0) return( 1);
#if 1 /* force some reordering to make me happy */
if (strcmp(an,"FILES LST")==0) return(-1);
if (strcmp(bn,"FILES LST")==0) return( 1);
if (strcmp(an+2,bn+2)==0) return(strcmp(an,bn));
if (strcmp(an+2," ")==0) return( 1);
if (strcmp(bn+2," ")==0) return(-1);
#endif
}
/* Compare the converted filenames */
return(strcmp(an,bn));
}
/************************************************************************/
/* write_dir() */
/************************************************************************/
#define SENTRY(n) (secsize==128?n:(n/8)*8+n)
void write_dir(int sector)
{
struct direct **d;
int used;
int i;
int e;
int count;
int start;
char aname[12];
struct atari_dirent dir[128]; /* 64 + 64 DD wasted space */
int lastfreesave=0;
aname[11]=0;
for(i=0;i<8*256;++i) ((char *)dir)[i]=0;
rootdir=(sector==361);
i=scandir(".",&d,NULL,mydirsort);
used=0;
while (i) {
/* Process **d */
do {
struct stat sbuf;
int subdir;
/* Hidden files--ignore silently */
if ((*d)->d_name[0]=='.') break;
if (lastfreesave) {
lastfree=lastfreesave;
lastfreesave=0;
}
/* Convert name */
if (!afnamecpy(aname,(*d)->d_name)) {
printf("Warning: %s: Can't convert to Atari name\n",(*d)->d_name);
break;
}
/* If it's DOS.SYS, start at sector 4, even if we're reserving the first 720 sectors */
if (rootdir) {
if (strcmp(aname,"DOS SYS")==0) {
set_dos_version((*d)->d_name);
}
if (
strcmp(aname,"DOS SYS")==0 ||
strcmp(aname,"DUP SYS")==0 ||
strcmp(aname,"AUTORUN SYS")==0
) {
lastfreesave=lastfree;
lastfree=3;
}
}
/* Determine if it's a file or directory */
if (stat((*d)->d_name,&sbuf)) {
printf("Warning: %s: Can't stat file\n",(*d)->d_name);
break;
}
subdir=0;
if (!sbuf.st_mode&(S_IFDIR|S_IFREG)) {
printf("Warning: %s: Not a normal file or directory\n",(*d)->d_name);
break;
}
if (sbuf.st_mode&S_IFDIR) subdir=1;
if (subdir && !mydos) {
printf("Warning: %s/: Can't process subdirectory for standard Atari images\n",(*d)->d_name);
break;
}
/* Create the entry */
e=SENTRY(used);
if (used>63) {
printf("Warning: More than 64 files in this directory\n");
printf(" Additional files or subdirectories ignored\n");
return;
}
strcpy(dir[e].namelo,aname);
if (subdir) {
dir[e].flag=16;
count=8;
start=use_8_sector();
}
else {
dir[e].flag=0x46;
if (!sbuf.st_mode&0000200) dir[e].flag &=32; /* locked */
count=(sbuf.st_size+(secsize-3)-1)/(secsize-3);
start=use_sector();
}
dir[e].countlo=count&0xff;
dir[e].counthi=count/0x100;
dir[e].startlo=start&0xff;
dir[e].starthi=start/0x100;
/* Write the directory sector */
fseek(fout,SEEK(sector),SEEK_SET);
fwrite(dir,secsize,8,fout);
++used;
/* Write the file/subdir */
if (!subdir) {
FILE *fin;
fin=fopen((*d)->d_name,"rb");
if (!fin) {
printf("Warning: %s: Can't open file\n",(*d)->d_name);
break;
}
if (debug) printf("\tWriting file %s starting at sector %d\n",(*d)->d_name,start);
write_file(fin,start,used-1);
fclose(fin);
}
else {
if (debug) printf("\tWriting directory %s\n",(*d)->d_name);
if (chdir((*d)->d_name)) {
fprintf(stderr,"Unable to change to directory: %s\n",(*d)->d_name);
break;
}
write_dir(start);
chdir("..");
}
} while(0); /* for break */
free(*d);
++d;--i;
}
}
/************************************************************************/
/* set_dos_version() */
/* Read the first K of dos.sys and make an educated guess as to which */
/* version it is. */
/************************************************************************/
void set_dos_version(char *fname)
{
FILE *dosfile;
unsigned char buf[1024];
dosfile=fopen(fname,"rb");
if (!dosfile) return;
fread(buf,1,1024,dosfile);
fclose(dosfile);
if (buf[18]==0x08) dosver=450; /* MyDOS 4.50 */
if (buf[18]==0xFD) dosver=453; /* MyDOS 4.53/4 */
if (dosver==0) {
printf("Warning: Unable to determine DOS.SYS version\n");
}
dos=1;
}
/************************************************************************/
/* use_sector() */
/* Return a sector number that is free to use after marking it used. */
/************************************************************************/
int use_sector(void)
{
while (lastfree<=seccount&&bitmap[lastfree]) ++lastfree;
if (lastfree>seccount) {
fprintf(stderr,"Disk image full\n");
write_bitmaps();
exit(1);
}
bitmap[lastfree]=1;
return(lastfree);
}
/************************************************************************/
/* use_8_sector() */
/* Get 8 consecutive sectors for a directory */
/************************************************************************/
int use_8_sector(void)
{
int i=lastfree;
int j;
while ((bitmap[i+0]||bitmap[i+1]||bitmap[i+2]||bitmap[i+3]||
bitmap[i+4]||bitmap[i+5]||bitmap[i+6]||bitmap[i+7])
&& i+7<64*1024) ++i;
if (i+7<64*1024) {
for (j=0;j<8;++j) bitmap[i+j]=1;
return(i);
}
fprintf(stderr,"Disk image full--no room for directory\n");
write_bitmaps();
exit(1);
}
/************************************************************************/
/* write_boot() */
/* Write out the first 3 sectors */
/************************************************************************/
void write_boot(void)
{
/*
* Sectors 1 through 3
*
* Copied from a blank 720-sector DOS2.0S-formatted disk
* DOS2.5 generates the same data for 720- and 1040-sector disks.
*
* Writing DOS files may change some bytes, but I haven't checked
* to see which bytes change.
*/
char dos20init[128*3]={
0x00,0x03,0x00,0x07,0x40,0x15,0x4c,0x14,0x07,0x03,0x03,0x00,0x7c,0x1a,0x00,0x04,
0x00,0x7d,0xcb,0x07,0xac,0x0e,0x07,0xf0,0x36,0xad,0x12,0x07,0x85,0x43,0x8d,0x04,
0x03,0xad,0x13,0x07,0x85,0x44,0x8d,0x05,0x03,0xad,0x10,0x07,0xac,0x0f,0x07,0x18,
0xae,0x0e,0x07,0x20,0x6c,0x07,0x30,0x17,0xac,0x11,0x07,0xb1,0x43,0x29,0x03,0x48,
0xc8,0x11,0x43,0xf0,0x0e,0xb1,0x43,0xa8,0x20,0x57,0x07,0x68,0x4c,0x2f,0x07,0xa9,
0xc0,0xd0,0x01,0x68,0x0a,0xa8,0x60,0x18,0xa5,0x43,0x6d,0x11,0x07,0x8d,0x04,0x03,
0x85,0x43,0xa5,0x44,0x69,0x00,0x8d,0x05,0x03,0x85,0x44,0x60,0x8d,0x0b,0x03,0x8c,
0x0a,0x03,0xa9,0x52,0xa0,0x40,0x90,0x04,0xa9,0x57,0xa0,0x80,0x8d,0x02,0x03,0x8c,
0x03,0x03,0xa9,0x31,0xa0,0x0f,0x8d,0x00,0x03,0x8c,0x06,0x03,0xa9,0x03,0x8d,0xff,
0x12,0xa9,0x00,0xa0,0x80,0xca,0xf0,0x04,0xa9,0x01,0xa0,0x00,0x8d,0x09,0x03,0x8c,
0x08,0x03,0x20,0x59,0xe4,0x10,0x1d,0xce,0xff,0x12,0x30,0x18,0xa2,0x40,0xa9,0x52,
0xcd,0x02,0x03,0xf0,0x09,0xa9,0x21,0xcd,0x02,0x03,0xf0,0x02,0xa2,0x80,0x8e,0x03,
0x03,0x4c,0xa2,0x07,0xae,0x01,0x13,0xad,0x03,0x03,0x60,0xaa,0x08,0x14,0x0b,0xbe,
0x0a,0xcb,0x09,0x00,0x0b,0xa6,0x0b,0x07,0x85,0x44,0xad,0x0a,0x07,0x8d,0xd6,0x12,
0xad,0x0c,0x07,0x85,0x43,0xad,0x0d,0x07,0x85,0x44,0xad,0x0a,0x07,0x8d,0x0c,0x13,
0xa2,0x07,0x8e,0x0d,0x13,0x0e,0x0c,0x13,0xb0,0x0d,0xa9,0x00,0x9d,0x11,0x13,0x9d,
0x29,0x13,0x9d,0x31,0x13,0xf0,0x36,0xa0,0x05,0xa9,0x00,0x91,0x43,0xe8,0x8e,0x01,
0x03,0xa9,0x53,0x8d,0x02,0x03,0x20,0x53,0xe4,0xa0,0x02,0xad,0xea,0x02,0x29,0x20,
0xd0,0x01,0x88,0x98,0xae,0x0d,0x13,0x9d,0x11,0x13,0xa5,0x43,0x9d,0x29,0x13,0xa5,
0x44,0x9d,0x31,0x13,0x20,0x70,0x08,0x88,0xf0,0x03,0x20,0x70,0x08,0xca,0x10,0xb2,
0xac,0x09,0x07,0xa2,0x00,0xa9,0x00,0x88,0x10,0x01,0x98,0x9d,0x19,0x13,0x98,0x30,
0x0d,0xa5,0x43,0x9d,0x39,0x13,0xa5,0x44,0x9d,0x49,0x13,0x20,0x70,0x08,0xe8,0xe0,
0x10,0xd0,0xe2,0xa5,0x43,0x8d,0xe7,0x02,0xa5,0x44,0x8d,0xe8,0x02,0x4c,0x7e,0x08,
0x18,0xa5,0x43,0x69,0x80,0x85,0x43,0xa5,0x44,0x69,0x00,0x85,0x44,0x60,0xa0,0x7f
};
/*
* Sectors 1 through 3
*
* Rick D. <rldetlefsen@delphi.com> reported:
> MYDOS will store the same info in the boot sector as any other DOS. This is
> because the OS must use it to locate and load DOS into ram.
> Sector 1, byte offset 0-19 hold the useful info. b14=1=DOS;=0=No DOS,
> B15 & 16=sector to start of DOS, B18 & B19=DOS load address, B9= #file buffers,
> B10=drive bits, and B17=Disp to sector link(effectivly, disk density). The
> rest of the stuff is either in DOS(ramdisk config), or Mydos guese, i.e. >720
> sectors, or double sided.
*
*/
char mydosinit453[3*128]={
0x4d,0x03,0x00,0x07,0xe0,0x07,0x4c,0x14,0x07,0x03,0x09,0x01,0xe8,0x1b,0x02,0x04
,0x00,0xfd,0x0a,0x0b,0xac,0x12,0x07,0xad,0x13,0x07,0x20,0x58,0x07,0xad,0x10,0x07
,0xac,0x0f,0x07,0x18,0xae,0x0e,0x07,0xf0,0x1d,0x20,0x63,0x07,0x30,0x18,0xac,0x11
,0x07,0xb1,0x43,0x29,0xff,0x48,0xc8,0x11,0x43,0xf0,0x0e,0xb1,0x43,0x48,0x20,0x4d
,0x07,0x68,0xa8,0x68,0x90,0xdd,0xa9,0xc0,0xa0,0x68,0x0a,0xa8,0x60,0xad,0x11,0x07
,0x18,0x65,0x43,0xa8,0xa5,0x44,0x69,0x00,0x84,0x43,0x85,0x44,0x8c,0x04,0x03,0x8d
,0x05,0x03,0x60,0x8d,0x0b,0x03,0x8c,0x0a,0x03,0xa0,0x03,0xa9,0x52,0x90,0x02,0xa9
,0x50,0x84,0x48,0x8d,0x02,0x03,0x18,0x8c,0x06,0x03,0xa9,0x80,0xca,0xf0,0x0d,0xae
,0x0b,0x03,0xd0,0x07,0xae,0x0a,0x03,0xe0,0x04,0x90,0x01,0x0a,0x8d,0x08,0x03,0x2a
,0x8d,0x09,0x03,0xa0,0x31,0x8c,0x00,0x03,0xc6,0x48,0x30,0x16,0xae,0x02,0x03,0xe8
,0x8a,0xa2,0x40,0x29,0x06,0xd0,0x02,0xa2,0x80,0x8e,0x03,0x03,0x20,0x59,0xe4,0x88
,0x30,0xe6,0xa6,0x2e,0xc8,0x98,0x60,0x10,0x69,0x01,0x00,0x80,0xf6,0x00,0x00,0x00
,0x23,0x28,0x50,0x4d,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x52,0xd2,0xd2
,0xd2,0xd2,0xd2,0xd2,0x5c,0x0c,0x5c,0x0e,0x62,0x0d,0xc6,0x0d,0x50,0x0e,0x67,0x10
,0xa9,0x69,0x8d,0xb8,0x07,0xa9,0x01,0x8d,0xb9,0x07,0xa2,0x08,0x8e,0x01,0x03,0x20
,0xb6,0x0b,0xbd,0xcb,0x07,0x30,0x12,0x20,0x9a,0x0b,0xf0,0x0d,0xbd,0xcb,0x07,0xc9
,0x40,0xb0,0x06,0xbc,0xc3,0x07,0x20,0x24,0x0b,0xca,0xd0,0xe0,0xa0,0xae,0x8a,0x99
,0x55,0x08,0x88,0xd0,0xfa,0xee,0x59,0x08,0xad,0x0c,0x07,0x8d,0xe7,0x02,0xac,0x0d
,0x07,0xa2,0x0f,0xec,0x09,0x07,0x90,0x05,0xde,0xdd,0x08,0x30,0x05,0x98,0x9d,0xed
,0x08,0xc8,0xca,0x10,0xee,0x8c,0xe8,0x02,0xe8,0xe8,0xe8,0xbd,0x18,0x03,0xf0,0x04
,0xc9,0x44,0xd0,0xf4,0xa9,0x44,0x9d,0x18,0x03,0xa9,0xd4,0x9d,0x19,0x03,0xa9,0x07
,0x9d,0x1a,0x03,0x4c,0x79,0x1a,0x00,0x00,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x80
,0xfd,0x00,0x03,0x04,0x00,0x00,0x00,0x00,0x00,0x69,0x01,0x00,0x00,0x00,0x00,0x00
};
char mydosinit450[3*128]={
0x4d,0x03,0x00,0x07,0xe0,0x07,0x4c,0x14,0x07,0x03,0xff,0x01,0xe9,0x1b,0x02,0x04
,0x00,0xfd,0x15,0x0b,0xac,0x12,0x07,0xad,0x13,0x07,0x20,0x58,0x07,0xad,0x10,0x07
,0xac,0x0f,0x07,0x18,0xae,0x0e,0x07,0xf0,0x1d,0x20,0x63,0x07,0x30,0x18,0xac,0x11
,0x07,0xb1,0x43,0x29,0xff,0x48,0xc8,0x11,0x43,0xf0,0x0e,0xb1,0x43,0x48,0x20,0x4d
,0x07,0x68,0xa8,0x68,0x90,0xdd,0xa9,0xc0,0xa0,0x68,0x0a,0xa8,0x60,0xad,0x11,0x07
,0x18,0x65,0x43,0xa8,0xa5,0x44,0x69,0x00,0x84,0x43,0x85,0x44,0x8c,0x04,0x03,0x8d
,0x05,0x03,0x60,0x8d,0x0b,0x03,0x8c,0x0a,0x03,0xa0,0x03,0xa9,0x52,0x90,0x03,0xad
,0x79,0x07,0x84,0x48,0x8d,0x02,0x03,0x18,0xa9,0x57,0x8c,0x06,0x03,0xa9,0x80,0xca
,0xf0,0x0d,0xae,0x0b,0x03,0xd0,0x07,0xae,0x0a,0x03,0xe0,0x04,0x90,0x01,0x0a,0x8d
,0x08,0x03,0x2a,0x8d,0x09,0x03,0xa0,0x31,0x8c,0x00,0x03,0xc6,0x48,0x30,0x16,0xae
,0x02,0x03,0xe8,0x8a,0xa2,0x40,0x29,0x06,0xd0,0x02,0xa2,0x80,0x8e,0x03,0x03,0x20
,0x59,0xe4,0x88,0x30,0xe6,0xa6,0x2e,0xc8,0x98,0x60,0x10,0x71,0x01,0x00,0x80,0xf6
,0x23,0x28,0x50,0x4d,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x12,0xd2,0xd2
,0xd2,0xd2,0xd2,0xd2,0x5c,0x0c,0x5c,0x0e,0x62,0x0d,0xc6,0x0d,0x50,0x0e,0x67,0x10
,0xa9,0x69,0x8d,0xbb,0x07,0xa9,0x01,0x8d,0xbc,0x07,0xa2,0x08,0x8e,0x01,0x03,0x20
,0xb6,0x0b,0xbd,0xcb,0x07,0x30,0x1d,0x20,0x9a,0x0b,0xf0,0x18,0xa0,0x09,0xb9,0x25
,0x0b,0x99,0x02,0x03,0x88,0x10,0xf7,0xbd,0xcb,0x07,0xc9,0x40,0xb0,0x06,0xbc,0xc3
,0x07,0x20,0x2f,0x0b,0xca,0xd0,0xd5,0xa0,0xae,0x8a,0x99,0x60,0x08,0x88,0xd0,0xfa
,0xee,0x64,0x08,0xad,0x0c,0x07,0x8d,0xe7,0x02,0xac,0x0d,0x07,0xa2,0x0f,0xec,0x09
,0x07,0x90,0x05,0xde,0xe8,0x08,0x30,0x05,0x98,0x9d,0xf8,0x08,0xc8,0xca,0x10,0xee
,0x8c,0xe8,0x02,0xe8,0xe8,0xe8,0xbd,0x18,0x03,0xf0,0x04,0xc9,0x44,0xd0,0xf4,0xa9
,0x44,0x9d,0x18,0x03,0xa9,0xd4,0x9d,0x19,0x03,0xa9,0x07,0x9d,0x1a,0x03,0x4c,0x8c
,0x1a,0x00,0x00,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x80,0xfd,0x00,0x03,0x04,0x00
};
char *mydosinit;
if (debug && mydos) {
printf("Mydos version: %d\n",dosver);
}
switch (dosver) {
case 450:
mydosinit=mydosinit450;
break;
case 453:
mydosinit=mydosinit453;
break;
default:
mydosinit=mydosinit450;
if (mydos && dos) {
printf("Warning: Failed to detect MyDOS version, may not boot\n");
}
}
mydosinit[0]='M'; /* Indicate MyDOS 4.5 or later */
mydosinit[1]=3; /* number of sectors in the boot */
mydosinit[9]=3; /* Max number of open files at one time */
mydosinit450[10]=255; /* Ram Disk unit number */
mydosinit453[10]=9; /* Ram Disk unit number */
mydosinit[11]=1; /* Default unit number (D:) */
/* [12],[13]: First byte of free memory */
mydosinit[14]=((secsize==256)?2:1);
mydosinit[15]=4;mydosinit[16]=0; /* DOS.SYS start sector */
mydosinit[17]=secsize-3; /* Offset to the sector link field */
/* [18],[19]: Address to load dos.sys into */
if (dos) {
mydosinit450[18]=21;
mydosinit453[18]=10;
}
/*
* The following seemed to be correct based on experimentation:
*/
mydosinit453[196]=((secsize==256)?2:1);
mydosinit453[368]=secsize-3;
fseek(fout,SEEK(1),SEEK_SET);
fwrite(mydos?mydosinit:dos20init,128,3,fout);
}
/************************************************************************/
/* write_bitmaps() */
/* Write out the free bitmap (VTOC) */
/* I'm a bit clueless on much of this, but it tries to do what I've */
/* observed from real disk images. */
/************************************************************************/
void write_bitmaps(void)
{
char sec360[256] /******** ={
0x02,0xc3,0x02,0xc3,0x02,0x00,0x00,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
}********/;
int i;
int byte,bit;
int free;
for(i=0;i<256;++i)sec360[i]=0;
/*
* We need to clean up the computation of total data sectors.
*
* For non-MyDos>720, we need to take into account the second VTOC
* For MyDos, we need to count 720, but not additional VTOC sectors.
*/
{
int total;
total=seccount-3-9-1; /* Boot, VTOC+DIR, 720 */
if (mydos) {
total=seccount-3-8; /* boot and dir */
total-=(1+(seccount-(943+(secsize-128)*8)+(secsize*8-1))/(secsize*8)); /* VTOC */
}
else if (seccount>720) {
if (total>1023-3-8-1-1) total=1023-3-8-1-1;
}
sec360[2]=(total)/256;
sec360[1]=(total)%256;
}
/*
* Record the number of free sectors
* For DOS2.5, this is the number of free sectors in this VTOC.
*/
free=0;
for(i=0;i<=(mydos?seccount:720);++i) {
if (bitmap[i]==0) ++free;
}
sec360[4]=free/256;
sec360[3]=free%256;
if (debug) {
printf("%d sectors %sfree\n",free,mydos?"":"<720 ");
}
/*
* I'm clueless--is this some sort of version code?
* I think this agrees with how MyDOS and DOS2.5 set this byte.
*/
sec360[0]=2;
if (mydos && seccount>943) sec360[0]+=(seccount-943+(secsize*8-1))/(secsize*8)+1;
/*
* bitmap[i] is true if the sector has been used
*
* The corresponding bit should be one if the sector is *free*
*/
if (!mydos) {
for(i=0;i<720;++i) {
byte=10+i/8;
bit=i%8;
bit=7-bit;
bit=1<<bit;
if(bitmap[i]) {
sec360[byte]&= ~bit;
}
else {
sec360[byte]|=bit;
}
}
/* Write sector 360 */
fseek(fout,SEEK(360),SEEK_SET);
fwrite(sec360,128,1,fout);
if(seccount>720) {
/* Copy most of first VTOC */
for(i=0;i<128-16;++i)sec360[i]=sec360[i+16];
free=0;
for(i=720;i<1024;++i) {
byte=i/8-6;
bit=i%8;
bit=7-bit;
bit=1<<bit;
if(bitmap[i]) {
sec360[byte]&= ~bit;
++free;
}
else {
sec360[byte]|=bit;
}
}
/* Record number of free extended sectors */
sec360[123]=free/256;
sec360[122]=free%256;
fseek(fout,SEEK(1024),SEEK_SET);
fwrite(sec360,128,1,fout);
}
}
else {
for(i=0;i<=943;++i) {
byte=10+i/8;
bit=i%8;
bit=7-bit;
bit=1<<bit;
if(bitmap[i]) {
sec360[byte]&= ~bit;
}
else {
sec360[byte]|=bit;
}
}
/* Write sector 360 */
fseek(fout,SEEK(360),SEEK_SET);
fwrite(sec360,128,1,fout);
if(seccount>943) {
int ss;
int sn=359;
for(ss=944;ss<=seccount;ss+=8*128,--sn) {
for(i=0;i<128;++i)sec360[i]=0;
for(i=0;i<8*128;++i) {
byte=i/8;
bit=i%8;
bit=7-bit;
bit=1<<bit;
if(bitmap[i+ss]) {
sec360[byte]&= ~bit;
}
else {
sec360[byte]|=bit;
}
}
/* Write sector */
{
int s,o;
if (secsize==128) {
s=sn;
o=0;
}
else {
/*
* Hack for DD sectors
*/
s=360-sn;
o=(s&1)*128;
s=s/2;
s=360-s;
}
fseek(fout,SEEK(s)+o,SEEK_SET);
fwrite(sec360,128,1,fout);
}
}
}
}
}
/************************************************************************/
/* afnamecpy() */
/* Convert a Unix filename to an Atari filename. */
/* Return 0 on failure. */
/************************************************************************/
int afnamecpy(char *an,const char *n)
{
int i;
for(i=0;i<11;++i) an[i]=' '; /* Space fill the Atari name */
an[11]=0;
for(i=0;i<8;++i) {
if (!*n) return(1); /* Ok */
if (*n=='.') break; /* Extension */
if (*n==':') return(0); /* Illegal name */
if (upcase) an[i]=toupper(*n);
else an[i]= *n;
++n;
}
if (*n=='.') ++n;
for(i=8;i<11;++i) {
if (!*n) return(1); /* Ok */
if (*n=='.') return(0); /* Illegal name */
if (*n==':') return(0); /* Illegal name */
if (upcase) an[i]=toupper(*n);
else an[i]= *n;
++n;
}
if (*n) return(0); /* Extension too long or more than 11 characters */
return(1);
}

BIN
UTIL/atr2unix Executable file

Binary file not shown.

BIN
UTIL/dcm2atr Executable file

Binary file not shown.

BIN
UTIL/sio2linux Executable file

Binary file not shown.

BIN
UTIL/unix2atr Executable file

Binary file not shown.

BIN
funky.atr Normal file

Binary file not shown.

BIN
test/HELLO.BAS Normal file

Binary file not shown.

57
test/MEMTEST.BAS Normal file
View File

@ -0,0 +1,57 @@
51 REM ATARI RAM TEST PROGRAM
52 REM BY ED STEWART 03/82
53 REM 11025 SAGEBRUSH AVE
54 REM UNIONTOWN OHIO 44685
99 REM SETUP SOME REQUIRED CONSTANTS
100 N1 = 1 : N2 = N1 + N1 : N255 = 255 : N256 = N255 + N1
200 DIM S$(N2) : S$(N1, N1) = CHR$(157) : S$(N2, N2) = CHR$(159)
299 REM READ IN THE MACHINE LANGUAGE PROGRAM
300 GOSUB 2900
399 REM GET LOW AND HIGH MEMORY BOUNDS
400 L = PEEK(15) * N256 : H = PEEK(742) * N256 : IF PEEK(14)< >NO THEN L = L + N256
499 REM DISPLAY BOUNDS AND GET REPLY
500 ? CHR$(125); S$; "ATARI MEMORY TEST PROGRAM"; CHR$(155); S$; "MEMORY
BOUNDS ARE"
600 ? S$; "LOW = "; L : ? S$; "HIGH = "; H
700 ? S$; "GIVE TEST BOUNDS"; CHR$(155)
800 TRAP 800 : ? S$; "LOW = "; : INPUT LOW : IF LOW < L OR LOW > H THEN 800
900 TRAP 900 : ? S$; "HIGH = "; : INPUT HIGH : IF HIGH > H OR HIGH < L OR
HIGH-LOW < N256 THEN 900
999 REM SETUP BOUNDS FOR THE MLP
1000 POKE 205, NO : POKE 206, INT(HIGH/N256)
1100 TRAP 32767 : POKE 203, NO : POKE 204, INT(LOW/N256)
1200 POKE 764, N255
1299 REM INVOKE THE MLP TO DO THE TEST
1300 POKE 559, NO : POKE 764, N255 : X = USR(1536)
1399 REM CHECK RETURN FROM MLP
1400 IF PEEK(208) = NO THEN 2200
1499 REM SHOW MEMORY ERROR ON SCREEN
1500 ? " ERROR AT "; (PEEK(203) + PEEK(204) * N256); " EXP =
"; PEEK(207); " ACT = "; PEEK(209)
1600 SOUND NO, PASS, 6, 8 : FOR I = N1 TO 5 : NEXT I : SOUND NO, NO, NO, NO
1699 REM SETUP NEXT BYTE TO TEST SO WE DONT STOP WITH FIRST ERROR
1700 IF PEEK(203) = N255 THEN POKE 204, (PEEK(204) + N1) : POKE 203, NO : GOTO 1900
1800 POKE 203, (PEEK(203) + N1)
1900 POKE 764, N255 : POKE 559, 34
1999 REM CONTINUE ONLY IF KEY PRESSED
2000 IF PEEK(764) = N255 THEN 2000
2099 REM CONTINUE TESTING BAD RANGE
2100 GOTO 1300
2199 REM GOOD TEST PASS SO SAY SO
2200 PASS = PASS + N1 : ? " GOOD PASS NUMBER "; PASS : SOUND NO, PASS, 10, 8
2300 FOR I = N1 TO 5 : NEXT I : SOUND NO, NO, NO, NO
2399 REM STOP AND DISPLAY STUFF IF KEY IS PRESSED
2400 IF PEEK(764)< >N255 THEN 2600
2499 REM CONTINUE WITH NEXT PASS
2500 GOTO 1100
2600 POKE 764, N255
2699 REM WAIT HERE UNTIL A KEY IS PRESSED
2700 POKE 559, 34 : IF PEEK(764) = N255 THEN 2700
2799 REM CONTINUE WITH NEXT PASS
2800 GOTO 1100
2899 REM READ IN MACHINE LANGUAGE PROGRAM
2900 FOR L = 1536 TO 1576 : READ H : POKE L, H : NEXT L : RETURN
3000 DATA 104, 169, 0, 160, 0, 24, 145, 203, 209, 203, 208, 18, 105,
1, 208, 246, 200, 208, 242, 230, 204, 166, 204, 228, 206
3100 DATA 208, 234, 133, 208, 96, 133, 207, 177, 203, 133, 209, 169,
1, 133, 208, 96

57
test/MEMTEST2.BAS Normal file
View File

@ -0,0 +1,57 @@
51 REM ATARI RAM TEST PROGRAM
52 REM BY ED STEWART 03/82
53 REM 11025 SAGEBRUSH AVE
54 REM UNIONTOWN OHIO 44685
99 REM SETUP SOME REQUIRED CONSTANTS
100 N1 = 1 : N2 = N1 + N1 : N255 = 255 : N256 = N255 + N1
200 DIM S$(N2) : S$(N1, N1) = CHR$(157) : S$(N2, N2) = CHR$(159)
299 REM READ IN THE MACHINE LANGUAGE PROGRAM
300 GOSUB 2900
399 REM GET LOW AND HIGH MEMORY BOUNDS
400 L = PEEK(15) * N256 : H = PEEK(742) * N256 : IF PEEK(14)< >NO THEN L = L + N256
499 REM DISPLAY BOUNDS AND GET REPLY
500 ? CHR$(125); S$; "ATARI MEMORY TEST PROGRAM"; CHR$(155); S$; "MEMORY
BOUNDS ARE"
600 ? S$; "LOW = "; L : ? S$; "HIGH = "; H
700 ? S$; "GIVE TEST BOUNDS"; CHR$(155)
800 TRAP 800 : ? S$; "LOW = "; : INPUT LOW : IF LOW < L OR LOW > H THEN 800
900 TRAP 900 : ? S$; "HIGH = "; : INPUT HIGH : IF HIGH > H OR HIGH < L OR
HIGH-LOW < N256 THEN 900
999 REM SETUP BOUNDS FOR THE MLP
1000 POKE 205, NO : POKE 206, INT(HIGH/N256)
1100 TRAP 32767 : POKE 203, NO : POKE 204, INT(LOW/N256)
1200 POKE 764, N255
1299 REM INVOKE THE MLP TO DO THE TEST
1300 POKE 559, NO : POKE 764, N255 : X = USR(1536)
1399 REM CHECK RETURN FROM MLP
1400 IF PEEK(208) = NO THEN 2200
1499 REM SHOW MEMORY ERROR ON SCREEN
1500 ? " ERROR AT "; (PEEK(203) + PEEK(204) * N256); " EXP =
"; PEEK(207); " ACT = "; PEEK(209)
1600 SOUND NO, PASS, 6, 8 : FOR I = N1 TO 5 : NEXT I : SOUND NO, NO, NO, NO
1699 REM SETUP NEXT BYTE TO TEST SO WE DONT STOP WITH FIRST ERROR
1700 IF PEEK(203) = N255 THEN POKE 204, (PEEK(204) + N1) : POKE 203, NO : GOTO 1900
1800 POKE 203, (PEEK(203) + N1)
1900 POKE 764, N255 : POKE 559, 34
1999 REM CONTINUE ONLY IF KEY PRESSED
2000 IF PEEK(764) = N255 THEN 2000
2099 REM CONTINUE TESTING BAD RANGE
2100 GOTO 1300
2199 REM GOOD TEST PASS SO SAY SO
2200 PASS = PASS + N1 : ? " GOOD PASS NUMBER "; PASS : SOUND NO, PASS, 10, 8
2300 FOR I = N1 TO 5 : NEXT I : SOUND NO, NO, NO, NO
2399 REM STOP AND DISPLAY STUFF IF KEY IS PRESSED
2400 IF PEEK(764)< >N255 THEN 2600
2499 REM CONTINUE WITH NEXT PASS
2500 GOTO 1100
2600 POKE 764, N255
2699 REM WAIT HERE UNTIL A KEY IS PRESSED
2700 POKE 559, 34 : IF PEEK(764) = N255 THEN 2700
2799 REM CONTINUE WITH NEXT PASS
2800 GOTO 1100
2899 REM READ IN MACHINE LANGUAGE PROGRAM
2900 FOR L = 1536 TO 1576 : READ H : POKE L, H : NEXT L : RETURN
3000 DATA 104, 169, 0, 160, 0, 24, 145, 203, 209, 203, 208, 18, 105,
1, 208, 246, 200, 208, 242, 230, 204, 166, 204, 228, 206
3100 DATA 208, 234, 133, 208, 96, 133, 207, 177, 203, 133, 209, 169,
1, 133, 208, 96

52
test/MEMTEST3.BAS Normal file
View File

@ -0,0 +1,52 @@
51 REM ATARI RAM TEST PROGRAM
52 REM BY ED STEWART 03/82
53 REM 11025 SAGEBRUSH AVE
54 REM UNIONTOWN OHIO 44685
99 REM SETUP SOME REQUIRED CONSTANTS
100 N1 = 1 : N2 = N1 + N1 : N255 = 255 : N256 = N255 + N1
200 DIM S$(N2) : S$(N1, N1) = CHR$(157) : S$(N2, N2) = CHR$(159)
299 REM READ IN THE MACHINE LANGUAGE PROGRAM
300 GOSUB 2900
399 REM GET LOW AND HIGH MEMORY BOUNDS
400 L = PEEK(15) * N256 : H = PEEK(742) * N256 : IF PEEK(14) <> NO THEN L = L + N256
499 REM DISPLAY BOUNDS AND GET REPLY
500 ? CHR$(125); S$; "ATARI MEMORY TEST PROGRAM"; CHR$(155); S$; "MEMORY BOUNDS ARE "
600 ? S$; "LOW = "; L : ? S$; "HIGH = "; H
700 ? S$; "GIVE TEST BOUNDS"; CHR$(155)
800 TRAP 800 : ? S$; "LOW = "; : INPUT LOW : IF LOW < L OR LOW > H THEN 800
900 TRAP 900 : ? S$; "HIGH = "; : INPUT HIGH : IF HIGH > H OR HIGH < L OR HIGH-LOW < N256 THEN 900
999 REM SETUP BOUNDS FOR THE MLP
1000 POKE 205, NO : POKE 206, INT(HIGH/N256)
1100 TRAP 32767 : POKE 203, NO : POKE 204, INT(LOW/N256)
1200 POKE 764, N255
1299 REM INVOKE THE MLP TO DO THE TEST
1300 POKE 559, NO : POKE 764, N255 : X = USR(1536)
1399 REM CHECK RETURN FROM MLP
1400 IF PEEK(208) = NO THEN 2200
1499 REM SHOW MEMORY ERROR ON SCREEN
1500 ? " ERROR AT "; (PEEK(203) + PEEK(204) * N256); " EXP = "; PEEK(207); " ACT = "; PEEK(209)
1600 SOUND NO, PASS, 6, 8 : FOR I = N1 TO 5 : NEXT I : SOUND NO, NO, NO, NO
1699 REM SETUP NEXT BYTE TO TEST SO WE DONT STOP WITH FIRST ERROR
1700 IF PEEK(203) = N255 THEN POKE 204, (PEEK(204) + N1) : POKE 203, NO : GOTO 1900
1800 POKE 203, (PEEK(203) + N1)
1900 POKE 764, N255 : POKE 559, 34
1999 REM CONTINUE ONLY IF KEY PRESSED
2000 IF PEEK(764) = N255 THEN 2000
2099 REM CONTINUE TESTING BAD RANGE
2100 GOTO 1300
2199 REM GOOD TEST PASS SO SAY SO
2200 PASS = PASS + N1 : ? " GOOD PASS NUMBER "; PASS : SOUND NO, PASS, 10, 8
2300 FOR I = N1 TO 5 : NEXT I : SOUND NO, NO, NO, NO
2399 REM STOP AND DISPLAY STUFF IF KEY IS PRESSED
2400 IF PEEK(764) <> N255 THEN 2600
2499 REM CONTINUE WITH NEXT PASS
2500 GOTO 1100
2600 POKE 764, N255
2699 REM WAIT HERE UNTIL A KEY IS PRESSED
2700 POKE 559, 34 : IF PEEK(764) = N255 THEN 2700
2799 REM CONTINUE WITH NEXT PASS
2800 GOTO 1100
2899 REM READ IN MACHINE LANGUAGE PROGRAM
2900 FOR L = 1536 TO 1576 : READ H : POKE L, H : NEXT L : RETURN
3000 DATA 104, 169, 0, 160, 0, 24, 145, 203, 209, 203, 208, 18, 105, 1, 208, 246, 200, 208, 242, 230, 204, 166, 204, 228, 206
3100 DATA 208, 234, 133, 208, 96, 133, 207, 177, 203, 133, 209, 169, 1, 133, 208, 96

BIN
test/P32P1.BAS Normal file

Binary file not shown.

BIN
test/P33P1.BAS Normal file

Binary file not shown.

BIN
test/P34P1.BAS Normal file

Binary file not shown.

BIN
test/P34P2.BAS Normal file

Binary file not shown.

BIN
test/TEST.BAS Normal file

Binary file not shown.