Status
SteamPeaks
ChartsSalesUpcomingPatchesNewsCalculator
New on SteamEvery app, DLC and depot the minute Steam creates itAppsEvery app on Steam, newest change firstPackagesSubs and bundles, and what each containsDepotsDepots, manifests and install sizesTagsSteam's user tags and the games under themDevelopers & publishersCompanies and their cataloguesTechnologiesEngines, SDKs and anti-cheat found in the filesChange historyEvery PICS changelist as it lands
SignalsNineteen readings of the whole catalogueCompareAny games side by sideRecordsAll-time peaks and the days they were setReportsWeekly and monthly write-upsAlerts & newsroomWatch a game, get told when it movesSteam statusIs Steam up, right nowWeb API explorerTry the endpoints in the browser
NewsSteam's own announcements and the sales calendarCalculatorWhat a Steam account is worth, and its pile of shame
/
Sign in
/
SteamPeaks
The ultimate resource for Steam data.
ExploreChartsSalesSales and festsUpcomingPatchesNewsRecordsTrendingSignals
DatabaseAppsPackagesDepotsTagsDevelopersTechnologiesChange history
ToolsCalculatorCompareSearchAlertsSteam statusAPI
SiteMethodologyFAQDiscordSupportSign in via Steam
Not affiliated with Valve or Steam. Game names and artwork belong to their owners. All times UTC.
PrivacyCookiesFair useStatus
CrosstalkNewsHardware Sniffers: MISC's programming language, DANGC
Community

Hardware Sniffers: MISC's programming language, DANGC

Crosstalk · published 13 Sep 2026, 02:39 UTC

All newsPlayers around this dateRead on Steam

Dev log #13

Welcome to the next devlog!

This one is both a dev log and a Hardware Sniffers entry to tell you a bit more about the MISC platform.

A few years ago I started designing a programming language that I thought I wanted for systems programming. I still did and even now do most work in C99 (specifically C99), but the more I do, I increasingly realize that I have many things that I would change to make myself feel like I'm telling the CPU exactly what I want to do without any ambiguity. Last year and early this year I finalized the design of the first revision of this language, which is called DANGC. It is inspired (clearly, based on the name) by C, but it takes a lot from Ada, which blew my mind the first time I saw it (especially SPARKS).

The main concept is that there are no types. I am tired of pretending that that are these various forms of data that we're exchanging between the CPU and memory. It's worse in C, because you could use int and have it mean different things on different platforms.

Saying 8 one_byte_wide_num; is far more expressive than int i_dont_know_how_wide_this_actually_is_guess_it_depends;. If the digit prior to the variable name is confusing, then remember that it's just the width in bits. You interpret those bits however you want. An 8-bit value could be interpreted as an integer, but also as a float. The standard library will provide some utilities to give users common things like IEEE 754 floating-points, but the standard library will itself be a DANGC program. The language doesn't have types.

From the head of DANGC's documentation file:

Neo: #define CHECKED_SK_CMP_FUNC(type, p) ((int (*)(const void *, const void *)) ((1 ? p : (int (*)(const type * const *, const type * const *))0)))DANGC: Do not try and bend the type. That's impossible. Instead, only try to realize the truth.Neo: What truth?DANGC: There is no type.Neo: There is no type?DANGC: Then you'll see that it is not the type that bends, it is only yourself.Neo: sort(64 *sk, 32 n) rets 1 where out == 1'0x0 => sorted(sk, n) == 1'0x1;

It has a built-in profiler and context management, where the main TU has a construct called world (which exists in .bss) and all other TUs have one called subsystem. All work happens in work units called "spins." There is also a built-in concurrency manager called "executor coordinator." An "executor unit" is something like a thread but more generic since MISC doesn't call these "threads." "Execution units" are individual units of work to be run within executor units. Inline assembly can be used for maximum human-readable control.

Here is an example:

example.dngs, a.k.a. a specification file (like a header file):

!INTERROGATE(CYCLES)
dim(32 color, 8 shift [8'0, 8'8)) rets 32 where out[8'31:8'24] == color[8'31:8'24], out[8'23:8'16] <= color[8'23:8'16], out[8'15:8'8] <= color[8'15:8'8], out[8'7:8'0] <= color[8'7:8'0];_start(64 *args) rets 64;
spin(64 dt, 64 abst, 64 idxt) rets 1;

example.dngb, a.k.a. a behavior file:

"example.dngs"init dim(color, shift)
8 r = color[8'23:8'16] >> shift;
8 g = color[8'15:8'8] >> shift;
8 b = color[8'7:8'0] >> shift;
out = {color[8'31:8'24], r, g, b};
ret;
term diminit _start(args)
call spin(64'0, 64'0, 64'0);
out = 64'0;
ret;
term _startinit spin(dt, abst, idxt)
32 pixel = call dim(32'0xFFCAFE42, 8'1);
64 cycles = dim.CYCLES;
out = 1'1;
ret;
term spin

A bit more involved example:

mlp.dngs:

#define FRAC_BITS 8'8
#define UNIT 64'256
#define RATE_SHIFT 8'2
#define INPUTS 64'2
#define HIDDEN 64'2
#define OUTPUT_WEIGHTS 64'4
#define HIDDEN_BIASES 64'6
#define OUTPUT_BIAS 64'8
#define PARAMS 64'9
#define TRAIN_STEPS 64'32
#define ERROR_Q8_TOLERANCE 64'2
#define LOSS_Q16_TOLERANCE (ERROR_Q8_TOLERANCE * ERROR_Q8_TOLERANCE)
#define SIGN_BIT 8'63world[4] = prediction;
world[5] = loss_q16;
world[6] = train_step;
world[7] = forward_cycles;
world[8] = backward_cycles;!INTERROGATE(CYCLES)
forward(64 *weights, 64 *hidden, 64 x0 [64'0, UNIT], 64 x1 [64'0, UNIT]) rets 64 where hidden[64'0][SIGN_BIT] == 1'0, hidden[64'1][SIGN_BIT] == 1'0;!INTERROGATE(CYCLES)
backward(64 *weights, 64 *hidden, 64 x0 [64'0, UNIT], 64 x1 [64'0, UNIT], 64 prediction, 64 target [64'0, UNIT]) rets 64 where out == (prediction - target) * (prediction - target);_start(64 *args) rets 64;
spin(64 dt, 64 abst, 64 idxt) rets 1 where out == 1'1, world.train_step == TRAIN_STEPS, world.loss_q16 <= LOSS_Q16_TOLERANCE;

mlp.dngb:

"mlp.dngs"init forward(weights, hidden, x0, x1)
64 idx = 64'0;
64 base = 64'0;
64 activation = 64'0; init layer:
base = idx * INPUTS;
activation = ((weights[base] * x0 + weights[base + 64'1] * x1) >>> FRAC_BITS) + weights[HIDDEN_BIASES + idx];
hidden[idx] = activation[SIGN_BIT] == 1'1 ? 64'0 : activation;
idx+;
jmp layer iff (idx < HIDDEN);
term layer out = ((weights[OUTPUT_WEIGHTS] * hidden[64'0] + weights[OUTPUT_WEIGHTS + 64'1] * hidden[64'1]) >>> FRAC_BITS) + weights[OUTPUT_BIAS];
ret;
term forwardinit backward(weights, hidden, x0, x1, prediction, target)
64 err = prediction - target;
64 grad = err + err;
64 delta = 64'0;
64 idx = 64'0;
64 base = 64'0;
out = err * err; init layer:
base = idx * INPUTS;
delta = (grad * weights[OUTPUT_WEIGHTS + idx]) >>> FRAC_BITS;
delta = hidden[idx] == 64'0 ? 64'0 : delta;
weights[OUTPUT_WEIGHTS + idx] -= ((grad * hidden[idx]) >>> FRAC_BITS) >>> RATE_SHIFT;
weights[base] -= ((delta * x0) >>> FRAC_BITS) >>> RATE_SHIFT;
weights[base + 64'1] -= ((delta * x1) >>> FRAC_BITS) >>> RATE_SHIFT;
weights[HIDDEN_BIASES + idx] -= delta >>> RATE_SHIFT;
idx+;
jmp layer iff (idx < HIDDEN);
term layer weights[OUTPUT_BIAS] -= grad >>> RATE_SHIFT;
ret;
term backwardinit _start(args)
call spin(64'0, 64'0, 64'0);
out = 64'0;
ret;
term _startinit spin(dt, abst, idxt)
64 weights[PARAMS] = {64'64, 64'128, 64'128, 64'64, 64'128, 64'128, 64'0, 64'0, 64'0};
64 hidden[HIDDEN] = {64'0, 64'0};
64 x0 = 64'128;
64 x1 = UNIT;
64 target = 64'192;
64 err = 64'0;
64 initial_loss_q16 = 64'0; world.prediction = call forward(weights, hidden, x0, x1);
err = world.prediction - target;
initial_loss_q16 = err * err;
world.loss_q16 = initial_loss_q16;
world.forward_cycles = forward.CYCLES;
world.backward_cycles = 64'0;
world.train_step = 64'0; init training:
world.loss_q16 = call backward(weights, hidden, x0, x1, world.prediction, target);
world.backward_cycles = world.backward_cycles + backward.CYCLES;
world.prediction = call forward(weights, hidden, x0, x1);
world.forward_cycles = world.forward_cycles + forward.CYCLES;
world.train_step = world.train_step + 64'1;
jmp training iff (world.train_step < TRAIN_STEPS);
term training err = world.prediction - target;
world.loss_q16 = err * err;
out = world.loss_q16 < initial_loss_q16 && world.loss_q16 <= LOSS_Q16_TOLERANCE;
ret;
term spin

Compiling using DANGC's toolchain would print:

align: 0/4 func entries off 64B cacheline; 19/22 local labels off 16B
call-graph:
forward -> (leaf)
backward -> (leaf)
_start -> spin
spin -> backward, forward

and then produce an ELF binary. It doesn't support MISC's EMIRU format yet:

./dangc-mlp-example: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped

As you can see, this is on Linux. DANGLING can't run the toolchain at this point but I want to port it as soon as I can.

There will be more DANGC example programs available in Crosstalk throughout Early Access.

This post is a part of the Hardware Sniffers "trivia" series about MISC.

If you're interested in the game, then consider wishlisting:

Thank you!

*DanglingPtr

More from Crosstalk

Other announcements

All news
Community13 Sep 2026Hardware Sniffers: MISC and virtual memorydisclaimer: some may find some of this content opinionated, but it stems from arbitrary external authorities making choices on users' behalf and not allowing that to be changed. Various manifestations of that occur on the x86 and in existing kernels > Someone: "Virtual memory is free" > Me: "yeah, no" See something odd? I practically cannot use the last ~50Gi of my physical memory. Virtual memo…Community11 Sep 2026Hardware Sniffers: The EMIRU binary formatMISC has its own executable format called "EMIRU." The E xecutable M inimal I mage R elocatable U nary · E : has a start and can be jmp'd to · M : doesn't include overhead, such as relocation tables · I : is a set of bytes loaded directly into memory, at a program base, by the kernel · R : supports address relocation at runtime without recompilation · U : it is its own freestanding thing ("unar…In-game event10 Sep 2026All achievements will be removed due to a Valve leakThere were unique and progression-important achievements in Crosstalk that were meant to be secret, however due to a scoping bug Valve leaked their names, descriptions, and images to the likes of SteamDB. All achievements are thereby removed from the game. New ones may be added later on. SteamDB happily showing confidential achievements