Uxn - Virtual Computer

Awesome, thanks! I wouldn’t really know where to start though, and it may take a long time for me to recover. However, if you or someone else could set up a really basic initial version with only mouse or NES controller support, I guess that would already be enough to free me from the painful keyboard experience.

Having it Uxntal centric would be good, I think, maybe with some kind of wrapping that allows code to be reused for different languages. But I guess that could complicate the whole as well, hmmm… Might require some “hammock driven development”.

Also I was thinking it would be awesome to really push usage of the NES controller to the limits here. For example, having a mode where if you push a button, it doesn’t do anything, so chording is possible, and the default action happens only when you release the button. So pushing the left button doesn’t move to the thing to the left, but releasing the left button without pushing another button at the same time does. Then we could have something like a keyboard chording mode, where if you push and hold the left button, the left side of the displayed keyboard is highlighted. Then you press the A button to select the left side of the keyboard. Then you press and hold up + left to highlight the Q button (if the displayed keyboard has a QWERTY layout), release, and push A to insert the Q character.

Kinda like Vim its normal mode, but with a NES controller, on steroids :smile:

I wouldn’t really know where to start though, and it may take a long time for me to recover.

So, my guess is that you’re currently writing an on-screen keyboard? Left already listens to standard keyboard events, so you should be able to navigate the interface with the recently added drop-down menus, and an on-screen keyboard(let me know if there’s actions that you cannot do). But the trick here, would be to reduce the number of key-strokes to get you there.

Uxntal is somewhat verbose, I can think of two ways that could help you put this together with as few key strokes as possible.

First off, heavy use of macros, and short label names.

You can define %macros for your uxntal programs, so instead of typing the ADD2-like mnemonics, you could write a bank of macros for each one like +2. This would dramatically reduce the number of keystrokes needed to write the chorded keyboard IDE.

Have you gone through sejo’s Uxntal book yet? uxntal is quite easily planned on paper. You could draft most of the program on paper, and only validate it with an emulator from time to time to reduce typing.

I love the chorded NES controller idea, that’s how Orca already works :slight_smile: Try it out!

Here it is, I’m terrible at it tho, I’ve only designed this so if I get injured before a show, I can still perform somewhat.

2 Likes

Ah cool, I didn’t know that was a thing in Orca!

So, my guess is that you’re currently writing an on-screen keyboard?

I’ve written 0 code yet, I couldn’t help myself from making the design diagram but that was already a bit too much for the injury :sweat_smile:

Also I guess the path of lowest resistance for me would be to write the editor in Janet first as I’m pretty sufficient at that, otherwise I’d be (1) learning a new programming paradigm, (2) learning the VM and (3) coding an editor in a new language.

I’ve never even created an editor, so probably a bit much to do that + all the above! :grin:

Uxntal is somewhat verbose, I can think of two ways that could help you put this together with as few key strokes as possible.

It’s a bit of a catch-22 at the moment: with sIDE I would only need to type characters when naming new things, everything else would be possible through menus. So for example, not typing “ADD”, but clicking on something that shows all 32 operators in a screen, where you can click on the “ADD” one.

I guess my first goal is to get a mouse-only interface going, with menus like in the UI diagrams in my repo. Then the NES controller stuff is just an awesome extra. Would be fun though, to see videos of people lounging on a chair, writing Uxn programs using only an NES controller :grin:

Might be a bit silly, but Left supports pasting anything found in an invisible file called .snarf. Honestly, I think if I was you, what I would do, I’d make the process of navigating a bunch of snippets as painless as possible with a mouse like you said, a bit like a sound-board, y’know like these big flash toys with buttons all over that will play sounds.

You could write a little Janet gui program that fills the snarf file with whatever you click on, when writing uxntal, you always just end up typing the same words over and over again anyways.

Alternatively, you could instead write directly into hexadecimal from the sound-board, you click EQU2, and it appends 0x28 to the file. Press F4, see the modified rom.

1 Like

a bit like a sound-board

Exactly! That’s a good description of the intended user experience! :+1:

Alternatively, you could instead write directly into hexadecimal from the sound-board, you click EQU2 , and it appends 0x28 to the file.

Yeah the goal is modifying the file directly with clicks, eventually even without having to look at the file itself anymore. I hope I can prevent having to use the intermediate .snarf file, may be a good workaround at first though! :slight_smile:

I really appreciate your feedback/tips, by the way. Thanks a lot!


Update:

Made a first rough draft screen for sIDE in Janet (typing with a few fingers, grandpa-style :grin: )

This is what the file overview for left.tal would currently look like.

Not too easy on the eyes yet, but I guess it’s already arguably better than scrolling through a file of >1000 lines :slight_smile:

I probably want to add an option to sort the labels alphabetically…

1 Like

I have been following the cheat sheet to make a for loop, but this code keeps doing a stack underflow?

%EMIT! { .Console/write DEO }
( ... )
#3a #30
&loop
		DUP EMIT!
		INC GTHk ,&loop JCN
POP2

What could I be doing wrong? And when it does print something after mashing through beetbug, it’s all zeroes.
&loop is inside a label, if that’s important.

That’s strange, it looks fine to me. I don’t have uxnasm with macros support atm, but does it work for you without the emit macro?

The assembled rom should be:

803a 8030 0680 1817 018a 80f7 0d22 0000

It still doesn’t work, and gives me a built rom of

a03a 3003 8018 1701 8a80 f70d 2200

I did notice in my original program, when stepping through Beetbug, that f7 showed up in the stack a lot.
I should note that I am using uxnasm on windows, not Driftblim. (I tried using driftblim but it kept telling me “load: failed” and I can’t figure out how to use it.)

Perhaps I should try on linux instead?

Looking at your rom, 80 seems to be the bytecode for LIT. So what on earth is going on with My rom then?..
If 3a and 30 never get pushed (and come to think of it I dont think I ever saw it in the stack) that would certainly explain the stack underflow.

image (the weird characters are because I had it open in VSCode last. Not to be a traitor or anything.)

Side note; just curious, how are you going about running uxn apps inside Potato? I was playing around with it earlier and apart from stack issues, it seemed to work pretty well. And, how are you planning to approach some kind of internal CLI in the terminal you mentioned? Potato interests me greatly.

Wow, this is super bizarre, it could be a windows thing, but I doubt it? Could you try on linux to see if you’re getting the same thing?

There are no “apps” yet in potato, I haven’t totally figured out how I want to about doing that yet, right now if you open a rom, and press f4, you’ll return to potato if potato is called launcher.rom and located where you started uxnemu.

I’m still ironing out the details :slight_smile:

I just pushed a little update to Drifblim where you can just:

uxncli drifblim.rom source.tal output.rom

it could be a windows thing, but I doubt it? Could you try on linux to see if you’re getting the same thing?

Mkay I tried built on linux (mint uma) and it works fine. So I guess it’s windows. Maybe I’ll try ruxnasm, because driftblim still isn’t behaving, even though i downloaded the rom like an hour ago (maybe I should build from tal?)
image

you’ll return to potato if potato is called launcher.rom and located where you started uxnemu.

ooh yeah that explains why f4 wasn’t working for me. Also, if it’s meant for handhelds, im sure youve considered some kind of on-screen keyboard. What I wonder though, is how that would work with such limited real estate?.. Maybe something like the, what was it called, petal keyboard thing the steam controller used, where you worked your way down to a letter by moving down categories with the dpad?
Either way, I’ve been blown away by Potato, it even has a little window manager and everything.

Another aside, but what features would a theoretical language that compiles to uxn have? Something like

  • device support
  • manifest support
  • the ability to have rust-like macros that can write tal directly for hand-optimized things

The error is saying that the drifblim.rom is not found? Are you use it’s visible from the location where you’re trying to run this?

I’ll probably build something like this, but for F4, it’ll be one of the shoulder buttons on the DS and GBA

I don’t think it should have manifest support, but just devices support might be nice, or let people implement those themselves in that language, it doesn’t have to have reserved words like UF.

Are you use it’s visible from the location where you’re trying to run this?
Yep. EMU works fine.
Ach, now no sprites draw on the screen on linux, even following the tutorial. Boy howdy.
By the way, is there an executable available for Linux that has beetbug and the console in, or just uxnasm printing to the console?
I wonder if my download got corrupted.

Beetbug is only a uxn32 thing, but you can run it in wine easily(it’s what I do).

No sprite drawing? You’re really getting all the bugs :confused: You’ve tested a pre-assembled nasu or noodle rom, and nothing shows up either?

These are the files that I use to test the implementations, maybe they can help you figure out the issues you’re having.

I’m trying to loop through entities and draw them on the screen, but I can’t get it to work:

https://paste.sr.ht/~harryvederci/7cecb1e5430c19f6a617b0b2887ece5eba1bc30e

Any idea what I’m doing wrong?

There’s so many macros in there, I can’t tell what’s what.

But basically, here’s how you can do this:

|00 @System	&vector $2 &pad $6 &r $2 &g $2 &b $2
|10 @Console &vector $2 &read $1 &pad $5 &write $1 &error $1
|20 @Screen &vector $2 &width $2 &height $2 &auto $1 &pad $1 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1

|0100

	( theme )
	#19df .System/r DEO2
	#058c .System/g DEO2
	#047a .System/b DEO2

	( draw entities )
	#4000
	&loop
		#00 OVR #0006 MUL2 ;entities ADD2
		LDA2k .Screen/x DEO2 INC2 INC2
		LDA2k .Screen/y DEO2 INC2 INC2
		LDA2 .Screen/addr DEO2
		#01 .Screen/sprite DEO
		INC GTHk ,&loop JCN
	POP2

BRK

@entities ( x*, y*, sprite* )
	0020 0030 :spritesheet/1
	0052 0026 :spritesheet/2
	0012 0032 :spritesheet/3
	0067 0072 :spritesheet/4

@spritesheet
	&1 007e 7e7e 7e7e 7e00
	&2 007e 425a 5a42 7e00
	&3 0002 060e 1e3e 7e00
	&4 007e 7c78 7060 4000
1 Like

Ah, thanks for the Devine intervention :smile:

Fixed now, here’s what I did wrong:

  • I did an increment at the end of a loop for no reason, and
  • I used semicolons (";") for the pointers where I should have used colons (":").
1 Like

I’ve been looking through bits of the potato source, and I have many questions about some stuff I’ve discovered.

  1. main.tal line 127 - there are brackets surrounding some instructions. What does this do?
  2. in main.tal, there are memory functions. I don’t know the codebase very well nor do I have a mental stack to understand tal code at a glance, but is this a kind of heap implementation?
  3. How do you approach calling subroutines with arguments? do you just shuffle the stack around until things are in the right order?
  4. What is the purpose of operating on the return stack? is JMP2r like a return statement? Some parts of code have code after the return statement, but then no BRK.
  5. is having variables and LDR/STR within a subroutine valid? how does that work?
  6. Using tal requires a way of thought I am not accustomed to- are there any comparable programming languages (6502 for example) that operate similarly I could also refer to to get used to the idea?

I automatically look for possible optimisation and errors with uxnlin, the linter ignores what is inside brackets, sometimes it’s valid hacky ways to do something and I want to keep it but mute the warnings, so I put them withing square brackets :slight_smile:

Exactly, it frees and allocate memory to windows, it’s still early in its development tho.

I prepare the arguments on the stack before jumping, I recommend that you look for the book Starting Forth, if you’re interested to know more about this way of thinking.

The return stack gives you a bit more options when juggling multiple items on the stack, you can put some stuff in it momentarily before returning from a subroutine, when you have like positions and colors and other things to sort out in the stack, being able to send one to the return stack is simplifying things a lot.

JMP2r is just JMP2, but on the return stack, think of it like this: if you put an address #1234 on the return stack, like LIT2 1234, and then JMP2r, it will jump to that address. When you JSR2, it puts your current location in the program to the return stack automatically.

Of course, that’s how most things work, that’s how loops are made.

Forth is a famous one that will get you there, I recommend again to look through Starting Forth, it’s an excellent book. If you come from the Lambda/Lisp world, I recommend that you come through Joy.

Uxntal is a mixture of Forth and 6502, it’s a kind of strange 8-bit hybrid of the languages. But knowing 6502 will only get you as far as understanding how memory works on small systems.

If you’re not familiar with how low-level computing works, you could have a look at CHIP-8, Gyo, or paper computers.

If you’re interested in learning forth, I recommend using UF, it’s an amazing graphical forth system for Varvara, it’s easy to setup, and it will let you mess around forth to your heart’s content. If you’d like to familiarize yourself with RPN notation, you could noodle around with CCCC.

Let me know if you need a hand with anything, I’ll be happy to help you figure these things out!

3 Likes

Ah, that’s a great starting point, thank you. I do better understand how Forth works, I think. I get how it thinks, anywho.
In an effort to create a foundation for myself where I could actually read my own Tal code (I find it difficult to follow basic instructions), I sought to translate my recently-acquired looping skills to legible instructions. However, I encountered a problem: it only loops once, and I don’t know why!
This is the code:


( Pardon the photograph, I’m not a seasoned linux user and I got frustrated trying to yank lines from Vim into my clipboard.)

My line of logic is as follows:

  1. At the beginning of the macro “routine”, my stack should look like this, assuming I have popped my working stack frame:
    • address (short)
    • iterator (byte)
    • iterator max (byte)
  2. since the iterator and max always travel together, I can treat them as a short while I’m shuffling things around. I swap the address and the M-I pair to bring the pair to the front to compare.
    • M-I pair (short)
    • address
  3. Comparing M and I results in a single byte. I need to shuffle things around, so I add a dummy byte to crate a “short”.
    • dummy (#00)
    • boolean
    • M-I pair
    • address
  4. JCN expects a boolean as the top argument, and an address as the second. I shuffle things around so the address is now second, and pop the dummy byte as I don’t need it anymore.
    • boolean (byte)
    • address (short)
    • M-I pair
  5. I JCN2 to the address if need be.

However, when I run the code, it only ever loops through once, and I don’t know why. I wrote a sanity check conventional loop, and it works fine.
My output is 01234567890, with the last 0 being the second loop.
How could this be?
Also, I am well aware that doing it this way adds way more instructions than need be, but I just wanted to see if I could actually do it.

Exactly, it frees and allocate memory to windows

  1. So when you “virtualize” the processes of the child programs, if you’re going to do that, this will act as a virtual memory for them? How are you going to track what memory is stored where, free, fetch, and allocate? Do you even know yet or are you winging it?
  2. The Uxn machine has 256 bytes of working stack, and 64 Kb of memory (I think). is the 64 Kb of memory for the actual bytes of the program, or just anything you use in general (and the program happens to start at 0x0100?) With a heap, I imagine that it will be dynamically growing and shrinking, somehow. Will it use this 64Kb? How will it know when it has run out (if heap.size > end of program - heap start?)

It doesn’t. It expected an address on top.

JCN cond8 addr – If the byte preceeding the address is not 00, moves the program counter by a signed value equal to the byte on the top of the stack, or an absolute address in short mode.

Yes, right now, if you open the About panel it displays how the memory is being used in its current order. When you close a window, it frees up that memory, so another application can use it.

Since the memory is so small, I don’t have to fracture the allocation like that, I can just shift everything after the closed window by that window’s allocation lenght, and move the pointers by that offset, it’s what my memory helpers do. It’s fast enough.

It’s everything. All the OS can do is give away bits of that 64kb space, it won’t extend Uxn’s working memory. Right now, if an allocation ends at a lower address than where it starts, it means it overflows, and a pop-up will say “Please close some windows” or something :slight_smile:

An aside,

Uxntal doesn’t use variables or registers like some other forth machines have, it doesn’t need it because it has a super-power that none of the others do, you can write bytes directly into the program, instead of juggling complicated stacks, you can instead write the value that you will need later, directly at the end of your routine inside a LIT.

Whenever you see something that looks like [ LIT &var $1 ], it means that I’m storing my variable directly in memory, it’s faster than doing a load, because it’s already ready to be read as a literal and put into the stack :slight_smile: It’s a good thing to remember when trying to juggle complicated stacks.

Also, here’s a vim syntax highlight for uxntal.

2 Likes