From 852d3a1b67b7e148c823b0ccd6b1b1a30f9cdf1c Mon Sep 17 00:00:00 2001 From: Greg Gauthier Date: Thu, 6 Jul 2023 19:23:21 +0100 Subject: [PATCH] testing disk generator --- FDISK/BOOTDISK2.atr | Bin 0 -> 736912 bytes FDISK/test.atr | Bin 0 -> 92176 bytes SRC/atr2unix-1.3.c | 362 +++++++++++ SRC/dcmtoatr-1.4.c | 476 +++++++++++++++ SRC/sio2linux-3.1.0.c | 1347 +++++++++++++++++++++++++++++++++++++++++ SRC/unix2atr-0.9.c | 925 ++++++++++++++++++++++++++++ UTIL/atr2unix | Bin 0 -> 22088 bytes UTIL/dcm2atr | Bin 0 -> 22384 bytes UTIL/sio2linux | Bin 0 -> 35624 bytes UTIL/unix2atr | Bin 0 -> 26512 bytes funky.atr | Bin 0 -> 183952 bytes test/HELLO.BAS | Bin 0 -> 54 bytes test/MEMTEST.BAS | 57 ++ test/MEMTEST2.BAS | 57 ++ test/MEMTEST3.BAS | 52 ++ test/P32P1.BAS | Bin 0 -> 460 bytes test/P33P1.BAS | Bin 0 -> 751 bytes test/P34P1.BAS | Bin 0 -> 498 bytes test/P34P2.BAS | Bin 0 -> 1280 bytes test/TEST.BAS | Bin 0 -> 53 bytes 20 files changed, 3276 insertions(+) create mode 100644 FDISK/BOOTDISK2.atr create mode 100644 FDISK/test.atr create mode 100644 SRC/atr2unix-1.3.c create mode 100644 SRC/dcmtoatr-1.4.c create mode 100644 SRC/sio2linux-3.1.0.c create mode 100644 SRC/unix2atr-0.9.c create mode 100755 UTIL/atr2unix create mode 100755 UTIL/dcm2atr create mode 100755 UTIL/sio2linux create mode 100755 UTIL/unix2atr create mode 100644 funky.atr create mode 100644 test/HELLO.BAS create mode 100644 test/MEMTEST.BAS create mode 100644 test/MEMTEST2.BAS create mode 100644 test/MEMTEST3.BAS create mode 100644 test/P32P1.BAS create mode 100644 test/P33P1.BAS create mode 100644 test/P34P1.BAS create mode 100644 test/P34P2.BAS create mode 100644 test/TEST.BAS diff --git a/FDISK/BOOTDISK2.atr b/FDISK/BOOTDISK2.atr new file mode 100644 index 0000000000000000000000000000000000000000..4100fdedc29e9d2e2b8ce5395f8dbd889d74e46c GIT binary patch literal 736912 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 XElP)EK95)<%(l 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 z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL rKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#~E9}D~!ARoA; literal 0 HcmV?d00001 diff --git a/FDISK/test.atr b/FDISK/test.atr new file mode 100644 index 0000000000000000000000000000000000000000..450768127fbab0c074ae987677da9655544cc8a8 GIT binary patch literal 92176 zcmeI2U2I!NcE{(6*Cu^U>w}_b*^=y${2?ip9g&nM$#!C0kyj$u6v^c!Eo=K?XD!EW zVmYuCG-!KwCC6Sn8#~y2Xb^x1AQ*9B1#z%h1nonCv_-K%x{EA=EzqZ;Xp5i?`ch*b zivsEY%)O*2C+TLLM11HWAaTCu%x}(|Ih>i-o0cQXqVD4p{>hGP*zfa+Kiw^K;rz<~ zPP6}E;z7uNBY8*nJ!tpeNZr}ud(i5Cr^Vm-ZnIxL?;qazPMiO|13o$bNo&uqKMM_a-kn@4e$?c9 zxNWVMzMAeXzvlC0@A}`>+8_9QXWkBkw|`*#YMa>p=i4Fk1H*skA43m<7{-GgUOd=- z*ZEwIUs^x@ zw|mJu|Iu_Wb?4Kj><)0wSwF#7t;Hqfb~H(1am&?2s*6(pEN`kA%h6tsN1u z91ibl38oWARqBx`(~i{5-`5K!Mx(N5%}TRm7BjMF&dQQymt>)spFzYJjj7zJd1hqPMW!t zOlM}&a@Ly77w6?vzMMxTscWiWNGZEYm9ikr!saSYgT(xLXbd3tB{>HM$z{PpwPEDL?bpjcnp+|$v#&N zJVEO9gT&=8I%8>MN$0W_7)n_DB+bj|;V=nv+?_$y6)D5S27UK1O`{2=QF_qH7D&~HWg&mk zlCj}Y=wcoMdC|lW##I`i=AWeL9W=1sJmKT9vBcPV(fG!iBW_K|RINzsLNz;^ zB~L>0O66isP8ajDa+XGo1)w)OG*?RhW5eUL2CGUPgSaSD#g_(KPc5xt5&ZHwX(x-8 zl{2EQHup(4!z_`)4R~$F2eB}`@JMwfLEBOKH0)1{^OQS*sN$6xQ@LicM9G2p9~~f zJ}*;mbE;}HlSjW%QrRf2Fs}e|tF;wL)HbNlBZ^dQQRzl}1Vy}ggFP>0a%BtCm7OP9 zPg?V^o0e@`DHv)!N$fSw}iRhh}> zQ{IM#*&?DgOro7PNV_nDdb@*U7+}ivHkT974OLGi=E}2ER*^JHMeC>2ReCpLGWI$&+Bd3`PQ+*NMqjCp z(l8R*h|!86TzZEi$)Ffi?~yr0nkUk;Vxmr6-`=uWBeoVWtnhe?)$rjO)!j?}PtE!x?>Z`uf z$qvD!!;7HhN4u13rVPv{ya;TEGCGVUg!MWkG1IUC>N`ehBQVynVJs1-Xe~634Elp5 zcP$G%512Om8-cBW+SQ_PJM>NmnnNk74^;r6Sd7XKCyY4hwUWYZB2LBPsz;QVKzT1V zhR_)PDRI0s$V6h-q^PfGxL%_!{^-B{>aQE;0tR+F@B$m>0tUJq*F9{I3mE7o``0)Z zFwo<8Ze3$sz`!0yrj5qAfPuXZJW4Vbjd1}3(!uYF#<_rjUI$)a<6OW%pHsh`ZMq8> z*yq3tY@7=i*zaJ&X`BlfIN-QjhWgF1`7U7KphG{`H##&My@hYp1q}2%u3y(67cek@ z@mGH)HNXW73_8l~Z>LBnj&i$$$UvR|n4q7(%+^_2K1xIoI)_`-r>ghl*;S6lL(?=ekI?%DK;Fxm~ z0&M1y-v(zdIPPrrk>7^%zTkwj*++gGoW0;tXS0v|Hk|hbk2!Row3$bK8_xTJ$DPMH z@>90|anJnf5B!2pIdtYAN+(!a@!Aaj2-x3GKS!8IfTAMbgz1{RdlbK54aQ+{%x$;NZ9R4BKyzysL zS)20pU%+=0MFj4t_w5tjEioOh7K*s1l3BVRb&t&LN?7dLCFn>SC)1gtbepy(+a>UHSl019v+?9o^SLNmN^8CdsSC{1T7Z(>QF>&BPV)^j&(PmRipwFQL zDmX^L{mo|6DFhB54lCKq44^vuGQ%CzY1O{}2yGSyo?&^)Q3d|l0g=xI$l zJ)*RL4$oh{A{Q3VkpzV+m!G|I_EP10BGlqv>1%ce-WBSIoKu6oa&d7ZQQe0LCB8fNNdWuCid)kl)>V{OCEyT zA`$_DWp4xu{!rv~JQ6UPCtslPRG$Z=Vn++{SRs0(lt1~Ep9i#xGMdn~Xj`?2_L1*j zeRx~&i@!&bx$;wLT$`kPJW!wsJ16@3K0oDjUx+TPoGmeUD8*bllT6DgYX;ZmXfBha zp_i;#3%B~R@)8xPPS-QxX=mZti;IgF7oR2aFSz7o<=R)7`P(E<^1|80XBXtvrL#*5 zmliNFOAA*nU0gi7g!!zzE_UwROEbTPMiFYB?4$3uw?%t9#!5O}9o+k9EUGE?6i?Z^e*tu=* za%d&&3ZqlK&`RVtA`(tJetjhz5e21GUip8*$`IwnbC+FxKEJSVPF_4O7x9fy<=;gQ z^s?8}=dK+NIO9z2 zqMBX3dz&Y(Q3#Ym^c{{L_CiQeD<`6BZmr1)DzKr-{#q3ks#R&${Qhk#kxs3*R}@}c zs;({h%-QchCzmdVzvIZo%U3R)eO^}jw0$k0Qbnyr1@^huLie`c|0 z&gaZo>%Lur3eHgQEzdIl?YanRQm|Ap$|kh4;tNt+Lg?l-AC*!{FT^=<b9i?E+YTw2Jhu(JP9IQgM1Up(nr|<-6qcE^^2M(wXlWDVvJ9%8isvU*y z$LYG&!uC>G6|UzXncb?N7JbmV9FdrvH*CVeJ7J#e*MKo5jy6Jh9qn_txfvDJ(Fz3;%Julu`> zifr?eylX+R-HmJ5y9Az6!MNikmsG;Rnv+h-N|R`94KJ_jhEMeO*A*rWF$+*+?0J|Z zw-z=4os65iN6clqi%vERp7ipI?5}Eg3+dm=y8f-JVq~l6*%}J>c*dH#sOk(__KQSI z;ue;@(*AHlcz5^E&h=8?DMNE=L+Z92D^&@=vWrYEnJuSC05#10va*fldp=(-%Br6; zOYf=F#-?t=u_MCvs~|4J%^aSTn6m{eCiF<}Rp1t3F`<#N?Y^tQ(~%m?V!m9;be9}B zOxP3$TEn!=Byk@K4=DKlHPpa%cr>kTPu067!HB;1?$k!y~W=NQ?lqri_< zO81bnMLl+Z&k4O6 zxuyI4#`Q-`WQ_LbZ+mm@7JDE??fq^4m%P7iZ{O9j9q(_+B7dV|NkNLjA11&Am;e)C z0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C z0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C z0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C z0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%n85!_ z0!@F{^jy=UBX9ZacYVYUe^-gR{70Lwk56kt7ilY-%}Xh#OnW*kwuo74wq)5QFTSf9 zkGc7WtMNF+bzzD^JXVN$_5H#^JYI|IB8&J)Exuh8R6ORD*Tf$P)tMWwmyN?rfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G zCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@G cCcp%k025#WOn?b60Vco%m;e)C0!-k40SaCQc>n+a literal 0 HcmV?d00001 diff --git a/SRC/atr2unix-1.3.c b/SRC/atr2unix-1.3.c new file mode 100644 index 0000000..d8386e4 --- /dev/null +++ b/SRC/atr2unix-1.3.c @@ -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 */ +/* Initial public release */ +/* 20 Dec 95 Version 1.1 Chad Wagner */ +/* Ported to MS-DOS machines */ +/* 10 Feb 98 Version 1.2 Preston Crow */ +/* 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 +#include +#include +#include +#include +#include + +#ifdef MSDOS +#include +#include +#else +#include +#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); +} diff --git a/SRC/dcmtoatr-1.4.c b/SRC/dcmtoatr-1.4.c new file mode 100644 index 0000000..0f22bda --- /dev/null +++ b/SRC/dcmtoatr-1.4.c @@ -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 +#include + +/* 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> 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 + * + * This is Floppy EMULator - it will turn your linux machine into + * atari 800's floppy drive. Copyright 1997 Pavel Machek + * distribute under GPL. + */ + + +/* + * Standard include files + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +/* + * Data structures + */ +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]; +}; + +enum seekcodes { + xfd, /* This is a xfd (raw sd) image */ + atr, /* This is a regular ATR image */ + atrdd3, /* This is a dd ATR image, including the first 3 sectors */ + direct /* This is a directory pretending to be a disk image */ +}; + +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 trackformat { + int offset[18]; /* sector offset from start: offset[i]==i*100 if no skew */ + int bad[18]; /* Only set with special SIO2Linux command */ +}; + +struct image { + int secsize; /* 128 or 256 */ + int seccount; /* 720, 1040, or whatever */ + enum seekcodes seekcode;/* Image type */ + int diskfd; /* file descriptor */ + int ro; /* non-zero if read-only */ + int active; /* non-zero if Linux is responding for this disk */ + int fakewrite; /* non-zero if writes are accepted but dropped */ + int blank; /* non-zero if disk can grow as needed */ + /* + * Stuff for directories as virtual disk images + */ + DIR *dir; /* NULL if not a directory */ + int filefd; /* fd of open file in directory */ + int afileno; /* afileno (0-63) of open file */ + int secoff; /* sector offset of open file */ + char *dirname; /* directory name, used to append filenames */ + /* + * Stuff for real disks, so that we can analyze the format + */ + int lastsec; /* last sector read for real disks */ + int prevsec; /* sector before last for real disks */ + struct timeval lasttime;/* time that lastsec[] was read */ + struct trackformat track[40]; /* format information derived from observations */ +}; + +/* + * Prototypes + */ +static void err(const char *s); +static void raw(int fd); +static void ack(unsigned char c); +static void senddata(int disk,int sec); +static void sendrawdata(unsigned char *buf,int size); +static void recvdata(int disk,int sec); +static int get_atari(void); +void getcmd(unsigned char *buf); +static void loaddisk(char *path,int disk); +int firstgood(int disk,int sec); +void addtiming(int disk,int sec); +static void decode(unsigned char *buf); +void write_atr_head(int disk); +void snoopread(int disk,int sec); +int afnamecpy(char *an,const char *n); + +/* + * Macros + */ +#define SEEK(n,i) (disks[disk].seekcode==xfd)?SEEK0(n,i):((disks[i].seekcode=atr)?SEEK1(n,i):SEEK2(n,i)) +#define SEEK0(n,i) ((n-1)*disks[i].secsize) +#define SEEK1(n,i) (ATRHEAD + ((n<4)?((n-1)*128):(3*128+(n-4)*disks[i].secsize))) +#define SEEK2(n,i) (ATRHEAD + ((n-1)*disks[i].secsize)) +#define ATRHEAD 16 +#define MAXDISKS 8 +#define TRACK18(n) (((n)-1)/18) /* track of sector 'n' if 18 sectors per track (0-39) */ +#define OFF18(n) (((n)-1)%18) /* offset of sector 'n' in track (0-17) */ +#define TRACKSTART(n) ((((n)-1)/18)*18+1) +#define RPM(_uspr) (60*1000*1000/_uspr) /* microseconds for one revolution -> RPMs */ +#define RPM3(_uspr) ((int)((60*1000ull*1000ull*1000ull/_uspr)%1000ull)) /* Fractional RPMS to 3 decimal points */ +/* + * Default Timings from SIO2PC: + * Time before first ACK: 85us + * Time before second ACK: 1020us + * Time before COMPLETE: 255us + * Time after COMPLETE: 425us + */ +#define ACK1 2000 /* Atari may wait 650-950us to raise the command line; device permitted 0-16ms */ +#define ACK2 1020 /* 850ms min */ +#define COMPLETE1 500 /* 250 is the min, but add more for transmission delays */ +#define COMPLETE2 425 + +/* + * Global variables + */ +struct image disks[MAXDISKS]; +int atari; /* fd of the serial port hooked up to the SIO2PC cable */ +/* Config options */ +int snoop; /* If true, display detailed data on unmapped drives */ +int quiet; /* If true, don't display per-I/O data */ +int noring; /* If true, the serial port ring detect doesn't work */ +char *serial; +int uspr=208333; /* microseconds per revolution, default for 288 RPM */ +int speed=19200; /* Baud rate */ + +/* + * main() + * + * Read the command line, open the disk images, connect to the Atari, + * and listen for commands. + * + * This never terminates. + */ +int main(int argc,char *argv[]) +{ + int i; + int numdisks=0; + + /* + * Parse command-line options + */ +#define USAGE \ + "Options:\n" \ + " -r next parameter is read-only image\n"\ + " -f next parameter is image, fake accepting writes (no change to image)\n"\ + " -s next parameter is serial device to use (default: /dev/ttyS0)\n"\ + " -b next parameter is blank single-density image to create\n" \ + " -B next parameter is blank double-density image to create\n" \ + " -x skip next drive image\n" \ + " -n no ring detect on serial port (some USB converters)\n" \ + " disk image to mount as next disk (D1 through D8 in order)\n" \ + " directory to mount as next disk\n" + + if (argc==1) { + fprintf(stderr,"SIO2Linux: The Atari floppy drive emulator\n"); + fprintf(stderr,USAGE); + fprintf(stderr,"Example:\n %s boot.atr -x -b d3.atr\n(D1: is boot.atr, D2: is ignored, D3: is a new blank image)\n",argv[0]); + exit(1); + } + + setvbuf(stdout,NULL,_IONBF,0); + setvbuf(stderr,NULL,_IONBF,0); + + memset(disks,0,sizeof(disks)); + for(i=0;i=4+64*5 && i!=720 && (i<360 || i>368)) { + buf[byte]|=bit; + } + } + sendrawdata(buf,size); + return; + } + if ( sec>=361 && sec<=368 ) { /* Create directory */ + rewinddir(disks[disk].dir); + readdir(disks[disk].dir); + readdir(disks[disk].dir); + for(i=0;i<8*(sec-361);++i) { + if (!readdir(disks[disk].dir)) { + sendrawdata(buf,size); + return; + } + } + for(i=0;i<8;++i) { + int start; + int count; + int fn; + struct stat sb; + struct atari_dirent ad; + + de=readdir(disks[disk].dir); + fn=(sec-361)*8+i; + start=4+fn*5; + if ( de ) { + memset(&ad,0,sizeof(ad)); + strcpy(path,disks[disk].dirname); + strcat(path,"/"); + strcat(path,de->d_name); + r=stat(path,&sb); + count=(sb.st_size+125)/125; + ad.countlo=count%256; + ad.counthi=count/256; + ad.startlo=start%256; + ad.starthi=start/256; + ad.flag=0x80; /* If unable to convert name, deleted file */ + if ( !r && afnamecpy(ad.namelo,de->d_name) ) { + ad.flag=0x42; + } + memcpy(buf+16*i,&ad,sizeof(ad)); + } + else break; + } + sendrawdata(buf,size); + return; + } + if ( sec>=4 && sec<4+64*5 ) { /* send file data */ + int fn; + int off; + off_t seekto; + + fn=(sec-4)/5; + off=sec-4-fn*5; + if ( off ) { + /* This file had better be open already */ + if ( fn != disks[disk].afileno ) { + if ( !quiet ) printf("-no data-"); + memset(buf,0,size); + sendrawdata(buf,size); + return; + } + seekto=(disks[disk].secoff+off)*125; + } + else { + if ( disks[disk].afileno ) close(disks[disk].afileno); + disks[disk].secoff=0; + disks[disk].afileno=fn; + rewinddir(disks[disk].dir); + readdir(disks[disk].dir); + readdir(disks[disk].dir); + for(i=0;i<=fn;++i) de=readdir(disks[disk].dir); + strcpy(path,disks[disk].dirname); + strcat(path,"/"); + strcat(path,de->d_name); + disks[disk].filefd=open(path,O_RDONLY); + seekto=0; + } + r=lseek(disks[disk].filefd,seekto,SEEK_SET); + if ( r<0 ) { + if ( !quiet ) printf("-lseek errno %d-",errno); + memset(buf,0,size); + sendrawdata(buf,size); + return; + } + r=read(disks[disk].filefd,buf,125); + buf[125]=fn<<2; + buf[126]=sec+1; + if ( off==4 ) { + buf[126] -= 4; + disks[disk].secoff+=4; + } + buf[127]=r; + if ( r<125 ) { + buf[126]=0; + } + sendrawdata(buf,size); + return; + } + memset(buf,0,size); + sendrawdata(buf,size); + return; +} + +static void senddata(int disk,int sec) +{ + unsigned char buf[256]; + int size; + off_t check,to; + int i; + + if ( disks[disk].dir ) { + senddirdata(disk,sec); + return; + } + size=disks[disk].secsize; + if (sec<=3) size=128; + + if ( sec > disks[disk].seccount ) { + memset(buf,0,size); + } + else { + to=SEEK(sec,disk); + check=lseek(disks[disk].diskfd,to,SEEK_SET); + if (check!=to) { + if (errno) perror("lseek"); + fprintf(stderr,"lseek failed, went to %ld instead of %ld\n",check,to); + exit(1); + } + /* printf("-%d-",check); */ + i=read(disks[disk].diskfd,buf,size); + if (i!=size) { + if (i<0) perror("read"); + fprintf(stderr,"Incomplete read\n"); + exit(1); + } + } + sendrawdata(buf,size); +} + +static void sendrawdata(unsigned char *buf,int size) +{ + int i, sum = 0; + int c=0; + struct timeval t1,t2; + int usecs,expected; + + /* + * Compute checksum + */ + for( i=0; i>8); + } + + + gettimeofday(&t1,NULL); + /* + * Send buffer; let the port queue as much as it can handle + */ + for( i=0; i> 8); + } + read(atari,&i,1); + if ((i & 0xff) != (sum & 0xff) && !quiet) printf( "[BAD SUM]" ); + else if (disks[disk].fakewrite) { + if ( !quiet) printf("[write discarded]"); + } + else { + lseek(disks[disk].diskfd,SEEK(sec,disk),SEEK_SET); + i=write(disks[disk].diskfd,mybuf,size); + if (i!=size) if ( !quiet) printf("[write failed: %d]",i); + if ( disks[disk].blank && sec>disks[disk].seccount ) { + disks[disk].seccount=sec; + write_atr_head(disk); + } + } + if ( !quiet) printf("-%d bytes+sum recvd-",size); +} + +void snoopread(int disk,int sec) +{ + int i, sum = 0; + unsigned char mybuf[ 2048 ]; + int size; + int r; + + size=disks[disk].secsize; + if (sec<=3 || size<128 ) size=128; + r=read(atari,&i,1); + if ( r!=1 ) { + fprintf(stderr,"snoop read failed\n"); + return; + } + if ( !quiet ) printf("[%c]",i); + if ( i!='A' ) { + return; + } + r=read(atari,&i,1); + if ( r!=1 ) { + fprintf(stderr,"snoop read failed\n"); + return; + } + if ( !quiet ) printf("[%c]",i); + if ( i!='C' ) { + return; + } + for( i=0; i> 8); + } + read(atari,&i,1); + if ((i & 0xff) != (sum & 0xff)) { + if (!quiet) printf( "[BAD SUM]" ); + return; + } +} + +void write_atr_head(int disk) +{ + struct atr_head buf; + int paragraphs; + + lseek(disks[disk].diskfd,0,SEEK_SET); + + memset(&buf,0,sizeof(buf)); + buf.h0=0x96; + buf.h1=0x02; + paragraphs=disks[disk].seccount*(disks[disk].secsize/16) - (disks[disk].secsize-128)/16; + buf.seccountlo=(paragraphs&0xff); + buf.seccounthi=((paragraphs>>8)&0xff); + buf.hiseccountlo=((paragraphs>>16)&0xff); + buf.hiseccounthi=((paragraphs>>24)&0xff); + buf.secsizelo=(disks[disk].secsize&0xff); + buf.secsizehi=((disks[disk].secsize>>8)&0xff); + write(disks[disk].diskfd,&buf,16); +} + +/* + * get_atari() + * + * Open the serial device and return the file descriptor. + * It assumes that it is /dev/ttyS0 unless there's a symlink + * from /dev/mouse to that, in which case /dev/ttyS1 is used. + */ +static int get_atari(void) +{ + int fd; + struct stat stat_mouse,stat_tty; + + if (stat("/dev/mouse",&stat_mouse)==0) { + stat(serial,&stat_tty); + if (stat_mouse.st_rdev==stat_tty.st_rdev) { + printf("/dev/ttyS0 is the mouse, using ttyS1\n"); + serial="/dev/ttyS1"; + } + } + + fd = open(serial,O_RDWR); + if (fd<0) { + fprintf(stderr,"Can't open %s\n",serial); + exit(1); + } + raw(fd); /* Set up port parameters */ + return(fd); +} + +/* + * getcmd() + * + * Read one 5-byte command + * + * The Atari will activate the command line while sending + * the 5-byte command. + */ +void getcmd(unsigned char *buf) +{ + int i,r; + + /* + * Clear RTS (override hw flow control) + * [Necessary to get some of the cables to work.] + * See: http://www.atarimax.com/flashcart/forum/viewtopic.php?p=2426 + */ + i = TIOCM_RTS; + if ( ioctl(atari, TIOCMBIC, &i) < 0 ) + { + perror("ioctl(TIOCMBIC) failed"); + } + + /* + * Wait for a command + */ + if ( !noring && ioctl(atari,TIOCMIWAIT,TIOCM_RNG) < 0 ) /* Wait for a command */ + { + perror("ioctl(TIOCMIWIAT,TIOCM_RNG) failed"); + } + + if ( tcflush(atari,TCIFLUSH) < 0 ) /* Clear out pre-command garbage */ + { + perror("tcflush(TCIFLUSH) failed"); + } + + /* + * Read 5 bytes + * This should take 2.6ms. *** FIXME *** set an alarm + * Use setitimer(ITIMER_REAL,(struct itimerval),NULL) + */ + i=0; + while (1) { + for ( ; i<5; ++i ) + { + r=read(atari,buf+i,1); + if ( r <=0 ) + { + perror("read from serial port failed"); + fprintf(stderr,"read returned %d\n",r); + exit(1); + } + } + + /* + * Compute the checksum + */ + { + int sum=0; + + for(i=0;i<4;++i) { + sum+=buf[i]; + sum = (sum&0xff) + (sum>>8); + } + if (buf[4]==sum) { + return; /* Match; normal return */ + } + } + + /* + * Error -- bad checksum + */ + if ( !quiet ) printf("%02x garbage\n",buf[0]); + buf[0]=buf[1]; + buf[1]=buf[2]; + buf[2]=buf[3]; + buf[3]=buf[4]; + i=4; // Read one more byte and recompute checksum + } +} + +/* + * loaddisk() + * + * Ready a disk image. + * The type of file (xfd/atr) is determined by the file size. + */ +static void loaddisk(char *path,int disk) +{ + int exists=0; + if (disk>=MAXDISKS) { + fprintf(stderr,"Attempt to load invalid disk number %d\n",disk+1); + exit(1); + } + + if ( disks[disk].blank ) { + disks[disk].diskfd=open(path,O_RDWR,0644); + if ( disks[disk].diskfd>=0 ) { + exists=1; + } + else { + disks[disk].diskfd=open(path,O_RDWR|O_CREAT,0644); + disks[disk].seekcode=atr; + } + } + else { + disks[disk].diskfd=open(path,(disks[disk].ro||disks[disk].fakewrite)?O_RDONLY:O_RDWR); + if (disks[disk].diskfd<0 && !disks[disk].ro && !disks[disk].fakewrite) { + if ( errno == EACCES ) { + disks[disk].ro=1; + disks[disk].diskfd=open(path,O_RDONLY); + } + else if ( errno == EISDIR ) { + disks[disk].filefd = -1; + disks[disk].afileno = -1; + disks[disk].dir=opendir(path); + if ( !disks[disk].dir ) { + fprintf(stderr,"Unable to open directory %s; drive %d disabled\n",path,disk); + return; + } + disks[disk].active=1; + disks[disk].secsize=128; + disks[disk].seccount=720; + disks[disk].seekcode=direct; + disks[disk].dirname=path; + printf( "D%d: %s simulated disk (%d %d-byte sectors)\n",disk+1,path,disks[disk].seccount,disks[disk].secsize); + return; + } + } + } + + if (disks[disk].diskfd<0) { + fprintf(stderr,"Unable to open disk image %s; drive %d disabled\n",path,disk); + return; + } + disks[disk].active=1; + if ( !disks[disk].blank || exists ) { + + /* + * Determine the file type based on the size + */ + disks[disk].secsize=128; + { + struct stat buf; + + fstat(disks[disk].diskfd,&buf); + disks[disk].seekcode=atrdd3; + if (((buf.st_size-ATRHEAD)%256)==128) disks[disk].seekcode=atr; + if (((buf.st_size)%128)==0) disks[disk].seekcode=xfd; + disks[disk].seccount=buf.st_size/disks[disk].secsize; + } + + /* + * Read disk geometry + */ + if (disks[disk].seekcode!=xfd) { + struct atr_head atr; + long paragraphs; + + read(disks[disk].diskfd,&atr,sizeof(atr)); + disks[disk].secsize=atr.secsizelo+256*atr.secsizehi; + paragraphs=atr.seccountlo+atr.seccounthi*256+ + atr.hiseccountlo*256*256+atr.hiseccounthi*256*256*256; + if (disks[disk].secsize==128) { + disks[disk].seccount=paragraphs/8; + } + else { + paragraphs+=(3*128/16); + disks[disk].seccount=paragraphs/16; + } + } + + } + else { + write_atr_head(disk); + } + printf( "D%d: %s opened%s (%d %d-byte sectors)\n",disk+1,path,disks[disk].ro?" read-only":"",disks[disk].seccount,disks[disk].secsize); +} + +/* + * firstgood() + * + * Return the first non-bad sector in the same track. + */ +int firstgood(int disk,int sec) +{ + int i; + + for(i=TRACKSTART(sec);i 720 ) return; + gettimeofday(&newtime,NULL); + if ( !disks[disk].prevsec || TRACK18(disks[disk].prevsec)!=TRACK18(disks[disk].lastsec) ) { + goto done; + } + + diff=newtime.tv_sec-disks[disk].lasttime.tv_sec; + if ( diff > 1 ) goto done; /* more than a second */ + + diff *= 1000000; + diff += newtime.tv_usec; + diff -= disks[disk].lasttime.tv_usec; + + if ( disks[disk].prevsec==disks[disk].lastsec ) { + uspr = diff; /* Observed microsceonds for one revolution */ + if ( !quiet ) printf(" %d.%03d RPMs ",RPM(uspr),RPM3(uspr)); + goto done; + } + usps = uspr/18; + + revs=diff/uspr; + secs=(diff-revs*uspr)/usps; + secpct = (diff - revs*uspr - secs*usps) * 100 / usps; + + if ( revs>1 ) { + if ( !quiet ) printf(" %d revolutions (%d us) [delayed read]",revs,diff); + goto done; + } + + fgs = firstgood(disk,disks[disk].lastsec); + if ( disks[disk].lastsec != fgs ) { + /* Not the first good sector on the track */ + if ( disks[disk].prevsec==fgs || + disks[disk].track[TRACK18(disks[disk].prevsec)].offset[OFF18(disks[disk].prevsec)]) { + /* We can measure directly or indirectly from the first good sector */ + disks[disk].track[TRACK18(disks[disk].lastsec)].offset[OFF18(disks[disk].lastsec)] = + ( disks[disk].track[TRACK18(disks[disk].prevsec)].offset[OFF18(disks[disk].prevsec)] + secs*100 + secpct ) % 1800; + if ( !quiet ) printf(" sec %d is %d.%02d sectors after sec %d [RECORDED]", + disks[disk].lastsec, + disks[disk].track[TRACK18(disks[disk].lastsec)].offset[OFF18(disks[disk].lastsec)]/100, + disks[disk].track[TRACK18(disks[disk].lastsec)].offset[OFF18(disks[disk].lastsec)]%100, + fgs + ); + goto done; + } + } + + if ( !quiet ) { + printf(" sec %d is %d.%02d sectors after sec %d", disks[disk].lastsec, secs, secpct, disks[disk].prevsec ); + printf(" fgs:%d",fgs); + } + + + done: + disks[disk].prevsec = disks[disk].lastsec; + disks[disk].lastsec = sec; + disks[disk].lasttime = newtime; +} + +/* + * decode() + * + * Given a command frame (5-bytes), decode it and + * do whatever needs to be done. + */ +static void decode(unsigned char *buf) +{ + int disk = -1, rs = -1, printer = -1; + int sec; + + if ( !quiet) printf( "%02x %02x %02x %02x %02x ",buf[0],buf[1],buf[2],buf[3],buf[4]); + + switch( buf[0] ) { + case 0x31: if ( !quiet) printf( "D1: " ); disk = 0; break; + case 0x32: if ( !quiet) printf( "D2: " ); disk = 1; break; + case 0x33: if ( !quiet) printf( "D3: " ); disk = 2; break; + case 0x34: if ( !quiet) printf( "D4: " ); disk = 3; break; + case 0x35: if ( !quiet) printf( "D5: " ); disk = 4; break; + case 0x36: if ( !quiet) printf( "D6: " ); disk = 5; break; + case 0x37: if ( !quiet) printf( "D7: " ); disk = 6; break; + case 0x38: if ( !quiet) printf( "D8: " ); disk = 7; break; + case 0x40: if ( !quiet) printf( "P: " ); printer = 0; break; + case 0x41: if ( !quiet) printf( "P1: " ); printer = 0; break; + case 0x42: if ( !quiet) printf( "P2: " ); printer = 1; break; + case 0x43: if ( !quiet) printf( "P3: " ); printer = 2; break; + case 0x44: if ( !quiet) printf( "P4: " ); printer = 3; break; + case 0x45: if ( !quiet) printf( "P5: " ); printer = 4; break; + case 0x46: if ( !quiet) printf( "P6: " ); printer = 5; break; + case 0x47: if ( !quiet) printf( "P7: " ); printer = 6; break; + case 0x48: if ( !quiet) printf( "P8: " ); printer = 7; break; + case 0x50: if ( !quiet) printf( "R1: " ); rs = 0; break; + case 0x51: if ( !quiet) printf( "R2: " ); rs = 1; break; + case 0x52: if ( !quiet) printf( "R3: " ); rs = 2; break; + case 0x53: if ( !quiet) printf( "R4: " ); rs = 3; break; + default: if ( !quiet) printf( "???: ignored\n");return; + } + if (disk>=0&&!disks[disk].active) { if ( !quiet) printf( "[no image] " ); } + if (printer>=0) {if ( !quiet) printf("[Printers not supported]\n"); return; } + if (rs>=0) {if ( !quiet) printf("[Serial ports not supported]\n"); return; } + + sec = buf[2] + 256*buf[3]; + + switch( buf[1] ) { + case 'B': + ; + if ( !disks[disk].active ) { + disks[disk].track[TRACK18(sec)].bad[OFF18(sec)]=1; + if ( !quiet ) printf("announce bad sector %d: ",sec); + } + case 'R': + if ( !quiet) printf("read sector %d: ",sec); + if ( !disks[disk].active ) { + addtiming(disk,sec); + if ( snoop ) snoopread(disk,sec); + break; + } + usleep(ACK1); + ack('A'); + usleep(COMPLETE1); + ack('C'); + usleep(COMPLETE2); + senddata(disk,sec); + break; + case 'W': + if ( !quiet) printf("write sector %d: ",sec); + if ( !disks[disk].active ) break; + usleep(ACK1); + if (disks[disk].ro) { + ack('N'); + if ( !quiet) printf("[Read-only image]"); + break; + } + ack('A'); + recvdata(disk,sec); + usleep(ACK2); + ack('A'); + usleep(COMPLETE1); + ack('C'); + break; + case 'P': + if ( !quiet) printf("put sector %d: ",sec); + if ( !disks[disk].active ) break; + usleep(ACK1); + if (disks[disk].ro) { + ack('N'); + if ( !quiet) printf("[Read-only image]"); + break; + } + ack('A'); + recvdata(disk, sec); + usleep(ACK2); + ack('A'); + usleep(COMPLETE1); + ack('C'); + break; + case 'S': + if ( !quiet) printf( "status:" ); + if ( !disks[disk].active ) break; + usleep(ACK1); + ack('A'); + { + /* + * Bob Woolley wrote on comp.sys.atari.8bit: + * + * at your end of the process, the bytes are + * CMD status, H/W status, Timeout and unused. + * CMD is the $2EA value previously + * memtioned. Bit 7 indicates an ED disk. Bits + * 6 and 5 ($6x) indicate DD. Bit 3 indicates + * write protected. Bits 0-2 indicate different + * error conditions. H/W is the FDD controller + * chip status. Timeout is the device timeout + * value for CIO to use if it wants. + * + * So, I expect you want to send a $60 as the + * first byte if you want the OS to think you + * are in DD. OK? + */ + static unsigned char status[] = { 0x10, 0x00, 1, 0 }; + status[0]=(disks[disk].secsize==128?0x10:0x60); + if (disks[disk].secsize==128 && disks[disk].seccount>720) status[0]=0x80; + if (disks[disk].ro) { + status[0] |= 8; + } + else { + status[0] &= ~8; + } + usleep(COMPLETE1); + ack('C'); + usleep(COMPLETE2); + sendrawdata(status,sizeof(status)); + } + break; + case 'N': + if ( !quiet) printf("815 configuration block read"); + if ( !disks[disk].active ) break; + /* We get 19 of these from DOS 2.0 when you hit reset */ + usleep(ACK1); + ack('A'); + usleep(COMPLETE1); + ack('C'); + { + unsigned char status[12]; + + memset(status,0,sizeof(status)); + status[0]=1; /* 1 big track */ + status[1]=1; /* Why not? */ + status[2]=disks[disk].seccount>>8; + status[3]=disks[disk].seccount&0xff; + status[5]=((disks[disk].secsize==256)?4:0); + status[6]=disks[disk].secsize>>8; + status[7]=disks[disk].secsize&0xff; + sendrawdata(status,sizeof(status)); + } + break; + case 'O': + if ( !quiet) printf("815 configuration block write (ignored)"); + if ( !disks[disk].active ) break; + usleep(ACK1); + ack('A'); + { + int i; + char s; + int sum=0; + + for( i=0; i<12; i++ ) { + read( atari, &s, 1 ); + if ( !quiet) printf(" %02x",s); + sum = sum + s; + sum = (sum & 0xff) + (sum >> 8); + } + read(atari,&s,1); + if ((s & 0xff) != (sum & 0xff)) if ( !quiet) printf( "[BAD SUM %02x]",sum ); + if ( !quiet) printf(" "); + } + usleep(ACK2); + ack('A'); + usleep(COMPLETE1); + ack('C'); + break; + case '"': + if ( !quiet) printf( "format enhanced " ); + if ( !disks[disk].active ) break; + /*** FIXME *** Acknowledge and zero disk image ***/ + usleep(ACK1); + ack('A'); + usleep(COMPLETE1); + ack('C'); + usleep(COMPLETE2); + senddata(disk,99999); + break; + case '!': + if ( !quiet) printf( "format " ); + if ( !disks[disk].active ) break; + /*** FIXME *** Acknowledge and zero disk image ***/ + usleep(ACK1); + ack('A'); + usleep(ACK1); + ack('C'); + break; + case 0x20: + if ( !quiet) printf( "download " ); + if ( !disks[disk].active ) break; + break; + case 0x54: + if ( !quiet) printf( "readaddr " ); + if ( !disks[disk].active ) break; + break; + case 0x51: + if ( !quiet) printf( "readspin " ); + if ( !disks[disk].active ) break; + break; + case 0x55: + if ( !quiet) printf( "motoron " ); + if ( !disks[disk].active ) break; + break; + case 0x56: + if ( !quiet) printf( "verify " ); + if ( !disks[disk].active ) break; + break; + default: + if ( !quiet) printf( "??? " ); + if ( !disks[disk].active ) break; + break; + } + if ( !quiet) printf( "\n" ); +} + +/* + * wait_for_cmd() + * + * Wait for the ring indicator to specify that a command block is being sent + */ +void wait_for_cmd(int fd) +{ + int r; + + r=ioctl(fd,TIOCMIWAIT,TIOCM_RNG); +} + +/************************************************************************/ +/* 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 (1) 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 (1) an[i]=toupper(*n); + else an[i]= *n; + ++n; + } + if (*n) return(0); /* Extension too long or more than 11 characters */ + return(1); +} diff --git a/SRC/unix2atr-0.9.c b/SRC/unix2atr-0.9.c new file mode 100644 index 0000000..bce7442 --- /dev/null +++ b/SRC/unix2atr-0.9.c @@ -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 */ +/* */ +/* 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 */ +/* 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 */ +/* 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 */ +/* Bug fixes */ +/* */ +/* 7 Jun 95 Version 0.5 Preston Crow */ +/* 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 +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************/ +/* 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 %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. 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<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<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; + 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 Xy(~+YX$}!tbXe_cH_@TsV8wp{1Zmc3 literal 0 HcmV?d00001 diff --git a/UTIL/dcm2atr b/UTIL/dcm2atr new file mode 100755 index 0000000000000000000000000000000000000000..dee11c66721d731c1aa91a1e67b3b3d1d74c6118 GIT binary patch literal 22384 zcmeHPe{@vUoxhW0Bp_r05{;tu)j|a|F+qZeMiR)t!vdm(Rx3D6G7~b8%*2^DCb6VM z2Q1?lWp}mJ*7kVnk7KpnT1x?`#RM#@-PXpQYHd}>TF?o>Hd@+7i_Ct$_ucR0&10r} z_K)4OXV2W6yzl*fzCZ50-+SMEZ|-~VZgwwQT;OmBPKDxHLEOs8CQ_#aBiE}8NS&A` z&cyLk;sS97_#%m!@;Z}1YNnQgOj@k)LQt}MO3Cf?e5J>fYeqGYWUi{$c5I-uG;j~k=PCz$L;mEEYaV>+k; z!Ia}kZs`9d<=0LdAfv>TbSbSoYWOIBWVU2aqmP)dV9Itkz)m$?Y5ZfNnkQ~l<>iV? zxvD=?)m(9TYoKxNoXcB%6|I3_w6mgf-rS10b1EaD%Gt8rQ&BvPsU<5`i(TE%JXhkI zUh?ieQ{KPlclWe>ZOUT3cXQ`j2Fk_(`a^O_MZ2EI@;J4+#FUo{-8}?G&i?KBP}9ggqzyCgugRjh~`kcKS)TpsU6&0)V6Zra0vpwTQm zo~BN(r#TSxwg&F-gT?vQW4ObgC)I?1XmxV&B}gLxL* zI`7w6a4MUVZoxU$BwK00)umdR++@KguoKXA7W_;L-eSQgS@3oXUSh#JEqJK~@3G)& zC`jox3vQh^wp;MCEPfuc;566dQ$7Ou2;?J>k3c>G|Cb}6$Bq~43Fq4jgwVJ483m~U zJ@!)Z{&ba7HSa)_nsEe2*M)V+5#K`cp}`c=jNcPaw?;z)lK(aFbPF=nC;6WfPq!XJ z&q{tD@pQ{E^r+fZ1vtrkHMwhTiXwb=fOh+H*ll%YGWg`B!$d}`2jVGlXpuP9tNq<+oEq%-T39v{*B|F}T! zA1%}!2lQ7@8B^h)OgSh{4K~Yi*uJOs1BgWQ^3{5*_OGS(PP~sB3e48LEx}ckGV%2vG0=~haQvG#WCqtxVCJ>$QoLK!$J3PxU;y|dsjNx zRlIbF?#`J_2-i;G+S?Z!?KG~#Ve>7q(c6rRaoBuAZ1g5$E)JWQ#6~NOak0@GjFRE2 z;T`s3=sP$hoZm!Tw)VLm=yUDti#vP44aFgF?JVm?em8agtbuLLb}+*cTcHDp{#PN; zduyJ;DuEt9xEtys*(8JFY$Z`*^$5h@v5Ff^@$wwv84$lnHB4@liX7w2AY@c!OP_1& zFd}b{Z1-^yJtsr+nhMvJZ$Wd|v0cUeE91>f!B=!NXZJPfI{$H+rAgaQQa?K%&LO@H zVzbV>q@t>GsouMFK#qvl5uD^Re}@wj*-MKIg#C@Mt$oqYrd1Cne?(Y(A0v)|gQC*c z)OMh*NT|9-FXC3k`Y@--awu4FSPrACzUIz%kKGRRtjFDj2dj_aMgXpfJYi z3HRUuRL-vxhP=m{mFQq&;u;w09-yD5MQG(eQmy&tHSwy<< z_B{x;xl^v4Zji%7Dn3Fl#6}&r&vNZtO{&k&C$}|?R(}ts{k@6Yc5ZWT&16-}9f0+? z^9iy|IKNE<^BL801LaXmYI|?Z98=${<$|==tz@n`skf%iR7!eGrz^=r!dXuQO?dvJ zR4U;vC=d9F4hza|g`H*;|0o znJKVa`l7*}?vy*)($jtTqi7?v{#9!A@0kXpy>vRFgrA&?v+}6v{5~b8MFy7dA^Fct zc~Hr#E%IX|e**Gh4J9m78nhO`9zG_G7&Oct44A$aO3j1GW24lAhhST!kYXsHXZ|%qM>AHU!(AtkE+q(tF*yxhYEwR!1?wTQb3{cT8u`^s>{WCK0KD~G9R%Fmn z=O?H}qNqTBNbfEC0C|k()L<-G9~*`C&+OX67VX2VU3(B}uKORtQChZxX3aK278jHRxZulGt z;9cal)7UUPIDTy0jN?bf=jrs>(${$<`r>i2M^(ykXVV;aeiv*~$6bvc?}zk0uzSd- z9)E?jZim0&sTjImBbV?oDt#OU%0ApDuXdl*2_GKKu~ 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 literal 0 HcmV?d00001 diff --git a/UTIL/sio2linux b/UTIL/sio2linux new file mode 100755 index 0000000000000000000000000000000000000000..deedb4894b0deb24e2100bfdf37800a97507b2ca GIT binary patch literal 35624 zcmeHw3wRXO+5c>kH8CdHAfUk;gMtzvAs|pLq9kN-Xh9&a#D&QEID#g4^d{)Ye zvN;`gIj57U#Ow9daJ*tlYit}YQzIYQCeq09k+sR`TrvQTrky;Md}I#diwVA%;FD>u zFoaB{J;^5Ydsf)foK^!zhfIlh~gcx20+ zSDnxn{qUWdnmaCN=-Y7De~{j!1IZ&AI*49W$MU04COm7GWdjPuSp>TXKRQOAd)GNH zyIyRZ`f*sgB}W*}BajzE#{gB7c^Tl-P@$Sc$qN9dl|yckPChA=4*tsw@K6T$CmG;0 zJkrVkLk9StGQe-m0Dm|Ge0B!-)(r5@4Diwn@D&;06cW?5cYg-@Ye268XFdjJkW&c4 zbn?&6K>vOQdK#DM$5TTrMYZH@G}XqpJ}xrM4D~9&c@fx6To8dp$~^4q!(hKl=dp6-r%$*Y9H7N_~^h?FrNa1xi+HZEf9ZM{T{^<7jZ-;!>c@s%61?g|)!T zTTokzh+0?c4>){*+D3=lgI26YiCR<7GekfUcCvEC+&NXVYA2LWD4(R%&RICG7P`8Y zyZr%|Z{fUI4PK9Hp<`Kt3#`iM6YDA*h}Ys^v7w_Q6(@IMDCIBB{|Oo z&vKti*mA(=kn^wf7j-a)_lx;e!h41DswRJt`1Dxg}c|;8GGb9jc zzX5)M0Uk5JFEqes3Vmn|LvxZmmKxx4o+4aHGpEQ!B22&lssS$NK0=H(z~vlI@CpN* z>XyfpW}YMYWD9xBZ00$F(@!2+GtUuB+L|CW&2;9p=rH}bu9;_vK3|6_%2EUTGy{Bv z0bXE$HyPj*bLFwRndeA;kpv=bZsrAoi=`a{v>D*i#|W|603SpEacpho8Iog+hxZ%c z!UY-OuMKdDx$=0dndeB(nG%R}M>8)Fyo6`jxucmE2tJHw*}1!!7YKe9&$4q*GcOSQ zY@TK3L(RNE@N;;UoqL;kf#B!zEIUVxl1^%%Gw3cIeTG;wGucBzJ9f7QPkJj>R-d>$CKIt$} z@li)`whf<&9F#uBoI~aNS$QXw zX=;gXX647JOjAmp7qQ$K2qcTkiQH7Onq_U05{a*nvY8jPj3W)Zy^7T}v&>!t# z<@r>mkRR<}l_`Wr z6;^(a$`rbz{a;f1_cSU>{brQeG5-BIp_gyaLWi}MBmFfC=eAq#ycDj~UU&gZW^{ro zK6Dj$j@yP;6J|yy1ZwTpos>+C1%|@?t^}Uk@6>p&ZFn;Y-YZhjf0xlux|5R9ue4CV z*7?EZT4yXvI3_r>$g$1ERlRNjs6Fai@<|{qK4KU(?Y@CefAis*s}JRCD?$z|&q1;cXZd68|*e?`C*=uNE!_*~>)MKI!qxh@l-De*l5q;-{?E~6Y z&E0Vbo~N}By$J;Sa@c@qu@6{U)(+&ZdmWv&iYaG3W28j^D;xD&pa|z~AMza2CyW+Z zdbF@&+pb(%W^27HGlkaDVF8tGS4T^vswFnrc1JddLmgWCkX9zE-MR@?hI6u@UHj16 zsCr9Jyfcr9>AD#$8iqZW5%Z4*}$6C4DlvR6ENYN z;`X*QxP`!l3W`k}Ra_QDHxp(i$B+^*4iuegKW1ya0cCX4yDO>JI(O2jk`6Iu2D)V3 zfb4E3awd^)feU?N5?RDW-jhaTjC^d2E^<(+$a~X@B(H*&m1#siNFon?A+_9v9Qg;D zINg3Mcrmz6OT%?Has6E9YC|rA$7mtz&Jh-+?{W;GHN-_TP2czo)Zs<3&_Qzl=Mf*N z`}=Y?_vLKvvusW%WxJ~uejfP}5jSML60)^+``?M@F~nS%fAb>La#RfSVlA{b7P;Uv zC`rR|+Kogv>1}AE56d$?XTxncp`ZlN-A42Y@bXdnV-O0lHKDanYwe3V!uF@N&_O6L z0=U+WH6>{3CTi-{B(#0T_bGo9qRu}1el#BAtb-@dQqpCA)zW1@NSb%-DguC-@@kAp zDggHl#C-|4lL(GNAyh>KbBN${M!7ffdt6}BKZ*UX7lrVrAI#jhN ztsTMq-LzdC`S1j6Wc_S78Fk*kPV!7G^df{^2!#;O*HeY>PY31CAT4Zt6_nsU%eLJ< zVB6ji>H_+&K=W8v2_{+NhGTS98G5DwHVHkM$1KzO7=-Mkam{q5hF=Dja4QiRNBFPd zG#JMr`;k=KW{zu#6o%}*EzgkT?DfOKi;igROg{IgH?V$)IWV{09SGeTSY z<~Z8f+F{f7bjI@9S|6vT*?aHne6PgPgI1OHw6*?@!^&oYC1ig#Y=73wwT)3co5b}5 zU|md$ED@KZVN?a@Z?DM}6=t_|0X4=03(sS@32K@YtiUi5mXr?WQ;{n?QdvLDh~*7hs5jdw#d z{PKQOy^~g)y5G(Vsd2~65N+>JdUh{?29}_#n2uJvGmmMQ^tYK-mkUS z43=Qd`Vy+q+P4&wFe!n>+wBv`uMcS9)|m{at<`qEbYj8V5B~63RSR`%C*IRSJy@dU zXq}&3u7&=nk&pI-?LA5U{xk3bW*!;L~^vc9?kvA^7{IEt@Azg<UWnvyXljT2W+`iKyOxuR+XNh2^&e55jAuE~a*ML5;-l@PK3O(~W&Av|_!a3YZdE>I? zqgvtG7*c12w_%JyidwzbcdD&>P4^h+J7@?b8m zC1UC9&28x@2IE*+!$7KpUqAxdj2f()p(u+~n1IbT4RJE~dcVQf_q|WU&mO^S649pH z`vcXHApnJG0-+_XeLR-5KZg;tu=Q+6Aa+~_L~tE25h(pK;X^R->wqmF=C(}Hq0q{7 z$kW=}$;jNj9|R|@U+qVx+Xn)dwyZs(u+@7Uvsh#_ulZ+7sH#rBGC&)#RG4vu@Kb>2 z)t*PyE*e01AklnMhl?osy1oY2Iy*waZTsxU0LHaOj3)z>^i_!N58HR(s++FUw__4N zMoX4sNO=j1UIwx#>;5+DGYTBe+Ky{PfipqG~&!-;4H6bor=<0Oa zts9|LhpyG%AsDrHpx=71JaKo-tg>NEa~!a4TKFEPMjb~Afjj5;xk&)*^k3P))r#@G{$}$t$hIsgstzK&aR1$8Lo*=*V|k}uGQDLQtKv>nfnjzA)MC+h42XE(k3n`Ku&7wahMqZwOSRCG z5uC+r7H%bwF}~b{npv2LwLC+FEKJ0jp~pV^ah#RD`DBjvE&ZGkOQx`OV30*IH1d6F z7KqrT1kvGwi1z?at3|euu-*eI zYBhX)PPuGwF6g3vW%0<|sBPD?MuB-`*m^BvwzWP=5uts?>AHZfCRzRH;Kmm=+ z!UCGPnn|2W4`^omxxkCP8);kwG!kbDXuJjlG_!>N{tCFg>1kUcZ9}}%A;A$`U9KPB*rvZqid1}P5uY|zJV&E zZ35}<>rO$?Sx=KA^ZKxLII4t8_8VNXfE%b~?Qu(B6o%_L5JJP1HvHvqJw67*^$8G0 z=aNfVd$C8yM`}OQ{9WMrNWJo1>Yo0VSf#CX7^8g{w5BTW0}=W}ukxX5Q>)xSRnDX; z{{ltA)<#p60lmuCj*2R0*;*e0?LK=y&TMSs3NUGGs}N#n`XH|CKQXrZ+1N&G>=$GE zU|~wD_HsS+v5n!m15~inFbvJci=~OifUfTpv8|`iTNR_;gRDQUC6Ym)WOBG#BTS^^kV z8M>b%n3#7=xTiS|?!z0*=hGh?F^&#eW@_!Nbn6Te0+y~Vh36bSpDvDrv*6Iv3#hBM z^suD}-&_R}lVF<`ZjBLi>Ym_PV4OgVWe|?r0^dSj3t8i*ffx5XknEymhCVA_gMJ8M z8+`46vSzFn9(s@yzPXT;nN-5K#T}2QAdyet4luz!=*FFF9vIMjU&X2=f=P+)B8IJN zNLc%#-8W-JI98t)yVB^2LG<_7`VQATj%;MaqVJU zC7_iabytGoVWRjEDCG3$rkM}d*tBY7ljEEDNdu?{ykcduej+TmkpwJ;0NCun0yKr~ zB!>aj4fhCGxHT4#Du!9JC6=@9ZZVfj1u6^*i1pe(oPAqj+3RQ-7QtRg4qM`NV0$ZY zbJ$u6?P08Q3CR)6VZOv(IgehO50mPItg%qqhHFM@IxpF_&&+DWrV4|w6p(BklFd11 z=Con6ll5fuLO5k2j(4DQw9qpefT1U=aTbkjd4>wP>&nBelwq}5x6Egrv;JK;D`z11v%c5nU zmEBAf`mw77-oZb8D{aFUX3}fA6l@D!msYLwbb{7zq$RK>2+jaOo5Ody2@@V>|t zl9}o+<3X&Yb(k{=gYKez=rRO@eOEz~cII&5E##C4l6yxIw{VzyQA2bA!e6SsyTL2( z60!keboosj*$n4PW16NXMiA#yQe7%SqOpo zmJj77gb_9fD?{C(m)Qo`j4v*b;bz1eX!H%xAXUtsD*>gUyoSuzMkSN^jzElVzH3R+ zkhGGT!JE;1D`ho-e45H^8>gkU)o3mwy_L`8GBCx~P{*>po14#0*Qn?`rV6TnaqZ1o zOQcx454*-w*tK{EE?Tu2R7biY{s`x#*h9Q6z3a)h(!_#|oDg)3Fpb+@4~p=Re68+d z)PCZtP-m+7r-OvH$x^!aLgM8i_MEh%>r_r)TC)7=b-Hl0AHg*vl6PKhMHVi_$%Gha%h3W9eXv{ekEfxDb|W8R$a?OS^!@#j{q|iRVnX zw20an%L={J86RF63ne6$cH)*%-RD}}LF_VVbx;#GlX~&I4<%We`{nJpML{J?46Bxr zhKEI-`6gK)3%+heZGD6FO{oZ;1HgDggOb_{6TDp7X=1qS>lwOmW2k>>CoU#%lL_9{19wW+#|i;7 zbHI4rv`IxvY>Vyg?}Hxgmz!Dx;5|f}TI_BkZZF|_#MrFDt~pFhp1c)h!Vmoc@a(cE ziL05QIeAm}*jn%4ogcCu&;YZ35NCJDTZ>2!YX@LjT}<1dTz5sR5R`m_;=~DZKR97$ zB-?QN@Wf%(-MCfe?uj5q69t;q8J@8ka&{my z(#j4er#wd2=Gf1$e)<(}_b}3ftjsq}-o)c|e1I)^6AI9DqdXS?tIVT&RNemBihJSs??*E5Fc8Fof zX0d88WNjP0G$kh+M*UZ{{%|(4!vD6`bE%pkS?~vVfdzhXtbHO%Nd{cXRmo)WS4;Pq z7{&?RYY-&&BnQdLP){YoZgpt~e6O1#Z?~l*govWmb%FA^Cw~52j3d?3-xuzq*oT7zJ|BQAJWE7EBq~E%43b`*4)qYi7Kjgen!(?=p}Qf72d)b+MCd6)D?!A&Cn5vPD5XO z^grv1L$jzon2t#=-X7A+N_xFW(`!;g4m0XJ+{ML2A9^|TF$`ff-}l(N|tNWUm$u@dc@ z5G8wrbvtUcck_)Bwz}fR@s~)0J6>knC4!_SGQK5tzU_{=*=S*hAs$|M7WFcJ-t{cx zvCg6AU4Iy3%F%-z({zzV5Gl4rqUS>pp8rUYmFQ&e_AoN6z?JA1G=8n~5@es^*~uL= z+9MsD3`U4qP`la1tLrx4i`Ms{a{Y_3lB?Bpscw+HI+=r$K`SL1WMumiWIxl%rg1W6 z-YXf|{Ry)5I@w@O#>{&WBU_UoTcVR4dyzRfGcP?l8Me+(kWJUgp5tW9ynlg$Ve6O# z*)W~#C!CC#_i;v+lOQ`WR2t-FMh4$OOT&!pZ=dJ}`Lj+|!^xnP(ziTp{X>FgyG}Ef z(~!~nW`(U=5;Xs*)8ug)vRL2nu=OTJV{29OX$G4S09~Z@Pgr-^0HEvk)swKAGenu8 z;mgosx^4=d9kxzLR54qx;z96Zk*BPN{6Rwg-cy} zMi7xgM4Jh~!v+r`ENmc%@Bl+sx^(9`k`!9-biCRU`-bg~ck)cpVk7!SMvK+R^JtOW zyod2hN5 zX#9Q($`6?Eg*tu^;gegs=Tgzq;CMWa0VG>Z7vKr0u=N@y$hMI#^9;x?>FX?S0AER^~oQh&)+ee zd0QqEbwb<2Z=x9k7%!1?scEdagQ;n(xu@#QjbnO=?u8WG=QOqIsncbv?nG6lZkR5$ zwQcl~4$QKTr?%cE>13-mp~A5Bv5)xJnF?OC>N35m;nb=N^j0k;>O`vw^j2Mgs(7nr zfP}Z|5`wW#ETvYxkBAty&So_QX;S@skZjN&o=<7ejnjnrZ5w|DM&6*epbf9(RZLDM z6O7~>Gn&y^!Q36iNcyZhmLh4h?wAT`$&UL8f#mMfNE7mPfuwDUb-7*En^A5y(LBp( zu=R7gZM*dvlv=v;+N|@C=_>}LnjpO=+N{%&;T9P|`ZJ513H`ZS7Xr46<`h_D5GW%D zUW2hZ00~=%^)tsNWBnQJ;cJGwx>K4y1AIK(Y+MUQZmexEDmT_|FmZ7O?k5;i;9kJ6 z_44}80#q$G@gqwiyUYGM{@>wm^dBb1i2eK&RtLKc`i2Sj2*9vf}YZ*Z>7R=8C4DxpU^mYsVE6j}tQT={63I4AzQGJbG z{Z=%?RQ;Sp_1^;{uf79n@@?s>e)NR|o(A{6$j|mbCG0%0#TV6J>Bb%S7JIKn)SSES2e|Z=g35zdhJ*%KL@Irb zga)}xgFgH(tEe8)k?QQbUP7ixh}4U#aNa*sA%ER{dNlzd)XHjm9{*umttge(&c!n* zCU1{P`UWiGAccWvui%9D;kTQa?YQ1BnOLf%Mxgg!MTxG96@~fjgUKQ_R@+^0$0WX(TO2YgZ zg!x@Qx1&LIx>mXC7)#LaQb#*o^^RaeV46A(h;f0yngtb1%CZbnmNhs$D^)-AXmFJ| zT^_$XAR0ni)S+ z^?Fp%$R@8ZppN!?8(r$61yyRD*R#sygZ=%~woB{X4X(>nr`x}hn~gMY^aecv)!`Sl z5pHz#cr~!X=M64jp;k{(-5%BJ!yBHM2)vu>G8H0xsMqUTlU_o;VqfiOY-(_kKaBFL z%e>w|xg+3H%T}vp%T(tjRLDm))5tF*cC1=GfdSmhJzk&7iSi|^?0{}JtGol4AxiU= zM6Z$iDf5E;D1X4}6uw31c=kIy_DlZyZE5zU9G2 zmnTrJD32l(IWZsnyME7`>VFD>>+5v6-$37j{0h()rP2RCfg9zVri}9EC*CE7F$pJf z(o4ux_HHq}OicBv;x%ZAQ`zfo$Z&HLq&UtWw!IiV-pA+BuaA$12n2wK99?ZwxdrgCahMMJABJ1rc>Y1Q5guh8k<m%)4PE?$}CRAQNs^Su-I=^O~Uj-ikkhIF% z5M=WrV+;CA)x}O%gJTWUCOhIEc1T;IMdvdS6P!|i;jaR}c)oqsRr9Ou)!?DypX5{2 z`sMy0QyBrooJ#JQ==oGx;$9S)WIhtKyi9+ z_OM~YT7#ES`gptiO_+<7MlbvuQ@(D-;zU^2%?nnM@{LV&O@_@6Pojv^k zY(5OX*tU3F#Wh>r?{WQrv;-;k#*{CSE=BpsQ}Ot%NT)vy+air2rE8uWpNYp0A-%pU z9*-gI>5j+gJ;zUA(~a(FJ%9}fdTy5PC#^=>iEX*9NN;}`{76?~NBR)bW7uelA>EI? zxsq(qy$yb(z0mhMr1{W!HPY+;4t}INkoF?&MjAtU2x)N+6vlzwbaq&7nXgz@7hBFQ z$j#eq$t@=MIrypD|AH*KfgoY$;ee%ADhFBy40 z2_Sx4hABIqgk1?BjuNEb!EX!ddlxz?l|{w3XU!_aW-oic;cBEyccOog8gZoKJ^1|) zxMz&GtQ}|xZ^Jggr=U-KN%%$`e*o}1f$t}UWWCvac|<_+kK=beHXc?{yL9|bSrR`4 zefb#r^lhXG{2LaDp9r`gechkL->3601b!B_r{789@74JOfak$CrY7Mh>iByAAAzmH z=TN;~e^!UyzHPvF0iQ|!0pP>%wGFt7pz~+nnk)4`4*W4ZxYU~@|219y5VY%IJbv{_ z5`VwWKN0v1cous&cF+>?&nlAg7Xsh>K|Fr3QND|bXZ8;Oe<$#Bphtqgnzf&N=^o&B zU<|XVvZ|=~?yNaQC7ZJCMQVGFy=e4Z*6N~)+fUJornKZwLnAcv}v#}H(W1KtfdZQ{#=@&)kI4!~^^crra{fs+fs+=9a!XrXqsW*&@A0r1c_Q zCDPkPdap=-DbnpC?GouhkscN4ry@NCk6qGnhDa|I>12`47U?x2trzJkk=`!Sdqw(7 zk!}}hmq-ta^r%Qb73nE>xRli|(hEh(q1gZ2z;k~pLr;B+zAt1^u9!7z8t$39mbo1s zb$kWBiZs4#a;eCv6DlT*uNXhRLQ2S-WDS5dQx!R0lHvJ^99PM3jAGI6$?yV2O$#qn zDop)BeA)P7&&;%Nn?vU~`yF+zAg8(#*K-#s*9v+0XHv>9zWvX#Ml{4=7mv3n@v zUNU^Bl5TuuD`zP3J5tH?h)T^y2+wCD>XZmSG-9)HH)3X5xQxaLYKlWS%18LW+~kAe zeirQ6WU?o1)e`)E6MTe#%Xvgf`vx)==(9rTL-o-y3qMO5``idP$(QpI(bBOBKT8@r zZvi}={=Wj8oj+7p7Wbn%fif z0dNqW;B`ViyT<_7^8&8YjSCz;o+y7pO7yV{IDp*~K=v;Jej6DO2fLSm^e}!z|Jo>m z;=5pCeD@)5LBCfBd*(1K!P47-?on9aw{!7kP4kh?ZZ|>@)!Tn1rvwJAW{tf+@uHLf*{eO++^z5DxvLgVecGXNlML6X8 zXEfl&XxBucCqv@213zX5K`;Gt9Fs4p66vfA@Wl*Xq-6Ul`3LNWXnVz$Xa*XZHv}@_PoCwI$LQGQi&ya_Id(bcn}p zln({`F)^^%Jy_ts${+`?OoZKrDc6a1F=04eE9A@+#uL+zG8hdcdh_@i4mh=U6#k`) z4t7r*=|}+|BK)wIkT}X2oac?_stoY!GQd3<;OhyFxN4pk?#Mv@(+u#(Gr*q%d=UI? ztjRxL$Uy&k2Ka|02mUri$dR_7cW$V%U`U7JLiBt?S!OE$Pv_^e04Kj)D&)&Jsnp?_ zr9iO0zPwIJd>pkl&{&HPwR&8Bd>Ym1tzF*WUFK-0b<*={wT|FwMLxyoEU!pUK_78- z*E)PY$C_F^6zN-|)YB8zwa#E;;~M%@Yob&O%0LpS-|d~iKbL(;`S|h*s79Zdr3a1Z zAv$`bvlh=~`rOdC&g*n3KF7@pp59da_#`dz^w1{DvkZI4kwMtAQcU65^DF1sYwcH7 z*WzQZ$@M#x+Ujp#SvhactYi%P;4DD+2zRYrtK|~3>iJ6T6?3nus+?PU)$G{|>^xF zhQ1e^1i0COj=;lSwRMf`!C6Z9^V&+Siy2dV^*4#j@O9oKIQ0geljOa@zB`&z_2p87Cp#^flrn2>a}C5=8$%vI**NCIM2uH=KmU^WUUG z(BI@!ZVI~DHBi_>tAm+LB*G(lc3~2NdPFo#)aV<)k%2%W$Ppmxws>c3}WB5rcYug zf%#{slR&k#3+K&}1D}Rg+OIq(e}+0q0RO^u5{Q2RI|-ze``0uE9Ltafd^}wtbL<(? zCZ!w?k-Ey4dxGW5g6;-qncFEql~r@f0*>Vh!>w@OliB6YH6F<0DZb6kFnFdCVbYUS zs0Gf4=XQxfrg%ZV}ez}<-m26a{31Z1bsOt{okatUu(e+%S?92eJ7d9{aS%$v@%cW1^Ce( zspOaYQ!*V%M1}*?ZPG!@6(c{bgXxf|%1VionZFt+eBr_?>zDgoGOZA-n4a08&r z%Q{>|>iWxlF`0H?eMSfELzA5(zql+>t^tflWc_mgOr~<58YJu>8OGxV6lhOa^2>cT znab@cslTL?=}Pd^9W>KjrFKlkPwFq@FO3hWyOCd8 e%S+eDz$K8fUP(I$nRNU=xs6lgnixz)<^KTg&K`LH literal 0 HcmV?d00001 diff --git a/UTIL/unix2atr b/UTIL/unix2atr new file mode 100755 index 0000000000000000000000000000000000000000..99fb6cd25c24e6733ef0b81d357ffb110bd0e9df GIT binary patch literal 26512 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 d!Z(P>lq82$0nJHTaR2}S literal 0 HcmV?d00001 diff --git a/test/HELLO.BAS b/test/HELLO.BAS new file mode 100644 index 0000000000000000000000000000000000000000..1871b21054819d308e34a0d7dab1afbac4228ad9 GIT binary patch literal 54 zcmZQzU|?im1OX974Mqko23}qTepU}xA0K})5e7CkQ89)F5fMp#9uG4su&ADsW3U(i Db94rj literal 0 HcmV?d00001 diff --git a/test/MEMTEST.BAS b/test/MEMTEST.BAS new file mode 100644 index 0000000..90e3653 --- /dev/null +++ b/test/MEMTEST.BAS @@ -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 diff --git a/test/MEMTEST2.BAS b/test/MEMTEST2.BAS new file mode 100644 index 0000000..56085c1 --- /dev/null +++ b/test/MEMTEST2.BAS @@ -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 diff --git a/test/MEMTEST3.BAS b/test/MEMTEST3.BAS new file mode 100644 index 0000000..7c72ee7 --- /dev/null +++ b/test/MEMTEST3.BAS @@ -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 diff --git a/test/P32P1.BAS b/test/P32P1.BAS new file mode 100644 index 0000000000000000000000000000000000000000..dccb3951226f4cb54266acea255017092fe6c91e GIT binary patch literal 460 zcmZ8dUrWMJ6hAXCh}_cL1qt<-jSMW%z(9I%vT2gevCSTOGj>fOXUqjY&Y-tm>t)}d z579U1sV~&sToApS`#W%d=l2HyxIHe-op2wC&xEWfhH8HIwb55!V*>!>mp3+nYi}J- z*_#L#fE_58K{tk7Lmr?tMBV6V7WR9ZirQ$57nyDkzIKR76#dtx36+q8QujhsRryJpwnKshk%H)e>;{uW(9}xYGCR#VwHlw1>qv}o zXBHL~FU-u$Y)CM$Fte~QGc$4LSW#L0-&y~^d++@N0J1@{gp%*;zt)fS(U)%kphxe- z7l?M26v$>Foyu!*6Ezh%4^UDxOIG?>T1h3$T+Wcsy)g^W z<`WG4E5UD_4Fc54&<&ef`DXHvnI$|PZ?LMa} zfcC>g(&-u4wl&@}4l{SpyxRYPVAWvy2m!f9QSCrUT*a45=Km(-21Qv~r^f{ANG>Rgd@4D%><$IxxS8I9U2LWp zH}S01h14<750`D1$pa9AW2;&J9Hx&@DJ`TFqiagHf;CdFY*iMq+Y&P52~1Ow8#9SV zUcqs)A`w55H2;Pq>mqo}8NS&E*vmNd#GO5rWuu*TqU_+pversPf4dd$?8c2c{xA6k D<%3|m literal 0 HcmV?d00001 diff --git a/test/P34P2.BAS b/test/P34P2.BAS new file mode 100644 index 0000000000000000000000000000000000000000..b6f2055c4546e531423595e5fe78489d67287669 GIT binary patch literal 1280 zcmZuxJ8u&~5FW=DI|;~ktYbrLoNN*kTiA(|2bW-w@Y>$QhwfqB!$~>{DhfnFL51>m z9@I3~P^5^c2tv@&AyM%YsHsy^Fnf1NPLPxCW@l%1zHc6T01&$utHh3DzxvPnTduBe zoUpl5Hh=1H+d0ux1rlRdZi5#KY|gy5;iLfIF{tvJ9i$N*C4&>zY~ zD3hTasG}!7gP}eY${T@P^yvI2&yH@HR3m5A39*LLV-KD^}(z{m)wMpJWJA}2q= zBJ~DgauPO7*Pi z5ZC5DQ`fkJrIzVBs)0dXLpdYwU8UHAG3rkelTK;z*>*0@vyj1?*nB5`o1V_Hko36v@wH)8WXj<8wNwL^VM3P5` zQY=GpMLvi|UA12{iuq$!C7+>mTiIT|(2;~cmvX6mwTa;0Ad$F5e&83p-|<`yt|f3D zM~XJC$h@k%t{SODoCv=Pbm9=x+GMRkkH{M*r|sO z$AQXxhm4fZgKi=Q$5D-rjF*!tca&b>yeORSrs@MIp?Dxyl*7Pq-;Yw1D(PfzBE|Y# z)bj9fC>ibO{1-gHZm*a)8irCY){UMwcwgPB+Js+Sir@fH$%)NGGdmvN?t=6 z8Ns-nTC=uUErsE#M3V?X0I@lJSiC^#hA4FrIYbc&Bg#`Lhj%F#xk~{6^`1*uZwvoB zCeC?S>fj1n+;J^~dat77_afx?$(tzRQDE{BkI8|QOb+c5*p%hb^v%|Mt+TM$nV)Si GoBRduweHdY literal 0 HcmV?d00001 diff --git a/test/TEST.BAS b/test/TEST.BAS new file mode 100644 index 0000000000000000000000000000000000000000..1e749bd9b297e558b3e72057a06cf15228d4ee18 GIT binary patch literal 53 zcmZQzU|?im1OX97bw&m*23}qTepU}xA0K})5e7CkQ89)FVPQ#rZVxl75ZB-kJtxOt FF#v4k23!CD literal 0 HcmV?d00001