mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-07 11:51:49 +09:00
dos kernel wip
This commit is contained in:
@@ -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);
|
||||
@@ -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")
|
||||
println("Hello, world!");
|
||||
55
assets/tvdos/TVDOS.SYS
Normal file
55
assets/tvdos/TVDOS.SYS
Normal file
@@ -0,0 +1,55 @@
|
||||
// Boot script
|
||||
var _TVDOS = {};
|
||||
_TVDOS.DRIVES = {}; // Object where key-value pair is <drive-letter> : [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);
|
||||
@@ -1,5 +1,5 @@
|
||||
const DOS_VERSION = "1.0";
|
||||
const PROMPT_TEXT = ">";
|
||||
let PROMPT_TEXT = ">";
|
||||
let CURRENT_DRIVE = "A";
|
||||
|
||||
let shell_pwd = [""];
|
||||
|
||||
@@ -55,9 +55,9 @@ Returns: none
|
||||
|
||||
Description: reads status of the device, if applicable
|
||||
Returns:
|
||||
0x06 <status code> <0x1F> <message string> 0x17
|
||||
0x15 <status code> <0x1F> <message string> 0x17
|
||||
Status Code is single byte number. Also see section 1.0
|
||||
<status code> <0x1F> <message string> 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"<path to file>",<drive number>
|
||||
|
||||
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,<file type>,<drive number>
|
||||
|
||||
Description: changes the file's file type (or its extension)
|
||||
Description: changes the open file's file type (or its extension)
|
||||
|
||||
CHDIR"<path>"
|
||||
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,<drive number>
|
||||
LIST"<path>",<drive number>
|
||||
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:
|
||||
<file/dir type> <filename> [<0x1E for separator> <file/dir type> <filename> ...] <0x17>
|
||||
file/dir type: 0x11 for file, 0x12 for directory
|
||||
|
||||
USAGE,<drive number>
|
||||
|
||||
|
||||
@@ -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: <Int>, message: <String> } */
|
||||
fun getDeviceStatus(portNo: Int) = SerialHelper.getDeviceStatus(vm, portNo)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -31,19 +31,6 @@ class TestDiskDrive(private val driveNum: Int) : BlockTransferInterface(false, t
|
||||
|
||||
fun composePositiveAns(vararg msg: String): ByteArray {
|
||||
val sb = ArrayList<Byte>()
|
||||
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<Byte>()
|
||||
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"))
|
||||
|
||||
@@ -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<Byte>()
|
||||
sb.add(0x06) // always positive ans
|
||||
sb.addAll(msg[0].toByteArray().toTypedArray())
|
||||
for (k in 1 until msg.lastIndex) {
|
||||
sb.add(0x1F)
|
||||
|
||||
Reference in New Issue
Block a user