diff --git a/assets/bios1.js b/assets/bios1.js index f00dd4d..d7dc9e1 100644 --- a/assets/bios1.js +++ b/assets/bios1.js @@ -1,6 +1,10 @@ println("TERRAN Megatrends inc."); //println("Main RAM:"+(system.maxmem() >> 10)+" KBytes"); +/////////////////////////////////////////////////////////////////////////////// + +// Perform memtest + let memptr = 0; const memtestptn = [ // Overclockers will LOVE this! @@ -62,4 +66,20 @@ catch (e) { } } +/////////////////////////////////////////////////////////////////////////////// + +// probe bootable device + +var _BIOS = {}; + +// Syntax: [Port, Drive-number] +// Port #0-3: Serial port 1-4 +// #4+ : Left for future extension +// Drive-number always starts at 1 +_BIOS.FIRST_BOOTABLE_PORT = [0,1]; // ah screw it + +Object.freeze(_BIOS); + +/////////////////////////////////////////////////////////////////////////////// + con.move(4,1); \ No newline at end of file diff --git a/assets/serialtest.js b/assets/serialtest.js index 274f83a..ab2af21 100644 --- a/assets/serialtest.js +++ b/assets/serialtest.js @@ -1,36 +1 @@ -function getStatusMessage(portNo) { - return com.sendMessageGetBytes(portNo, "DEVSTU"+String.fromCharCode(0x17)); -} - -let ba = com.sendMessageGetBytes(0, "DEVNAM"+String.fromCharCode(0x17)); -serial.println(ba); - -ba = com.pullMessage(0) -serial.print(ba); -serial.println("# END OF MSG"); - - - -ba = com.sendMessageGetBytes(1, "DEVNAM"+String.fromCharCode(0x17)); -serial.println(ba); - -serial.println(getStatusMessage(1)); - -ba = com.sendMessageGetBytes(1, "LIST"); -ba = com.pullMessage(1); -println(ba); - -serial.println(getStatusMessage(1)); - -com.sendMessage(1, "OPENR\"fsh.js\""); - -println("Status code: "+com.getStatusCode(1)); - -com.sendMessage(1, "READ"); -println("Status code: "+com.getStatusCode(1)); -let source = com.pullMessage(1); -println(source); - -eval(source); - -serial.println("k bye") \ No newline at end of file +println("Hello, world!"); \ No newline at end of file diff --git a/assets/tvdos/TVDOS.SYS b/assets/tvdos/TVDOS.SYS new file mode 100644 index 0000000..75335b3 --- /dev/null +++ b/assets/tvdos/TVDOS.SYS @@ -0,0 +1,55 @@ +// Boot script +var _TVDOS = {}; +_TVDOS.DRIVES = {}; // Object where key-value pair is : [serial-port, drive-number] +// actually figure out the drive letter association +// Drive A is always the device we're currently on +_TVDOS.DRIVES["A"] = _BIOS.FIRST_BOOTABLE_PORT; + + + +Object.freeze(_TVDOS); + +/////////////////////////////////////////////////////////////////////////////// + +var filesystem = {}; +filesystem._toPorts = function(driveLetter) { + let port = _TVDOS.DRIVES[driveLetter.toUpperCase()]; + if (port === undefined) { + throw Error("Drive letter '" + driveLetter.toUpperCase() + "' does not exist"); + } + return port +}; +filesystem._close = function(portNo) { + com.sendMessage(portNo, "CLOSE"); +}; +filesystem._flush = function(portNo) { + com.sendMessage(portNo, "FLUSH"); +}; +// @return true if operation committed successfully, false otherwise; throws error +// if unknown mode or invalid drive letter was given +filesystem.open = function(driveLetter, path, operationMode) { + let port = filesystem._toPorts(driveLetter); + + filesystem._flush(port[0]); filesystem._close(port[0]); + + let mode = operationMode.toUpperCase(); + if (mode != "R" && mode != "W" && mode != "A") { + throw Error("Unknown file opening mode: " + mode); + } + + com.sendMessage(port[0], "OPEN"+mode+'"'+path+'",'+port[1]); + let response = com.getStatusCode(); + return (response == 0); +}; +// @return the entire contents of the file in String +filesystem.readAll = function() { + let port = filesystem._toPorts(driveLetter); + com.sendMessage(port[0], "READ"); + let response = com.getStatusCode(); + if (response < 0 || response >= 128) { + let status = com.getDeviceStatus(port[0]); + throw Error("Reading a file failed with "+status.code+": "+status.message); + } + return com.pullMessage(port[0]); +}; +Object.freeze(filesystem); \ No newline at end of file diff --git a/assets/tvdos/command.js b/assets/tvdos/command.js index 9a39845..fae013b 100644 --- a/assets/tvdos/command.js +++ b/assets/tvdos/command.js @@ -1,5 +1,5 @@ const DOS_VERSION = "1.0"; -const PROMPT_TEXT = ">"; +let PROMPT_TEXT = ">"; let CURRENT_DRIVE = "A"; let shell_pwd = [""]; diff --git a/serialdev.txt b/serialdev.txt index 7575203..696e3f5 100644 --- a/serialdev.txt +++ b/serialdev.txt @@ -55,9 +55,9 @@ Returns: none Description: reads status of the device, if applicable Returns: - 0x06 <0x1F> 0x17 - 0x15 <0x1F> 0x17 -Status Code is single byte number. Also see section 1.0 + <0x1F> 0x17 +Status Code is single byte number, negative numbers (or >= 128) is used for negative response by convention. +Also see section 1.0 2. Device-specific commands @@ -69,7 +69,8 @@ Status Code is single byte number. Also see section 1.0 2.1.0 NOTE - comma-followed-by-drive-number can be omitted; drive number 1 will be substituted + - comma-followed-by-drive-number can be omitted; drive number 1 will be substituted + - drive number always starts at 1 2.1.1 File Control @@ -108,23 +109,24 @@ Description: closes any file that is open. LOAD"", -Description: loads an executable file for running. Will throw an error if the file is not executable. +Description: loads a file onto the main memory. The pointer to the file will be sent back to the host device. CHTYPE,, -Description: changes the file's file type (or its extension) +Description: changes the open file's file type (or its extension) - CHDIR"" + LIST -Description: changes the working directory of the filesystem to given path. Disk with non-hierarchical filesystem should - ignore this command. +Description: lists contents of the open (with OPENR) directory in READABLE FORMAT + (no 0x17 at the end, terminates string with zero) + When a file is opened instead of a directory, its filename should be printed + Raw filesystem (e.g. EPROM) should return first 4096 bytes of its contents. - LIST, - LIST"", + LISTFILES -Description: lists contents of the given directory in READABLE FORMAT (no 0x17 at the end, terminates string with zero) - If no path is given, current working directory will be used instead. Non-hierarchical system should ignore - PATH argument, and raw filesystem (e.g. EPROM) should return first 4096 bytes of its contents. +Description: same as the LIST, but in machine readable format, which follows the following format: + [<0x1E for separator> ...] <0x17> + file/dir type: 0x11 for file, 0x12 for directory USAGE, diff --git a/src/net/torvald/tsvm/SerialHelper.kt b/src/net/torvald/tsvm/SerialHelper.kt index bb4a530..8f9f07e 100644 --- a/src/net/torvald/tsvm/SerialHelper.kt +++ b/src/net/torvald/tsvm/SerialHelper.kt @@ -80,7 +80,6 @@ object SerialHelper { fun getDeviceStatus(vm: VM, portNo: Int): DeviceStatus { val msgStr = sendMessageGetBytes(vm, portNo, "DEVSTU$END_OF_SEND_BLOCK".toByteArray(VM.CHARSET)) return DeviceStatus( - msgStr[0] == 0x06.toByte(), msgStr[1].toUint(), msgStr.sliceArray(3 until msgStr.size - 1).toString(VM.CHARSET) ) @@ -130,7 +129,7 @@ object SerialHelper { private fun Boolean.toInt() = if (this) 1 else 0 - data class DeviceStatus(val isError: Boolean, val code: Int, val message: String) + data class DeviceStatus(val code: Int, val message: String) } class SerialHelperDelegate(val vm: VM) { @@ -138,7 +137,8 @@ class SerialHelperDelegate(val vm: VM) { fun pullMessage(portNo: Int) = SerialHelper.pullMessage(vm, portNo).toString(VM.CHARSET) fun sendMessageGetBytes(portNo: Int, message: String) = SerialHelper.sendMessageGetBytes(vm, portNo, message.toByteArray(VM.CHARSET)).toString(VM.CHARSET) fun fetchResponse(portNo: Int) = SerialHelper.fetchResponse(vm, portNo).toString(VM.CHARSET) - fun getDeviceStatus(portNo: Int) = SerialHelper.getDeviceStatus(vm, portNo) fun waitUntilReady(portNo: Int) = SerialHelper.waitUntilReady(vm, portNo) fun getStatusCode(portNo: Int) = SerialHelper.getStatusCode(vm, portNo) + /** @return Object where { code: , message: } */ + fun getDeviceStatus(portNo: Int) = SerialHelper.getDeviceStatus(vm, portNo) } \ No newline at end of file diff --git a/src/net/torvald/tsvm/VMGUI.kt b/src/net/torvald/tsvm/VMGUI.kt index f02c967..8bd7aa1 100644 --- a/src/net/torvald/tsvm/VMGUI.kt +++ b/src/net/torvald/tsvm/VMGUI.kt @@ -65,6 +65,10 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter() val tvgl = fr2.readText() fr2.close() + val fr3 = FileReader("./assets/tvdos/TVDOS.SYS") + val tvknl = fr3.readText() + fr3.close() + //val fr = FileReader("./assets/tvdos/command.js") //val fr = FileReader("./assets/zippytest.js") @@ -77,7 +81,7 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter() vmRunner = VMRunnerFactory(vm, "js") coroutineJob = GlobalScope.launch { - vmRunner.evalGlobal(bios + "\n" + tvgl) + vmRunner.evalGlobal("$bios\n$tvknl\n$tvgl") vmRunner.executeCommand(prg) } } diff --git a/src/net/torvald/tsvm/peripheral/IOSpace.kt b/src/net/torvald/tsvm/peripheral/IOSpace.kt index 0ad3639..60d136d 100644 --- a/src/net/torvald/tsvm/peripheral/IOSpace.kt +++ b/src/net/torvald/tsvm/peripheral/IOSpace.kt @@ -38,8 +38,8 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor { private val keyEventBuffers = ByteArray(8) init { - blockTransferPorts[0].attachDevice(TestFunctionGenerator()) - blockTransferPorts[1].attachDevice(TestDiskDrive(0)) + //blockTransferPorts[0].attachDevice(TestFunctionGenerator()) + blockTransferPorts[0].attachDevice(TestDiskDrive(0)) } private fun composeBlockTransferStatus(portno: Int): Int { diff --git a/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt b/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt index 42a2327..40a13b8 100644 --- a/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt +++ b/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt @@ -31,19 +31,6 @@ class TestDiskDrive(private val driveNum: Int) : BlockTransferInterface(false, t fun composePositiveAns(vararg msg: String): ByteArray { val sb = ArrayList() - sb.add(GOOD_NEWS) - sb.addAll(msg[0].toByteArray().toTypedArray()) - for (k in 1 until msg.size) { - sb.add(UNIT_SEP) - sb.addAll(msg[k].toByteArray().toTypedArray()) - } - sb.add(END_OF_SEND_BLOCK) - return sb.toByteArray() - } - - fun composeNegativeAns(vararg msg: String): ByteArray { - val sb = ArrayList() - sb.add(BAD_NEWS) sb.addAll(msg[0].toByteArray().toTypedArray()) for (k in 1 until msg.size) { sb.add(UNIT_SEP) @@ -130,14 +117,8 @@ class TestDiskDrive(private val driveNum: Int) : BlockTransferInterface(false, t writeMode = false writeModeLength = -1 } - else if (inputString.startsWith("DEVSTU\u0017")) { - if (statusCode < 128) { - recipient?.writeout(composePositiveAns("${statusCode.toChar()}", errorMsgs[statusCode])) - } - else { - recipient?.writeout(composeNegativeAns("${statusCode.toChar()}", errorMsgs[statusCode])) - } - } + else if (inputString.startsWith("DEVSTU\u0017")) + recipient?.writeout(composePositiveAns("${statusCode.toChar()}", errorMsgs[statusCode])) else if (inputString.startsWith("DEVTYP\u0017")) recipient?.writeout(composePositiveAns("STOR")) else if (inputString.startsWith("DEVNAM\u0017")) diff --git a/src/net/torvald/tsvm/peripheral/TestFunctionGenerator.kt b/src/net/torvald/tsvm/peripheral/TestFunctionGenerator.kt index 55abe11..09bef5a 100644 --- a/src/net/torvald/tsvm/peripheral/TestFunctionGenerator.kt +++ b/src/net/torvald/tsvm/peripheral/TestFunctionGenerator.kt @@ -90,7 +90,6 @@ Nunc mollis nibh vitae sapien consequat, ut vestibulum sem pharetra. Aliquam iac fun composeSerialAns(vararg msg: String): ByteArray { val sb = ArrayList() - sb.add(0x06) // always positive ans sb.addAll(msg[0].toByteArray().toTypedArray()) for (k in 1 until msg.lastIndex) { sb.add(0x1F)