mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-09 22:54:03 +09:00
can read mouse position via mmio
This commit is contained in:
@@ -39,6 +39,14 @@ class GraphicsJSR223Delegate(val vm: VM) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun plotPixel(x: Int, y: Int, color: Byte) {
|
||||||
|
getFirstGPU()?.let {
|
||||||
|
if (x in 0 until GraphicsAdapter.WIDTH && y in 0 until GraphicsAdapter.HEIGHT) {
|
||||||
|
it.poke(y.toLong() * GraphicsAdapter.WIDTH + x, color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun GraphicsAdapter._loadbulk(fromAddr: Int, toAddr: Int, length: Int) {
|
private fun GraphicsAdapter._loadbulk(fromAddr: Int, toAddr: Int, length: Int) {
|
||||||
UnsafeHelper.memcpy(
|
UnsafeHelper.memcpy(
|
||||||
vm.usermem.ptr + fromAddr,
|
vm.usermem.ptr + fromAddr,
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ class VM(
|
|||||||
|
|
||||||
val peripheralTable = Array(8) { PeripheralEntry() }
|
val peripheralTable = Array(8) { PeripheralEntry() }
|
||||||
|
|
||||||
|
internal fun getIO(): IOSpace = peripheralTable[0].peripheral as IOSpace
|
||||||
|
|
||||||
lateinit var printStream: OutputStream
|
lateinit var printStream: OutputStream
|
||||||
lateinit var errorStream: OutputStream
|
lateinit var errorStream: OutputStream
|
||||||
lateinit var inputStream: InputStream
|
lateinit var inputStream: InputStream
|
||||||
@@ -73,7 +75,7 @@ class VM(
|
|||||||
init {
|
init {
|
||||||
peripheralTable[0] = PeripheralEntry(
|
peripheralTable[0] = PeripheralEntry(
|
||||||
"io",
|
"io",
|
||||||
IOSpace(),
|
IOSpace(this),
|
||||||
HW_RESERVE_SIZE,
|
HW_RESERVE_SIZE,
|
||||||
MMIO_SIZE.toInt() - 256,
|
MMIO_SIZE.toInt() - 256,
|
||||||
64
|
64
|
||||||
@@ -90,6 +92,10 @@ class VM(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun update(delta: Float) {
|
||||||
|
getIO().update(delta)
|
||||||
|
}
|
||||||
|
|
||||||
fun dispose() {
|
fun dispose() {
|
||||||
usermem.destroy()
|
usermem.destroy()
|
||||||
peripheralTable.forEach { it.peripheral?.dispose() }
|
peripheralTable.forEach { it.peripheral?.dispose() }
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ package net.torvald.tsvm
|
|||||||
|
|
||||||
import com.badlogic.gdx.ApplicationAdapter
|
import com.badlogic.gdx.ApplicationAdapter
|
||||||
import com.badlogic.gdx.Gdx
|
import com.badlogic.gdx.Gdx
|
||||||
|
import com.badlogic.gdx.InputProcessor
|
||||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
||||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.torvald.tsvm.peripheral.GraphicsAdapter
|
import net.torvald.tsvm.peripheral.GraphicsAdapter
|
||||||
|
import net.torvald.tsvm.peripheral.IOSpace
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
@@ -25,7 +27,7 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
|
|||||||
override fun create() {
|
override fun create() {
|
||||||
super.create()
|
super.create()
|
||||||
|
|
||||||
gpu = GraphicsAdapter(lcdMode = true)
|
gpu = GraphicsAdapter(vm, lcdMode = false)
|
||||||
|
|
||||||
vm.peripheralTable[1] = PeripheralEntry(
|
vm.peripheralTable[1] = PeripheralEntry(
|
||||||
VM.PERITYPE_TERM,
|
VM.PERITYPE_TERM,
|
||||||
@@ -49,8 +51,11 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
|
|||||||
// TEST PRG
|
// TEST PRG
|
||||||
vmRunner = VMRunnerFactory(vm, "js")
|
vmRunner = VMRunnerFactory(vm, "js")
|
||||||
coroutineJob = GlobalScope.launch {
|
coroutineJob = GlobalScope.launch {
|
||||||
vmRunner.executeCommand(sanitiseJS(gpuTestPaletteJs))
|
vmRunner.executeCommand(sanitiseJS(shitcode))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Gdx.input.inputProcessor = vm.getIO()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var updateAkku = 0.0
|
private var updateAkku = 0.0
|
||||||
@@ -77,16 +82,11 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
|
|||||||
private var latch = true
|
private var latch = true
|
||||||
|
|
||||||
private fun updateGame(delta: Float) {
|
private fun updateGame(delta: Float) {
|
||||||
|
vm.update(delta)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun poke(addr: Long, value: Byte) = vm.poke(addr, value)
|
fun poke(addr: Long, value: Byte) = vm.poke(addr, value)
|
||||||
|
|
||||||
private fun paintTestPalette() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private val gpuTestPaletteKt = """
|
private val gpuTestPaletteKt = """
|
||||||
val w = 560
|
val w = 560
|
||||||
val h = 448
|
val h = 448
|
||||||
@@ -265,6 +265,13 @@ println("Starting TVDOS...");
|
|||||||
println("TSVM Disk Operating System, version 1.20");
|
println("TSVM Disk Operating System, version 1.20");
|
||||||
println("");
|
println("");
|
||||||
print("C:\\\\>");
|
print("C:\\\\>");
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
var mx = vm.peek(-33) + vm.peek(-34) * 256;
|
||||||
|
var my = vm.peek(-35) + vm.peek(-36) * 256;
|
||||||
|
println("mx: "+mx+", my: "+my);
|
||||||
|
graphics.plotPixel(mx, my, (mx + my) % 255);
|
||||||
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
private val gpuTestPaletteJava = """
|
private val gpuTestPaletteJava = """
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import net.torvald.tsvm.peripheral.GraphicsAdapter
|
|||||||
class VMJSR223Delegate(val vm: VM) {
|
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())!!.toInt().and(255)
|
||||||
fun nanoTime() = System.nanoTime()
|
fun nanoTime() = System.nanoTime()
|
||||||
fun malloc(size: Int) = vm.malloc(size)
|
fun malloc(size: Int) = vm.malloc(size)
|
||||||
fun free(ptr: Int) = vm.free(ptr)
|
fun free(ptr: Int) = vm.free(ptr)
|
||||||
|
|||||||
@@ -204,8 +204,6 @@ abstract class GlassTty(val TEXT_ROWS: Int, val TEXT_COLS: Int) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
abstract fun resetTtyStatus()
|
abstract fun resetTtyStatus()
|
||||||
abstract fun cursorUp(arg: Int = 1)
|
abstract fun cursorUp(arg: Int = 1)
|
||||||
abstract fun cursorDown(arg: Int = 1)
|
abstract fun cursorDown(arg: Int = 1)
|
||||||
@@ -247,6 +245,17 @@ abstract class GlassTty(val TEXT_ROWS: Int, val TEXT_COLS: Int) {
|
|||||||
INITIAL, ESC, CSI, NUM1, SEP1, NUM2, SEP2, NUM3
|
INITIAL, ESC, CSI, NUM1, SEP1, NUM2, SEP2, NUM3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts a key into a keyboard buffer
|
||||||
|
*/
|
||||||
|
abstract fun putKey(key: Int)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a key from a keyboard buffer
|
||||||
|
*/
|
||||||
|
abstract fun takeKey(): Int
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -8,13 +8,18 @@ import net.torvald.UnsafeHelper
|
|||||||
import net.torvald.tsvm.AppLoader
|
import net.torvald.tsvm.AppLoader
|
||||||
import net.torvald.tsvm.VM
|
import net.torvald.tsvm.VM
|
||||||
import net.torvald.tsvm.kB
|
import net.torvald.tsvm.kB
|
||||||
|
import net.torvald.util.CircularArray
|
||||||
import sun.nio.ch.DirectBuffer
|
import sun.nio.ch.DirectBuffer
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
import kotlin.experimental.and
|
import kotlin.experimental.and
|
||||||
|
|
||||||
class GraphicsAdapter(val lcdMode: Boolean = false) : GlassTty(Companion.TEXT_ROWS, Companion.TEXT_COLS), PeriBase {
|
class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Companion.TEXT_ROWS, Companion.TEXT_COLS), PeriBase {
|
||||||
|
|
||||||
|
override fun getVM(): VM {
|
||||||
|
return vm
|
||||||
|
}
|
||||||
|
|
||||||
internal val framebuffer = Pixmap(WIDTH, HEIGHT, Pixmap.Format.Alpha)
|
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)
|
||||||
@@ -569,6 +574,16 @@ class GraphicsAdapter(val lcdMode: Boolean = false) : GlassTty(Companion.TEXT_RO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun putKey(key: Int) {
|
||||||
|
vm.poke(-39, key.toByte())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return key code in 0..255 (TODO: JInput Keycode or ASCII-Code?)
|
||||||
|
*/
|
||||||
|
override fun takeKey(): Int {
|
||||||
|
return vm.peek(-38)!!.toInt().and(255)
|
||||||
|
}
|
||||||
|
|
||||||
private fun Boolean.toInt() = if (this) 1 else 0
|
private fun Boolean.toInt() = if (this) 1 else 0
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,94 @@
|
|||||||
package net.torvald.tsvm.peripheral
|
package net.torvald.tsvm.peripheral
|
||||||
|
|
||||||
class IOSpace : PeriBase {
|
import com.badlogic.gdx.Gdx
|
||||||
|
import com.badlogic.gdx.InputProcessor
|
||||||
|
import net.torvald.UnsafeHelper
|
||||||
|
import net.torvald.tsvm.VM
|
||||||
|
import net.torvald.util.CircularArray
|
||||||
|
|
||||||
|
class IOSpace(val vm: VM) : PeriBase, InputProcessor {
|
||||||
|
|
||||||
|
override fun getVM(): VM {
|
||||||
|
return vm
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Absolute x-position of the computer GUI */
|
||||||
|
var guiPosX = 0
|
||||||
|
/** Absolute y-position of the computer GUI */
|
||||||
|
var guiPosY = 0
|
||||||
|
|
||||||
|
private val keyboardBuffer = CircularArray<Byte>(32, true)
|
||||||
|
private var mouseX: Short = 0
|
||||||
|
private var mouseY: Short = 0
|
||||||
|
private var mouseDown = false
|
||||||
|
|
||||||
override fun peek(addr: Long): Byte? {
|
override fun peek(addr: Long): Byte? {
|
||||||
TODO("Not yet implemented")
|
return mmio_read(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun poke(addr: Long, byte: Byte) {
|
override fun poke(addr: Long, byte: Byte) {
|
||||||
TODO("Not yet implemented")
|
mmio_write(addr, byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mmio_read(addr: Long): Byte? {
|
override fun mmio_read(addr: Long): Byte? {
|
||||||
TODO("Not yet implemented")
|
val adi = addr.toInt()
|
||||||
|
return when (addr) {
|
||||||
|
in 0..31 -> keyboardBuffer[(addr.toInt())] ?: -1
|
||||||
|
in 32..33 -> (mouseX.toInt() shr (adi - 32).times(8)).toByte()
|
||||||
|
in 34..35 -> (mouseY.toInt() shr (adi - 34).times(8)).toByte()
|
||||||
|
36L -> if (mouseDown) 1 else 0
|
||||||
|
37L -> keyboardBuffer.removeHead() ?: -1
|
||||||
|
else -> -1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mmio_write(addr: Long, byte: Byte) {
|
override fun mmio_write(addr: Long, byte: Byte) {
|
||||||
TODO("Not yet implemented")
|
val adi = addr.toInt()
|
||||||
|
val bi = byte.toInt().and(255)
|
||||||
|
when (addr) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun update(delta: Float) {
|
||||||
|
mouseX = (Gdx.input.x + guiPosX).toShort()
|
||||||
|
mouseY = (Gdx.input.y + guiPosY).toShort()
|
||||||
|
mouseDown = Gdx.input.isTouched
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun touchUp(p0: Int, p1: Int, p2: Int, p3: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseMoved(p0: Int, p1: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun keyTyped(p0: Char): Boolean {
|
||||||
|
keyboardBuffer.appendTail(p0.toByte())
|
||||||
|
println("[IO] Key typed: $p0")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun scrolled(p0: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun keyUp(p0: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun touchDragged(p0: Int, p1: Int, p2: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun keyDown(p0: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun touchDown(p0: Int, p1: Int, p2: Int, p3: Int): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package net.torvald.tsvm.peripheral
|
package net.torvald.tsvm.peripheral
|
||||||
|
|
||||||
|
import net.torvald.tsvm.VM
|
||||||
|
|
||||||
interface PeriBase {
|
interface PeriBase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,4 +18,6 @@ interface PeriBase {
|
|||||||
fun mmio_write(addr: Long, byte: Byte)
|
fun mmio_write(addr: Long, byte: Byte)
|
||||||
|
|
||||||
fun dispose()
|
fun dispose()
|
||||||
|
|
||||||
|
fun getVM(): VM
|
||||||
}
|
}
|
||||||
192
src/net/torvald/util/CircularArray.kt
Normal file
192
src/net/torvald/util/CircularArray.kt
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
package net.torvald.util
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* buffer[head] contains the most recent item, whereas buffer[tail] contains the oldest one.
|
||||||
|
*
|
||||||
|
* Notes for particle storage:
|
||||||
|
* Particles does not need to be removed, just let it overwrite as their operation is rather
|
||||||
|
* lightweight. So, just flagDespawn = true if it need to be "deleted" so that it won't update
|
||||||
|
* anymore.
|
||||||
|
*
|
||||||
|
* Created by minjaesong on 2017-01-22.
|
||||||
|
*/
|
||||||
|
class CircularArray<T>(val size: Int, val overwriteOnOverflow: Boolean): Iterable<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What to do RIGHT BEFORE old element is being overridden by the new element (only makes sense when ```overwriteOnOverflow = true```)
|
||||||
|
*
|
||||||
|
* This function will not be called when ```removeHead()``` or ```removeTail()``` is called.
|
||||||
|
*/
|
||||||
|
var overwritingPolicy: (T) -> Unit = {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
val buffer: Array<T> = arrayOfNulls<Any>(size) as Array<T>
|
||||||
|
|
||||||
|
/** Tail stands for the oldest element. The tail index points AT the tail element */
|
||||||
|
var tail: Int = 0; private set
|
||||||
|
/** Head stands for the youngest element. The head index points AFTER the head element */
|
||||||
|
var head: Int = 0; private set
|
||||||
|
|
||||||
|
private var overflow = false
|
||||||
|
|
||||||
|
val lastIndex = size - 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of elements that forEach() or fold() would iterate.
|
||||||
|
*/
|
||||||
|
val elemCount: Int
|
||||||
|
get() = if (overflow) size else head - tail
|
||||||
|
val isEmpty: Boolean
|
||||||
|
get() = !overflow && head == tail
|
||||||
|
|
||||||
|
private inline fun incHead() { head = (head + 1).wrap() }
|
||||||
|
private inline fun decHead() { head = (head - 1).wrap() }
|
||||||
|
private inline fun incTail() { tail = (tail + 1).wrap() }
|
||||||
|
private inline fun decTail() { tail = (tail - 1).wrap() }
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
tail = 0
|
||||||
|
head = 0
|
||||||
|
overflow = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the overflowing is enabled, tail element (ultimate element) will be changed into the penultimate element.
|
||||||
|
*/
|
||||||
|
fun appendHead(item: T) {
|
||||||
|
if (overflow && !overwriteOnOverflow) {
|
||||||
|
throw StackOverflowError()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (overflow) {
|
||||||
|
overwritingPolicy.invoke(buffer[head])
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[head] = item
|
||||||
|
incHead()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overflow) {
|
||||||
|
incTail()
|
||||||
|
}
|
||||||
|
|
||||||
|
// must be checked AFTER the actual head increment; otherwise this condition doesn't make sense
|
||||||
|
if (tail == head) {
|
||||||
|
overflow = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun appendTail(item: T) {
|
||||||
|
// even if overflowing is enabled, appending at tail causes head element to be altered, therefore such action
|
||||||
|
// must be blocked by throwing overflow error
|
||||||
|
|
||||||
|
if (overflow) {
|
||||||
|
throw StackOverflowError()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
decTail()
|
||||||
|
buffer[tail] = item
|
||||||
|
}
|
||||||
|
|
||||||
|
// must be checked AFTER the actual head increment; otherwise this condition doesn't make sense
|
||||||
|
if (tail == head) {
|
||||||
|
overflow = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeHead(): T? {
|
||||||
|
if (isEmpty) return null
|
||||||
|
|
||||||
|
decHead()
|
||||||
|
overflow = false
|
||||||
|
|
||||||
|
return buffer[head]
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeTail(): T? {
|
||||||
|
if (isEmpty) return null
|
||||||
|
|
||||||
|
val ret = buffer[tail]
|
||||||
|
incTail()
|
||||||
|
overflow = false
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the youngest (last of the array) element */
|
||||||
|
fun getHeadElem(): T? = if (isEmpty) null else buffer[(head - 1).wrap()]
|
||||||
|
/** Returns the oldest (first of the array) element */
|
||||||
|
fun getTailElem(): T? = if (isEmpty) null else buffer[tail]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relative-indexed get. Index of zero will return the head element.
|
||||||
|
*/
|
||||||
|
operator fun get(index: Int): T? = buffer[(head - 1 - index).wrap()]
|
||||||
|
|
||||||
|
private fun getAbsoluteRange() = 0 until when {
|
||||||
|
head == tail -> buffer.size
|
||||||
|
tail > head -> buffer.size - (((head - 1).wrap()) - tail)
|
||||||
|
else -> head - tail
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun iterator(): Iterator<T> {
|
||||||
|
if (isEmpty) {
|
||||||
|
return object : Iterator<T> {
|
||||||
|
override fun next(): T = throw EmptyStackException()
|
||||||
|
override fun hasNext() = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val rangeMax = getAbsoluteRange().last
|
||||||
|
var counter = 0
|
||||||
|
return object : Iterator<T> {
|
||||||
|
override fun next(): T {
|
||||||
|
val ret = buffer[(counter + tail).wrap()]
|
||||||
|
counter += 1
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasNext() = (counter <= rangeMax)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates the array with oldest element (tail) first.
|
||||||
|
*/
|
||||||
|
fun forEach(action: (T) -> Unit) {
|
||||||
|
// for (element in buffer) action(element)
|
||||||
|
// return nothing
|
||||||
|
|
||||||
|
iterator().forEach(action)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <R> fold(initial: R, operation: (R, T) -> R): R {
|
||||||
|
// accumulator = initial
|
||||||
|
// for (element in buffer) accumulator = operation(accumulator, element)
|
||||||
|
// return accumulator
|
||||||
|
|
||||||
|
var accumulator = initial
|
||||||
|
|
||||||
|
if (isEmpty)
|
||||||
|
return initial
|
||||||
|
else {
|
||||||
|
iterator().forEach {
|
||||||
|
accumulator = operation(accumulator, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun Int.wrap() = this fmod size
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "CircularArray(size=${buffer.size}, head=$head, tail=$tail, overflow=$overflow)"
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline infix fun Int.fmod(other: Int) = Math.floorMod(this, other)
|
||||||
|
}
|
||||||
@@ -37,6 +37,23 @@ User area: 8 MB, hardware area: 8 MB
|
|||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
IO Device
|
||||||
|
|
||||||
|
Endianness: little
|
||||||
|
|
||||||
|
MMIO
|
||||||
|
|
||||||
|
0..31: Raw Keyboard Buffer read. Won't shift the key buffer
|
||||||
|
32..33: Mouse X pos
|
||||||
|
34..35: Mouse Y pos
|
||||||
|
36: Mouse down? (1 for TRUE, 0 for FALSE)
|
||||||
|
37: Read/Write single key input. Key buffer will be shifted. Manual writing is
|
||||||
|
usually unnecessary as such action must be automatically managed via LibGDX
|
||||||
|
input processing.
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
VRAM Bank 0 (256 kB)
|
VRAM Bank 0 (256 kB)
|
||||||
|
|
||||||
Endianness: little
|
Endianness: little
|
||||||
|
|||||||
Reference in New Issue
Block a user