💾 Archived View for sdf.org › gvv › tinylog.gmi captured on 2024-05-12 at 15:15:56. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-12-28)
-=-=-=-=-=-=-
author: @gvv@sdf.org
license: CC BY
Finished typing in enough of an emulator to execute common instructions, but it still needs testing and debugging.
Also found instruction set quirks after starting assembler in itself:
With the x-bit used to distinguish call and jmp, I can't encode a conditional jmp followed by subroutine exit in one instruction as I had intended.
I'm also not thrilled with deo using direct addressing, because that takes up bits used for autoinc that make writing strings easier. What to do?
Answers for yesterday's questions:
1. 64k is small enough already, dei/deo with devices in their own address space;
2. tuck stack ops into otherwise invalid bit patterns, e.g. `mul %t, 2` doubles top of data stack, but so does `mul %d, 2` - I should use it for `pick %d, 2` (aka over).
And, of course, I re-ordered the microde bits again.
And updated the documentation to match.
And made a skeleton for the emulator in C. But need to update the assembler again first...
Rewrote documentation to keep up with tweaks I made to the instruction microcodes while implementing the bootstrap assembler; but putting off some final decisions until I have more assembly code written...
1. do I memory map devices to 0-page for efficient access with fetch/store direct operands, or rename to dei/deo and have their own address space?
2. use an operation slot for stack rotation instructions for simplicity, or tuck them in to otherwise invalid bit patterns?
finished enough of the Lua bootstrap assembler to assemble some examples that match my hand-assembled results. Back patching forward jumps was two lines of Lua:
1. add unknown forward label refs to fwdaddr->name map in first pass;
2. at the end, write address in final labeladdrs[name] into each fwdaddr.
An earlier implementation in C took hundreds of LOC. Lua tables are so great! ...nonetheless, going back to C for writing an emulator.
But first, assembling relative addrs!
J1/H2 Forth CPUs use a dedicated opcode 'x' bit to return from a subroutine call in the same clock cycle as its final instruction. But JMP & CALL repurpose that bit towards the target address -- you can't set the instruction pointer twice at the same time (RET from a subroutine and CALL another at once).
Added x-bit fusion to my assembler, and learned that fusing CALL followed by RET sets an x-bit and makes a JMP instruction that gives us tail call elimination for free!! # 2023-12-02 14:33 UTC Today's #DecemberAdventure: Repurposed a Lua tokenizer I wrote for an old project and made progress on the parser to assemble 1 of the 4 microcode instruction types I need (16 bits as 4 nibbles (nybbles?) for: opcode, dest register, 4 ALU flag bits, and src register). For simplicity, I decided not to use LPEG to bootstrap, and consequently already >200 LOC Glad I decided against using C!
Applied for a gemini hosting account, so I'll post more details there when I've finished registration...
Repurposed a Lua tokenizer I wrote for an old project and made progress on the parser to assemble 1 of the 4 microcode instruction types I need (16 bits as 4 nibbles (nybbles?) for: opcode, dest register, 4 ALU flag bits, and src register).
For simplicity, I decided not to use LPEG to bootstrap, and consequently already >200 LOC Glad I decided against using C!
Applied for a gemini hosting account, so I'll post more details there when I've finished registration...
Previously, I've noodled with an archival virtual machine spec for years, but never implemented anything. This seems like a fun way to get some traction without over-committing.
So, following the most recent design for a "move machine" with 16-bit micro-coded machine instructions, I had already written some example code to output a 16-bit unsigned value as a 4-character hex string. Today I started on a simplistic recursive descent assembler in Lua to bootstrap...