terug.gif
(***************************************************************************)
(*                                                                         *)
(*         AtomCom v1.10 (c) by Wouter Ras, Delft, Dec 97 - Mar 98         *)
(*         -------------------------------------------------------         *)
(*                                                                         *)
(* This source code may be distributed freely within the following         *)
(* restrictions                                                            *)
(* 1. You may not charge for this program or for any part of it.           *)
(* 2. This copyright message may not be removed from it.                   *)
(* 3. You may use sections of code from this program in your applications, *)
(*    but you must acknowledge its use. I'd appreciate it if you'd let me  *)
(*    know, i.e. send me a copy of your work.                              *)
(*                                                                         *)
(* Please report any problems, questions, comments to me at this address:  *)
(* avio@casema.net                                                         *)
(*                                                                         *)
(* The latest version of the emulator can be downloaded from my Atom-page: *)
(* http://www.casema.net/~avio/atom.htm                                    *)
(*                                                                         *)
(***************************************************************************)
{$g+,f-,i-,r-,m 16384,80000,655360}
PROGRAM ATOMCOM;
USES DOS,CRT,HEXA;
CONST SAMPLESIZE = $2000;
      WAVE0 : ARRAY[0..94] OF SHORTINT =
              (  0, -4,-11,-17,-24,-30,-35,-38,-40,-42,
               -44,-45,-47,-49,-50,-52,-53,-53,-53,-53,
               -53,-52,-50,-47,-44,-41,-38,-37,-36,-34,
               -33,-32,-32,-32,-31,-31,-30,-28,-26,-23,
               -20,-18,-14,-11, -8, -4,  0,  4,  9, 14,
                19, 24, 29, 34, 38, 43, 48, 51, 53, 55,
                59, 61, 62, 63, 64, 66, 67, 66, 65, 65,
                64, 62, 60, 56, 53, 50, 47, 46, 45, 44,
                43, 42, 41, 40, 39, 38, 36, 33, 30, 27,
                23, 19, 16, 11,  6);
      WAVE1 : ARRAY[0..91] OF SHORTINT =
              (  0, -6,-13,-18,-22,-26,-30,-32,-33,-33,
               -34,-34,-34,-34,-33,-33,-32,-31,-27,-22,
               -17,-12, -6,  0,  7, 14, 21, 27, 30, 32,
                34, 36, 37, 38, 38, 38, 38, 38, 36, 34,
                32, 30, 27, 22, 15,  8,  0, -6,-11,-17,
               -22,-28,-32,-33,-34,-34,-35,-35,-35,-35,
               -34,-34,-32,-29,-25,-21,-17,-12, -6,  0,
                 8, 16, 22, 26, 39, 31, 34, 36, 37, 37,
                 36, 36, 36, 34, 32, 31, 29, 26, 21, 14,
                 8,  3);
      SILENCE    = $80;
      SILENCEMIN = $7C;
      SILENCEMAX = $84;
      MAXWAVE1   = +11;
      MINWAVE0   = +16;
      MAXWAVE0   = +21;
TYPE ATMBUFTYPE   = ARRAY[$0000..$FFF7] OF BYTE;
     DMABUFTYPE   = ARRAY[$0000..PRED(SAMPLESIZE)] OF BYTE;
     SPEEDTYPE    = (SCOS,FCOS);
     ATMHEADERREC = RECORD
                      ATOMNAME     : ARRAY[$00..$0F] OF BYTE;
                      STARTADDRESS : WORD;
                      EXECADDRESS  : WORD;
                      DATASIZE     : WORD;
                    END;
VAR DSPVERSION    : WORD;        {hi:major; lo:minor}
    IOPORT        : WORD;        {soundblaster i/o-port}
    IRQ           : BYTE;        {soundblaster irq number}
    DMA           : BYTE;        {soundblaster dma channel}
    SPEEDMODE     : SPEEDTYPE;   {fcos or scos}
    ATMBUF        : ^ATMBUFTYPE; {buffer containing .atm file}
    ATMSIZE       : WORD;        {size of .atm file}
    DMABUF        : ^DMABUFTYPE; {samplebuffer 1}
    DMABUFNR      : BYTE;        {buffernumber currently outputted to dsp}
    ATMBUFPTR     : WORD;        {pointer to data from/to atmbuffer}
    DMABUFPTR     : WORD;        {pointer to data from/to _NOT_ dmabuffer}
    WAVEPOS       : REAL;        {pointer to data retrieved from wave arrays}
    CHECKSUM      : BYTE;        {checksum for sending after datablock}
    IRQOCC        : BYTE;        {irq occurred? 00h=no; 01h=yes}
    ENDOFDATA     : BYTE;        {whether or not end of data has been reached}
    USERBREAK     : BOOLEAN;     {escape pressed?}
    FIRSTMAIN     : BOOLEAN;     {first time main menu called: don't clrscr}
    FIRSTWAVEDOWN : BOOLEAN;
    WAVELENGTH    : BYTE;
    ATMHEADER     : ATMHEADERREC;
PROCEDURE INPUTSTRING (LENGTE:BYTE;VAR S:STRING);
LABEL 1;
VAR CH,DH:CHAR;
    N,P:BYTE;
    XC,YC:BYTE;
    T:STRING;
BEGIN
  USERBREAK := FALSE;
  T := S;
1:S := T;
  XC := WHEREX;
  YC := WHEREY;
  P := SUCC(LENGTH(S));
  REPEAT
    WHILE LENGTH(S) < LENGTE DO S := S + '_';
    INLINE ($B8/$00/$01/$B9/$07/$26/$CD/$10); {---hidecursor---}
    GOTOXY (XC,YC);
    WRITE (S);
    GOTOXY (XC+PRED(P),YC);
    INLINE ($B8/$00/$01/$B9/$06/$05/$CD/$10); {---showcursor---}
    CH := READKEY;
    IF CH=#0 THEN
    BEGIN
      DH := READKEY;
      IF (DH=#75) AND (P>1) THEN DEC(P);
      IF (DH=#77) AND (P<=LENGTE) THEN INC(P);
      IF (DH=#83) AND (P<=LENGTE) THEN BEGIN
                                         DELETE (S,P,1);
                                         S := S + '_';
                                       END;
      IF (DH=#$75) AND (P<=LENGTE) THEN
      BEGIN
        FOR N := P TO LENGTE DO S[N] := '_';
      END;
      IF DH=#$47 THEN P := 1;
      IF DH=#$4F THEN BEGIN
                        P := SUCC(LENGTE);
                        WHILE S[PRED(P)]='_' DO DEC(P);
                      END;
    END;
    IF (CH=#8) AND (P>1) THEN BEGIN
                                DELETE (S,PRED(P),1);
                                S := S + '_';
                                DEC(P);
                              END;
    IF (CH>=' ') AND (P<=LENGTE) Then
    BEGIN
      DELETE (S,LENGTH(S),1);
      INSERT (CH,S,P);
      INC (P);
    END;
    IF CH=#27 THEN BEGIN
                     USERBREAK := TRUE;
                     EXIT;
                   END;
  UNTIL (CH=#13);
  WHILE S[LENGTH(S)] = '_' DO DELETE (S,LENGTH(S),1);
  IF S='' THEN GOTO 1;
  GOTOXY (XC,YC);
  WRITE (S);
  CLREOL;
END;
PROCEDURE RESETDSP; ASSEMBLER;
ASM;
               MOV   DX,WORD PTR IOPORT
               ADD   DL,$06
               MOV   AL,$01
               OUT   DX,AL
               MOV   CX,$0400
@RESDSP1:      NOP
               LOOP  @RESDSP1
               MOV   AL,$00
               OUT   DX,AL
               MOV   BL,$10
@RESDSP3:      MOV   DX,WORD PTR IOPORT
               ADD   DL,$0E
               MOV   CX,$0100
@RESDSP2:      IN    AL,DX
               TEST  AL,$80
               JNZ   @RESDSP4
               LOOP  @RESDSP2
               JMP   @RESDSP5
@RESDSP4:      SUB   DL,$04
               IN    AL,DX
               CMP   AL,$AA
               JZ    @RESDSP6
               DEC   BL
               JNZ   @RESDSP3
@RESDSP5:      MOV   WORD PTR IOPORT,$0000
@RESDSP6:
END;
PROCEDURE OUTBYTE; ASSEMBLER;
ASM;
               MOV   AH,AL
@OUTB1:        IN    AL,DX
               OR    AL,AL
               JS    @OUTB1
               MOV   AL,AH
               OUT   DX,AL
END;
PROCEDURE INBYTE; ASSEMBLER; {uitvoer AL=byte}
ASM;
               MOV   DX,WORD PTR IOPORT
               ADD   DL,$0E
@INB1:         IN    AL,DX
               OR    AL,AL
               JNS   @INB1
               SUB   DL,$04
               IN    AL,DX
END;
PROCEDURE STARTDMA (SEGM,ADRS:WORD;DIRECTION:BYTE); ASSEMBLER;
ASM; {direction=00h:from PC to ATOM; 01h:from ATOM to PC}
               {set samplerate}
               MOV   DX,WORD PTR IOPORT
               ADD   DL,$0C
               MOV   AL,$40
               CALL  OUTBYTE
               MOV   AL,$D2 {22050 Hz}
               CALL  OUTBYTE
               CMP   WORD PTR DSPVERSION,$0400
               JB    @SK1
               {set 8-bit, mono mode on SB16}
               MOV   AL,$C6
               CALL  OUTBYTE
               MOV   AL,$00
               CALL  OUTBYTE
@SK1:          {set dma blocksize}
               MOV   AL,$48
               CALL  OUTBYTE
               MOV   AL,((SAMPLESIZE SHR 1) - 1) AND $FF
               CALL  OUTBYTE
               MOV   AL,((SAMPLESIZE SHR 1) - 1) SHR 8
               CALL  OUTBYTE
               {enable speaker}
               MOV   AL,$D1
               CALL  OUTBYTE
               {setup dma}
               MOV   AL,BYTE PTR DMA
               OR    AL,$04
               OUT   $0A,AL
               MOV   AL,$00
               OUT   $0C,AL
               MOV   AL,$58
               CMP   BYTE PTR DIRECTION,$00
               JZ    @SK2
               MOV   AL,$54
@SK2:          OR    AL,BYTE PTR DMA
               OUT   $0B,AL
               MOV   AX,WORD PTR ADRS
               MOV   DX,WORD PTR SEGM
               ROL   DX,4
               MOV   CX,DX
               AND   DX,+$0F
               AND   CX,-$10
               ADD   AX,CX
               ADC   DX,+$00
               PUSH  DX
               MOV   DL,BYTE PTR DMA
               SHL   DL,1
               MOV   DH,$00
               OUT   DX,AL {address byte 0}
               MOV   AL,AH
               OUT   DX,AL {address byte 1}
               INC   DX
               MOV   AL,(SAMPLESIZE - 1) AND $FF
               OUT   DX,AL {byte count lo}
               MOV   AL,(SAMPLESIZE - 1) SHR 8
               OUT   DX,AL {byte count hi}
               MOV   BL,BYTE PTR DMA
               MOV   BH,$00
               MOV   DL,BYTE PTR @PAGENR[CS:BX]
               MOV   DH,$00
               POP   AX
               OUT   DX,AL {address byte 2}
               MOV   AL,BYTE PTR DMA
               OUT   $0A,AL
               {perform auto-init}
               MOV   DX,WORD PTR IOPORT
               ADD   DL,$0C
               MOV   AL,$1C
               CMP   BYTE PTR DIRECTION,$00
               JZ    @SK3
               MOV   AL,$2C
@SK3:          CALL  OUTBYTE
               JMP   @ENDOFPROC
@PAGENR:       DB    $87,$83,$81,$82
@ENDOFPROC:
END;
PROCEDURE IRQVECTOR (ZETTEN:BYTE); ASSEMBLER;
ASM;
               MOV   BL,BYTE PTR IRQ
               TEST  BL,$08
               JZ    @SETCLRIRQ2
               AND   BL,$07
               ADD   BL,$70
               JMP   @SETCLRIRQ1
@SETCLRIRQ2:   ADD   BL,$08
@SETCLRIRQ1:   MOV   BH,$00
               SHL   BX,2
               SUB   AX,AX
               MOV   ES,AX
               TEST  BYTE PTR ZETTEN,$FF
               JZ    @CLRIRQVEC
               CLI
               MOV   AX,WORD PTR [ES:BX]
               MOV   WORD PTR @ORGIRQVEC[CS:$00],AX
               MOV   AX,WORD PTR [ES:BX+$02]
               MOV   WORD PTR @ORGIRQVEC[CS:$02],AX
               MOV   AX,OFFSET @IRQHANDLER
               MOV   WORD PTR [ES:BX],AX
               MOV   WORD PTR [ES:BX+$02],CS
               STI
               JMP   @ENDOFPROC
@CLRIRQVEC:    CLI
               MOV   AX,WORD PTR @ORGIRQVEC[CS:$00]
               MOV   WORD PTR [ES:BX],AX
               MOV   AX,WORD PTR @ORGIRQVEC[CS:$02]
               MOV   WORD PTR [ES:BX+$02],AX
               STI
               JMP   @ENDOFPROC
@IRQHANDLER:   PUSH  DS
               PUSH  DX
               PUSH  AX
               MOV   AX,SEG IOPORT
               MOV   DS,AX
               MOV   DX,WORD PTR IOPORT
               ADD   DL,$0E
               IN    AL,DX
               CMP   BYTE PTR ENDOFDATA,$01
               JB    @IRQH2
               INC   BYTE PTR ENDOFDATA
@IRQH2:        XOR   BYTE PTR DMABUFNR,$03
               MOV   BYTE PTR IRQOCC,$01
               MOV   AL,$20
               CMP   BYTE PTR IRQ,$07
               JBE   @IRQH1
               OUT   $A0,AL
@IRQH1:        OUT   $20,AL
               POP   AX
               POP   DX
               POP   DS
               IRET
@ORGIRQVEC:    DD    $00000000
@ENDOFPROC:
END;
PROCEDURE CLRIRQMASK; ASSEMBLER;
ASM;
               MOV   DX,$0021
               MOV   CL,BYTE PTR IRQ
               TEST  CL,$08
               JZ    @SETMASK1
               AND   CL,$07
               MOV   DL,$A1
@SETMASK1:     MOV   AH,$01
               SHL   AH,CL
               NOT   AH
               IN    AL,DX
               AND   AL,AH
               OUT   DX,AL
END;
PROCEDURE SETIRQMASK; ASSEMBLER;
ASM;
               MOV   DX,$0021
               MOV   CL,BYTE PTR IRQ
               TEST  CL,$08
               JZ    @CLRMASK1
               AND   CL,$07
               MOV   DL,$A1
@CLRMASK1:     MOV   AH,$01
               SHL   AH,CL
               IN    AL,DX
               OR    AL,AH
               OUT   DX,AL
END;
PROCEDURE STOPDMA; ASSEMBLER;
ASM;
               MOV   DX,WORD PTR IOPORT
               ADD   DL,$0C
               {disable speaker}
               MOV   AL,$D3
               CALL  OUTBYTE
               {halt dma}
               MOV   AL,$D0
               CALL  OUTBYTE
               {exit auto-init mode}
               MOV   AL,$DA
               CALL  OUTBYTE
               {halt dma}
               MOV   AL,$D0
               CALL  OUTBYTE
END;
FUNCTION HEX2DEC (S:STRING):WORD;
VAR I:BYTE;
BEGIN
  FOR I := 1 TO LENGTH(S) DO S[I] := UPCASE(S[I]);
  WHILE LENGTH(S) < 4 DO S := '0' + S;
  FOR I := 1 TO 4 DO
  BEGIN
    DEC (S[I],48);
    IF ORD(S[I]) > 9 THEN DEC (S[I],7);
  END;
  HEX2DEC := SWAP((ORD(S[1]) SHL 4) + ORD(S[2])) +
             (ORD(S[3]) SHL 4) + ORD(S[4]);
END;
PROCEDURE INITBLASTER;
VAR S,T:STRING[80];
    I,J:BYTE;
    CODE:INTEGER;
    PS,IS,DS:BOOLEAN;
BEGIN
  PS := FALSE;
  IS := FALSE;
  DS := FALSE;
  S := GETENV ('BLASTER');
  FOR I := 1 TO LENGTH(S) DO S[I] := UPCASE(S[I]);
  WHILE (LENGTH(S) > 0) DO
  BEGIN
    IF (S[1]='A') OR (S[1]='I') OR (S[1]='D') THEN
    BEGIN
      T := '';
      I := 2;
      WHILE (I <= LENGTH(S)) AND (S[I] <> ' ') DO
      BEGIN
        T := T + S[I];
        INC (I);
      END;
      IF S[1] = 'A' THEN
      BEGIN
        IOPORT := HEX2DEC (T);
        PS := TRUE;
      END;
      IF S[1] = 'I' THEN
      BEGIN
        VAL (T,IRQ,CODE);
        IF CODE=0 THEN IS := TRUE;
      END;
      IF S[1] = 'D' THEN
      BEGIN
        VAL (T,DMA,CODE);
        IF CODE=0 THEN DS := TRUE;
      END;
      DELETE (S,1,I);
    END ELSE
    BEGIN
      DELETE (S,1,1);
    END;
  END;
  IF NOT (PS AND IS AND DS) THEN
  BEGIN
    WRITELN ('Blaster environment string not set or not set correctly. Program aborted.');
    HALT;
  END;
  WRITELN ('Soundcard detected at I/O-port    ',HEXW(IOPORT),'h');
  WRITELN ('                      IRQ-number  ',IRQ);
  WRITELN ('                      DMA-channel ',DMA);
  RESETDSP;
  IF IOPORT = $0000 THEN
  BEGIN
    WRITELN ('Cannot initialize SoundBlaster. Program aborted.');
    HALT;
  END;
  ASM;
               MOV   DX,WORD PTR IOPORT
               ADD   DL,$0C
               MOV   AL,$E1
               CALL  OUTBYTE
               CALL  INBYTE
               MOV   AH,AL
               CALL  INBYTE
               MOV   WORD PTR DSPVERSION,AX
  END;
  WRITE ('Card type: SoundBlaster ');
  CASE HI(DSPVERSION) OF 1: WRITE;
                         2: WRITE ('2');
                         3: WRITE ('Pro');
                       ELSE WRITE ('16');
  END;
  WRITELN (' or clone');
  WRITE ('           DSP-version ',HI(DSPVERSION),'.');
  IF LO(DSPVERSION) < 10 THEN WRITE ('0');
  WRITELN (LO(DSPVERSION));
  WRITELN;
  IF HI(DSPVERSION) <= 1 THEN
  BEGIN
    WRITELN ('Sorry, this card cannot handle "auto-init" mode. Program aborted.');
    HALT;
  END;
  FIRSTMAIN := TRUE;
END;
{---[main menu]-------------------------------------------------------------}
PROCEDURE MAINMENU (VAR SELECTION:BYTE);
VAR CH:CHAR;
BEGIN
  IF NOT FIRSTMAIN THEN CLRSCR
                   ELSE FIRSTMAIN := FALSE;
  TEXTCOLOR (LIGHTCYAN);
  WRITELN ('M A I N   M E N U');
  TEXTCOLOR (CYAN);
  WRITELN;
  WRITELN ('1   : Transfer data from PC to ATOM,');
  WRITELN ('2   : Transfer data from ATOM to PC,');
  WRITELN ('Esc : Return to OS.');
  TEXTCOLOR (LIGHTGRAY);
  WHILE KEYPRESSED DO CH := READKEY;
  REPEAT
    CH := READKEY;
    IF CH=#27 THEN HALT;
  UNTIL (CH >= '1') AND (CH <= '2');
  SELECTION := ORD(CH)-48;
  WRITELN;
END;
{---[data from pc to atom]--------------------------------------------------}
FUNCTION BUFHALF:WORD;
BEGIN
  IF DMABUFNR = 1 THEN BUFHALF := SIZEOF(DMABUFTYPE) SHR 1
                  ELSE BUFHALF := 0;
END;
PROCEDURE WAITFORDMA; {buffer filled, wait until other buffer is free}
VAR CH:CHAR;
BEGIN
  DMABUFPTR := $0000;
  REPEAT
    IF KEYPRESSED THEN
    BEGIN
      CH := READKEY;
      IF CH = #27 THEN USERBREAK := TRUE;
      WHILE KEYPRESSED DO CH := READKEY;
    END;
  UNTIL (IRQOCC <> $00) OR USERBREAK;
  IRQOCC := $00;
END;
PROCEDURE WRITEWAVE (BIT:BYTE);
VAR I,AANT:BYTE;
BEGIN
  IF SPEEDMODE = SCOS THEN AANT := 4
                      ELSE AANT := 1;
  IF BIT=0 THEN
  BEGIN
    FOR I := 1 TO AANT DO
    BEGIN
      WHILE (ROUND(WAVEPOS) < SIZEOF(WAVE0)) AND (NOT USERBREAK) DO
      BEGIN
        DMABUF^[BUFHALF+DMABUFPTR] := $80 - WAVE0[ROUND(WAVEPOS)];
        WAVEPOS := WAVEPOS + SIZEOF(WAVE0)/(22050/1200);
        INC (DMABUFPTR);
        IF DMABUFPTR >= (SIZEOF(DMABUFTYPE) SHR 1) THEN WAITFORDMA;
      END;
      WAVEPOS := WAVEPOS - SIZEOF(WAVE0);
    END;
  END ELSE
  BEGIN
    FOR I := 1 TO AANT DO
    BEGIN
      WHILE (ROUND(WAVEPOS) < SIZEOF(WAVE1)) AND (NOT USERBREAK) DO
      BEGIN
        DMABUF^[BUFHALF+DMABUFPTR] := $80 - WAVE1[ROUND(WAVEPOS)];
        WAVEPOS := WAVEPOS + SIZEOF(WAVE1)/(22050/1200);
        INC (DMABUFPTR);
        IF DMABUFPTR >= (SIZEOF(DMABUFTYPE) SHR 1) THEN WAITFORDMA;
      END;
      WAVEPOS := WAVEPOS - SIZEOF(WAVE1);
    END;
  END;
END;
PROCEDURE WRITEBYTE (BT:BYTE);
VAR I:WORD;
BEGIN
  CHECKSUM := (CHECKSUM + BT) AND $FF;
  WRITEWAVE (0); {---startbit---}
  I := $01;
  WHILE I < $0100 DO
  BEGIN
    IF BT AND I <> $00 THEN WRITEWAVE (1)
                       ELSE WRITEWAVE (0);
    I := I SHL 1;
  END;
  WRITEWAVE (1); {---stopbit---}
  {---extra half wave1---}
  WHILE (ROUND(WAVEPOS) < 46) AND (NOT USERBREAK) DO
  BEGIN
    DMABUF^[BUFHALF+DMABUFPTR] := $80 - WAVE1[ROUND(WAVEPOS)];
    WAVEPOS := WAVEPOS + SIZEOF(WAVE1)/(22050/1200);
    INC (DMABUFPTR);
    IF DMABUFPTR >= (SIZEOF(DMABUFTYPE) SHR 1 ) THEN WAITFORDMA;
  END;
  WAVEPOS := WAVEPOS - 46;
END;
PROCEDURE LOADSOURCEFILE;
VAR FROMF:FILE;
    SOURCEFILENAME:STRING;
    I:BYTE;
    CH:CHAR;
BEGIN
  WRITE ('Name of .ATM-file ? ');
  SOURCEFILENAME := '';
  INPUTSTRING (59,SOURCEFILENAME);
  IF USERBREAK THEN EXIT;
  WRITELN;
  WRITELN;
  FOR I := 1 TO LENGTH(SOURCEFILENAME) DO
    SOURCEFILENAME[I] := UPCASE(SOURCEFILENAME[I]);
  IF COPY(SOURCEFILENAME,LENGTH(SOURCEFILENAME)-3,4) <> '.ATM' THEN
    SOURCEFILENAME := SOURCEFILENAME + '.ATM';
  ASSIGN (FROMF,SOURCEFILENAME);
  RESET (FROMF,1);
  IF IORESULT <> 0 THEN
  BEGIN
    WRITELN (SOURCEFILENAME,' not found.');
    WHILE KEYPRESSED DO CH := READKEY;
    CH := READKEY;
    WHILE KEYPRESSED DO CH := READKEY;
    USERBREAK := TRUE;
    EXIT;
  END;
  ATMSIZE := FILESIZE(FROMF);
  BLOCKREAD (FROMF,ATMBUF^,ATMSIZE);
  CLOSE (FROMF);
END;
PROCEDURE PC_TO_ATOM;
LABEL 1,2,3;
VAR CH:CHAR;
    I:WORD;
    BLOCKNUMBER:BYTE;
    NUMBYTES:WORD;
    STARTADDRESS:WORD;
    ENDADDRESS:WORD;
    W:WORD;
    S:STRING;
BEGIN
  TEXTCOLOR (YELLOW);
  I := 0;
  WHILE (I < 16) AND (ATMBUF^[I] <> $00) DO
  BEGIN
    WRITE (CHR(ATMBUF^[I]));
    INC (I);
  END;
  WHILE WHEREX < 18 DO WRITE (' ');
  STARTADDRESS := ATMBUF^[$10] + SWAP(ATMBUF^[$11]);
  ENDADDRESS := ATMBUF^[$14] + SWAP(ATMBUF^[$15]) + STARTADDRESS;
  WRITE (HEXW(STARTADDRESS),' ',HEXW(ENDADDRESS),' ');
  WRITELN (HEXW(ATMBUF^[$12]+SWAP(ATMBUF^[$13])));
  TEXTCOLOR (LIGHTGRAY);
  WRITE ('Use SLOW or FAST tape interface [S/F] ? ');
  IF SPEEDMODE = SCOS THEN WRITE ('S')
                      ELSE WRITE ('F');
  WRITE (#8);
  WHILE KEYPRESSED DO CH := READKEY;
  REPEAT
    CH := UPCASE(READKEY);
    IF CH=#27 THEN GOTO 1;
    IF CH=#13 THEN IF SPEEDMODE = SCOS THEN CH := 'S'
                                       ELSE CH := 'F';
  UNTIL (CH='S') OR (CH='F');
  WRITELN (CH);
  IF CH='S' THEN SPEEDMODE := SCOS
            ELSE SPEEDMODE := FCOS;
2:GOTOXY (1,WHEREY);
  WRITE ('Start at ? ');
  CLREOL;
  S := HEXW(STARTADDRESS);
  INPUTSTRING (4,S);
  IF USERBREAK THEN GOTO 1;
  W := HEX2DEC (S);
  IF (W < STARTADDRESS) OR (W >= ENDADDRESS) THEN GOTO 2;
  STARTADDRESS := W;
  WRITELN ('h');
3:GOTOXY (1,WHEREY);
  WRITE ('End at ? ');
  CLREOL;
  S := HEXW(ENDADDRESS);
  INPUTSTRING (4,S);
  IF USERBREAK THEN GOTO 1;
  W := HEX2DEC (S);
  IF (W <= STARTADDRESS) OR (W > ENDADDRESS) THEN GOTO 3;
  ENDADDRESS := W;
  WRITELN ('h');
  WRITELN;
  USERBREAK := FALSE;
  ENDOFDATA := $00;
  IRQOCC := $00;
  DMABUFNR := 1;
  DMABUFPTR := $0000;
  ATMBUFPTR := $0016;
  W := STARTADDRESS - (ATMBUF^[$10] + SWAP(ATMBUF^[$11]));
  MOVE (ATMBUF^[$0016+W],ATMBUF^[$0016],ATMSIZE-W);
  ATMSIZE := $0016 + ENDADDRESS - STARTADDRESS;
  WAVEPOS := 0;
  FILLCHAR (DMABUF^,SIZEOF(DMABUFTYPE),$80);
  BLOCKNUMBER := $00;
  IRQVECTOR (1);
  CLRIRQMASK;
  STARTDMA (SEG(DMABUF^),OFS(DMABUF^),$00);
  TEXTCOLOR (WHITE);
  WRITE ('Send status:');
  TEXTCOLOR (LIGHTGRAY);
  WHILE (ATMBUFPTR < ATMSIZE) AND (NOT USERBREAK) DO
  BEGIN
    NUMBYTES := $0100;
    IF ATMSIZE - ATMBUFPTR < $0100 THEN NUMBYTES := ATMSIZE - ATMBUFPTR;
    FOR I := 1 TO 1200 DO WRITEWAVE (1);
    WRITELN;
    FOR I := 0 TO 15 DO
    BEGIN
      IF ATMBUF^[I] = $00 THEN WRITE (' ')
                          ELSE WRITE (CHR(ATMBUF^[I]));
    END;
    I := STARTADDRESS + SWAP(BLOCKNUMBER);
    WRITE (' ',HEXW(I),' ',HEXW(I+PRED(NUMBYTES)));
    WRITE (' ',HEXW(SWAP(ATMBUF^[$13])+ATMBUF^[$12]));
    WRITE (' ',HEX(BLOCKNUMBER));
    CLREOL;
    {---write control block---}
    CHECKSUM := $00;
    FOR I := 1 TO 4 DO WRITEBYTE (ORD('*'));
    I := 0;
    WHILE (I < 16) AND (ATMBUF^[I] <> $00) DO
    BEGIN
      WRITEBYTE (ATMBUF^[I]);
      INC (I);
    END;
    WRITEBYTE ($0D);
    {---last block?---}
    IF ATMBUFPTR + 256 >= ATMSIZE THEN WRITEBYTE ($7F)
                                  ELSE WRITEBYTE ($FF);
    WRITEBYTE ($00);
    WRITEBYTE (BLOCKNUMBER);
    WRITEBYTE (PRED(NUMBYTES));
    WRITEBYTE (ATMBUF^[$13]);
    WRITEBYTE (ATMBUF^[$12]);
    WRITEBYTE (HI(STARTADDRESS + SWAP(BLOCKNUMBER)));
    WRITEBYTE (LO(STARTADDRESS));
    IF SPEEDMODE = SCOS THEN FOR I := 1 TO 240 DO WRITEWAVE (1)
                        ELSE FOR I := 1 TO 300 DO WRITEWAVE (1);
    {---write datablock---}
    FOR I := 0 TO PRED(NUMBYTES) DO WRITEBYTE (ATMBUF^[ATMBUFPTR+I]);
    INC (ATMBUFPTR,NUMBYTES);
    {---write checksum---}
    WRITEBYTE (CHECKSUM);
    INC (BLOCKNUMBER);
  END;
  WRITEWAVE (1);
  FILLCHAR (DMABUF^[BUFHALF+DMABUFPTR],(SIZEOF(DMABUFTYPE) SHR 1)-DMABUFPTR,$80);
  ENDOFDATA := $01;
  REPEAT UNTIL (ENDOFDATA = $03) OR USERBREAK;
  STOPDMA;
  SETIRQMASK;
  IRQVECTOR (0);
1:GOTOXY (1,WHEREY);
  IF USERBREAK THEN WRITE ('User break.')
               ELSE WRITE ('Transfer ended.');
  CLREOL;
  WRITELN;
END;
{---[data from atom to pc]--------------------------------------------------}
FUNCTION GETBYTE:BYTE;
VAR CH:CHAR;
BEGIN
  IF USERBREAK THEN EXIT;
  IF DMABUFPTR >= (SIZEOF(DMABUFTYPE) SHR 1) THEN
  BEGIN
    DMABUFPTR := $0000;
    REPEAT
      IF KEYPRESSED THEN
      BEGIN
        CH := READKEY;
        IF CH = #27 THEN USERBREAK := TRUE;
        WHILE KEYPRESSED DO CH := READKEY;
      END;
    UNTIL (IRQOCC <> $00) OR USERBREAK;
    IRQOCC := $00;
  END;
  GETBYTE := DMABUF^[BUFHALF+DMABUFPTR];
  INC (DMABUFPTR);
  INC (WAVELENGTH);
END;
PROCEDURE SEEKENDOFWAVE;
BEGIN
  WAVELENGTH := 0;
  IF FIRSTWAVEDOWN THEN
  BEGIN
    REPEAT
      IF USERBREAK THEN EXIT;
    UNTIL GETBYTE > SILENCE;
    REPEAT
      IF USERBREAK THEN EXIT;
    UNTIL (GETBYTE < SILENCE) OR (WAVELENGTH = $FF);
    IF (WAVELENGTH > MAXWAVE1) AND (WAVELENGTH < MINWAVE0) THEN
    BEGIN
      REPEAT
        IF USERBREAK THEN EXIT;
      UNTIL GETBYTE > SILENCE;
      WAVELENGTH := (MINWAVE0 + MAXWAVE0) DIV 2;
      FIRSTWAVEDOWN := FALSE;
    END;
  END ELSE
  BEGIN
    REPEAT
      IF USERBREAK THEN EXIT;
    UNTIL GETBYTE < SILENCE;
    REPEAT
      IF USERBREAK THEN EXIT;
    UNTIL (GETBYTE > SILENCE) OR (WAVELENGTH = $FF);
    IF (WAVELENGTH > MAXWAVE1) AND (WAVELENGTH < MINWAVE0) THEN
    BEGIN
      REPEAT
        IF USERBREAK THEN EXIT;
      UNTIL GETBYTE < SILENCE;
      WAVELENGTH := (MINWAVE0 + MAXWAVE0) DIV 2;
      FIRSTWAVEDOWN := TRUE;
    END;
  END;
END;
FUNCTION READONEATMBYTE (FIRSTWAVEDONE:BOOLEAN):BYTE;
VAR DATABITS:ARRAY[0..9] OF BYTE;
    S:STRING[16];
    I:BYTE;
BEGIN
  I := 0;
  DATABITS[0] := 0;
  S := '';
  IF SPEEDMODE = SCOS THEN
  BEGIN
    IF FIRSTWAVEDONE THEN S := '00';
  END ELSE
  BEGIN
    IF FIRSTWAVEDONE THEN I := 1;
  END;
  WHILE I <= 9 DO
  BEGIN
    SEEKENDOFWAVE;
    IF WAVELENGTH <= MAXWAVE1 THEN
    BEGIN
      S := S + '1';
    END ELSE
      IF WAVELENGTH >= MINWAVE0 THEN
      BEGIN
        S := S + '00';
      END;
    IF ((SPEEDMODE = FCOS) AND (S='00')) OR
       ((SPEEDMODE = SCOS) AND (S='00000000')) THEN
    BEGIN
      DATABITS[I] := 0;
      INC (I);
      S := '';
    END ELSE
      IF ((SPEEDMODE = FCOS) AND (S='11')) OR
         ((SPEEDMODE = SCOS) AND (S='11111111')) THEN
      BEGIN
        DATABITS[I] := 1;
        INC (I);
        S := '';
      END;
    IF ((SPEEDMODE = FCOS) AND (LENGTH(S) > 2)) OR
       ((SPEEDMODE = SCOS) AND (LENGTH(S) > 8)) THEN
    BEGIN
      GOTOXY (1,WHEREY);
      WRITELN ('Error: Misformed wave pattern.');
      USERBREAK := TRUE;
      EXIT;
    END;
  END;
  SEEKENDOFWAVE; {stopbit always has one extra wave}
  IF DATABITS[0] <> 0 THEN
  BEGIN
    GOTOXY (1,WHEREY);
    WRITELN ('Error: No startbit (0) found.');
    USERBREAK := TRUE;
    EXIT;
  END;
  IF DATABITS[9] <> 1 THEN
  BEGIN
    GOTOXY (1,WHEREY);
    WRITELN ('Error: No stopbit (1) found.');
    USERBREAK := TRUE;
    EXIT;
  END;
  ASM;
               MOV   DI,$0001
  @LP1:        SHR   BYTE PTR DATABITS[DI],1
               RCR   AL,1
               INC   DI
               CMP   DI,+$09
               JB    @LP1
               MOV   BYTE PTR I,AL
  END;
  READONEATMBYTE := I;
END;
FUNCTION READFIRSTBYTEHEADER:BOOLEAN;
CONST NIL_FAST = '00';
      NIL_SLOW = '00000000';
      ONE_FAST = '11';
      ONE_SLOW = '11111111';
      ASTERISK_FAST = NIL_FAST +
                      NIL_FAST + ONE_FAST + NIL_FAST + ONE_FAST +
                      NIL_FAST + ONE_FAST + NIL_FAST + NIL_FAST +
                      ONE_FAST + '1';
      ASTERISK_SLOW = NIL_SLOW +
                      NIL_SLOW + ONE_SLOW + NIL_SLOW + ONE_SLOW +
                      NIL_SLOW + ONE_SLOW + NIL_SLOW + NIL_SLOW +
                      ONE_SLOW + '1';
VAR S:STRING;
BEGIN
  S := '00';
  REPEAT
    SEEKENDOFWAVE;
    IF WAVELENGTH <= MAXWAVE1 THEN
    BEGIN
      S := S + '1';
    END ELSE
      IF WAVELENGTH >= MINWAVE0 THEN
      BEGIN
        S := S + '00';
      END;
    IF S = ASTERISK_FAST THEN
    BEGIN
      SPEEDMODE := FCOS;
      READFIRSTBYTEHEADER := TRUE;
      EXIT;
    END;
    IF S = ASTERISK_SLOW THEN
    BEGIN
      SPEEDMODE := SCOS;
      READFIRSTBYTEHEADER := TRUE;
      EXIT;
    END;
  UNTIL (LENGTH(S) > LENGTH(ASTERISK_SLOW)) OR USERBREAK;
  READFIRSTBYTEHEADER := FALSE;
END;
PROCEDURE ATOM_TO_PC;
LABEL 1,2,3,4;
VAR HEADER:ARRAY[$00..$FF] OF BYTE;
    HP:BYTE;
    NUMBYTES:WORD;
    I:BYTE;
    W:WORD;
    EERSTE:BOOLEAN;
    LASTBLOCK:BOOLEAN;
    TOF:FILE;
    STARTOFBLOCK:WORD;
    CH:CHAR;
    DESTFILENAME:STRING;
BEGIN
  USERBREAK := FALSE;
  ENDOFDATA := $00;
  IRQOCC := $00;
  DMABUFNR := 1;
  DMABUFPTR := $0000;
  ATMBUFPTR := $0000;
  FILLCHAR (DMABUF^,SIZEOF(DMABUFTYPE),$80);
  IRQVECTOR (1);
  CLRIRQMASK;
  IF HI(DSPVERSION) >= 3 THEN
  BEGIN
    ASM;
               MOV   DX,WORD PTR IOPORT
               ADD   DL,$04
               MOV   AL,$0C
               OUT   DX,AL
               INC   DX
               IN    AL,DX
               OR    AL,00000110b
               OUT   DX,AL
    END;
  END;
  IF HI(DSPVERSION) >= 4 THEN
  BEGIN
    ASM;
               MOV   DX,WORD PTR IOPORT
               ADD   DL,$04
               MOV   AL,$3D
               OUT   DX,AL
               INC   DX
               MOV   AL,00011000b
               OUT   DX,AL
               DEC   DX
               MOV   CX,$0200
    @LP1:      NOP
               LOOP  @LP1
               MOV   AL,$3E
               OUT   DX,AL
               INC   DX
               MOV   AL,00011000b
               OUT   DX,AL
    END;
  END;
  STARTDMA (SEG(DMABUF^),OFS(DMABUF^),$01);
  TEXTCOLOR (WHITE);
  WRITELN ('Receive status:');
  TEXTCOLOR (LIGHTGRAY);
2:STARTOFBLOCK := ATMBUFPTR;
  FIRSTWAVEDOWN := FALSE;
  WRITE ('Waiting for control block...');
  REPEAT
    SEEKENDOFWAVE;
    IF USERBREAK THEN GOTO 1;
  UNTIL (WAVELENGTH > MAXWAVE1) AND (WAVELENGTH <= MAXWAVE0);
  GOTOXY (1,WHEREY);
  IF NOT READFIRSTBYTEHEADER THEN GOTO 2;
  WRITE ('Receiving control block...');
  CLREOL;
  HEADER[0] := $2A;
  HP := 1;
  CHECKSUM := $2A;
  REPEAT
    HEADER[HP] := READONEATMBYTE (FALSE);
    IF USERBREAK THEN GOTO 1;
    CHECKSUM := LO(CHECKSUM + HEADER[HP]);
    INC (HP);
  UNTIL ((HP >= $0D) AND (HEADER[HP-$09] = $0D)) OR (HP >= $80);
  GOTOXY (1,WHEREY);
  IF (HEADER[$00] <> ORD('*')) OR (HEADER[$01] <> ORD('*')) OR
     (HEADER[$02] <> ORD('*')) OR (HEADER[$03] <> ORD('*')) THEN
  BEGIN
    WRITELN ('Error: Control block corrupted.');
    USERBREAK := TRUE;
    GOTO 1;
  END;
  I := $04;
  WHILE HEADER[I] <> $0D DO
  BEGIN
    WRITE (CHR(HEADER[I]));
    ATMHEADER.ATOMNAME[I-$04] := HEADER[I];
    INC (I);
  END;
  INC (I);
  WHILE WHEREX < 17 DO WRITE (' ');
  W := HEADER[I+$07] + (WORD(HEADER[I+$06]) SHL 8);
  IF HEADER[I+$02] = $00 THEN ATMHEADER.STARTADDRESS := W;
  WRITE (HEXW(W),' ');
  NUMBYTES := SUCC(WORD(HEADER[I+$03]));
  INC (W,PRED(NUMBYTES));
  WRITE (HEXW(W),' ');
  W := HEADER[I+$05] + (WORD(HEADER[I+$04]) SHL 8);
  IF HEADER[I+$02] = $00 THEN ATMHEADER.EXECADDRESS := W;
  WRITE (HEXW(W),'  ');
  W := HEADER[I+$02];
  WRITELN (HEX(W));
  W := HEADER[I];
  IF W AND $80 = $00 THEN LASTBLOCK := TRUE
                     ELSE LASTBLOCK := FALSE;
  {---searching datablock---}
  FIRSTWAVEDOWN := FALSE;
  WRITE ('Waiting for data block...');
  REPEAT
    SEEKENDOFWAVE;
    IF USERBREAK THEN GOTO 1;
  UNTIL (WAVELENGTH > MAXWAVE1) AND (WAVELENGTH <= MAXWAVE0);
  {---read datablock---}
  GOTOXY (1,WHEREY);
  WRITE ('Receiving data block...');
  CLREOL;
  EERSTE := TRUE;
  FOR W := 1 TO NUMBYTES DO
  BEGIN
    ATMBUF^[ATMBUFPTR] := READONEATMBYTE (EERSTE);
    EERSTE := FALSE;
    IF USERBREAK THEN GOTO 1;
    CHECKSUM := LO(CHECKSUM + ATMBUF^[ATMBUFPTR]);
    INC (ATMBUFPTR);
  END;
  I := READONEATMBYTE (FALSE); {---checksum---}
  GOTOXY (1,WHEREY);
  CLREOL;
  IF I <> CHECKSUM THEN
  BEGIN
    WRITELN ('Checksum error: ',HEX(CHECKSUM),'h must be ',HEX(I),'h.');
    USERBREAK := TRUE;
    GOTO 1;
  END;
  IF NOT LASTBLOCK THEN GOTO 2;
  STOPDMA;
  SETIRQMASK;
  IRQVECTOR (0);
3:ATMHEADER.DATASIZE := ATMBUFPTR;
  WRITELN;
  WRITELN;
4:WRITE ('Name of .ATM-file ? ');
  DESTFILENAME := '';
  INPUTSTRING (59,DESTFILENAME);
  IF USERBREAK THEN EXIT;
  WRITELN;
  WRITELN;
  FOR I := 1 TO LENGTH(DESTFILENAME) DO
    DESTFILENAME[I] := UPCASE(DESTFILENAME[I]);
  IF COPY(DESTFILENAME,LENGTH(DESTFILENAME)-3,4) <> '.ATM' THEN
    DESTFILENAME := DESTFILENAME + '.ATM';
  ASSIGN (TOF,DESTFILENAME);
  RESET (TOF,1);
  IF IORESULT = 0 THEN
  BEGIN
    CLOSE (TOF);
    WRITE ('Filename ',DESTFILENAME,' already exists. Overwrite [Y/N] ? Y',#8);
    WHILE KEYPRESSED DO CH := READKEY;
    REPEAT
      CH := UPCASE(READKEY);
      IF CH=#27 THEN CH := 'N';
      IF CH=#13 THEN CH := 'Y';
    UNTIL (CH='Y') OR (CH='N');
    WRITELN (CH);
    WRITELN;
    IF CH='N' THEN GOTO 4;
  END;
  REWRITE (TOF,1);
  IF IORESULT <> 0 THEN
  BEGIN
    WRITELN ('Access denied or other I/O-error.');
    GOTO 4;
  END;
  BLOCKWRITE (TOF,ATMHEADER,SIZEOF(ATMHEADER));
  BLOCKWRITE (TOF,ATMBUF^,ATMBUFPTR);
  CLOSE (TOF);
  EXIT;
  {if error occurred}
1:STOPDMA;
  SETIRQMASK;
  IRQVECTOR (0);
  ATMBUFPTR := STARTOFBLOCK;
  IF ATMBUFPTR = $0000 THEN EXIT;
  WRITELN;
  WRITE (HEXW(ATMBUFPTR),'h (',ATMBUFPTR,') bytes of data have been ');
  WRITE ('received and verified. Save [Y/N] ? Y',#8);
  WHILE KEYPRESSED DO CH := READKEY;
  REPEAT
    CH := UPCASE(READKEY);
    IF CH=#27 THEN CH := 'N';
    IF CH=#13 THEN CH := 'Y';
  UNTIL (CH='Y') OR (CH='N');
  WRITE (CH);
  IF CH='Y' THEN GOTO 3;
END;
{---[change baudrate]-------------------------------------------------------}
PROCEDURE CHANGEBAUDRATE;
VAR CH:CHAR;
BEGIN
  WRITE ('Use SLOW or FAST tape interface [S/F] ? ');
  IF SPEEDMODE = SCOS THEN WRITE ('S')
                      ELSE WRITE ('F');
  WRITE (#8);
  WHILE KEYPRESSED DO CH := READKEY;
  REPEAT
    CH := UPCASE(READKEY);
    IF (CH=#13) OR (CH=#27) THEN EXIT;
  UNTIL (CH='S') OR (CH='F');
  WRITELN (CH);
  IF CH='S' THEN SPEEDMODE := SCOS
            ELSE SPEEDMODE := FCOS;
END;
{---[main]------------------------------------------------------------------}
LABEL 1;
VAR SELECTION:BYTE;
    PHYSADDR:LONGINT;
    DUMMY:POINTER;
    DUMMYSIZE:LONGINT;
BEGIN
  SPEEDMODE := FCOS;
  CLRSCR;
  TEXTCOLOR (WHITE);
  WRITELN ('-------------------------------------------------------');
  WRITELN (' AtomCom v1.10 (c) Wouter Ras, Delft, Dec 97 - Mar 98.');
  WRITELN ('-------------------------------------------------------');
  WRITELN;
  TEXTCOLOR (LIGHTGRAY);
  WINDOW (1,5,80,25);
  INITBLASTER;
  GETMEM (ATMBUF,SIZEOF(ATMBUFTYPE));
  {allocate memory for dma buffer, make sure it's entirely on 1 page}
  GETMEM (DUMMY,1);
  PHYSADDR := (LONGINT(SEG(DUMMY^)) SHL 4) + LONGINT(OFS(DUMMY^));
  DUMMYSIZE := $10000 - (PHYSADDR AND $FFFF);
  IF DUMMYSIZE >= SIZEOF(DMABUFTYPE) THEN DUMMYSIZE := 0;
  FREEMEM (DUMMY,1);
  GETMEM (DUMMY,DUMMYSIZE);
  GETMEM (DMABUF,SIZEOF(DMABUFTYPE));
1:MAINMENU (SELECTION);
  CASE SELECTION OF 1: BEGIN
                         WRITELN ('Transfer data from PC to ATOM.');
                         WRITELN;
                         LOADSOURCEFILE;
                         IF USERBREAK THEN GOTO 1;
                         PC_TO_ATOM;
                       END;
                    2: BEGIN
                         WRITELN ('Transfer data from ATOM to PC.');
                         WRITELN;
                         ATOM_TO_PC;
                       END;
  END;
  GOTO 1;
END.
terug.gif