mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-13 22:46:06 +09:00
gpu to actually use 8bpp texture format to make memcpying easier
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
package net.torvald.tsvm
|
package net.torvald.tsvm
|
||||||
|
|
||||||
|
import net.torvald.UnsafeHelper
|
||||||
import net.torvald.tsvm.peripheral.GraphicsAdapter
|
import net.torvald.tsvm.peripheral.GraphicsAdapter
|
||||||
|
import sun.nio.ch.DirectBuffer
|
||||||
|
|
||||||
class GraphicsJSR223Delegate(val vm: VM) {
|
class GraphicsJSR223Delegate(val vm: VM) {
|
||||||
|
|
||||||
@@ -25,4 +27,23 @@ class GraphicsJSR223Delegate(val vm: VM) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun loadBulk(fromAddr: Int, toAddr: Int, length: Int) {
|
||||||
|
getFirstGPU()?.let {
|
||||||
|
it._loadbulk(fromAddr, toAddr, length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun GraphicsAdapter._loadbulk(fromAddr: Int, toAddr: Int, length: Int) {
|
||||||
|
if (toAddr < 250880) {
|
||||||
|
UnsafeHelper.memcpy(
|
||||||
|
vm.usermem.ptr + fromAddr,
|
||||||
|
(this.framebuffer.pixels as DirectBuffer).address() + toAddr,
|
||||||
|
length.toLong()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else if (toAddr < 250972) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,8 @@ import net.torvald.tsvm.firmware.Firmware.Companion.toLuaValue
|
|||||||
import net.torvald.tsvm.peripheral.IOSpace
|
import net.torvald.tsvm.peripheral.IOSpace
|
||||||
import net.torvald.tsvm.peripheral.PeriBase
|
import net.torvald.tsvm.peripheral.PeriBase
|
||||||
import org.luaj.vm2.LuaValue
|
import org.luaj.vm2.LuaValue
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.math.ceil
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,6 +57,8 @@ class VM(
|
|||||||
val id = java.util.Random().nextInt()
|
val id = java.util.Random().nextInt()
|
||||||
|
|
||||||
val memsize = minOf(USER_SPACE_SIZE, _memsize.toLong())
|
val memsize = minOf(USER_SPACE_SIZE, _memsize.toLong())
|
||||||
|
private val MALLOC_UNIT = 64
|
||||||
|
private val mallocBlockSize = (memsize / MALLOC_UNIT).toInt()
|
||||||
|
|
||||||
internal val usermem = UnsafeHelper.allocate(memsize)
|
internal val usermem = UnsafeHelper.allocate(memsize)
|
||||||
|
|
||||||
@@ -135,8 +139,55 @@ class VM(
|
|||||||
(memspace as PeriBase).peek(offset)
|
(memspace as PeriBase).peek(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Byte.toLuaValue() = LuaValue.valueOf(this.toInt())
|
private val mallocMap = BitSet(mallocBlockSize)
|
||||||
|
private val mallocSizes = HashMap<Int, Int>() // HashMap<Block Index, Block Count>
|
||||||
|
|
||||||
|
private fun findEmptySpace(blockSize: Int): Int? {
|
||||||
|
var cursorHead = 0
|
||||||
|
var cursorTail: Int
|
||||||
|
val cursorHeadMaxInclusive = mallocBlockSize - blockSize
|
||||||
|
while (cursorHead <= cursorHeadMaxInclusive) {
|
||||||
|
cursorHead = mallocMap.nextClearBit(cursorHead)
|
||||||
|
cursorTail = cursorHead + blockSize - 1
|
||||||
|
if (cursorTail > mallocBlockSize) return null
|
||||||
|
if (mallocMap.get(cursorTail) == false) {
|
||||||
|
var isNotEmpty = false
|
||||||
|
for (k in cursorHead..cursorTail) {
|
||||||
|
isNotEmpty = isNotEmpty or mallocMap[k]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNotEmpty) {
|
||||||
|
mallocMap.set(cursorHead, cursorTail + 1)
|
||||||
|
return cursorHead
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursorHead = cursorTail + 1
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun malloc(size: Int): Int {
|
||||||
|
val allocBlocks = ceil(size.toDouble() / MALLOC_UNIT).toInt()
|
||||||
|
val blockStart = findEmptySpace(allocBlocks)
|
||||||
|
if (blockStart == null) throw OutOfMemoryError()
|
||||||
|
|
||||||
|
mallocSizes[blockStart] = allocBlocks
|
||||||
|
return blockStart * MALLOC_UNIT
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun free(ptr: Int) {
|
||||||
|
val index = ptr / MALLOC_UNIT
|
||||||
|
val count = mallocSizes[index]
|
||||||
|
if (count == null) throw OutOfMemoryError()
|
||||||
|
|
||||||
|
mallocMap.set(index, index + count, false)
|
||||||
|
mallocSizes.remove(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
//fun Byte.toLuaValue() = LuaValue.valueOf(this.toInt())
|
||||||
|
|
||||||
|
|
||||||
|
internal data class VMNativePtr(val address: Int, val size: Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class PeripheralEntry(
|
data class PeripheralEntry(
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
|
|||||||
override fun create() {
|
override fun create() {
|
||||||
super.create()
|
super.create()
|
||||||
|
|
||||||
gpu = GraphicsAdapter(lcdMode = true)
|
gpu = GraphicsAdapter(lcdMode = false)
|
||||||
|
|
||||||
vm.peripheralTable[1] = PeripheralEntry(
|
vm.peripheralTable[1] = PeripheralEntry(
|
||||||
VM.PERITYPE_GRAPHICS,
|
VM.PERITYPE_GRAPHICS,
|
||||||
@@ -43,15 +43,10 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
|
|||||||
Gdx.gl20.glViewport(0, 0, appConfig.width, appConfig.height)
|
Gdx.gl20.glViewport(0, 0, appConfig.width, appConfig.height)
|
||||||
|
|
||||||
|
|
||||||
// TEST LUA PRG
|
// TEST PRG
|
||||||
//vmRunner = VMRunnerFactory(vm, "lua")
|
vmRunner = VMRunnerFactory(vm, "js")
|
||||||
//vmRunner.executeCommand(gpuTestPalette)
|
|
||||||
// TEST KTS PRG
|
|
||||||
vmRunner = VMRunnerFactory(vm, "kts")
|
|
||||||
//vmRunner.executeCommand(gpuTestPaletteKt)
|
|
||||||
//launch { vmRunner.executeCommand(gpuTestPaletteKt) } }
|
|
||||||
coroutineJob = GlobalScope.launch {
|
coroutineJob = GlobalScope.launch {
|
||||||
vmRunner.executeCommand(gpuTestPaletteKt)
|
vmRunner.executeCommand(gpuTestPaletteJs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,6 +161,7 @@ while (true) {
|
|||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
|
|
||||||
private val gpuTestPalette = """
|
private val gpuTestPalette = """
|
||||||
local vm = require("rawmem")
|
local vm = require("rawmem")
|
||||||
local bit = require("bit32")
|
local bit = require("bit32")
|
||||||
@@ -213,55 +209,54 @@ while true do
|
|||||||
end
|
end
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
private val gpuTestPaletteJs = """
|
private val jscode = """
|
||||||
var w = 560
|
var w = 560;
|
||||||
var h = 448
|
var h = 448;
|
||||||
var hwoff = 1048576
|
var hwoff = 1048576;
|
||||||
|
|
||||||
print(typeof print) //function
|
|
||||||
print(typeof vm.poke) //function
|
|
||||||
|
|
||||||
function inthash(x) {
|
function inthash(x) {
|
||||||
x = ((x >> 16) ^ x) * 0x45d9f3b
|
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||||
x = ((x >> 16) ^ x) * 0x45d9f3b
|
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||||
x = (x >> 16) ^ x
|
x = (x >> 16) ^ x;
|
||||||
return x
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
var rng = Math.floor(Math.random() * 2147483647) + 1
|
var rng = Math.floor(Math.random() * 2147483647) + 1;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
var tstart = vm.nanoTime()
|
var tstart = vm.nanoTime();
|
||||||
|
|
||||||
for (var y = 0; y < 360; y++) {
|
for (var y = 0; y < 360; y++) {
|
||||||
for (var x = 0; x < w; x++) {
|
for (var x = 0; x < w; x++) {
|
||||||
var palnum = 20 * Math.floor(y / 30) + Math.floor(x / 28)
|
var palnum = 20 * Math.floor(y / 30) + Math.floor(x / 28);
|
||||||
vm.poke(-(y * w + x + 1) - hwoff, inthash(palnum + rng))
|
vm.poke(-(y * w + x + 1) - hwoff, inthash(palnum + rng));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var y = 360; y < h; y++) {
|
for (var y = 360; y < h; y++) {
|
||||||
for (var x = 0; x < w; x++) {
|
for (var x = 0; x < w; x++) {
|
||||||
var palnum = 240 + Math.floor(x / 35)
|
var palnum = 240 + Math.floor(x / 35);
|
||||||
vm.poke(-(y * w + x + 1) - hwoff, palnum)
|
vm.poke(-(y * w + x + 1) - hwoff, palnum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var k = 0; k < 2560; k++) {
|
for (var k = 0; k < 2560; k++) {
|
||||||
vm.poke(-(253952 + k + 1) - hwoff, -2) // white
|
vm.poke(-(253952 + k + 1) - hwoff, -2); // transparent
|
||||||
vm.poke(-(253952 + 2560 + k + 1) - hwoff, -1) // transparent
|
vm.poke(-(253952 + 2560 + k + 1) - hwoff, -1); // white
|
||||||
vm.poke(-(253952 + 2560*2 + k + 1) - hwoff, Math.round(Math.random() * 255))
|
vm.poke(-(253952 + 2560*2 + k + 1) - hwoff, Math.round(Math.random() * 255));
|
||||||
}
|
}
|
||||||
|
|
||||||
rng = inthash(rng)
|
rng = inthash(rng);
|
||||||
|
|
||||||
var tend = vm.nanoTime()
|
var tend = vm.nanoTime();
|
||||||
|
|
||||||
print("Apparent FPS: " + (1000000000 / (tend - tstart)))
|
print("Apparent FPS: " + (1000000000 / (tend - tstart)));
|
||||||
}
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
private val gpuTestPaletteJs = "eval('${jscode.replace(Regex("//[^\\n]*"), "").replace('\n', ' ')}')"
|
||||||
|
|
||||||
""".trimIndent()
|
|
||||||
|
|
||||||
private val gpuTestPaletteJava = """
|
private val gpuTestPaletteJava = """
|
||||||
int w = 560;
|
int w = 560;
|
||||||
@@ -370,6 +365,7 @@ while True:
|
|||||||
super.dispose()
|
super.dispose()
|
||||||
batch.dispose()
|
batch.dispose()
|
||||||
coroutineJob.cancel()
|
coroutineJob.cancel()
|
||||||
|
vm.dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,7 @@ class VMJSR223Delegate(val vm: VM) {
|
|||||||
fun poke(addr: Int, value: Int) = vm.poke(addr.toLong(), value.toByte())
|
fun poke(addr: Int, value: Int) = vm.poke(addr.toLong(), value.toByte())
|
||||||
fun peek(addr: Int) = vm.peek(addr.toLong())
|
fun peek(addr: Int) = vm.peek(addr.toLong())
|
||||||
fun nanoTime() = System.nanoTime()
|
fun nanoTime() = System.nanoTime()
|
||||||
fun dmagload(from: Int, to: Int, length: Int) {
|
fun malloc(size: Int) = vm.malloc(size)
|
||||||
val periid = vm.findPeribyType("gpu")
|
fun free(ptr: Int) = vm.free(ptr)
|
||||||
if (periid == null)
|
|
||||||
throw IllegalStateException("GPU not found")
|
|
||||||
else {
|
|
||||||
(vm.peripheralTable[periid].peripheral as GraphicsAdapter).bulkLoad(vm, from.toLong(), to.toLong(), length.toLong())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ internal class Firmware(val vm: VM) : TwoArgFunction() {
|
|||||||
val t = LuaTable()
|
val t = LuaTable()
|
||||||
t["poke"] = Poke(vm)
|
t["poke"] = Poke(vm)
|
||||||
t["peek"] = Peek(vm)
|
t["peek"] = Peek(vm)
|
||||||
t["nanotime"] = object : ZeroArgFunction() {
|
t["nanoTime"] = object : ZeroArgFunction() {
|
||||||
override fun call(): LuaValue {
|
override fun call(): LuaValue {
|
||||||
return LuaValue.valueOf(System.nanoTime().toDouble())
|
return LuaValue.valueOf(System.nanoTime().toDouble())
|
||||||
}
|
}
|
||||||
|
|||||||
137
src/net/torvald/tsvm/peripheral/GlassTty.kt
Normal file
137
src/net/torvald/tsvm/peripheral/GlassTty.kt
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
package net.torvald.tsvm.peripheral
|
||||||
|
|
||||||
|
import com.badlogic.gdx.utils.Queue
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements standard TTY that can interpret some of the ANSI escape sequences
|
||||||
|
*/
|
||||||
|
abstract class GlassTty(val TEXT_ROWS: Int, val TEXT_COLS: Int) {
|
||||||
|
|
||||||
|
abstract fun getCursorPos(): Pair<Int, Int>
|
||||||
|
abstract fun setCursorPos(x: Int, y: Int)
|
||||||
|
|
||||||
|
abstract var rawCursorPos: Int
|
||||||
|
abstract var blinkCursor: Boolean
|
||||||
|
|
||||||
|
abstract var ttyFore: Int
|
||||||
|
abstract var ttyBack: Int
|
||||||
|
abstract var ttyRawMode: Boolean
|
||||||
|
|
||||||
|
abstract fun putChar(x: Int, y: Int, text: Byte, foreColour: Byte = ttyFore.toByte(), backColour: Byte = ttyBack.toByte())
|
||||||
|
|
||||||
|
private var ttyMode = Queue<Byte>() // stores escape sequences like: <ESC> [
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ONLY accepts a character to either process the escape sequence, or say the input character is allowed to print.
|
||||||
|
* This function will alter the internal state of the TTY intepreter (aka this very class)
|
||||||
|
*
|
||||||
|
* Any unrecognisable escape sequence will result the internal state to be reset but the character WILL NOT be marked
|
||||||
|
* as printable.
|
||||||
|
*
|
||||||
|
* @return true if character should be printed as-is
|
||||||
|
*/
|
||||||
|
private fun acceptChar(char: Byte): Boolean {
|
||||||
|
TODO()
|
||||||
|
|
||||||
|
if (ESC == char) {
|
||||||
|
// beginning of the escape sequence
|
||||||
|
if (ttyMode.isEmpty) {
|
||||||
|
ttyMode.addLast(char)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Any escape sequences
|
||||||
|
else if (ttyMode.size >= 1) {
|
||||||
|
// make a state machine; if the machine should move into accepting state: accept a char, and return false;
|
||||||
|
// for a rejecting state (sequence not in the transition table): clear the ttyMode, and return false;
|
||||||
|
// for a terminating state (escape sequence is terminated successfully): run interpretCSI(), and return false.
|
||||||
|
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun interpretEscapeSequence() {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private val ESC = 0x1B.toByte()
|
||||||
|
private val LBRACKET = 0x5B.toByte()
|
||||||
|
|
||||||
|
private val FORE_DEFAULT = 254
|
||||||
|
private val BACK_DEFAULT = 255
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note 1. State machine for Escape sequence
|
||||||
|
|
||||||
|
digraph G {
|
||||||
|
|
||||||
|
ESC -> Reset [label="c"]
|
||||||
|
ESC -> CSI [label="["]
|
||||||
|
|
||||||
|
CSI -> numeral [label="0..9"]
|
||||||
|
CSI -> CursorUp [label="A"]
|
||||||
|
CSI -> CursorDown [label="B"]
|
||||||
|
CSI -> CursorFwd [label="C"]
|
||||||
|
CSI -> CursorBack [label="D"]
|
||||||
|
CSI -> CursorNextLine [label="E"]
|
||||||
|
CSI -> CursorPrevLine [label="F"]
|
||||||
|
CSI -> CursorY [label="G"]
|
||||||
|
CSI -> EraseDisp [label="J"]
|
||||||
|
CSI -> EraseLine [label="K"]
|
||||||
|
CSI -> ScrollUp [label="S"]
|
||||||
|
CSI -> ScrollDown [label="T"]
|
||||||
|
|
||||||
|
numeral -> numeral [label="0..9"]
|
||||||
|
numeral -> CursorUp [label="A"]
|
||||||
|
numeral -> CursorDown [label="B"]
|
||||||
|
numeral -> CursorFwd [label="C"]
|
||||||
|
numeral -> CursorBack [label="D"]
|
||||||
|
numeral -> CursorNextLine [label="E"]
|
||||||
|
numeral -> CursorPrevLine [label="F"]
|
||||||
|
numeral -> CursorY [label="G"]
|
||||||
|
numeral -> EraseDisp [label="J"]
|
||||||
|
numeral -> EraseLine [label="K"]
|
||||||
|
numeral -> ScrollUp [label="S"]
|
||||||
|
numeral -> ScrollDown [label="T"]
|
||||||
|
|
||||||
|
numeral -> SGR [label="(any unacceptable char)"]
|
||||||
|
|
||||||
|
numeral -> separator1 [label=";"]
|
||||||
|
separator1 -> numeral2 [label="0..9"]
|
||||||
|
numeral2 -> numeral2 [label="0..9"]
|
||||||
|
numeral2 -> CursorPos [label="H"]
|
||||||
|
|
||||||
|
numeral2 -> separator2 [label=";"]
|
||||||
|
|
||||||
|
separator2 -> numeral3 [label="0..9"]
|
||||||
|
numeral3 -> numeral3 [label="0..9"]
|
||||||
|
|
||||||
|
numeral3 -> "SGR-Colour" [label="(any unacceptable char)"]
|
||||||
|
|
||||||
|
ESC [shape=Mdiamond]
|
||||||
|
Reset -> end
|
||||||
|
CursorUp -> end
|
||||||
|
CursorDown -> end
|
||||||
|
CursorFwd -> end
|
||||||
|
CursorBack -> end
|
||||||
|
CursorNextLine -> end
|
||||||
|
CursorPrevLine -> end
|
||||||
|
CursorY -> end
|
||||||
|
EraseDisp -> end
|
||||||
|
EraseLine -> end
|
||||||
|
ScrollUp -> end
|
||||||
|
ScrollDown -> end
|
||||||
|
CursorPos -> end
|
||||||
|
SGR -> end
|
||||||
|
"SGR-Colour" -> end
|
||||||
|
end [shape=Msquare]
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
@@ -11,9 +11,9 @@ import net.torvald.tsvm.kB
|
|||||||
import sun.nio.ch.DirectBuffer
|
import sun.nio.ch.DirectBuffer
|
||||||
import kotlin.experimental.and
|
import kotlin.experimental.and
|
||||||
|
|
||||||
class GraphicsAdapter(val lcdMode: Boolean = false) : PeriBase {
|
class GraphicsAdapter(val lcdMode: Boolean = false) : GlassTty(Companion.TEXT_ROWS, Companion.TEXT_COLS), PeriBase {
|
||||||
|
|
||||||
internal val framebuffer = Pixmap(WIDTH, HEIGHT, Pixmap.Format.RGBA8888)
|
internal val framebuffer = Pixmap(WIDTH, HEIGHT, Pixmap.Format.Alpha)
|
||||||
private var rendertex = Texture(1, 1, Pixmap.Format.RGBA8888)
|
private var rendertex = Texture(1, 1, Pixmap.Format.RGBA8888)
|
||||||
internal val paletteOfFloats = FloatArray(1024) {
|
internal val paletteOfFloats = FloatArray(1024) {
|
||||||
val rgba = DEFAULT_PALETTE[it / 4]
|
val rgba = DEFAULT_PALETTE[it / 4]
|
||||||
@@ -29,15 +29,16 @@ class GraphicsAdapter(val lcdMode: Boolean = false) : PeriBase {
|
|||||||
private val paletteShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, if (lcdMode) DRAW_SHADER_FRAG_LCD else DRAW_SHADER_FRAG)
|
private val paletteShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, if (lcdMode) DRAW_SHADER_FRAG_LCD else DRAW_SHADER_FRAG)
|
||||||
private val textShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, if (lcdMode) TEXT_TILING_SHADER_LCD else TEXT_TILING_SHADER)
|
private val textShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, if (lcdMode) TEXT_TILING_SHADER_LCD else TEXT_TILING_SHADER)
|
||||||
|
|
||||||
private var textmodeBlinkCursor = true
|
override var blinkCursor = true
|
||||||
|
override var ttyRawMode = false
|
||||||
private var graphicsUseSprites = false
|
private var graphicsUseSprites = false
|
||||||
private var lastUsedColour = (-1).toByte()
|
private var lastUsedColour = (-1).toByte()
|
||||||
private var currentChrRom = 0
|
private var currentChrRom = 0
|
||||||
private var chrWidth = 7f
|
private var chrWidth = 7f
|
||||||
private var chrHeight = 14f
|
private var chrHeight = 14f
|
||||||
|
|
||||||
private var ttyFore: Int = 254 // cannot be Byte
|
override var ttyFore: Int = 254 // cannot be Byte
|
||||||
private var ttyBack: Int = 255 // cannot be Byte
|
override var ttyBack: Int = 255 // cannot be Byte
|
||||||
|
|
||||||
private val textForePixmap = Pixmap(TEXT_COLS, TEXT_ROWS, Pixmap.Format.RGBA8888)
|
private val textForePixmap = Pixmap(TEXT_COLS, TEXT_ROWS, Pixmap.Format.RGBA8888)
|
||||||
private val textBackPixmap = Pixmap(TEXT_COLS, TEXT_ROWS, Pixmap.Format.RGBA8888)
|
private val textBackPixmap = Pixmap(TEXT_COLS, TEXT_ROWS, Pixmap.Format.RGBA8888)
|
||||||
@@ -52,7 +53,14 @@ class GraphicsAdapter(val lcdMode: Boolean = false) : PeriBase {
|
|||||||
private val memTextBackOffset = 2980L + 2560
|
private val memTextBackOffset = 2980L + 2560
|
||||||
private val memTextOffset = 2980L + 2560 + 2560
|
private val memTextOffset = 2980L + 2560 + 2560
|
||||||
|
|
||||||
private fun getTtyCursorPos() = spriteAndTextArea.getShort(memTextCursorPosOffset) % TEXT_COLS to spriteAndTextArea.getShort(3938L) / TEXT_COLS
|
override var rawCursorPos: Int
|
||||||
|
get() = spriteAndTextArea.getShort(memTextCursorPosOffset).toInt()
|
||||||
|
set(value) { spriteAndTextArea.setShort(memTextCursorPosOffset, value.toShort()) }
|
||||||
|
|
||||||
|
override fun getCursorPos() = rawCursorPos % TEXT_COLS to rawCursorPos / TEXT_COLS
|
||||||
|
override fun setCursorPos(x: Int, y: Int) {
|
||||||
|
rawCursorPos = toTtyTextOffset(x, y)
|
||||||
|
}
|
||||||
private fun toTtyTextOffset(x: Int, y: Int) = y * TEXT_COLS + x
|
private fun toTtyTextOffset(x: Int, y: Int) = y * TEXT_COLS + x
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -71,12 +79,15 @@ class GraphicsAdapter(val lcdMode: Boolean = false) : PeriBase {
|
|||||||
// when in text mode, and that's undesired behaviour
|
// when in text mode, and that's undesired behaviour
|
||||||
// -1 is preferred because it points to the colour CLEAR, and it's constant.
|
// -1 is preferred because it points to the colour CLEAR, and it's constant.
|
||||||
spriteAndTextArea.fillWith(-1)
|
spriteAndTextArea.fillWith(-1)
|
||||||
|
|
||||||
|
|
||||||
|
println(framebuffer.pixels.limit())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun peek(addr: Long): Byte? {
|
override fun peek(addr: Long): Byte? {
|
||||||
val adi = addr.toInt()
|
val adi = addr.toInt()
|
||||||
return when (addr) {
|
return when (addr) {
|
||||||
in 0 until 250880 -> framebuffer.getPixel(adi % WIDTH, adi / WIDTH).toByte()
|
in 0 until 250880 -> framebuffer.pixels.get(adi)//framebuffer.getPixel(adi % WIDTH, adi / WIDTH).toByte()
|
||||||
in 250880 until 250972 -> unusedArea[adi - 250880]
|
in 250880 until 250972 -> unusedArea[adi - 250880]
|
||||||
in 250972 until 261632 -> spriteAndTextArea[addr - 250972]
|
in 250972 until 261632 -> spriteAndTextArea[addr - 250972]
|
||||||
in 261632 until 262144 -> peekPalette(adi - 261632)
|
in 261632 until 262144 -> peekPalette(adi - 261632)
|
||||||
@@ -94,7 +105,7 @@ class GraphicsAdapter(val lcdMode: Boolean = false) : PeriBase {
|
|||||||
when (addr) {
|
when (addr) {
|
||||||
in 0 until 250880 -> {
|
in 0 until 250880 -> {
|
||||||
lastUsedColour = byte
|
lastUsedColour = byte
|
||||||
framebuffer.drawPixel(adi % WIDTH, adi / WIDTH, bi.shl(24))
|
framebuffer.pixels.put(adi, byte)
|
||||||
}
|
}
|
||||||
250883L -> {
|
250883L -> {
|
||||||
unusedArea[adi - 250880] = byte
|
unusedArea[adi - 250880] = byte
|
||||||
@@ -110,13 +121,16 @@ class GraphicsAdapter(val lcdMode: Boolean = false) : PeriBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTextmodeAttirbutes(): Byte = (currentChrRom.and(15).shl(4) or textmodeBlinkCursor.toInt()).toByte()
|
private fun getTextmodeAttirbutes(): Byte = (currentChrRom.and(15).shl(4) or
|
||||||
|
ttyRawMode.toInt().shl(1) or
|
||||||
|
blinkCursor.toInt()).toByte()
|
||||||
|
|
||||||
private fun getGraphicsAttributes(): Byte = graphicsUseSprites.toInt().toByte()
|
private fun getGraphicsAttributes(): Byte = graphicsUseSprites.toInt().toByte()
|
||||||
|
|
||||||
private fun setTextmodeAttributes(rawbyte: Byte) {
|
private fun setTextmodeAttributes(rawbyte: Byte) {
|
||||||
currentChrRom = rawbyte.toInt().and(0b11110000).ushr(4)
|
currentChrRom = rawbyte.toInt().and(0b11110000).ushr(4)
|
||||||
textmodeBlinkCursor = rawbyte.and(1) == 1.toByte()
|
blinkCursor = rawbyte.and(0b0001) != 0.toByte()
|
||||||
|
ttyRawMode = rawbyte.and(0b0010) != 0.toByte()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setGraphicsAttributes(rawbyte: Byte) {
|
private fun setGraphicsAttributes(rawbyte: Byte) {
|
||||||
@@ -173,35 +187,17 @@ class GraphicsAdapter(val lcdMode: Boolean = false) : PeriBase {
|
|||||||
* @param to memory "offset" in Graphics Adapter's memory space, starts from zero.
|
* @param to memory "offset" in Graphics Adapter's memory space, starts from zero.
|
||||||
* @param length how many bytes should be moved
|
* @param length how many bytes should be moved
|
||||||
*/
|
*/
|
||||||
fun bulkLoad(vm: VM, from: Long, to: Long, length: Long) {
|
/*fun bulkLoad(vm: VM, from: Long, to: Long, length: Long) {
|
||||||
UnsafeHelper.unsafe.copyMemory(null, vm.usermem.ptr + from, (framebuffer.pixels as DirectBuffer).address(), to, length)
|
UnsafeHelper.unsafe.copyMemory(null, vm.usermem.ptr + from, (framebuffer.pixels as DirectBuffer).address(), to, length)
|
||||||
}
|
}*/
|
||||||
|
|
||||||
private fun putChar(x: Int, y: Int, text: Byte, foreColour: Byte = ttyFore.toByte(), backColour: Byte = ttyBack.toByte()) {
|
override fun putChar(x: Int, y: Int, text: Byte, foreColour: Byte, backColour: Byte) {
|
||||||
val textOff = toTtyTextOffset(x, y)
|
val textOff = toTtyTextOffset(x, y)
|
||||||
spriteAndTextArea[memTextForeOffset + textOff] = foreColour
|
spriteAndTextArea[memTextForeOffset + textOff] = foreColour
|
||||||
spriteAndTextArea[memTextBackOffset + textOff] = backColour
|
spriteAndTextArea[memTextBackOffset + textOff] = backColour
|
||||||
spriteAndTextArea[memTextOffset + textOff] = text
|
spriteAndTextArea[memTextOffset + textOff] = text
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun advanceCursor() {
|
|
||||||
spriteAndTextArea.setShort(
|
|
||||||
memTextCursorPosOffset,
|
|
||||||
((spriteAndTextArea.getShort(memTextCursorPosOffset) + 1) % (TEXT_COLS * TEXT_ROWS)).toShort()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// how TTY should work with all those ASCII control characters
|
|
||||||
fun print(char: Byte) {
|
|
||||||
val (cx, cy) = getTtyCursorPos()
|
|
||||||
when (char) {
|
|
||||||
in 0x20..0x7E, in 0x80..0xFF -> {
|
|
||||||
putChar(cx, cy, char)
|
|
||||||
advanceCursor()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
framebuffer.dispose()
|
framebuffer.dispose()
|
||||||
rendertex.dispose()
|
rendertex.dispose()
|
||||||
@@ -225,7 +221,7 @@ class GraphicsAdapter(val lcdMode: Boolean = false) : PeriBase {
|
|||||||
|
|
||||||
fun render(delta: Float, batch: SpriteBatch, x: Float, y: Float) {
|
fun render(delta: Float, batch: SpriteBatch, x: Float, y: Float) {
|
||||||
rendertex.dispose()
|
rendertex.dispose()
|
||||||
rendertex = Texture(framebuffer)
|
rendertex = Texture(framebuffer, Pixmap.Format.RGBA8888, false)
|
||||||
|
|
||||||
|
|
||||||
batch.shader = null
|
batch.shader = null
|
||||||
@@ -383,7 +379,7 @@ float rand(vec2 co){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
gl_FragColor = pal[int(texture2D(u_texture, v_texCoords).r * 255.0)];
|
gl_FragColor = pal[int(texture2D(u_texture, v_texCoords).a * 255.0)];
|
||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
@@ -403,7 +399,7 @@ float rand(vec2 co){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec4 palCol = pal[int(texture2D(u_texture, v_texCoords).r * 255.0)];
|
vec4 palCol = pal[int(texture2D(u_texture, v_texCoords).a * 255.0)];
|
||||||
float lum = floor((3.0 * palCol.r + 4.0 * palCol.g + palCol.b) / 8.0 * intensitySteps) / intensitySteps;
|
float lum = floor((3.0 * palCol.r + 4.0 * palCol.g + palCol.b) / 8.0 * intensitySteps) / intensitySteps;
|
||||||
vec4 outIntensity = vec4(vec3(1.0 - lum), palCol.a);
|
vec4 outIntensity = vec4(vec3(1.0 - lum), palCol.a);
|
||||||
|
|
||||||
|
|||||||
7
src/net/torvald/tsvm/peripheral/TermSim.kt
Normal file
7
src/net/torvald/tsvm/peripheral/TermSim.kt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package net.torvald.tsvm.peripheral
|
||||||
|
|
||||||
|
internal class TermSim {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -92,7 +92,7 @@ MMIO
|
|||||||
Text mode rows
|
Text mode rows
|
||||||
1 bytes RW
|
1 bytes RW
|
||||||
Text-mode attributes
|
Text-mode attributes
|
||||||
0b kkkk 000c (k: currently using character rom, c: Cursor blink)
|
0b kkkk 00rc (k: currently using character rom, r: TTY Raw mode, c: Cursor blink)
|
||||||
1 bytes RW
|
1 bytes RW
|
||||||
Graphics-mode attributes
|
Graphics-mode attributes
|
||||||
0b 0000 000g (g: Use sprites(wipes out text buffer))
|
0b 0000 000g (g: Use sprites(wipes out text buffer))
|
||||||
|
|||||||
Reference in New Issue
Block a user