mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-12 15:44:05 +09:00
a working internet modem that only reads
This commit is contained in:
@@ -334,6 +334,18 @@ Array.prototype.tail = function() {
|
|||||||
Array.prototype.init = function() {
|
Array.prototype.init = function() {
|
||||||
return this.slice(0, this.length - 1)
|
return this.slice(0, this.length - 1)
|
||||||
}
|
}
|
||||||
|
String.prototype.head = function() {
|
||||||
|
return this[0]
|
||||||
|
}
|
||||||
|
String.prototype.last = function() {
|
||||||
|
return this[this.length - 1]
|
||||||
|
}
|
||||||
|
String.prototype.tail = function() {
|
||||||
|
return this.substring(1)
|
||||||
|
}
|
||||||
|
String.prototype.init = function() {
|
||||||
|
return this.substring(0, this.length - 1)
|
||||||
|
}
|
||||||
Array.prototype.shuffle = function() {
|
Array.prototype.shuffle = function() {
|
||||||
let counter = this.length;
|
let counter = this.length;
|
||||||
|
|
||||||
|
|||||||
@@ -8,19 +8,18 @@ for (let y = 0; y < 40; y++) {
|
|||||||
for (let x = 0; x < 30; x++) {
|
for (let x = 0; x < 30; x++) {
|
||||||
let octet = imageBits[y * 30 + x]
|
let octet = imageBits[y * 30 + x]
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
graphics.plotPixel(8*x + i, y+8, ((octet >>> (7 - i)) & 1 != 0) ? 255 : 239)
|
graphics.plotPixel(120 + 8*x + i, 36 + y, ((octet >>> (7 - i)) & 1 != 0) ? 255 : 239)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
con.move(8,1+(40-t.length>>1))
|
con.move(13,1+(80-t.length>>1))
|
||||||
print(t)
|
print(t)
|
||||||
// wait arbitrary time
|
// wait arbitrary time
|
||||||
for (let b=0;b<sys.maxmem()*10;b++) {
|
let tmr = sys.nanoTime();
|
||||||
sys.poke(0,(Math.random()*255)|0)
|
while (sys.nanoTime() - tmr < 2147483648) sys.spin();
|
||||||
sys.poke(0,0)
|
// clear screen
|
||||||
}
|
graphics.clearPixels(255);con.color_pair(239,255);
|
||||||
con.clear()
|
con.clear();con.move(1,1);
|
||||||
graphics.clearPixels(255)
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|||||||
3
assets/disk0/devcontest.js
Normal file
3
assets/disk0/devcontest.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
let f = files.open("CON")
|
||||||
|
f.swrite("Hello, world! I'm just writing to a file named 'CON'\n")
|
||||||
|
f.close()
|
||||||
10
assets/disk0/devipftest.js
Normal file
10
assets/disk0/devipftest.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
let fout = files.open("FBIPF")
|
||||||
|
let fin = files.open(_G.shell.resolvePathInput(exec_args[1]).full)
|
||||||
|
|
||||||
|
let ipfRead = fin.bread()
|
||||||
|
println(`Input file: ${ipfRead.length} bytes`)
|
||||||
|
|
||||||
|
fout.bwrite(ipfRead)
|
||||||
|
|
||||||
|
fin.close()
|
||||||
|
fout.close()
|
||||||
17
assets/disk0/devrandomtest.js
Normal file
17
assets/disk0/devrandomtest.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
let f = files.open("RND")
|
||||||
|
let mlen = 512
|
||||||
|
let m = sys.malloc(mlen)
|
||||||
|
|
||||||
|
println(f.driverID)
|
||||||
|
println(`Ptr: ${m}`)
|
||||||
|
|
||||||
|
f.pread(m, mlen, 0)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
for (let i = 0; i < mlen; i++) {
|
||||||
|
print(sys.peek(m+i).toString(16).padStart(2,'0'))
|
||||||
|
print(' ')
|
||||||
|
}
|
||||||
|
println()
|
||||||
|
|
||||||
|
sys.free(m)
|
||||||
20
assets/disk0/fstest.js
Normal file
20
assets/disk0/fstest.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
let f = files.open("A:/tvdos/bin")
|
||||||
|
|
||||||
|
//f.driveLetter = "Z"
|
||||||
|
|
||||||
|
|
||||||
|
println(`File path: ${f.path}`)
|
||||||
|
println(`FS driver: ${f.driverID}`)
|
||||||
|
println(`DrvLetter: ${f.driveLetter}`)
|
||||||
|
println(`Parent: ${f.parentPath}`)
|
||||||
|
println(`Size: ${f.size}`)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
println(`List of files:`)
|
||||||
|
let ls = f.list()
|
||||||
|
ls.forEach(it=>{
|
||||||
|
println(`${it.path}\t${it.name}\t${it.size}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
println(`Size again: ${f.size}`)
|
||||||
9
assets/disk0/memtest.js
Normal file
9
assets/disk0/memtest.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
let ptr1 = sys.malloc(1024)
|
||||||
|
let ptr2 = sys.malloc(4321)
|
||||||
|
println(`ptr: ${ptr1} ${ptr2}; used mem: ${sys.getUsedMem()}`)
|
||||||
|
println(`freeing ptr1`)
|
||||||
|
sys.free(ptr1)
|
||||||
|
println(`used mem now: ${sys.getUsedMem()}`)
|
||||||
|
println(`freeing ptr2`)
|
||||||
|
sys.free(ptr2)
|
||||||
|
println(`used mem now: ${sys.getUsedMem()}`)
|
||||||
11
assets/disk0/nettest.js
Normal file
11
assets/disk0/nettest.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
let url="http://localhost/testnet/test.txt"
|
||||||
|
|
||||||
|
let file = files.open("B:\\"+url)
|
||||||
|
|
||||||
|
if (!file.exists) {
|
||||||
|
printerrln("No such URL: "+url)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
let text = file.sread()
|
||||||
|
println(text)
|
||||||
@@ -36,11 +36,38 @@ const _TVDOS = {};
|
|||||||
_TVDOS.VERSION = "1.0";
|
_TVDOS.VERSION = "1.0";
|
||||||
_TVDOS.DRIVES = {}; // Object where key-value pair is <drive-letter> : [serial-port, drive-number]
|
_TVDOS.DRIVES = {}; // Object where key-value pair is <drive-letter> : [serial-port, drive-number]
|
||||||
_TVDOS.DRIVEFS = {}; // filesystem driver for the drive letter
|
_TVDOS.DRIVEFS = {}; // filesystem driver for the drive letter
|
||||||
|
_TVDOS.DRIVEINFO = {};
|
||||||
// actually figure out the drive letter association
|
// actually figure out the drive letter association
|
||||||
// Drive A is always the device we're currently on
|
// 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"
|
_TVDOS.DRIVEFS["A"] = "SERIAL"
|
||||||
//TODO
|
_TVDOS.DRIVEINFO["A"] = {
|
||||||
|
name: com.sendMessageGetBytes(_BIOS.FIRST_BOOTABLE_PORT[0], "DEVNAM\x17").init(),
|
||||||
|
type: com.sendMessageGetBytes(_BIOS.FIRST_BOOTABLE_PORT[0], "DEVTYP\x17").substring(0,4)
|
||||||
|
}
|
||||||
|
|
||||||
|
// probe filesystem devices
|
||||||
|
let devnameToDriver = {"PRNT":"LP","STOR":"SERIAL","COMM":"COM","HTTP":"NET"}
|
||||||
|
let currentDriveLetter = ["A","B","C","D"]
|
||||||
|
for (let portNo = 1; portNo < 4; portNo++) {
|
||||||
|
if (com.areYouThere(portNo)) {
|
||||||
|
com.sendMessage(portNo, "DEVRST\x17")
|
||||||
|
sys.spin()
|
||||||
|
let devname = com.sendMessageGetBytes(portNo, "DEVTYP\x17").substring(0,4)
|
||||||
|
let driver = devnameToDriver[devname]
|
||||||
|
serial.println(`port: ${portNo}, devname: ${devname} ${com.sendMessageGetBytes(portNo, "DEVNAM\x17")}`)
|
||||||
|
if (driver) {
|
||||||
|
let dlet = currentDriveLetter[portNo]
|
||||||
|
_TVDOS.DRIVEFS[dlet] = driver
|
||||||
|
_TVDOS.DRIVES[dlet] = [portNo, 1]
|
||||||
|
_TVDOS.DRIVEINFO[dlet] = {
|
||||||
|
name: com.sendMessageGetBytes(portNo, "DEVNAM\x17").init(),
|
||||||
|
type: devname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_TVDOS.DRV = {}
|
_TVDOS.DRV = {}
|
||||||
|
|
||||||
|
|
||||||
@@ -590,6 +617,40 @@ Object.freeze(_TVDOS.DRV.FS.DEVFBIPF)
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
_TVDOS.DRV.FS.NET = {}
|
||||||
|
|
||||||
|
|
||||||
|
_TVDOS.DRV.FS.NET.sread = (fd) => {
|
||||||
|
let port = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter)
|
||||||
|
let url = fd.path.substring(fd.path.indexOf("\\")+1).replaceAll("\\","/")
|
||||||
|
|
||||||
|
serial.println("NETFILE GET " + url)
|
||||||
|
com.sendMessage(port[0], "GET " + url)
|
||||||
|
com.waitUntilReady(port[0])
|
||||||
|
|
||||||
|
return com.pullMessage(port[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
_TVDOS.DRV.FS.NET.flush = () => {}
|
||||||
|
_TVDOS.DRV.FS.NET.close = () => {}
|
||||||
|
_TVDOS.DRV.FS.NET.isDirectory = () => false
|
||||||
|
_TVDOS.DRV.FS.NET.listFiles = () => undefined
|
||||||
|
_TVDOS.DRV.FS.NET.touch = () => {}
|
||||||
|
_TVDOS.DRV.FS.NET.mkDir = () => {}
|
||||||
|
_TVDOS.DRV.FS.NET.mkFile = () => {}
|
||||||
|
_TVDOS.DRV.FS.NET.remove = () => {}
|
||||||
|
_TVDOS.DRV.FS.NET.exists = (fd) => {
|
||||||
|
let port = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter)
|
||||||
|
let url = fd.path.substring(fd.path.indexOf("\\")+1).replaceAll("\\","/")
|
||||||
|
|
||||||
|
com.sendMessage(port[0], "GET " + url)
|
||||||
|
com.waitUntilReady(port[0])
|
||||||
|
|
||||||
|
return (0 == com.getStatusCode(port[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
// Legacy Serial filesystem, !!pending for removal!!
|
// Legacy Serial filesystem, !!pending for removal!!
|
||||||
|
|
||||||
|
|||||||
5
assets/disk0/tvdos/bin/drives.js
Normal file
5
assets/disk0/tvdos/bin/drives.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Object.entries(_TVDOS.DRIVES).forEach(it=>{
|
||||||
|
let [letter, [port, drivenum]] = it
|
||||||
|
let dinfo = _TVDOS.DRIVEINFO[letter]
|
||||||
|
println(`${letter}: COM${port+1},${drivenum} (${dinfo.name}-${dinfo.type})`)
|
||||||
|
})
|
||||||
@@ -25,6 +25,10 @@ Your Javascript program is stored into the Program Memory, and since its capacit
|
|||||||
\1\inlinesynopsis[Array]{init}{}{returns the subarray that omits the \emph{last} element.}
|
\1\inlinesynopsis[Array]{init}{}{returns the subarray that omits the \emph{last} element.}
|
||||||
\1\inlinesynopsis[Array]{sum}{selector}{returns the sum of the elements of the array. Selector is optionally defined to indicate how the value must be transformed to obtain the sum.}
|
\1\inlinesynopsis[Array]{sum}{selector}{returns the sum of the elements of the array. Selector is optionally defined to indicate how the value must be transformed to obtain the sum.}
|
||||||
\1\inlinesynopsis[Array]{max}{selector}{returns the maximum among the elements of the array. Selector is optionally defined to indicate how the value must be transformed to obtain the max.}
|
\1\inlinesynopsis[Array]{max}{selector}{returns the maximum among the elements of the array. Selector is optionally defined to indicate how the value must be transformed to obtain the max.}
|
||||||
|
\1\inlinesynopsis[String]{head}{}{returns the first character of the string.}
|
||||||
|
\1\inlinesynopsis[String]{last}{}{returns the last character of the string.}
|
||||||
|
\1\inlinesynopsis[String]{tail}{}{returns the substring that omits the \emph{head} character.}
|
||||||
|
\1\inlinesynopsis[String]{init}{}{returns the substring that omits the \emph{last} character.}
|
||||||
\1\inlinesynopsis[String]{trimNull}{}{trims null characters at the \emph{end} of the string.}
|
\1\inlinesynopsis[String]{trimNull}{}{trims null characters at the \emph{end} of the string.}
|
||||||
\end{outline}
|
\end{outline}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ Returns: type of the device, of which but not exhaustive:
|
|||||||
- STOR: Storage device (floppy drive, etc.)
|
- STOR: Storage device (floppy drive, etc.)
|
||||||
- COMM: Modem (slave-mode device)
|
- COMM: Modem (slave-mode device)
|
||||||
- COMP: Modem (master-mode device, typically an other computer connected though a null-modem)
|
- COMP: Modem (master-mode device, typically an other computer connected though a null-modem)
|
||||||
|
- HTTP: Internet Modem
|
||||||
|
|
||||||
DEVNAM
|
DEVNAM
|
||||||
|
|
||||||
|
|||||||
177
tsvm_core/src/net/torvald/tsvm/peripheral/HttpModem.kt
Normal file
177
tsvm_core/src/net/torvald/tsvm/peripheral/HttpModem.kt
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
package net.torvald.tsvm.peripheral
|
||||||
|
|
||||||
|
import net.torvald.tsvm.VM
|
||||||
|
import net.torvald.tsvm.peripheral.TestDiskDrive.Companion.STATE_CODE_NO_SUCH_FILE_EXISTS
|
||||||
|
import net.torvald.tsvm.peripheral.TestDiskDrive.Companion.STATE_CODE_OPERATION_FAILED
|
||||||
|
import net.torvald.tsvm.peripheral.TestDiskDrive.Companion.STATE_CODE_SYSTEM_IO_ERROR
|
||||||
|
import net.torvald.tsvm.peripheral.TestDiskDrive.Companion.composePositiveAns
|
||||||
|
import java.io.*
|
||||||
|
import java.net.MalformedURLException
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2022-09-22.
|
||||||
|
*/
|
||||||
|
class HttpModem(private val vm: VM) : BlockTransferInterface(false, true) {
|
||||||
|
|
||||||
|
private val DBGPRN = true
|
||||||
|
|
||||||
|
private fun printdbg(msg: Any) {
|
||||||
|
if (DBGPRN) println("[WgetModem] $msg")
|
||||||
|
}
|
||||||
|
|
||||||
|
private var cnxOpen = false
|
||||||
|
private var cnxUrl: String? = null
|
||||||
|
|
||||||
|
private val messageComposeBuffer = ByteArrayOutputStream(BLOCK_SIZE) // always use this and don't alter blockSendBuffer please
|
||||||
|
private var blockSendBuffer = ByteArray(1)
|
||||||
|
private var blockSendCount = 0
|
||||||
|
|
||||||
|
private var writeMode = false
|
||||||
|
private var writeModeLength = -1
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
statusCode = TestDiskDrive.STATE_CODE_STANDBY
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasNext(): Boolean {
|
||||||
|
return (blockSendCount * BLOCK_SIZE < blockSendBuffer.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun startSendImpl(recipient: BlockTransferInterface): Int {
|
||||||
|
if (blockSendCount == 0) {
|
||||||
|
blockSendBuffer = messageComposeBuffer.toByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
val sendSize = if (blockSendBuffer.size - (blockSendCount * BLOCK_SIZE) < BLOCK_SIZE)
|
||||||
|
blockSendBuffer.size % BLOCK_SIZE
|
||||||
|
else BLOCK_SIZE
|
||||||
|
|
||||||
|
recipient.writeout(ByteArray(sendSize) {
|
||||||
|
blockSendBuffer[blockSendCount * BLOCK_SIZE + it]
|
||||||
|
})
|
||||||
|
|
||||||
|
blockSendCount += 1
|
||||||
|
|
||||||
|
return sendSize
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resetBuf() {
|
||||||
|
blockSendCount = 0
|
||||||
|
messageComposeBuffer.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun selfReset() {
|
||||||
|
//readModeLength = -1
|
||||||
|
cnxOpen = false
|
||||||
|
cnxUrl = null
|
||||||
|
blockSendCount = 0
|
||||||
|
writeMode = false
|
||||||
|
writeModeLength = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var writeBuffer: ByteArray
|
||||||
|
private var writeBufferUsage = 0
|
||||||
|
|
||||||
|
override fun writeoutImpl(inputData: ByteArray) {
|
||||||
|
if (writeMode) {
|
||||||
|
//println("[DiskDrive] writeout with inputdata length of ${inputData.size}")
|
||||||
|
//println("[DiskDriveMsg] ${inputData.toString(Charsets.UTF_8)}")
|
||||||
|
|
||||||
|
if (!cnxOpen) throw InternalError("Connection is not established but the modem is in write mode")
|
||||||
|
|
||||||
|
System.arraycopy(inputData, 0, writeBuffer, writeBufferUsage, minOf(writeModeLength - writeBufferUsage, inputData.size, BLOCK_SIZE))
|
||||||
|
writeBufferUsage += inputData.size
|
||||||
|
|
||||||
|
if (writeBufferUsage >= writeModeLength) {
|
||||||
|
// commit to the disk
|
||||||
|
TODO("do something with writeBuffer")
|
||||||
|
|
||||||
|
writeMode = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val inputString = inputData.trimNull().toString(VM.CHARSET)
|
||||||
|
|
||||||
|
if (inputString.startsWith("DEVRST\u0017")) {
|
||||||
|
printdbg("Device Reset")
|
||||||
|
selfReset()
|
||||||
|
statusCode = TestDiskDrive.STATE_CODE_STANDBY
|
||||||
|
}
|
||||||
|
else if (inputString.startsWith("DEVSTU\u0017"))
|
||||||
|
recipient?.writeout(composePositiveAns("${statusCode.toChar()}", TestDiskDrive.errorMsgs[statusCode]))
|
||||||
|
else if (inputString.startsWith("DEVTYP\u0017"))
|
||||||
|
recipient?.writeout(composePositiveAns("HTTP"))
|
||||||
|
else if (inputString.startsWith("DEVNAM\u0017"))
|
||||||
|
recipient?.writeout(composePositiveAns("Wget Company HTTP Modem"))
|
||||||
|
else if (inputString.startsWith("GET ")) {
|
||||||
|
if (cnxUrl != null) {
|
||||||
|
statusCode = TestDiskDrive.STATE_CODE_FILE_ALREADY_OPENED
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
printdbg("msg: $inputString, lastIndex: ${inputString.lastIndex}")
|
||||||
|
|
||||||
|
cnxUrl = inputString.substring(4).filter { it in '!'..'~' }
|
||||||
|
|
||||||
|
printdbg("URL: $cnxUrl")
|
||||||
|
|
||||||
|
this.ready = false
|
||||||
|
this.busy = true
|
||||||
|
|
||||||
|
var httpIn: InputStream? = null
|
||||||
|
var bufferedOut: OutputStream? = null
|
||||||
|
resetBuf()
|
||||||
|
try {
|
||||||
|
// check the http connection before we do anything to the fs
|
||||||
|
httpIn = BufferedInputStream(URL(cnxUrl).openStream())
|
||||||
|
messageComposeBuffer.reset()
|
||||||
|
bufferedOut = BufferedOutputStream(messageComposeBuffer, 1024)
|
||||||
|
val data = ByteArray(1024)
|
||||||
|
var fileComplete = false
|
||||||
|
var count = 0
|
||||||
|
while (!fileComplete) {
|
||||||
|
count = httpIn.read(data, 0, 1024)
|
||||||
|
if (count <= 0) {
|
||||||
|
fileComplete = true
|
||||||
|
} else {
|
||||||
|
bufferedOut.write(data, 0, count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statusCode = TestDiskDrive.STATE_CODE_STANDBY
|
||||||
|
}
|
||||||
|
catch (e: MalformedURLException) {
|
||||||
|
statusCode = STATE_CODE_NO_SUCH_FILE_EXISTS // MalformedUrl
|
||||||
|
printdbg("Malformed URL: $cnxUrl")
|
||||||
|
}
|
||||||
|
catch (e: IOException) {
|
||||||
|
statusCode = STATE_CODE_SYSTEM_IO_ERROR // IoException
|
||||||
|
printdbg("IOException: $cnxUrl")
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
try {
|
||||||
|
bufferedOut?.close()
|
||||||
|
messageComposeBuffer.close()
|
||||||
|
httpIn?.close()
|
||||||
|
}
|
||||||
|
catch (e: IOException) {
|
||||||
|
statusCode = STATE_CODE_OPERATION_FAILED // UnableToCloseOutputStream
|
||||||
|
printdbg("Unable to close: $cnxUrl")
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
printdbg("Data in the URL: ${messageComposeBuffer.toString(VM.CHARSET)}")
|
||||||
|
selfReset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
statusCode = TestDiskDrive.STATE_CODE_ILLEGAL_COMMAND
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,6 +7,9 @@ import java.io.FileInputStream
|
|||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param driveNum 0 for COM drive number 1, but the file path will still be zero-based
|
||||||
|
*/
|
||||||
class TestDiskDrive(private val vm: VM, private val driveNum: Int, theRootPath: File? = null) : BlockTransferInterface(false, true) {
|
class TestDiskDrive(private val vm: VM, private val driveNum: Int, theRootPath: File? = null) : BlockTransferInterface(false, true) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -41,6 +44,17 @@ class TestDiskDrive(private val vm: VM, private val driveNum: Int, theRootPath:
|
|||||||
errorMsgs[STATE_CODE_NOT_A_DIRECTORY] = "NOT A DIRECTORY"
|
errorMsgs[STATE_CODE_NOT_A_DIRECTORY] = "NOT A DIRECTORY"
|
||||||
errorMsgs[STATE_CODE_NO_FILE_OPENED] = "NO FILE OPENED"
|
errorMsgs[STATE_CODE_NO_FILE_OPENED] = "NO FILE OPENED"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun composePositiveAns(vararg msg: String): ByteArray {
|
||||||
|
val sb = ArrayList<Byte>()
|
||||||
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val DBGPRN = true
|
private val DBGPRN = true
|
||||||
@@ -49,17 +63,6 @@ class TestDiskDrive(private val vm: VM, private val driveNum: Int, theRootPath:
|
|||||||
if (DBGPRN) println("[TestDiskDrive] $msg")
|
if (DBGPRN) println("[TestDiskDrive] $msg")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun composePositiveAns(vararg msg: String): ByteArray {
|
|
||||||
val sb = ArrayList<Byte>()
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val rootPath = theRootPath ?: File("test_assets/test_drive_$driveNum")
|
private val rootPath = theRootPath ?: File("test_assets/test_drive_$driveNum")
|
||||||
|
|
||||||
private var fileOpen = false
|
private var fileOpen = false
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import kotlin.Pair;
|
|||||||
import kotlin.collections.CollectionsKt;
|
import kotlin.collections.CollectionsKt;
|
||||||
import net.torvald.tsvm.peripheral.*;
|
import net.torvald.tsvm.peripheral.*;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
public class AppLoader {
|
public class AppLoader {
|
||||||
|
|
||||||
public static String appTitle = "tsvm";
|
public static String appTitle = "tsvm";
|
||||||
@@ -28,28 +30,37 @@ public class AppLoader {
|
|||||||
appConfig.setWindowedMode(WIDTH, HEIGHT);
|
appConfig.setWindowedMode(WIDTH, HEIGHT);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
String diskPath = "assets/disk0";
|
||||||
|
|
||||||
|
|
||||||
// VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{BasicBios.INSTANCE, BasicRom.INSTANCE});
|
// VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{BasicBios.INSTANCE, BasicRom.INSTANCE});
|
||||||
// VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{OEMBios.INSTANCE, BasicRom.INSTANCE});
|
// VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{OEMBios.INSTANCE, BasicRom.INSTANCE});
|
||||||
VM vm = new VM("./assets", 64 << 10, new TheRealWorld(), new VMProgramRom[]{TandemBios.INSTANCE, BasicRom.INSTANCE}, 2);
|
VM vm = new VM("./assets", 64 << 10, new TheRealWorld(), new VMProgramRom[]{TandemBios.INSTANCE, BasicRom.INSTANCE}, 2);
|
||||||
// VM vm = new VM(128 << 10, new TheRealWorld(), new VMProgramRom[]{BasicBios.INSTANCE, WPBios.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[]{TsvmBios.INSTANCE});
|
||||||
// VM vm = new VM("./assets", 8192 << 10, new TheRealWorld(), new VMProgramRom[]{OpenBios.INSTANCE}, 8);
|
// 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);
|
// VM pipvm = new VM("./assets", 4096, new TheRealWorld(), new VMProgramRom[]{PipBios.INSTANCE, PipROM.INSTANCE}, 8);
|
||||||
|
|
||||||
|
vm.getIO().getBlockTransferPorts()[0].attachDevice(new TestDiskDrive(vm, 0, new File(diskPath)));
|
||||||
|
vm.getIO().getBlockTransferPorts()[1].attachDevice(new HttpModem(vm));
|
||||||
|
|
||||||
|
|
||||||
String diskPath = "assets/disk0";
|
|
||||||
|
|
||||||
EmulInstance reference = new EmulInstance(vm, "net.torvald.tsvm.peripheral.ReferenceGraphicsAdapter2", diskPath, 560, 448);
|
EmulInstance reference = new EmulInstance(vm, "net.torvald.tsvm.peripheral.ReferenceGraphicsAdapter2", diskPath, 560, 448);
|
||||||
EmulInstance reference2 = new EmulInstance(vm, "net.torvald.tsvm.peripheral.ReferenceLikeLCD", diskPath, 560, 448);
|
EmulInstance reference2 = new EmulInstance(vm, "net.torvald.tsvm.peripheral.ReferenceLikeLCD", diskPath, 560, 448);
|
||||||
EmulInstance term = new EmulInstance(vm, "net.torvald.tsvm.peripheral.Term", diskPath, 720, 480);
|
EmulInstance term = new EmulInstance(vm, "net.torvald.tsvm.peripheral.Term", diskPath, 720, 480);
|
||||||
EmulInstance portable = new EmulInstance(vm, "net.torvald.tsvm.peripheral.CLCDDisplay", diskPath, 1080, 436);
|
EmulInstance portable = new EmulInstance(vm, "net.torvald.tsvm.peripheral.CLCDDisplay", diskPath, 1080, 436);
|
||||||
EmulInstance wp = new EmulInstance(vm, "net.torvald.tsvm.peripheral.WpTerm", "assets/wpdisk", 810, 360);
|
EmulInstance wp = new EmulInstance(vm, "net.torvald.tsvm.peripheral.WpTerm", "assets/wpdisk", 810, 360);
|
||||||
EmulInstance pip = new EmulInstance(pipvm, null, diskPath, 640, 480, CollectionsKt.listOf(new Pair(1, new PeripheralEntry2(
|
|
||||||
|
|
||||||
|
/*EmulInstance pip = new EmulInstance(pipvm, null, diskPath, 640, 480, CollectionsKt.listOf(new Pair(1, new PeripheralEntry2(
|
||||||
32768L,
|
32768L,
|
||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
"net.torvald.tsvm.peripheral.ExtDisp",
|
"net.torvald.tsvm.peripheral.ExtDisp",
|
||||||
pipvm, 160, 140
|
pipvm, 160, 140
|
||||||
))));
|
))));*/
|
||||||
|
|
||||||
new Lwjgl3Application(new VMGUI(portable, WIDTH, HEIGHT), appConfig);
|
new Lwjgl3Application(new VMGUI(portable, WIDTH, HEIGHT), appConfig);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,8 +76,6 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
|
|||||||
val loadedClassInstance = loadedClassConstructor.newInstance("./assets", vm, )
|
val loadedClassInstance = loadedClassConstructor.newInstance("./assets", vm, )
|
||||||
gpu = (loadedClassInstance as GraphicsAdapter)
|
gpu = (loadedClassInstance as GraphicsAdapter)
|
||||||
|
|
||||||
vm.getIO().blockTransferPorts[0].attachDevice(TestDiskDrive(vm, 0, File(loaderInfo.diskPath)))
|
|
||||||
|
|
||||||
vm.peripheralTable[1] = PeripheralEntry(
|
vm.peripheralTable[1] = PeripheralEntry(
|
||||||
gpu,
|
gpu,
|
||||||
GraphicsAdapter.VRAM_SIZE,
|
GraphicsAdapter.VRAM_SIZE,
|
||||||
@@ -95,14 +93,6 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe
|
|||||||
vm.getInputStream = { System.`in` }
|
vm.getInputStream = { System.`in` }
|
||||||
}
|
}
|
||||||
|
|
||||||
vm.getIO().blockTransferPorts[1].attachDevice(
|
|
||||||
WorldRadar(
|
|
||||||
Gdx.files.internal(
|
|
||||||
"test_assets/test_terrain.png"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
loaderInfo.extraPeripherals.forEach { (port, peri) ->
|
loaderInfo.extraPeripherals.forEach { (port, peri) ->
|
||||||
val typeargs = peri.args.map { it.javaClass }.toTypedArray()
|
val typeargs = peri.args.map { it.javaClass }.toTypedArray()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user