commit ee0b39f2f3d8c7087fef73543d0a8b5704aad9cb Author: Dreaded_X Date: Thu Jan 14 02:30:58 2021 +0100 Split tool from setup repository diff --git a/create-disk.py b/create-disk.py new file mode 100755 index 0000000..d2f7a70 --- /dev/null +++ b/create-disk.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +import math + +pageSize = 128 +sectorsPerTrack = 256 +blockSize = 16384 +pagesPerBlock = 128 +maxDirs = 128 +dirBlocks = 1 + + +def addBootloader(name): + loader = open(name, 'rb') + b = loader.read() + + if len(b) > pageSize: + raise RuntimeError("Bootloader binary cannot be larger than one page") + + out.seek(0) + out.write(b) + +def addOS(cpmName, biosName): + cpm = open(cpmName, 'rb') + bios = open(biosName, 'rb') + + b = cpm.read() + out.seek(pageSize) + out.write(b) + + b = bios.read() + out.seek(pageSize + 0x1600) + out.write(b) + +def seekBlock(i): + # Blocks start at track 1, sector 0 + out.seek(pageSize*sectorsPerTrack + i*blockSize) + +def initDirs(): + seekBlock(0) + out.write(bytearray(([0xe5] + [0x00] * 31) * maxDirs)) + +fileCounter = 0 +allocationCounter = 1 +def addFile(filename, n, t): + global fileCounter + global allocationCounter + + if fileCounter > maxDirs: + raise RuntimeError("Max dir entries has been reached") + + if len(n) > 8: + raise RuntimeError("Filename cannot be longer than 8") + + if len(t) > 3: + raise RuntimeError("Filetype cannot be longer than 3") + + f = open(filename, 'rb') + b = f.read() + + total_records = math.ceil(len(b)/pageSize) + records = (total_records - 1) % pagesPerBlock + 1 + extends = math.ceil(total_records/pagesPerBlock) + + if extends >= 8: + RuntimeError("File is to big to be stored in one entry, multple entries are not implemented") + + seekBlock(0) + out.seek(32*fileCounter, 1) + + # Write user (assume 0 for now) + out.write(bytearray(1)) + + # Write the name + out.write(n.upper().encode("ascii")) + out.write((" " * (8-len(n))).encode("ascii")) + + # Write the type + out.write(t.upper().encode("ascii")) + out.write((" " * (3-len(t))).encode("ascii")) + + # Write extend + # @todo This is actually wrong, as the order is EX S1 S2 with S1 being unused, however we never deal with files that big + out.write((extends-1).to_bytes(1, byteorder='little')) + + # Reserved byte + out.write(bytearray(2)) + + # Number of records + + out.write(records.to_bytes(1, byteorder='little')) + + allocationCounterOld = allocationCounter + # We are assuming one block per file for now, so we can use fileCounter + for i in range(extends): + out.write(allocationCounter.to_bytes(2, byteorder='little')) + allocationCounter += 1 + + seekBlock(allocationCounterOld) + out.write(b) + + fileCounter += 1 + + +def main(): + # @todo Load the config from a file that we specify instead of hardcoding everything + # We can probably keep the os part hardcoded as that is not something we really need to change between different projects + global out + out = open('../tools/disk.img', 'wb') + + addBootloader('../cpm/.build/loader.bin') + addOS('../cpm/.build/cpm22.bin', '../cpm/.build/bios.bin') + + initDirs() + + addFile("../cpm/.build/MONITOR.COM", "MONITOR", "COM") + addFile("../cpm/bin/STAT.COM", "STAT", "COM") + addFile("../cpm/bin/MBASIC.COM", "MBASIC", "COM") + addFile("../cpm/bin/s.com", "S", "COM") + # addFile("../xed/.build/XED.COM", "XED", "COM") + +if __name__ == "__main__": + main()