https://github.com/virtualagc/virtualagc
Revision 078c79d8734a9ed2860303a7c1662004284fe853 authored by Ron Burkey on 07 August 2022, 15:04:04 UTC, committed by Ron Burkey on 07 August 2022, 15:04:04 UTC
assembly listings from yaASM and yaLEMAP. Added some debugging messages
to 'make install'.  Tweaked debugging messages that VirtualAGC embeds in
'simulate'.  Verified buildability in Mint 21, 20, 19, 17, and verified
buildability using clang in Mint 17.
1 parent 6bb1acc
Raw File
Tip revision: 078c79d8734a9ed2860303a7c1662004284fe853 authored by Ron Burkey on 07 August 2022, 15:04:04 UTC
Fixed a potential string-overflow bug in yaASM. Removed timestamps from
Tip revision: 078c79d
binsourcer.py
#
# Python program to aid entering AGC binsource.
#
# Jim Lawton 2009-10-09
#
# binsource files are in the form of blocks of 5-digit octal numbers,
# 8 per line, 4 lines per block, 8 blocks per page, 4 pages per bank.
# Example:
#
#     50026 30001 30027 02177 50026 30001 30027 02034
#     50026 30001 30027 02630 50026 30001 30027 02042
#     50026 30001 30027 02037 50026 30001 30027 02377
#     20017 32075 50015 07005 03007 01101 02266 32075
#
# Comments begin with a semicolon. The rest of the line is ignored.
# the BANK keyword specifies the bank number (e.g. "BANK=2").

# TODO: calculate and print address of row
# TODO: check checksum


import os
import sys
import glob
import datetime
import signal


_DEFAULT_HEADER = \
"""
; Copyright:    Public domain
; Filename:     Solarium055.binsource
; Purpose:      An ASCII file used to input an AGC executable in octal format.
;               The actual octal (usable by the yaAGC program) must be created
;               by processing with the oct2bin program (which may be found in
;               the Tools directory of the virtualagc project).
;               Refer to www.ibiblio.org/apollo for explanations.
; Contact:
; History:      YYYY-MM-DD XXX  Created.
;
;
; This data has been manually transcribed from a scanned listing of TBD
; build NNN.
;
; For convenience, the page numbers (as marked on the printed assembly listing)
; are given in the comments. The notations V or A (or both or neither) have
; been added after the page numbers to indicate the proofing method used
; (Visual or Audio). Regardless of the proofing method (if any), all code is
; believed to be correct, on the basis of automated checking of the "bugger
; words" (i.e., bank checksums), except, of course, where stated otherwise.
; (The parenthesized number, if any, following the V or A, is the number of
; errors corrected on that proofing pass.)
;
; The rule followed here is that each memory page has to be proofed at least
; once, and that the *final* proofing of any given memory page must have
; encountered 0 errors.
;
; Input-data format:
;   Each memory bank begins with a "BANK=" line. The remainder of the bank
;   consists of octal values. Note that banks should be zero-filled at the end
;   to make the lengths come out correct.

NUMBANKS=34
"""


def signal_handler(signal, frame):
    global pagedata, page, outfile, useCommas
    print "Ctrl+C"
    savePage(outfile, page, pagedata, useCommas, crash=True)
    sys.exit(1)


def prompt(promptString, default=""):
    response = raw_input(promptString)
    if len(response) == 0:
        if len(default) > 0:
            response = default
        else:
            response = None
    return response


def octPrompt(promptString="5 digit octal: "):
    while True:
        response = raw_input(promptString)
        if len(response) == 0 or len(response) > 5:
            response = None
            break
        else:
            try:
                response = int(response, 8)
                break
            except:
                continue
    return response


def parse(infile):
    ifile = open(infile, 'r')
    lines = ifile.readlines()
    print "Parsing input file..."
    for line in lines:
        if line.startswith(';'):
            continue
        if line.startswith("BANK="):
            bank = int(line.split('=')[1])
            print "    Bank %d" % bank
    ifile.close()


def savePage(outfile, page, pagedata, useCommas=False, crash=False):
    print "Saving page..."
    if outfile is None:
        return
    ofile = open(outfile, 'a')
    lines = []
    if crash:
        if pagedata is None or pagedata == {}:
            lines = ["\n",
                "************************** CRASH *************************\n",
                "*                    No data to save!                    *\n",
                "**********************************************************\n"]
        else:
            lines = ["\n",
                "*********************** CRASH SAVE ***********************\n",
                "* Please check data below this point. It may be corrupt! *\n",
                "**********************************************************\n"]
    stop = False
    if pagedata:
        for row in range(32):
            line = ""
            for col in range(8):
                pos = row * 8 + col
                if pos not in pagedata.keys():
                    continue
                if useCommas:
                    line += "%05o, " % pagedata[pos]
                else:
                    line += "%05o " % pagedata[pos]
            line += "\n"
            if (row + 1) % 4 == 0:
                line += "\n"
            lines.append(line)
    if crash and not (pagedata is None or pagedata == {}):
        lines.extend(["\n",
            "*********************** CRASH SAVE ***********************\n",
            "\n"])
    ofile.write("; p. %d\n" % page)
    ofile.writelines(lines)
    ofile.write("\n")
    ofile.close()


def main():
    global pagedata, page, outfile, useCommas
    outfile = None
    page = None
    pagedata = {}
    useCommas = False

    startpage = prompt("Starting page: ")
    if startpage == None:
        print >>sys.stderr, "Error, must specify a starting page."
        sys.exit(1)
    else:
        startpage = int(startpage)
    bsFiles = glob.glob('*.binsource')
    if len(bsFiles) == 1:
        defInfile = bsFiles[0]
        promptStr = "Input file (default=%s): " % defInfile
    else:
        defInfile = None
        promptStr = "Input file: "
    infile = prompt(promptStr)
    if infile == None:
        infile = defInfile

    defOutfile = "%s-%d.binsource" % (datetime.datetime.now().strftime("%Y%m%d_%H%M%S"), startpage)
    promptStr = "Output file (default=%s): " % defOutfile

    outfile = prompt(promptStr)
    if outfile == None:
        outfile = defOutfile

    if os.path.exists(outfile):
        print "File %s already exists!" % outfile
        overwrite = prompt("Overwrite? (Y/N) [N]: ")
        if overwrite == None or overwrite == "N":
            print >>sys.stderr, "Exiting."
            sys.exit(1)

    direction = prompt("Processing direction (0=column order, 1=row order, 2=column/block order) [0]: ")
    if direction == None:
        direction = 0
    else:
        direction = int(direction)

    useCommas = prompt("Use comma delimiters? (Y/N) [N]: ")
    if useCommas == None or useCommas == "N":
        useCommas = False
    else:
        useCommas = True

#    startaddr = prompt("Starting address [02000]: ")
#    if startaddr == None:
#        startbank = 0
#        startaddr = 02000
#    else:
#        if ',' in startaddr:
#            startbank = int(startaddr.split(',')[0], 8)
#            startaddr = int(startaddr.split(',')[1], 8)
#        else:
#            startbank = 0
#            startaddr = int(startaddr, 8)

    print "Input file: %s" % infile
    print "Output file: %s" % outfile
    print "Direction: %s" % direction
    print "Starting page: %s" % startpage
#    print "Starting bank: %s" % oct(startbank)
#    print "Starting address: %s" % oct(startaddr)
    print "Comma delimiters: %s" % useCommas
    print

    if infile:
        parse(infile)
    else:
        # Put default header text in the output file.
        ofile = open(outfile, 'w')
        ofile.write(_DEFAULT_HEADER)
        ofile.write("\n")
        ofile.close()

    stop = False
    page = startpage

    while not stop:
        print "Page: %d" % page

        col = 0
        row = 0
        block = 0
        blockrow = 0

        zeroRest = False
        zeroCol = False

        # Can process input in different directions.
        # Output always stored in row order.
        if direction == 0:
            # Column order, i.e. top to bottom of page for each column, left to right.
            while col < 8:
                print "Column: %02d" % col
                row = 0
                while row < 32:
                    word = octPrompt("Row %02d: " % row)
                    if word == None:
                        response = prompt("Back (b), Retry (r), finish (f), zero rest of column (z) [r]: ", default='r')
                        if response == 'f':
                            stop = True
                            break
                        elif response == 'b':
                            row -= 1
                            if row < 0:
                                row = 0
                            continue
                        elif response == 'z':
                            zeroCol = True
                            break
                        else:
                            continue
                    pagedata[row * 8 + col] = word
                    if (row + 1) % 4 == 0:
                        print
                    row += 1
                if stop:
                    break
                if zeroCol:
                    for zrow in range(row, 32):
                        pagedata[zrow * 8 + col] = 0
                col += 1

        elif direction == 1:
            # Row order, i.e. left to right for each row of page, top to bottom.
            while row < 32:
                print "Row: %02d" % row
                col = 0
                while col < 8:
                    word = octPrompt("Col %02d: " % col)
                    if word == None:
                        response = prompt("Back (b), Retry (r), finish (f), zero rest of page (z) [r]: ", default='r')
                        if response == 'f':
                            stop = True
                            break
                        elif response == 'z':
                            zeroRest = True
                            break
                        elif response == 'b':
                            col -= 1
                            if col < 0:
                                col = 0
                            continue
                        else:
                            continue
                    pagedata[row * 8 + col] = word
                    col += 1
                if stop:
                    break
                if zeroRest:
                    break
            if zeroRest:
                for pos in range(row * 8 + col, 256):
                    pagedata[pos] = 0
            row += 1

        else:
            # Column block order in a page, i.e. top to botton of page for each block of 4 rows,
            # column order within each block.
            while block < 8:
                print "Block: %02d" % block
                col = 0
                while col < 8:
                    print "Column: %02d" % col
                    blockrow = 0
                    while blockrow < 4:
                        row = block * 4 + blockrow
                        word = octPrompt("Row %02d: " % blockrow)
                        if word == None:
                            response = prompt("Back (b), Retry (r), finish (f) [r]: ", default='r')
                            if response == 'f':
                                stop = True
                                break
                            elif response == 'b':
                                blockrow -= 1
                                if blockrow < 0:
                                    blockrow = 0
                                    continue
                            else:
                                continue
                        pagedata[row * 8 + col] = word
                        blockrow += 1
                    if stop:
                        break
                    col += 1
                if stop:
                    break
                print
                block += 1

        savePage(outfile, page, pagedata, useCommas)

        response = prompt("Next page (y/n) [n]: ")
        if response == 'y':
            page += 1
            continue
        else:
            break

    print "Done"


if __name__ == "__main__":
    global pagedata, page, outfile
    signal.signal(signal.SIGINT, signal_handler)
    main()
back to top