I know that 100 Rabbits specifically says there’s no intention to design bespoke hardware for UXN or Varvara, but I’ll design hypothetical hardware for it.
Unless otherwise noted each “port” (which I’ll denote in hex, after their name in quotes) would be a register holding data for use by other ports. Some would call into firmware.
If you actually wanted to build this I suppose you’d want to add a USB coprocessor to allow copying data over on memoysticks & to convert from USB peripherals to Varvara inputs. Wouldn’t need to be that complex if USB communication is all the computation it is running, maybe its a 2nd UXN core?
UXN is an integral 8/16bit bi-stack machine with 16bit memory-addressing, & 8bit I/O addressing. Includes multiplication, division, & remainder.
Bits preceding opcode allows choosing a stack, keeping read bytes on stack, & operate upon bytes or pairs thereof.
16bit addressing (65,536 bytes) is probably small enough to not require prefetching to make it fast enough, but even if not prefetching the program-counter, 0, last, & top-of-stacks “pages” should be a decent solution. Or could load all the program’s (compressed?) memory into the processor when we resume a program.
Stack machines seems like an elegant solution to memory latency!
Both stacks are easy to implement using shift registers even without enforcing a 256byte limit. Which I’d drop (by swapping lowerhalf between RAM) for the sake of interprocess-communication. Also for IPC I’d add an extra bit to each word indicating process boundaries, for BRK to pop to if present.
The opcodes would require decoding into microcode describing how many bytes to pop from the given stack, which of the 3 inputs to send to the ALU, whether to read/write memory, & other control lines. Keep mode would zero-out the number of items to pop before adding the number of items to push during the write cycle.
A vast majority can readily be handled via an 16bit-adder though some like SWP may need an extra bus to copy bytes around on the stack. And there’s MUL, DIV, AND, ORA, EOR, & SFT which need their own compute circuits. Or DIV could reuse SFT & SUB’s for 8 or 16 clockcycles.
Shortmode (16bit) would utilize an alternate circuit to read stackentries, and another for cases (SFT, IO) where one of the args are always a single byte. Or maybe the latter can handled by shifting before read…
For the “system” device I’d probably make “wst” 02 & “rst” 03 counters representing stack lengths.
“debug” 0e would run firmware which would copy data from one stack to the other & back whilst outputting hex debug output. “state” 0f would stop the program’s state from being saved, & disconnect the Console.
For the Console Device “write” 18 & “error” 19 would swap which UXN program is running while setting its “read” 12 register & its 10 interrupt. Probably add a buffer for performance, since the UXN design I wrote above is slow at taskswitching. Console’s simpler than I thought it’d be! Since with “read” 12 being constant per interrupt I don’t have to handle buffer underflows…
We could readily implement an ASCII terminal emulator in UXN upon the following graphics card, even if the font would use up a considerable of UXN’s memoryspace. Keyboard input can also readily be converted into stdin, handled as described yesterday. Allowing Console interactions.
A graphics card really involves little more than 32bit-addressed 8bit or 64bit RAM writes, which makes sense given the project’s goals! Should be easy to implement an emulator on even the simplest of platforms!
Ofcourse said (ideally dualported) RAM would need to be hooked up to a monitor via hardware like Ben Eater’s breadboard design, ideally with a power-of-two imagewidth. Incidentally that breadboard graphics card has the same colourdepth Varvara uses, though I’d hope to have a faster clock & thus higher resolution on this hypothetical graphics card.
Upon outputting to “pixel” 2e (if the x & y are within the given size) I’d convert that into a RAM write of the selected RGB byte to (layer,x,y) bit-concatenated in the graphics memory. I’d probably follow up any background writes with a foreground writes unless a bitmask says otherwise, to simplify the circuit reading this data out to the screen.
If we’re buffering writes whilst the output circuit is reading rather than using dualported RAM the Screen interrupt (triggers 60hz) should fire upon entering vertical interrupt. That should ease up load on those buffers.
For “sprite” 2f there’s control lines for flipx, flipy, foreground/background layer, 2bit vs 1bit mode, & the 2 colours. If both colours are the same one’s transparant, which I’d track in a bitmask.
Each 8 or 16bit row of the sprite would combine with the control lines, flipx controlline, RGB regs, & maybe bitmask + background to form a 64bit value to write to RAM. Then incremented or decremented (determined by flipy) for next row. Before incrementing x and/or y as determined by “auto” 26.
If we want multitasking, once we have a way to dispatch events to the correct program & to tell the graphics card which bbox to render into, it wouldn’t complicate things much to add a tiling window manager! Though moving those windows could be slow as we swap imagerows. Might want add an even wider wordsize available just for the window manager.
Audio & MIDI devices
The Audio devices would require DACs with lowpass filters reading asynchronously from UXN memory. I think pitch & mixing can be done on the analogue soundwave. Volume & in turn ADSR can definitely be!
I suspect the (work-in-progress) MIDI device can be efficiently lowered to the Audio devices in firmware.
The Controller device (if connected to a full keyboard) would require statemachines lookuptables to decide which “key” 83 was pressed. Once the keyboard its own lookuptable to decode which button(s) were pressed. At which point PS/2 might be simpler to handle, though USB keyboards communicate modifier keys pretty much the same way as Varvara.
Mouse device mostly just needs counters.
The File device would need to be implemented in firmware to be lowered to seeking to offsets in the SRAM or whatever persistant storage the device has. And track how to (de)allocate said persistant memory. Might as well implement (de)compression during the memory latency incurred here.
As for the Datetime device, the underlying hardware is a seconds-counter. Tweak how carries happen to split off units. Then again we’d want to run firmware to determine when months carry!
Also you’d want to either add extra hardware (networking or maybe GPS) to sync the clock or (which seems more in keeping with Varvara!) allow configuration apps to set these registers! Maybe add a hardware switch to enable & disable this permission.