diff --git a/assets/bios/openbios.js b/assets/bios/openbios.js index 6ed3a49..2bc1271 100644 --- a/assets/bios/openbios.js +++ b/assets/bios/openbios.js @@ -55,102 +55,99 @@ function bootFromFirst() { else bootFromPort(port) } + + + + +function drawHeader() { + let th = con.getmaxyx()[1] + let fillerspc = ' '.repeat((th - 28) / 2) + + con.move(1,1) + con.reset_graphics() + print(' ') + con.addch(17);con.curs_right() + con.video_reverse() + print(fillerspc) + print('OpenBIOS Setup Utility') + print(fillerspc) + con.video_reverse() + con.addch(16);con.curs_right() + print(' ') +} + +function drawMenubar() { + for (let i = 0; i < configMenus.length; i++) { + con.reset_graphics() + con.move(3 + 2*i, configMenuX) + if (i == configuratorMenu) + con.video_reverse() + print(configMenus[i]) + } +} + +function clearInfoArea() { + +} + +function printSysInfo() { + con.move(3,configContentsX) + let rtmin=(sys.currentTimeInMills()/60000)|0 + let min=rtmin%60 + let h=((rtmin/60)|0)%24 + let od=((rtmin/1440)|0)%120 + let d=(od%30)+1 + let m=((rtmin/43200)|0)%4 + let dw=od%7 // 0 for Mondag + if (119==od) dw=7 // Verddag + let y=((rtmin/5184000)|0)+125 + + print(`Current Time \xE7${y} ${["Spring","Summer","Autumn","Winter"][m]} ${d} ${["Mondag","Tysdag","Midtveke","Torsdag","Fredag","Laurdag","Sundag","Verddag"][dw]} ${(''+h).padStart(2,'0')}:${(''+min).padStart(2,'0')}`) + + let ut = (sys.uptime()/1000)|0 + let uh = (ut/3600)|0 + let um = ((ut/60)|0)%60 + let us = ut%60 + + con.move(4,configContentsX-1) + print(`System uptime ${uh}h${um}m${us}s`) + + con.move(6,configContentsX) + print(` User RAM ${system.maxmem()>>>10} Kbytes`) + con.move(7,configContentsX) + print(`Video RAM ${256*sys.peek(-131084)} Kbytes`) +} + +function printSerialDevs() { + +} + +function printExpCards() { + +} + +function printBMS() { + +} + +const configMenuX = 4 +const configContentsX = 28 +let configuratorMenu = 0 +const configMenus = [" System Info ", " Serial Devices ", " Expansion Cards ", " Power Status "] +const menuFunctions = [printSysInfo, printSerialDevs, printExpCards, printBMS] + function runConfigurator() { sys.unsetSysrq() con.clear() - con.move(2,2);print("Devices:") - for (let i = 0; i < 4; i++) { - con.move(i*2+4, 2) - let bootableMark = (bootable[i]) ? "* " : " " + drawHeader() + drawMenubar() - let deviceName = undefined - try { - com.sendMessage(i, "DEVNAM\x17") - deviceName = com.fetchResponse(i).substring(0,40) - } - catch (e) { - deviceName = `(device not connected)` - } - - println(bootableMark + `Serial port #${i+1}: ` + deviceName) - } - - let bootnum = undefined - while (true) { - con.move(12,1) - con.curs_set(1) - print("\n Hit 1, 2, 3 or 4 to boot from the specified device: ") - let dev = Number(read()) - serial.println(dev) - if (Number.isInteger(dev) && dev >= 1 && dev <= 4) { - bootnum = dev - 1 - break - } - } - bootFromPort(bootnum) -} - - - -/////////////////////////////////////////////////////////////////////////////// - -// Perform memtest - -if (!SKIP_MEMTEST) { -let memptr = 0 -let reportedMemsize = system.maxmem() -const memtestptn = (reportedMemsize >= 4194304) ? -[ - [0x00,0xFF,0xAA,0x55] -] : (reportedMemsize >= 1048576) ? -[ - [0x00,0xFF,0xAA,0x55 , 0x69,0x0F,0xA5,0x1E] -] : (reportedMemsize >= 262144) ? -[ - [0x00,0xFF,0xAA,0x55 , 0x69,0x0F,0xA5,0x1E , 0xC7,0x71,0x8E,0xE3 , 0xCA,0xFE,0xBA,0xBE] -] : -[ - [0x00,0xFF,0xAA,0x55 , 0x69,0x0F,0xA5,0x1E , 0xC7,0x71,0x8E,0xE3 , 0xCA,0xFE,0xBA,0xBE], - [0xFF,0xFF,0xFF,0xFF , 0xFF,0xFF,0xFF,0xFF , 0xFF,0xFF,0xFF,0xFF , 0xFF,0xFF,0xFF,0xFF] -] - -con.move(2,1) -print(" 000 KB OK") - -try { - while (memptr < (8 << 20)) { - // just print a number - con.move(2,1) - var memptrtext = ""+(1 + ((memptr) >> 10)) - print((memptrtext < 10) ? " 00"+memptrtext : (memptrtext < 100) ? " 0"+memptrtext : (memptrtext < 1000) ? " "+memptrtext : memptrtext) - - // perform memory test - for (var ptn = 0; ptn < memtestptn.length; ptn++) { - for (var bi = 0; bi < memtestptn[ptn].length; bi++) { - sys.poke(memptr + bi, memtestptn[ptn][bi]) - if (memtestptn[ptn][bi] != sys.peek(memptr + bi)) throw "Memory Error" - } - /*for (var bi = 0; bi < memtestptn[ptn].length; bi++) { - sys.poke(memptr + bi, 255 - memtestptn[ptn][bi]) - if (255 - memtestptn[ptn][bi] != sys.peek(memptr + bi)) throw "Memory Error" - }*/ - } - - memptr += memtestptn[0].length - } - throw undefined -} -catch (e) { - if (e == "Memory Error") - println(" "+e) - else - println(" KB OK!") -} + clearInfoArea() + menuFunctions[configuratorMenu]() } /////////////////////////////////////////////////////////////////////////////// - showSplash() showHowtoEnterMenu() diff --git a/assets/disk0/tvdos/TVDOS.SYS b/assets/disk0/tvdos/TVDOS.SYS index 55ebeb7..1477125 100644 --- a/assets/disk0/tvdos/TVDOS.SYS +++ b/assets/disk0/tvdos/TVDOS.SYS @@ -35,10 +35,13 @@ function generateRandomHashStr(len) { const _TVDOS = {}; _TVDOS.VERSION = "1.0"; _TVDOS.DRIVES = {}; // Object where key-value pair is : [serial-port, drive-number] +_TVDOS.DRIVEFS = {}; // filesystem driver for the drive letter // actually figure out the drive letter association // Drive A is always the device we're currently on -_TVDOS.DRIVES["A"] = _BIOS.FIRST_BOOTABLE_PORT; +_TVDOS.DRIVES["A"] = _BIOS.FIRST_BOOTABLE_PORT +_TVDOS.DRIVEFS["A"] = "SERIAL" //TODO +_TVDOS.DRV = {} _TVDOS.getPath = function() { @@ -59,7 +62,221 @@ Object.freeze(_TVDOS); /////////////////////////////////////////////////////////////////////////////// +_TVDOS.DRV.FS = {} + +class TVDOSFileDescriptor { + constructor(path, driverString) { + path = path.replaceAll("\\", "/") + // oh well... + while (path.endsWith("/")) { + path = path.substring(0, path.length - 1) + } + this.path = path + this.driverString = driverString + this.driver = _TVDOS.DRV.FS[driverString] + this.driveLetter = path[0] + } + + get size() { + return this.driver.getFileLen() + } + + /** reads the file bytewise and puts it to the specified memory address + * @param count optional -- how many bytes to read + * @param offset optional -- how many bytes to skip initially + */ + pread(ptr, count, offset) { + this.driver.pread(this, ptr, count, offset) + } + /** @return bytewise contents of the file in JS array */ + bread() { + return this.driver.bread(this) + } + /** @return textwise contents of the file in JS string */ + sread() { + return this.driver.sread(this) + } + + /** writes the bytes stored in the memory[ptr .. ptr+count-1] to file[offset .. offset+count-1] + * - @param offset is optional + */ + pwrite(ptr, count, offset) { + this.driver.pwrite(this, ptr, count, offset) + } + /** @param bytes bytewise contents to write, in JS array */ + bwrite(bytes) { + this.driver.bwrite(this, bytes) + } + /** @param string stringwise contents to write, in JS array */ + swrite(string) { + this.driver.swrite(this, string) + } + + flush() { + this.driver.flush(this) + } + + close() { + this.driver.close(this) + } + + get isDirectory() { + return this.driver.isDirectory(this) + } + + get name() { + return this.split("/").last() + } + + list() { + if (!this.isDirectory()) throw Error(`File is not a directory: ${this.path}`) + return this.driver.listFiles(this) + } + /** When the file does not exist, mkfile() will be called; if you want to make a directory, use mkdir() */ + touch() { + return this.driver.touch(this) + } + /** Creates the directory named by this abstract pathname, including any necessary but nonexistent parent directories */ + mkDir() { + return this.driver.mkDir(this) + } + + mkFile() { + return this.driver.mkFile(this) + } + + delete() { + return this.driver.delete(this) + } + +} + + +_TVDOS.DRV.FS.SERIAL = {} + + + +_TVDOS.DRV.FS.SERIAL._toPorts = (driveLetter) => { + if (driveLetter.toUpperCase === undefined) { + throw Error("'"+driveLetter+"' (type: "+typeof driveLetter+") is not a valid drive letter") + } + var port = _TVDOS.DRIVES[driveLetter.toUpperCase()] + if (port === undefined) { + throw Error("Drive letter '" + driveLetter.toUpperCase() + "' does not exist") + } + return port +} +_TVDOS.DRV.FS.SERIAL._close = (portNo) => { + com.sendMessage(portNo, "CLOSE") +} +_TVDOS.DRV.FS.SERIAL._flush = (portNo) => { + com.sendMessage(portNo, "FLUSH") +} +_TVDOS.DRV.FS.SERIAL.close = (fd) => { + let portNo = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter) + com.sendMessage(portNo, "CLOSE") +} +_TVDOS.DRV.FS.SERIAL.flush = (fd) => { + let portNo = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter) + com.sendMessage(portNo, "FLUSH") +} + +_TVDOS.DRV.FS.SERIAL.getFileLen = (driveLetter) => { + let port = _TVDOS.DRV.FS.SERIAL._toPorts(driveLetter) + com.sendMessage(port[0], "GETLEN") + var response = com.getStatusCode(port[0]) + if (135 == response) { + throw Error("File not opened") + } + if (response < 0 || response >= 128) { + throw Error("Reading a file failed with "+response) + } + return Number(com.pullMessage(port[0])) +} +// TODO pread replaces DMA.comToRam +// TODO pwrite replaces DMA.ramToCom +_TVDOS.DRV.FS.SERIAL.sread = (fd) => { + let port = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter) + com.sendMessage(port[0], "READ") + let response = com.getStatusCode(port[0]) + if (135 == response) { + throw Error("File not opened") + } + if (response < 0 || response >= 128) { + throw Error("Reading a file failed with "+response) + } + return com.pullMessage(port[0]) +} +_TVDOS.DRV.FS.SERIAL.swrite = (fd, str) => { + let port = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter) + com.sendMessage(port[0], "WRITE"+string.length) + let response = com.getStatusCode(port[0]) + if (135 == response) { + throw Error("File not opened") + } + if (response < 0 || response >= 128) { + throw Error("Writing a file failed with "+response) + } + com.sendMessage(port[0], string) + _TVDOS.DRV.FS.SERIAL._flush(port[0]);_TVDOS.DRV.FS.SERIAL._close(port[0]) +} +_TVDOS.DRV.FS.SERIAL.bread = (fd) => { + let str = _TVDOS.DRV.FS.SERIAL.readAll(fd.driveLetter) + let bytes = new Uint8Array(str.length) + for (let i = 0; i < str.length; i++) { + bytes[i] = str.charCodeAt(i) + } + return bytes +} +_TVDOS.DRV.FS.SERIAL.bwrite = (fd, bytes) => { // pwrite replaces DMA.ramToCom + let string = String.fromCharCode.apply(null, bytes) // no spreading: has length limit + _TVDOS.DRV.FS.SERIAL.swrite(fd, string) +} +_TVDOS.DRV.FS.SERIAL.isDirectory = (fd) => { + let port = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter) + com.sendMessage(port[0], "LISTFILES") + let response = com.getStatusCode(port[0]) + return (response === 0) +} +_TVDOS.DRV.FS.SERIAL.listFiles = (fd) => { + TODO() +} +_TVDOS.DRV.FS.SERIAL.touch = (fd) => { + let port = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter) + com.sendMessage(port[0], "TOUCH") + let response = com.getStatusCode(port[0]) + return (response === 0) +} +_TVDOS.DRV.FS.SERIAL.mkDir = (fd) => { + let port = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter) + com.sendMessage(port[0], "MKDIR") + let response = com.getStatusCode(port[0]) + + if (response < 0 || response >= 128) { + var status = com.getDeviceStatus(port[0]) + throw Error(`Creating a directory failed with (${response}): ${status.message}\n`) + } + return (response === 0) // possible status codes: 0 (success), 1 (fail) +} +_TVDOS.DRV.FS.SERIAL.mkFile = (fd) => { + let port = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter) + com.sendMessage(port[0], "MKFILE") + let response = com.getStatusCode(port[0]) + return (response === 0) +} +_TVDOS.DRV.FS.SERIAL.delete = (fd) => { + let port = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter) + com.sendMessage(port[0], "DELETE") + let response = com.getStatusCode(port[0]) + return (response === 0) +} + +Object.freeze(_TVDOS.DRV.FS.SERIAL) + +/////////////////////////////////////////////////////////////////////////////// + const filesystem = {}; + filesystem._toPorts = (driveLetter) => { if (driveLetter.toUpperCase === undefined) { throw Error("'"+driveLetter+"' (type: "+typeof driveLetter+") is not a valid drive letter"); @@ -71,11 +288,12 @@ filesystem._toPorts = (driveLetter) => { return port }; filesystem._close = (portNo) => { - com.sendMessage(portNo, "CLOSE"); -}; + com.sendMessage(portNo, "CLOSE") +} filesystem._flush = (portNo) => { - com.sendMessage(portNo, "FLUSH"); -}; + com.sendMessage(portNo, "FLUSH") +} + // @return disk status code (0 for successful operation) // throws if: // - java.lang.NullPointerException if path is null @@ -182,6 +400,21 @@ Object.freeze(filesystem); /////////////////////////////////////////////////////////////////////////////// +const files = {} + +/** This function only creates a file descriptor; will not actually interact with the drives yet. */ +files.open = (fullpath) => { + if (fullpath[1] != '/' && fullpath[1] != '\\') throw Error("Expected full path with drive letter") + let driveLetter = fullpath[0].toUpperCase() + let driver = _TVDOS.DRIVEFS[driveLetter] + return new TVDOSFileDescriptor(fullpath, driver) +} + + +Object.freeze(files) + +/////////////////////////////////////////////////////////////////////////////// + const input = {}; const inputwork = {}; diff --git a/tsvm_core/src/net/torvald/tsvm/VM.kt b/tsvm_core/src/net/torvald/tsvm/VM.kt index 22119dd..fa7ff69 100644 --- a/tsvm_core/src/net/torvald/tsvm/VM.kt +++ b/tsvm_core/src/net/torvald/tsvm/VM.kt @@ -97,7 +97,7 @@ class VM( fun findPeribyType(searchTerm: String): PeripheralEntry? { - for (i in 0..peripheralSlots) { + for (i in 0 until peripheralSlots) { if (peripheralTable[i].type == searchTerm) return peripheralTable[i] } return null diff --git a/tsvm_executable/src/net/torvald/tsvm/AppLoader.java b/tsvm_executable/src/net/torvald/tsvm/AppLoader.java index 440f0d2..7a0cd8c 100644 --- a/tsvm_executable/src/net/torvald/tsvm/AppLoader.java +++ b/tsvm_executable/src/net/torvald/tsvm/AppLoader.java @@ -33,8 +33,8 @@ public class AppLoader { // VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{TandemBios.INSTANCE, BasicRom.INSTANCE}); // VM vm = new VM(128 << 10, new TheRealWorld(), new VMProgramRom[]{BasicBios.INSTANCE, WPBios.INSTANCE}); // VM vm = new VM("./assets", 8192 << 10, new TheRealWorld(), new VMProgramRom[]{TsvmBios.INSTANCE}); - VM vm = new VM("./assets", 8192 << 10, new TheRealWorld(), new VMProgramRom[]{OpenBios.INSTANCE}); - VM pipvm = new VM("./assets", 4096, new TheRealWorld(), new VMProgramRom[]{PipBios.INSTANCE, PipROM.INSTANCE}); + VM vm = new VM("./assets", 8192 << 10, new TheRealWorld(), new VMProgramRom[]{OpenBios.INSTANCE}, 8); + VM pipvm = new VM("./assets", 4096, new TheRealWorld(), new VMProgramRom[]{PipBios.INSTANCE, PipROM.INSTANCE}, 8); String diskPath = "assets/disk0";