russellsprouts

Joined 13 years ago

Karma
289
Submissions
148
Member since
Apr 25
View on Hacker News

Recent submissions

Comment · 7 months ago
Very cool!

I did something related in the past: https://github.com/RussellSprouts/6502-enumerator. It uses C++ templates to share an emulator implementation between z3-powered symbolic execution and actual execution. It was meant to find equivalence between random instruction sequences for peephole optimization, rather than optimizing a specific input sequence.

Shadow instructions are very interesting and cursed. I've seen them used in very limited circumstances for NOP-slides for timing code: https://www.pagetable.com/?p=669. It would be fun to see it applied in otherwise normal code. My enumerator wouldn't support this -- it didn't execute actual 6502 instructions from bytes -- it had its own internal representation for `the first arbitrary absolute pointer` or `the second arbitrary immediate constant`. These would either be initialized with random concrete values or z3 variables.

Comment · 1 year ago
Comment · 2 years ago
This reminds me of Halide (https://halide-lang.org/), which is a really interesting design in this direction.

In Halide, you specify the algorithm at a high level, then specify the "schedule" (execution order, vectorization, storage) separately. Then, it verifies that the two match. For tight loops like image kernels, it's often counter-intuitive which execution plan will give the best performance, so being able to experiment with the guarantee that you are still implementing the algorithm correctly is valuable.

For a database, it would be as if you could send a high level SQL query and an execution plan together.

Halide is very specific, but I could imagine a general-purpose language with a Python-like high level representation for code behavior, with the option to specify a lower-level implementation with a lot of performance annotations.

Comment · 3 years ago
In Korean, sushi is 초밥 (cho-bap)
Comment · 3 years ago
> To solve [forward branches], those bytecodes would push information about how the branch destination address shall be fixed up into a late-patch buffer.

This reminds me of how Forth `if` and `then` can be compiled in a single pass -- `if` writes the branch instruction and pushes the current instruction pointer to the stack, and `then` pops it and patches the instruction to point to the current instruction pointer.

Comment · 3 years ago
Just read through the documentation. There are so many great ideas for generating efficient code. `goto mode` in particular is an awesome idea. Generalizing the program to have multiple "entry" points and overlapping their global variables to save RAM, I've never heard of that technique before.

The inline assembly integration looks nice too -- accessing the arguments and return address as fields on the function makes a lot of sense.

Comment · 4 years ago
You potentially get a problem for every '.' expression. In this code:

  import {Something} from './file';
  console.log(Something.PROP);
TypeScript doesn't know what to emit without type information. If Something is a class, then the JS will look the same. But if it's a const enum, then TypeScript has to erase the Something.PROP expression and replace it with the constant value of that enum member, since Something will not exist at runtime.
Comment · 4 years ago
const enums are one of the few cases where type information changes the emitted JS, something that's arguably a bigger problem than TypeScript-specific, but still just syntax sugar, syntax highlighted in the article.

Const enums are erased at compile time. If you have a reference to `MyEnum.VAR`, TS has to check whether the enum is a const enum, and if so, replace with something like `1 /* VAR */`. This means that the type information in one file (where the enum is defined) is necessary to determine the proper output of any file that uses it.

Comment · 5 years ago
Yeah, it will biased towards the center of the range rather than uniformly distributed
Comment · 6 years ago
Fair point, updated it along with some issues in the README
Comment · 6 years ago
Hi, author here. I think the only difficulty in making this work without a disk is that most of the memory space will be read only once you finalize the ROM. I had to allocate separate RAM addresses for variables. In Forth, you can often just increment HERE to make space for a variable, but I ended up creating many different HERE words because my dictionary headers, word implementations, and ram variables all used different blocks of memory.
Comment · 7 years ago
Comment · 7 years ago
Looking at the world download, it's using powered rails and observer blocks as a solid state storage.

There are only brief glimpses in the video, but here's what that looks like: https://imgur.com/a/AkOAzgF

The 14 left-right powered rail tracks are the music channels. Each vertical slice is a tick of music, and they are grouped into 9, the max length of a powered rail signal. The presence of an observer block underneath the rail indicates a note. The whole machine appears to be 128 x 14 bits. It has a serial read interface.

In more detail:

From the bottom of the image to the top you see:

- A row of redstone blocks, pistons, and redstone wire.

- A row of repeaters facing north

- A row of repeaters facing west

- An observer facing north

- 14 east-west powered rail/observer wires, sending signals to the east.

- In a layer underneath the east-west observer-rail wires, alternating columns of rails and redstone wire facing north-south. (Not visible in the picture)

- (A mirror image of the bottom)

The west facing repeaters control the current read location. The machine sends a signal until they all turn on, then waits until they all turn off, then turns them on again, etc. When one of the repeaters toggles between on and off, the north-facing observer above it sends a pulse. The pulse travels upwards in the north-south rail (in the invisible lower layer), and then if an observer is present, the signal is sent east along the east-west line for the channel.

The bottom two rows form a pause mechanism. The redstone block, piston, redstone wire row is an instant repeater line. When the north-facing repeaters are turned on, they will lock the west-facing repeaters in whatever state they are in. Using instant wire ensures the pause will happen immediately.

The whole system is mirrored at the top since the north-south rails in the lower layer can only send a signal up to 9 blocks. With read signals coming from both sides, this design could support up to 18 channels.

One last detail -- one column of music is read every 2 redstone ticks, so most of the repeaters are set to a 2 tick delay. However, the signal for a channel must be repeated using an observer every 9 blocks (adding a 1 tick delay), so the first repeater in each 9 block section is set to 1 tick. This compensates for the delay.

EDIT: I originally stated that there were 14 channels, but I overlooked that it's double-layered, and that there's a similar quad-layered system on the other side. There are 50 channels in total.

Comment · 8 years ago
Comment · 8 years ago

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton