!   "MAKEBINARY" -- MAKE SDOS BINARY FILES FROM MIKBUG
!
!   Revision History:
!       v1.0  1/2/81
!             Compiled under BASIC 1.4H, released with same
!       v1.1a 4/26/82
!             Modified to produce object file type suitable...
!             for machine on which the program is running
!             Cleaned up operator interface
!             Released with 6809 SDOS
!
        DIM Version$/"Make Binary v1.1a"/
        DIM HEADER$/1,0,0,0,0/,RECORD$/2,0,0,0,0/
        DIM SKP$/0,0,0/,TYPE3$/3/,IN/1/,OUT/2/
        DIM LINE$(132),MIKBUGFILE$(50),OBJECTFILE$(50)
        DIM CHAR$(1),NULL$/0/
        DIM CR$/:0D/,LF$/:0A/
        DIM SA$(80)
        DIM T$/':  '/,TEMPBYTE$/0/
        ! NULLOBJECTFILE$ CONTAINS 6800 SDOS OBJECT "FILE"...
        !     THAT LOADS 0 BYTES AT :2E00
        DIM NULLOBJECTFILE$/:1,:00,:00,:FF,:FF,:03,:2E,:00,:00,:00/
        DIM LOAD$/:5,14/

        DEF MSB(X1) = INT(X1/256)
        DEF LSB(X2) = X2 - INT(X2/256)*256

        IF COL(0)>1
        THEN
            ! Operator knows his SDOS, all data is on command line
            INPUT '' LINE$
            PRINT Version$
            LET LINE$=UPPERCASE$(LINE$)
            LET I=FIND(LINE$," TO ")
            IF I=0 THEN ERROR 102
            LET MIKBUGFILE$=LEFT$(LINE$,I)
            LET OBJECTFILE$=RIGHT$(LINE$,I+4)
        ELSE
            ! Operator is a dummy, prompt him for everything...
            PRINT Version$
            INPUT "Mikbug format file to be converted: " MIKBUGFILE$
            INPUT "Place SDOS object file in: " OBJECTFILE$
        FI
        INPUT "Start address (default is 1st load record address): " SA$
        ! Open the files...
        OPEN #IN, MIKBUGFILE$

        ! Determine proper type of object file
        FOR CPUTYPE=0 TO 255
            ! I contains CPU type to try
            CREATE #OUT, OBJECTFILE$
            NULLOBJECTFILE$(1)=CPUTYPE \ ! CHANGE OBJECT FILE CPU TYPE
            WRITE #OUT, NULLOBJECTFILE$
            CLOSE #OUT
            ! TRY CPU TYPE TO SEE IF SDOS COMPLAINS...
            ! (ISN'T THIS TACKY??)
            IF ERROR WHEN SYSCALL LOAD$,OBJECTFILE$,LINE$
            THEN CYCLE CPUTYPE
            ELSE FOUNDCPUTYPE
        NEXT CPUTYPE
        Print "Program bug! Cannot determine CPU type."
        ERROR 104

FOUNDCPUTYPE: ! CPUTYPE OF PROCESSOR WE ARE RUNNING ON IS NOW KNOWN
        CREATE #OUT,OBJECTFILE$ \ ! CREATE THE FILE
        LOADPTR=0 \ ! so it has a value if we display an error
        FILEPOSITION = 5 \ ! Where to put 1st data record
        RECORDSTARTED = FALSE
PROCESSMIKBUG: ! PROCESS THE NEXT MIKBUG CHARACTER
        GOSUB GETMIKBUGCHARACTER
        IF CHAR$ <> 'S' THEN BADMIKBUGCHARACTER
PROCESSMIKBUGTYPE: ! PROCESS TYPE OF MIKBUG CHARACTER
        GOSUB GETMIKBUGCHARACTER
        IF CHAR$ = '0'
        THEN
            ! EAT S0 RECORD CONTENTS AND IGNORE
            REPEAT
                GOSUB GETMIKBUGCHARACTER
            UNLESS CHAR$='S' END
            GOTO PROCESSMIKBUGTYPE
        FI
        IF CHAR$ = '9' THEN ENDOFMIKBUG
        IF CHAR$ <> '1' THEN BADMIKBUGCHARACTER \ ! VERIFY S1 RECORDS EXIST
        ! PROCESS THE START OF AN S1 RECORD
        ! Sets up checksum, data byte count and load pointer
        CHECKSUM = 0 \ ! Reset checksum total
        GOSUB GETMIKBUGHEXBYTE
        COUNTER = BYTE - 3
!       IF COUNTER = 0
!       THEN PRINT "Illegal Mikbug Count @ "; hex(LOADPTR$)\Error 104
        GOSUB GETMIKBUGHEXBYTE
        TEMP = BYTE
        GOSUB GETMIKBUGHEXBYTE
        LOADPTR = TEMP**8+BYTE
        IF SA$='' THEN SA$=HEX$(LOADPTR) \ ! SET START ADDRESS TO 1ST LOAD ADDR
300     IF NOT RECORDSTARTED
        THEN
            ! TIME TO START A NEW LOAD RECORD
310         RECORDSTARTED=TRUE
            RECORD$(2) = MSB(LOADPTR) \ RECORD$(3) = LSB(LOADPTR)
            RECORDADDRESS = FILEPOSITION
            WRITE #OUT@RECORDADDRESS, RECORD$ \ ! ALLOCATE RECORD HEAD SPACE
            FILEPOSITION = FILEPOSITION +5
            RECORDSTART = LOADPTR
            RECORDEND = LOADPTR - 1
            OFFSET = FILEPOSITION - RECORDSTART
        FI
        ! SEE IF THIS MIKBUG RECORD IS CONTIGUOUS WITH OR CONTAINED IN...
        ! THE CURRENTLY STARTED BINARY RECORD
        IF LOADPTR<RECORDSTART OR LOADPTR>RECORDEND+1
        THEN
            ! THIS MIKBUG RECORD DOES NOT BELONG IN THE CURRENT BINARY RECORD.
            GOSUB 500 \ ! finish the current record
            GOTO 300 \ ! and go start another
        FI
        ! NEW MIKBUG RECORD CONCATENATES OR OVERLAPS TAIL OF PREVIOUS.
        ! POSITION OBJECT FILE TO WRITE DATA BYTES FROM NEW MIKBUG RECORD.
330     IF ERROR WHEN RESTORE #OUT, LOADPTR+OFFSET
        THEN ! IGNORE POSITION EOF
        FOR I = 1 TO COUNTER
             ! COPY MIKBUG BYTES INTO OBJECT FILE
             GOSUB GETMIKBUGHEXBYTE
             TEMPBYTE$(1) = BYTE
             WRITE #OUT, TEMPBYTE$
        NEXT I

        DELTA = LOADPTR+COUNTER-RECORDEND-1\ ! = # BYTES RECORD WAS EXTENDED
        IF DELTA > 0
        THEN
            RECORDEND = RECORDEND + DELTA
            FILEPOSITION = FILEPOSITION + DELTA
        ELSE ! RECORD WAS NOT EXTENDED, DON'T ADJUST SIZE OF IT!
340     GOSUB GETMIKBUGHEXBYTE \ ! CHECK THE CHECKSUM BYTE
        IF CHECKSUM = :FF THEN PROCESSMIKBUG \ ! CHECKSUM IS OK, DO SOME MORE
        PRINT 'Checksum error at'; HEX$(LOADPTR)\ERROR 104

ENDOFMIKBUG: ! MIKBUG SOURCE FILE EXHAUSTED, CLEAN UP AND QUIT!
        GOSUB 500 \ ! FINISH OFF CURRENT RECORD
        WRITE #OUT@RECORDADDRESS, TYPE3$ \ ! MARK FINAL RECORD AS "GO" TYPE
        ! Finally, write out start record of object file
        LET STARTADDRESS=VAL(SA$) \ ! Too bad if you get a conversion err
        HEADER$(1)=CPUTYPE \ ! mark header with CPU type
        HEADER$(2)=MSB(STARTADDRESS) \ HEADER$(3)=LSB(STARTADDRESS)
        HEADER$(4)=COM(HEADER$(2))&:FF \ HEADER$(5)=COM(HEADER$(3))&:FF
        WRITE #OUT@0, HEADER$
        PRINT "All done."
        EXIT

500     ! WRITE RECORD LENGTH TO RECORD HEADER
        IF RECORDSTARTED
        THEN
            I = RECORDEND - RECORDSTART + 1 \ ! # BYTES IN RECORD
            RECORD$(4) = MSB(I) \ RECORD$(5) = LSB(I)
            WRITE #OUT@RECORDADDRESS, RECORD$ \ ! UPDATE COUNT IN RECORD
            IF ERROR WHEN RESTORE #OUT, FILEPOSITION
            THEN ! IGNORE EOF ON POSITION
            RECORDSTARTED = FALSE
        FI
        RETURN

GETMIKBUGHEXBYTE: ! READ HEX BYTE FROM MIKBUG FILE AND ADD TO CHECKSUM
        READ #IN,T$(2,2)\ ! T$ IS DIM'D AS... DIM T$/":0000"/
        IF EOF(IN) THEN ERROR 1001 \ ! PROPOGATE UNEXPECTED EOF ERROR
        IF ERROR WHEN BYTE = VAL(T$)
        THEN PRINT 'Conversion error at '; HEX$(LOADPTR) \ EXIT
        CHECKSUM = (CHECKSUM + BYTE) & :FF
        RETURN

GETMIKBUGCHARACTER: ! READ MIKBUG CHARACTER
        ! IGNORE <CR>, <LF>, OR :10 CODES, WHICH ARE NOISE CHARACTERS
        READ #IN,CHAR$ \ ! NOTE: PARITY BITS ARE ASSUMED TO BE ZERO
        IF EOF(IN) THEN ERROR 1001 \ ! PROPOGATE UNEXPECTED EOF ERROR
        IF CHAR$=CR$ OR CHAR$=LF$ OR CHAR$(1)=:10 THEN GETMIKBUGCHARACTER
        RETURN

BADMIKBUGCHARACTER: ! Something icky was encountered in the MIKBUG file.
        PRINT 'Unexpected char at ' ; HEX$(LOADPTR)
        ERROR 104 \ ! Program terminated abnormally

END
******************************************************************************
************** DEAD CODE FOLLOWS *********************************************
******************************************************************************
REM THIS SECTION ON SKIP RECORDS REMOVED BECAUSE THEY APPEAR TO BE USELESS
        ! DETERMINE SECTOR SIZE OF TARGET DISK.
        DEF MODULO(X3) = X3 - INT(X3/SECTORSIZE)*SECTORSIZE

        SYSCALL #OUT,SCGETPARAMS$,"",TEMP$
        SECTORSIZE=TEMP$[1]*256+TEMP$[2]
        PRINT "SECTORSIZE = ";SECTORSIZE

320     ! DOES THIS MIKBUG RECORD CROSS A PAGE BOUNDARY?
        IF LSB(LOADPTR) + COUNTER >= SECTORSIZE ...
&          AND MODULO(FILEPOSITION) <> MODULO(LOADPTR) THEN 325 \ ! YES
            ! SKIP RECORD NEEDED?
            IF LSB(LOADPTR) + COUNTER < SECTORSIZE THEN 310 \ ! NO, IT FITS IN THIS SECTOR
            IF MODULO(FILEPOSITION + 5) = MODULO(LOADPTR) THEN 310 \ ! NO
            THEN
                ! OUTPUT A SKIP RECORD
???WHAT THE HELL IS MODULO??
                SKIPCOUNT=MODULO(SECTORSIZE-MODULO(FILEPOSITION+8)+...
&                                MODULO(LOADPTR))
                SKP$(2)=MSB(SKIPCOUNT) \ SKP$(3)=LSB(SKIPCOUNT)
                WRITE #OUT, SKP$ \ FILEPOSITION=FILEPOSITION+3+SKIPCOUNT
                ! OUTPUT NULLS TO FILL THE SKIP RECORD
                FOR I = 1 TO SKIPCOUNT DO WRITE #OUT,NULL$
            FI
