Skip to content

Instantly share code, notes, and snippets.

@charlesastaylor
Created May 25, 2025 21:16
Show Gist options
  • Save charlesastaylor/6df1edccbbfa16a06e30f398d03d36dc to your computer and use it in GitHub Desktop.
Save charlesastaylor/6df1edccbbfa16a06e30f398d03d36dc to your computer and use it in GitHub Desktop.
A silly example of using inline arm assembler
//
// Do some drawing with assembly! A small host program, that sets up graphics and memory then calls update_and_render
// which is implemented with inline assembly to do whatever it's heart desires.
//
// @TODO(Charles): Do something more interesting than the scrolling noise!
#if IS_CROSS_COMPILING {
#run,host {
#import "Basic";
#import "Arm_Assembler";
}
}
update_and_render :: no_inline (frame_buffer: *Frame_Buffer, memory: *u8) {
// x0: context
// x1: frame_buffer
// x2: memory
// x0-x15 should be volatile, but maybe better to be safe and not touch x0,x1.
#insert #run,host -> string {
return assemble_arm64(#string ARM64
mov x14, x2 // @Hack I only added the memory param after I was already using w2 register! Just put it somewhere else.
ldr w2, [x1] // width
ldr w3, [x1, #4] // height
ldr x4, [x1, #8]
// Load our color
ldr w6, [x14]
mov x8, 0 // j
outer:
mov x9, 0 // i
// Modify the color on every row for some whack output
add w6, w6, 1
orr w6, w6, 0xFF000000 // But make sure we are never transparent!
inner:
// x10 = 4(width * j + i).
mul x10, x8, x2
add x10, x10, x9
str w6, [x4, x10, lsl 2]
add x9, x9, 1
cmp x9, x2
blt inner
add x8, x8, 1
cmp x8, x3
blt outer
str w6, [x14]
ARM64);
};
}
//
// "Host" program.
//
my_window: Window_Type;
window_width, window_height: s32;
// NOTE(Charles): I'm using Simp (and so opengl) to render to screen. But maybe it would be better to do the software_render.jai
// thing? Could actually somewhat reasonably make the entire program assembly at that point...
Frame_Buffer :: struct {
width, height: s32;
memory: *u8;
}
main :: () {
window_width = 1280;
window_height = 720;
my_window = create_window(window_width, window_height, "Game");
set_render_target(my_window, .LEFT_HANDED);
window_width, window_height = get_render_dimensions(my_window);
BYTES_PER_PIXEL ::4;
WIDTH :: 600;
HEIGHT :: 600;
screen_bitmap: Bitmap;
screen_texture: Texture;
bitmap_alloc(*screen_bitmap, WIDTH, HEIGHT, .RGBA8);
frame_buffer: Frame_Buffer;
{
using frame_buffer;
width = 600;
height = 600;
memory = screen_bitmap.data.data;
}
// When assembly my x64 code to a library I stored everything in data section. That's not really possible while
// using inline assembly, as we only extract the text section. You can embed constant data in code and branch over it
// but the memory will be read only afaict. So instead, just allocated some memory for the assembly to use as it
// pleases!
game_memory := cast(*u8, alloc(1024)); // 1Kb is enough memory for anyone!
memset(game_memory, 0, 1024);
// cast(*u32, game_memory).* = 0xFF00FF00;
quit := false;
while !quit {
update_window_events();
for get_window_resizes() {
update_window(it.window);
if it.window == my_window {
should_reinit := (it.width != window_width) || (it.height != window_height);
window_width = it.width;
window_height = it.height;
}
}
for events_this_frame {
if it.type == .QUIT then quit = true;
}
update_and_render(*frame_buffer, game_memory);
texture_updated := texture_load_from_bitmap(*screen_texture, *screen_bitmap);
assert(texture_updated);
clear_render_target(0.12, 0.12, 0.12, 1);
{
set_shader_for_images(*screen_texture);
buffer_ratio := cast(float) screen_bitmap.width / screen_bitmap.height;
window_ratio := cast(float) window_width / window_height;
x, y, width, height: float;
if buffer_ratio > window_ratio {
// window is tall and skinny
width = xx window_width;
height = width / buffer_ratio;
x = 0;
y = (window_height - height) / 2.;
} else {
height = xx window_height;
width = height * buffer_ratio;
x = (window_width - width) / 2.;
y = 0;
}
// @TODO: This will stretch and blur our image, if want to maintain pixels need to set the gl
// filter or whatever it is.
immediate_quad(x, y, x + width, y + height, .{1, 1, 1, 1});
}
swap_buffers(my_window);
reset_temporary_storage();
sleep_milliseconds(10);
}
}
#if OS == .ANDROID #import "Android"()(main, USE_GLUE_NATIVE_PORT = true);
#import "Basic";
#import "Simp";
#import "Input"; // Have to do input events for android to not complain about app not responding...
#import "Window_Creation";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment