From 344c35ed9b3c9a1085351259cacac8e6bf1e6da2 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Fri, 24 Apr 2020 10:20:14 +0900 Subject: [PATCH] fixing black screen bug --- FontROM7x14.kra | Bin 0 -> 105070 bytes FontROM7x14.png | Bin 0 -> 3864 bytes smpte_bars.png | Bin 0 -> 2185 bytes .../torvald/tsvm/GraphicsJSR223Delegate.kt | 28 +++++ src/net/torvald/tsvm/VM.kt | 4 +- src/net/torvald/tsvm/VMGUI.kt | 118 +++++++++++------- src/net/torvald/tsvm/VMJSR223Delegate.kt | 22 ++++ src/net/torvald/tsvm/VMKotlinAdapter.kt | 10 -- src/net/torvald/tsvm/VMRunnerFactory.kt | 8 +- .../tsvm/peripheral/GraphicsAdapter.kt | 99 ++++++++++++--- terranmon.txt | 19 ++- 11 files changed, 224 insertions(+), 84 deletions(-) create mode 100644 FontROM7x14.kra create mode 100644 FontROM7x14.png create mode 100644 smpte_bars.png create mode 100644 src/net/torvald/tsvm/GraphicsJSR223Delegate.kt create mode 100644 src/net/torvald/tsvm/VMJSR223Delegate.kt delete mode 100644 src/net/torvald/tsvm/VMKotlinAdapter.kt diff --git a/FontROM7x14.kra b/FontROM7x14.kra new file mode 100644 index 0000000000000000000000000000000000000000..30495fe3ab426bf72dad96adde5faf87b18d55f8 GIT binary patch literal 105070 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 Pk$@1zuTntoD&T(s1U+Z! literal 0 HcmV?d00001 diff --git a/FontROM7x14.png b/FontROM7x14.png new file mode 100644 index 0000000000000000000000000000000000000000..e4874a3d3fe2bc8f819f6fe1eaadc0aef1698bc8 GIT binary patch literal 3864 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 literal 0 HcmV?d00001 diff --git a/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt b/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt new file mode 100644 index 0000000..fe46a9c --- /dev/null +++ b/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt @@ -0,0 +1,28 @@ +package net.torvald.tsvm + +import net.torvald.tsvm.peripheral.GraphicsAdapter + +class GraphicsJSR223Delegate(val vm: VM) { + + private fun getFirstGPU(): GraphicsAdapter? { + return vm.peripheralTable[vm.findPeribyType("gpu") ?: return null].peripheral as? GraphicsAdapter + } + + fun resetPalette() { + getFirstGPU()?.poke(250883L, 1) + } + + /** + * @param index which palette number to modify, 0-255 + * @param r g - b - a - RGBA value, 0-15 + */ + fun setPalette(index: Int, r: Int, g: Int, b: Int, a: Int = 16) { + getFirstGPU()?.let { + it.paletteOfFloats[index * 4] = (r and 15) / 15f + it.paletteOfFloats[index * 4 + 1] = (g and 15) / 15f + it.paletteOfFloats[index * 4 + 2] = (b and 15) / 15f + it.paletteOfFloats[index * 4 + 3] = (a and 15) / 15f + } + } + +} \ No newline at end of file diff --git a/src/net/torvald/tsvm/VM.kt b/src/net/torvald/tsvm/VM.kt index 72bfc49..e3e105f 100644 --- a/src/net/torvald/tsvm/VM.kt +++ b/src/net/torvald/tsvm/VM.kt @@ -115,7 +115,7 @@ class VM( } } - fun poke(addr: Long, value: Byte) { + internal fun poke(addr: Long, value: Byte) { val (memspace, offset) = translateAddr(addr) if (memspace == null) Firmware.errorIllegalAccess(addr) @@ -125,7 +125,7 @@ class VM( (memspace as PeriBase).poke(offset, value) } - fun peek(addr:Long): Byte? { + internal fun peek(addr:Long): Byte? { val (memspace, offset) = translateAddr(addr) return if (memspace == null) null diff --git a/src/net/torvald/tsvm/VMGUI.kt b/src/net/torvald/tsvm/VMGUI.kt index d188e81..d1c795c 100644 --- a/src/net/torvald/tsvm/VMGUI.kt +++ b/src/net/torvald/tsvm/VMGUI.kt @@ -70,21 +70,12 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter() private var latch = true private fun updateGame(delta: Float) { - // black screening workaround - if (latch) { - latch = false - //paintTestPalette() - val peripheralSlot = vm.findPeribyType(VM.PERITYPE_GRAPHICS)!! - val hwoff = VM.HW_RESERVE_SIZE * peripheralSlot - for (i in 250880 until 250972) { - vm.poke(-(i + 1) - hwoff, 0) - } - } } fun poke(addr: Long, value: Byte) = vm.poke(addr, value) private fun paintTestPalette() { + } private val gpuTestPaletteKt = """ @@ -101,30 +92,25 @@ fun inthash(x: Int): Int { var rng = (Math.floor(Math.random() * 2147483647) + 1).toInt() -bindings.forEach { - println(it) -} - -println(zzz) - while (true) { val tstart: Long = System.nanoTime() for (y1 in 0..359) { for (x1 in 0 until w) { val palnum = 20 * (y1 / 30) + (x1 / 28) - vm.poke(-(y1 * w + x1 + 1L) - hwoff, inthash(palnum + rng).toByte()) + vm.poke(-(y1 * w + x1 + 1) - hwoff, inthash(palnum + rng)) } } for (y2 in 360 until h) { for (x2 in 0 until w) { val palnum = 240 + x2 / 35 - vm.poke(-(y2 * w + x2 + 1L) - hwoff, palnum.toByte()) + vm.poke(-(y2 * w + x2 + 1) - hwoff, palnum) } } - for (k in 0..2239) { - vm.poke(-(254912L + k + 1) - hwoff, -2) // white - vm.poke(-(254912L + 2240 + k + 1) - hwoff, -1) // transparent - vm.poke(-(254912L + 2240 * 2 + k + 1) - hwoff, Math.round(Math.random() * 255).toByte()) + + for (k in 0 until 2560) { + vm.poke(-(253952 + k + 1) - hwoff, -2) // white + vm.poke(-(253952 + 2560 + k + 1) - hwoff, -1) // transparent + vm.poke(-(253952 + 2560 * 2 + k + 1) - hwoff, Math.round(Math.random() * 255).toInt()) } rng = inthash(rng) @@ -133,6 +119,42 @@ while (true) { } """.trimIndent() + private val gpuTestPaletteKt2 = """ +val w = 560 +val h = 448 +val hwoff = 1048576 + +fun inthash(x: Int): Int { + var x = (x.shr(16) xor x) * 0x45d9f3b + x = (x.shr(16) xor x) * 0x45d9f3b + x = (x.shr(16) xor x) + return x +} + +var rng = ((Math.random() * 2147483647) + 1).toInt() + +while (true) { + for (y1 in 0..359) { + for (x1 in 0 until w) { + val palnum = 20 * (y1 / 30) + (x1 / 28) + vm.poke(-(y1 * w + x1 + 1) - hwoff, palnum)//inthash(palnum + rng)) + } + } + for (y2 in 360 until h) { + for (x2 in 0 until w) { + val palnum = 240 + x2 / 35 + vm.poke(-(y2 * w + x2 + 1) - hwoff, palnum) + } + } + + for (k in 0 until 255) { + graphics.setPalette(k, (Math.random() * 15).toInt(), (Math.random() * 15).toInt(), (Math.random() * 15).toInt()) + } + + println("arst") +} + """.trimIndent() + private val gpuTestPalette = """ local vm = require("rawmem") local bit = require("bit32") @@ -150,7 +172,7 @@ end local rng = math.floor(math.random() * 2147483647) while true do - local tstart = vm.nanotime() + local tstart = vm.nanoTime() for y = 0, 359 do for x = 0, w - 1 do @@ -167,14 +189,14 @@ while true do end for k = 0, 2239 do - vm.poke(-(254912 + k + 1) - hwoff, 254) - vm.poke(-(254912 + 2240 + k + 1) - hwoff, 255) - vm.poke(-(254912 + 2240*2 + k + 1) - hwoff, math.floor(math.random() * 255.0)) + vm.poke(-(253952 + k + 1) - hwoff, 254) + vm.poke(-(253952 + 2560 + k + 1) - hwoff, 255) + vm.poke(-(253952 + 2560*2 + k + 1) - hwoff, math.floor(math.random() * 255.0)) end rng = inthash(rng) - local tend = vm.nanotime() + local tend = vm.nanoTime() print("Apparent FPS: "..tostring(1000000000.0 / (tend - tstart))) end @@ -186,7 +208,7 @@ var h = 448 var hwoff = 1048576 print(typeof print) //function -print(typeof poke.invoke) //function +print(typeof vm.poke) //function function inthash(x) { x = ((x >> 16) ^ x) * 0x45d9f3b @@ -199,31 +221,31 @@ var rng = Math.floor(Math.random() * 2147483647) + 1 while (true) { - var tstart = nanotime.invoke() + var tstart = vm.nanoTime() for (var y = 0; y < 360; y++) { for (var x = 0; x < w; x++) { var palnum = 20 * Math.floor(y / 30) + Math.floor(x / 28) - poke.invoke(-(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 x = 0; x < w; x++) { var palnum = 240 + Math.floor(x / 35) - poke.invoke(-(y * w + x + 1) - hwoff, palnum) + vm.poke(-(y * w + x + 1) - hwoff, palnum) } } - for (var k = 0; k < 2240; k++) { - poke.invoke(-(254912 + k + 1) - hwoff, -2) // white - poke.invoke(-(254912 + 2240 + k + 1) - hwoff, -1) // transparent - poke.invoke(-(254912 + 2240*2 + k + 1) - hwoff, Math.round(Math.random() * 255)) + for (var k = 0; k < 2560; k++) { + vm.poke(-(253952 + k + 1) - hwoff, -2) // white + vm.poke(-(253952 + 2560 + k + 1) - hwoff, -1) // transparent + vm.poke(-(253952 + 2560*2 + k + 1) - hwoff, Math.round(Math.random() * 255)) } rng = inthash(rng) - var tend = nanotime.invoke() + var tend = vm.nanoTime() print("Apparent FPS: " + (1000000000 / (tend - tstart))) } @@ -250,7 +272,7 @@ int rng = Math.floor(Math.random() * 2147483647) + 1; while (true) { - long tstart = nanotime.invoke(); + long tstart = nanoTime.invoke(); for (int y1 = 0; y1 < 360; y1++) { for (int x1 = 0; x1 < w; x1++) { @@ -266,15 +288,15 @@ while (true) { } } - for (int k = 0; k < 2240; k++) { - poke.invoke(-(254912 + k + 1) - hwoff, -2); // white - poke.invoke(-(254912 + 2240 + k + 1) - hwoff, -1); // transparent - poke.invoke(-(254912 + 2240*2 + k + 1) - hwoff, Math.round(Math.random() * 255)); + for (int k = 0; k < 2560; k++) { + poke.invoke(-(253952 + k + 1) - hwoff, -2); // white + poke.invoke(-(253952 + 2560 + k + 1) - hwoff, -1); // transparent + poke.invoke(-(253952 + 2560*2 + k + 1) - hwoff, Math.round(Math.random() * 255)); } rng = inthash(rng); - long tend = nanotime.invoke(); + long tend = nanoTime.invoke(); System.out.println("Apparent FPS: " + (1000000000.0 / (tend - tstart))); } @@ -301,7 +323,7 @@ rng = random.randint(1, 2147483647) while True: - tstart = nanotime.invoke() + tstart = nanoTime.invoke() for y1 in range(0, 360): for x1 in range(0, w): @@ -313,14 +335,14 @@ while True: palnum = 240 + int(x2 / 35) poke.invoke(-(y2 * w + x2 + 1) - hwoff, palnum) - for k in range(0, 2240): - poke.invoke(-(254912 + k + 1) - hwoff, -2) - poke.invoke(-(254912 + 2240 + k + 1) - hwoff, -1) - poke.invoke(-(254912 + 2240*2 + k + 1) - hwoff, random.randint(0, 255)) + for k in range(0, 2560): + poke.invoke(-(253952 + k + 1) - hwoff, -2) + poke.invoke(-(253952 + 2560 + k + 1) - hwoff, -1) + poke.invoke(-(253952 + 2560*2 + k + 1) - hwoff, random.randint(0, 255)) rng = inthash(rng) - tend = nanotime.invoke() + tend = nanoTime.invoke() print("Apparent FPS: " + str(1000000000.0 / (tend - tstart))) diff --git a/src/net/torvald/tsvm/VMJSR223Delegate.kt b/src/net/torvald/tsvm/VMJSR223Delegate.kt new file mode 100644 index 0000000..fddcf90 --- /dev/null +++ b/src/net/torvald/tsvm/VMJSR223Delegate.kt @@ -0,0 +1,22 @@ +package net.torvald.tsvm + +import net.torvald.tsvm.peripheral.GraphicsAdapter + +/** + * Pass the instance of the class to the ScriptEngine's binding, preferably under the namespace of "vm" + */ +class VMJSR223Delegate(val vm: VM) { + + fun poke(addr: Int, value: Int) = vm.poke(addr.toLong(), value.toByte()) + fun peek(addr: Int) = vm.peek(addr.toLong()) + fun nanoTime() = System.nanoTime() + fun dmagload(from: Int, to: Int, length: Int) { + val periid = vm.findPeribyType("gpu") + if (periid == null) + throw IllegalStateException("GPU not found") + else { + (vm.peripheralTable[periid].peripheral as GraphicsAdapter).bulkLoad(vm, from.toLong(), to.toLong(), length.toLong()) + } + } + +} \ No newline at end of file diff --git a/src/net/torvald/tsvm/VMKotlinAdapter.kt b/src/net/torvald/tsvm/VMKotlinAdapter.kt deleted file mode 100644 index 76e206c..0000000 --- a/src/net/torvald/tsvm/VMKotlinAdapter.kt +++ /dev/null @@ -1,10 +0,0 @@ -package net.torvald.tsvm - -class VMKotlinAdapter(val vm: VM) { - - /*fun getClassLoader(): ClassLoader { - val cl = object : ClassLoader() { - - } - }*/ -} \ No newline at end of file diff --git a/src/net/torvald/tsvm/VMRunnerFactory.kt b/src/net/torvald/tsvm/VMRunnerFactory.kt index 3415c64..ee5bffb 100644 --- a/src/net/torvald/tsvm/VMRunnerFactory.kt +++ b/src/net/torvald/tsvm/VMRunnerFactory.kt @@ -52,10 +52,10 @@ object VMRunnerFactory { private val bind = context.getBindings(ScriptContext.ENGINE_SCOPE) init { - bind.put("zzz", 42) - bind.put("vm", vm) // TODO use delegator class to access peripheral (do not expose VM itself) - bind.put("poke", { a: Long, b: Byte -> vm.poke(a, b) }) // kts: lambda does not work... - bind.put("nanotime", { System.nanoTime() }) + bind.put("vm", VMJSR223Delegate(vm)) // TODO use delegator class to access peripheral (do not expose VM itself) + bind.put("graphics", GraphicsJSR223Delegate(vm)) + //bind.put("poke", { a: Long, b: Byte -> vm.poke(a, b) }) // kts: lambda does not work... + //bind.put("nanotime", { System.nanoTime() }) } override fun executeCommand(command: String) { diff --git a/src/net/torvald/tsvm/peripheral/GraphicsAdapter.kt b/src/net/torvald/tsvm/peripheral/GraphicsAdapter.kt index 7654e03..0e700a0 100644 --- a/src/net/torvald/tsvm/peripheral/GraphicsAdapter.kt +++ b/src/net/torvald/tsvm/peripheral/GraphicsAdapter.kt @@ -1,15 +1,14 @@ package net.torvald.tsvm.peripheral -import com.badlogic.gdx.Gdx import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Pixmap import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.graphics.g2d.SpriteBatch import net.torvald.UnsafeHelper -import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack import net.torvald.tsvm.AppLoader import net.torvald.tsvm.VM import net.torvald.tsvm.kB +import sun.nio.ch.DirectBuffer import kotlin.experimental.and class GraphicsAdapter : PeriBase { @@ -21,7 +20,7 @@ class GraphicsAdapter : PeriBase { val channel = it % 4 rgba.shr((3 - channel) * 8).and(255) / 255f } - private val chrrom0 = Texture("./EGA8x14.png") + private val chrrom0 = Texture("./FontROM7x14.png") private val faketex: Texture private val spriteAndTextArea = UnsafeHelper.allocate(10660L) @@ -34,11 +33,11 @@ class GraphicsAdapter : PeriBase { private var graphicsUseSprites = false private var lastUsedColour = (-1).toByte() private var currentChrRom = 0 - private var chrWidth = 8f + private var chrWidth = 7f private var chrHeight = 14f - private var ttyFore = 254 - private var ttyBack = 255 + private var ttyFore: Int = 254 // cannot be Byte + private var ttyBack: Int = 255 // cannot be Byte private val textForePixmap = Pixmap(TEXT_COLS, TEXT_ROWS, Pixmap.Format.RGBA8888) private val textBackPixmap = Pixmap(TEXT_COLS, TEXT_ROWS, Pixmap.Format.RGBA8888) @@ -48,7 +47,13 @@ class GraphicsAdapter : PeriBase { private var textBackTex = Texture(textBackPixmap) private var textTex = Texture(textPixmap) - private fun getTtyCursorPos() = spriteAndTextArea.getShort(3938L) % TEXT_COLS to spriteAndTextArea.getShort(3938L) / TEXT_COLS + private val memTextCursorPosOffset = 2978L + private val memTextForeOffset = 2980L + private val memTextBackOffset = 2980L + 2560 + private val memTextOffset = 2980L + 2560 + 2560 + + private fun getTtyCursorPos() = spriteAndTextArea.getShort(memTextCursorPosOffset) % TEXT_COLS to spriteAndTextArea.getShort(3938L) / TEXT_COLS + private fun toTtyTextOffset(x: Int, y: Int) = y * TEXT_COLS + x init { framebuffer.blending = Pixmap.Blending.None @@ -62,7 +67,10 @@ class GraphicsAdapter : PeriBase { faketex = Texture(pm) pm.dispose() - spriteAndTextArea.fillWith(0) + // initialise with NONZERO value; value zero corresponds with opaque black, and it will paint the whole screen black + // when in text mode, and that's undesired behaviour + // -1 is preferred because it points to the colour CLEAR, and it's constant. + spriteAndTextArea.fillWith(-1) } override fun peek(addr: Long): Byte? { @@ -88,6 +96,10 @@ class GraphicsAdapter : PeriBase { lastUsedColour = byte framebuffer.drawPixel(adi % WIDTH, adi / WIDTH, bi.shl(24)) } + 250883L -> { + unusedArea[adi - 250880] = byte + runCommand(byte) + } in 250880 until 250972 -> unusedArea[adi - 250880] = byte in 250972 until 261632 -> spriteAndTextArea[addr - 250972] = byte in 261632 until 262144 -> pokePalette(adi - 261632, byte) @@ -132,6 +144,64 @@ class GraphicsAdapter : PeriBase { TODO("Not yet implemented") } + private fun runCommand(opcode: Byte) { + val arg1 = unusedArea[4].toInt().and(255) + val arg2 = unusedArea[5].toInt().and(255) + + when (opcode.toInt()) { + 1 -> { + for (it in 0 until 1024) { + val rgba = DEFAULT_PALETTE[it / 4] + val channel = it % 4 + rgba.shr((3 - channel) * 8).and(255) / 255f + } + } + 2 -> { + framebuffer.setColor( + paletteOfFloats[arg1 * 4], + paletteOfFloats[arg1 * 4 + 1], + paletteOfFloats[arg1 * 4 + 2], + paletteOfFloats[arg1 * 4 + 3] + ) + framebuffer.fill() + } + } + } + + /** + * @param from memory address (pointer) on the VM's user memory. Because of how the VM is coded, only the user space is eligible for move. + * @param to memory "offset" in Graphics Adapter's memory space, starts from zero. + * @param length how many bytes should be moved + */ + 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) + } + + private fun putChar(x: Int, y: Int, text: Byte, foreColour: Byte = ttyFore.toByte(), backColour: Byte = ttyBack.toByte()) { + val textOff = toTtyTextOffset(x, y) + spriteAndTextArea[memTextForeOffset + textOff] = foreColour + spriteAndTextArea[memTextBackOffset + textOff] = backColour + 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() { framebuffer.dispose() rendertex.dispose() @@ -178,7 +248,6 @@ class GraphicsAdapter : PeriBase { // draw framebuffer batch.draw(rendertex, x, y) - // draw texts or sprites batch.color = Color.WHITE @@ -190,9 +259,9 @@ class GraphicsAdapter : PeriBase { for (y in 0 until TEXT_ROWS) { for (x in 0 until TEXT_COLS) { val addr = y.toLong() * TEXT_COLS + x - val char = spriteAndTextArea[3940 + 2240 + 2240 + addr].toInt().and(255) - val back = spriteAndTextArea[3940 + 2240 + addr].toInt().and(255) - val fore = spriteAndTextArea[3940 + addr].toInt().and(255) + val char = spriteAndTextArea[memTextOffset + addr].toInt().and(255) + val back = spriteAndTextArea[memTextBackOffset + addr].toInt().and(255) + val fore = spriteAndTextArea[memTextForeOffset + addr].toInt().and(255) textPixmap.setColor(Color(0f, 0f, char / 255f, 1f)) textPixmap.drawPixel(x, y) @@ -232,7 +301,7 @@ class GraphicsAdapter : PeriBase { batch.shader = null - if (textCursorIsOn) { + /*if (textCursorIsOn) { batch.color = Color( paletteOfFloats[4 * ttyFore], paletteOfFloats[4 * ttyFore + 1], @@ -241,7 +310,7 @@ class GraphicsAdapter : PeriBase { ) val (cursorx, cursory) = getTtyCursorPos() batch.draw(faketex, cursorx * chrWidth, (TEXT_ROWS - cursory - 1) * chrHeight, chrWidth, chrHeight) - } + }*/ } else { // draw sprites @@ -293,7 +362,7 @@ class GraphicsAdapter : PeriBase { companion object { const val WIDTH = 560 const val HEIGHT = 448 - const val TEXT_COLS = 70 + const val TEXT_COLS = 80 const val TEXT_ROWS = 32 val VRAM_SIZE = 256.kB() diff --git a/terranmon.txt b/terranmon.txt index 85f32e9..3c57cfa 100644 --- a/terranmon.txt +++ b/terranmon.txt @@ -44,7 +44,16 @@ Endianness: little From the start of the memory space: 250880 bytes Framebuffer -92 bytes +3 bytes + *reserved for future use* +1 byte + command (writing to this memory address changes the status) + 1: reset palette to default + 2: fill framebuffer with given colour (arg1) +2 bytes + argument for "command" (arg1: Byte, arg2: Byte) + write to this address FIRST and then write to "command" to execute the command +86 bytes *Unused* IF graphics_mode THEN (41 sprites : 260 bytes each -> 10660 bytes) @@ -56,15 +65,15 @@ IF graphics_mode THEN 256 bytes 16x16 texture for the sprite ELSE - 3938 bytes + 2978 bytes *Unused* 2 bytes Cursor position in: (y*32 + x) - 2240 bytes + 2560 bytes Text foreground colours - 2240 bytes + 2560 bytes Text background colours - 2240 bytes + 2560 bytes Text buffer of 70x32 (8x14 character size, and yes: actual character data is on the bottom) FI 512 bytes