]> rethought.computer Git - sorel-lang.git/commitdiff
qemu setup, plus some compiler cleanup keep/f7d5e56796f5c9008df29f40c3d19627756632c8
authorBryan English <bryan@rethought.computer>
Mon, 19 Jan 2026 20:01:52 +0000 (15:01 -0500)
committerBryan English <bryan@rethought.computer>
Tue, 10 Feb 2026 04:08:54 +0000 (04:08 +0000)
hylo-lang/.gitignore
hylo-lang/flake.nix
hylo-lang/hyloc/src/riscv_asm_codegen.rs
hylo-lang/qemu/run.sh [new file with mode: 0644]
hylo-lang/qemu/setup.sh [new file with mode: 0644]

index eb5a316cbd195d26e3f768c7dd8e1b47299e17f8..7fa3f17db341b2faf225ad5b6de2d7706a7203a9 100644 (file)
@@ -1 +1,2 @@
 target
+qemu/machine
index e1988527c743a28879171558f2c9c7ee70166fa4..550936fd79bd250bc9c1105e64d22ee54c9158bd 100644 (file)
@@ -11,6 +11,7 @@
   in {
     devShells.${system}.default = pkgs.mkShell {
       packages = [
+        pkgs.qemu
       ];
     };
   };
index 7810f5637e18a948e651b7ed795718915e07ceb8..3da147d07d0a94062e83f9102b46601d1011303d 100644 (file)
@@ -3,10 +3,12 @@ use hylo_ir::*;
 use anyhow::*;
 
 use std::collections::{HashMap, HashSet};
+use std::fmt::Display;
 
 pub struct CodeGen<'a> {
     module: &'a IRModule,
     data_stack_size: usize,
+    lines: Vec<String>,
 }
 
 
@@ -28,61 +30,68 @@ pub struct CodeGen<'a> {
 
 macro_rules! asm_macro {
     ($name:ident, $src:expr) => {
-        fn $name(lines: &mut Vec<String>) {
-            lines.push($src.to_string());
+        fn $name(&mut self) {
+            self.ine($src);
         }
     };
     ($name:ident, $src:expr, $arg0:ty) => {
-        fn $name(lines: &mut Vec<String>, val0: $arg0) {
-            lines.push(format!($src, val0));
+        fn $name(&mut self, val0: $arg0) {
+            self.line(format!($src, val0));
         }
     };
     ($name:ident, $src:expr, $arg0:ty, $arg1:ty) => {
-        fn $name(lines: &mut Vec<String>, val0: $arg0, val1: $arg1) {
-            lines.push(format!($src, val0, val1));
+        fn $name(&mut self, val0: $arg0, val1: $arg1) {
+            self.line(format!($src, val0, val1));
         }
     };
 }
 
-asm_macro!(copy_top_stack_value_to, "    lw   {}, 0(s2)", &str);
-asm_macro!(copy_offset_stack_value_to, "    lw   {}, {}*8(s2)", &str, isize);
-asm_macro!(deref_pointer_to_from, "    lw   {}, 0({})", &str, &str);
-asm_macro!(copy_to_top_of_stack, "    sw {}, 0(s2)", &str);
-asm_macro!(move_stack_ptr_by_cells, "    addi s2, s2, {}*8", isize);
-
-fn pop_to(lines: &mut Vec<String>, reg: &str) {
-    copy_top_stack_value_to(lines, reg);
-    move_stack_ptr_by_cells(lines, 1);
-}
-
-fn push_from(lines: &mut Vec<String>, reg: &str) {
-    move_stack_ptr_by_cells(lines, -1);
-    copy_to_top_of_stack(lines, reg);
-}
-
-
 impl<'a> CodeGen<'a> {
     pub fn new(ir_mod: &'a IRModule, data_stack_size: usize) -> Self {
         Self {
             module: ir_mod,
-            data_stack_size
+            data_stack_size,
+            lines: vec![],
         }
     }
 
+    fn line<S: Display>(&mut self, line: S) {
+        self.lines.push(format!("    {}", line));
+    }
+
+    fn label<S: Display>(&mut self, line: S) {
+        self.lines.push(line.to_string());
+    }
+
+    asm_macro!(copy_top_stack_value_to, "    lw   {}, 0(s2)", &str);
+    asm_macro!(copy_offset_stack_value_to, "    lw   {}, {}*8(s2)", &str, isize);
+    asm_macro!(deref_pointer_to_from, "    lw   {}, 0({})", &str, &str);
+    asm_macro!(copy_to_top_of_stack, "    sw {}, 0(s2)", &str);
+    asm_macro!(move_stack_ptr_by_cells, "    addi s2, s2, {}*8", isize);
+
+    fn pop_to(&mut self, reg: &str) {
+        self.copy_top_stack_value_to(reg);
+        self.move_stack_ptr_by_cells(1);
+    }
+
+    fn push_from(&mut self, reg: &str) {
+        self.move_stack_ptr_by_cells(-1);
+        self.copy_to_top_of_stack(reg);
+    }
+
     pub fn assembly(&mut self) -> Result<String>{
-        let mut lines = vec![];
         let mut string_table = HashMap::new();
         let mut string_index = 0;
 
         // Static strings
-        lines.push(".rodata\n".to_string());
+        self.label(".section .rodata\n");
         for ir in &self.module.data {
             match ir {
                 IR::StringDef(some_string) => {
                     string_table.insert(some_string.clone(), string_index);
-                    lines.push(format!("string_id_{}:", string_index));
-                    lines.push(format!("    .asciz \"{}\"", some_string)); // should this be .asciz?
-                    lines.push("".to_string());
+                    self.label(format!("string_id_{}:", string_index));
+                    self.line(format!(".asciz \"{}\"", some_string)); // should this be .asciz?
+                    self.label("");
 
                     string_index += 1;
                 },
@@ -91,175 +100,190 @@ impl<'a> CodeGen<'a> {
         }
 
         // Data stack
-        lines.push(".data\n".to_string());
-        lines.push("data_stack:".to_string());
-        lines.push(format!("    .space {}", self.data_stack_size));
-        lines.push("data_stack_end:".to_string());
+        self.label(".data\n");
+        self.label("data_stack:");
+        self.line(format!(".space {}", self.data_stack_size));
+        self.label("data_stack_end:");
 
         // Code
-        // TODO align?
-        lines.push(".text\n".to_string());
+        self.label(".text\n");
+        self.label(".align 3\n");
 
         let mut if_block_count = 0;
         let mut if_stack = vec![];
         let mut seen_else = HashSet::new();
+        let mut last_label = "";
 
         for ir in &self.module.text {
             match ir {
                 IR::Label(name) => {
-                    lines.push(format!("{}:", name));
-                    lines.push("    addi sp, sp, -16".to_string()); // allocate 16 bytes on stack
-                    lines.push("    sw   ra, 8(sp)".to_string());   // store return address on stack
+                    last_label = name;
+                    if name == "main" {
+                        self.label(".globl _start");
+                        self.label("_start:");
+                        self.line("la s2, data_stack_end"); // set stack pointer
+                    } else {
+                        self.label(format!(".globl {}", name));
+                        self.label(format!("{}:", name));
+                    }
+                    self.line("addi sp, sp, -16"); // allocate 16 bytes on stack
+                    self.line("sw ra, 8(sp)");   // store return address on stack
                 },
                 IR::Call(name) => {
-                    lines.push(format!("    call {}", name));    
+                    self.line(format!("call {}", name));    
                 },
                 IR::Ret => {
-                    lines.push("    lw   ra, 8(sp)".to_string());  // load return address from stack
-                    lines.push("    addi sp, sp, 16".to_string()); // restore stack pointer
-                    lines.push("    ret".to_string());
+                    self.line("lw ra, 8(sp)");  // load return address from stack
+                    self.line("addi sp, sp, 16"); // restore stack pointer
+                    if last_label == "main" {
+                        // exit 0 syscall
+                        self.line("li a7, 93");
+                        self.line("mv a0, x0");
+                        self.line("ecall");
+                    } else {
+                        self.line("ret");
+                    }
                 },
                 IR::Load => {
-                    copy_top_stack_value_to(&mut lines, "t0");
-                    deref_pointer_to_from(&mut lines, "t0", "t0");
-                    copy_to_top_of_stack(&mut lines, "t0");
+                    self.copy_top_stack_value_to("t0");
+                    self.deref_pointer_to_from("t0", "t0");
+                    self.copy_to_top_of_stack("t0");
                 },
                 IR::Store => { // ( x addr -- )
-                    copy_top_stack_value_to(&mut lines, "t1");
-                    copy_offset_stack_value_to(&mut lines, "t0", 1);
-                    lines.push("    sw t0, 0(t1)".to_string());                // store x at addr 
-                    move_stack_ptr_by_cells(&mut lines, 2);
+                    self.copy_top_stack_value_to("t1");
+                    self.copy_offset_stack_value_to("t0", 1);
+                    self.line("sw t0, 0(t1)");                // store x at addr 
+                    self.move_stack_ptr_by_cells(2);
                 },
                 IR::StackPush(num) => {
-                    lines.push(format!("    li t0, {}", num));
-                    push_from(&mut lines, "t0");
+                    self.line(format!("li t0, {}", num));
+                    self.push_from("t0");
                 },
                 IR::AddU64 => {
-                    pop_to(&mut lines, "t0");
-                    pop_to(&mut lines, "t1");
-                    lines.push("    addi t0, t0, t1".to_string());
-                    push_from(&mut lines, "t0");
+                    self.pop_to("t0");
+                    self.pop_to("t1");
+                    self.line("add t0, t0, t1");
+                    self.push_from("t0");
                 },
                 IR::SubtractU64 => {
-                    pop_to(&mut lines, "t1");
-                    pop_to(&mut lines, "t0");
-                    lines.push("    sub  t0, t0, t1".to_string());
-                    push_from(&mut lines, "t0");
+                    self.pop_to("t1");
+                    self.pop_to("t0");
+                    self.line("sub t0, t0, t1");
+                    self.push_from("t0");
                 },
                 IR::Dup => {
-                    copy_top_stack_value_to(&mut lines, "t0");
-                    push_from(&mut lines, "t0");
+                    self.copy_top_stack_value_to("t0");
+                    self.push_from("t0");
                 },
                 IR::Swap => {
-                    pop_to(&mut lines, "t0");
-                    pop_to(&mut lines, "t1");
-                    push_from(&mut lines, "t0");
-                    push_from(&mut lines, "t1");
+                    self.pop_to("t0");
+                    self.pop_to("t1");
+                    self.push_from("t0");
+                    self.push_from("t1");
                 },
                 IR::Drop => {
-                    move_stack_ptr_by_cells(&mut lines, 1);
+                    self.move_stack_ptr_by_cells(1);
                 },
                 IR::Equals => {
                     // Yes, this is the same as subtract, since we're treating 0 as true, and
                     // others as false.
-                    pop_to(&mut lines, "t1");
-                    pop_to(&mut lines, "t0");
-                    lines.push("    sub  t0, t0, t1".to_string());
-                    push_from(&mut lines, "t0");
+                    self.pop_to("t1");
+                    self.pop_to("t0");
+                    self.line("sub  t0, t0, t1");
+                    self.push_from("t0");
                 },
                 IR::GreaterThan => {
-                    pop_to(&mut lines, "t1");
-                    pop_to(&mut lines, "t0");
-                    lines.push("    sgt  t0, t0, t1".to_string());
-                    lines.push("    seqz t0, t0".to_string()); // remember, 0 is true, others are
-                                                               // false
-                    push_from(&mut lines, "t0");
+                    self.pop_to("t1");
+                    self.pop_to("t0");
+                    self.line("sgt  t0, t0, t1");
+                    self.line("seqz t0, t0"); // remember, 0 is true, others are false
+                    self.push_from("t0");
                 },
                 IR::BitwiseOr => {
-                    pop_to(&mut lines, "t1");
-                    pop_to(&mut lines, "t0");
-                    lines.push("    or   t0, t0, t1".to_string());
-                    push_from(&mut lines, "t0");
+                    self.pop_to("t1");
+                    self.pop_to("t0");
+                    self.line("or   t0, t0, t1");
+                    self.push_from("t0");
                 },
                 IR::Sys0 => {
-                    pop_to(&mut lines, "a7");
-                    lines.push("    ecall".to_string());
-                    push_from(&mut lines, "a0");
+                    self.pop_to("a7");
+                    self.line("ecall");
+                    self.push_from("a0");
                 },
                 IR::Sys1 => {
-                    pop_to(&mut lines, "a7");
-                    pop_to(&mut lines, "a0");
-                    lines.push("    ecall".to_string());
-                    push_from(&mut lines, "a0");
+                    self.pop_to("a7");
+                    self.pop_to("a0");
+                    self.line("ecall");
+                    self.push_from("a0");
                 },
                 IR::Sys2 => {
-                    pop_to(&mut lines, "a7");
-                    pop_to(&mut lines, "a1");
-                    pop_to(&mut lines, "a0");
-                    lines.push("    ecall".to_string());
-                    push_from(&mut lines, "a0");
+                    self.pop_to("a7");
+                    self.pop_to("a1");
+                    self.pop_to("a0");
+                    self.line("ecall");
+                    self.push_from("a0");
                 },
                 IR::Sys3 => {
-                    pop_to(&mut lines, "a7");
-                    pop_to(&mut lines, "a2");
-                    pop_to(&mut lines, "a1");
-                    pop_to(&mut lines, "a0");
-                    lines.push("    ecall".to_string());
-                    push_from(&mut lines, "a0");
+                    self.pop_to("a7");
+                    self.pop_to("a2");
+                    self.pop_to("a1");
+                    self.pop_to("a0");
+                    self.line("ecall");
+                    self.push_from("a0");
                 },
                 IR::Sys4 => {
-                    pop_to(&mut lines, "a7");
-                    pop_to(&mut lines, "a3");
-                    pop_to(&mut lines, "a2");
-                    pop_to(&mut lines, "a1");
-                    pop_to(&mut lines, "a0");
-                    lines.push("    ecall".to_string());
-                    push_from(&mut lines, "a0");
+                    self.pop_to("a7");
+                    self.pop_to("a3");
+                    self.pop_to("a2");
+                    self.pop_to("a1");
+                    self.pop_to("a0");
+                    self.line("ecall");
+                    self.push_from("a0");
                 },
                 IR::Sys5 => {
-                    pop_to(&mut lines, "a7");
-                    pop_to(&mut lines, "a4");
-                    pop_to(&mut lines, "a3");
-                    pop_to(&mut lines, "a2");
-                    pop_to(&mut lines, "a1");
-                    pop_to(&mut lines, "a0");
-                    lines.push("    ecall".to_string());
-                    push_from(&mut lines, "a0");
+                    self.pop_to("a7");
+                    self.pop_to("a4");
+                    self.pop_to("a3");
+                    self.pop_to("a2");
+                    self.pop_to("a1");
+                    self.pop_to("a0");
+                    self.line("ecall");
+                    self.push_from("a0");
                 },
                 IR::Sys6 => {
-                    pop_to(&mut lines, "a7");
-                    pop_to(&mut lines, "a5");
-                    pop_to(&mut lines, "a4");
-                    pop_to(&mut lines, "a3");
-                    pop_to(&mut lines, "a2");
-                    pop_to(&mut lines, "a1");
-                    pop_to(&mut lines, "a0");
-                    lines.push("    ecall".to_string());
-                    push_from(&mut lines, "a0");
+                    self.pop_to("a7");
+                    self.pop_to("a5");
+                    self.pop_to("a4");
+                    self.pop_to("a3");
+                    self.pop_to("a2");
+                    self.pop_to("a1");
+                    self.pop_to("a0");
+                    self.line("ecall");
+                    self.push_from("a0");
                 },
                 IR::PutN => {
-                    lines.push("    call putn".to_string());
+                    self.line("call putn");
                 },
                 // https://cmput229.github.io/229-labs-RISCV/RISC-V-Examples_Public/03-Conditionals/03b-If_Else.html
                 IR::If => {
-                    pop_to(&mut lines, "t0");
-                    lines.push(format!("    bnez t0, _else_{}", if_block_count));
+                    self.pop_to("t0");
+                    self.line(format!("bnez t0, _else_{}", if_block_count));
                     if_stack.push(if_block_count);
                     if_block_count += 1;
                 },
                 IR::Else => {
                     let if_counter = if_stack.last().unwrap().clone();
-                    lines.push(format!("    j _endif_{}", if_counter));
-                    lines.push(format!("_else_{}:", if_counter));
+                    self.line(format!("j _endif_{}", if_counter));
+                    self.label(format!("_else_{}:", if_counter));
                     seen_else.insert(if_counter);
                 },
                 IR::EndIf => {
                     let stack = &mut if_stack;
                     let if_counter = stack.last().unwrap().clone();
                     if !seen_else.contains(&if_counter) {
-                        lines.push(format!("_else_{}:", if_counter));
+                        self.label(format!("_else_{}:", if_counter));
                     } else {
-                        lines.push(format!("_endif_{}:", if_counter));
+                        self.label(format!("_endif_{}:", if_counter));
                         seen_else.remove(&if_counter);
                     }
                     stack.pop();
@@ -268,7 +292,7 @@ impl<'a> CodeGen<'a> {
             }
         }
 
-        Ok(lines.join("\n"))
+        Ok(self.lines.join("\n"))
     }
 }
 
diff --git a/hylo-lang/qemu/run.sh b/hylo-lang/qemu/run.sh
new file mode 100644 (file)
index 0000000..a9d3a7e
--- /dev/null
@@ -0,0 +1,17 @@
+
+qemu-system-riscv64 \
+    -machine virt \
+    -cpu rv64 \
+    -m 1G \
+    -device virtio-blk-device,drive=hd \
+    -drive file=machine/overlay.qcow2,if=none,id=hd \
+    -device virtio-net-device,netdev=net \
+    -netdev user,id=net,hostfwd=tcp::2222-:22 \
+    -kernel machine/u-boot-qemu/uboot.elf \
+    -object rng-random,filename=/dev/urandom,id=rng \
+    -device virtio-rng-device,rng=rng \
+    -append "root=LABEL=rootfs console=ttyS0" \
+    -nographic \
+
+echo "now do:"
+echo "  ssh debian@localhost -p 2222"
diff --git a/hylo-lang/qemu/setup.sh b/hylo-lang/qemu/setup.sh
new file mode 100644 (file)
index 0000000..c692095
--- /dev/null
@@ -0,0 +1,17 @@
+
+mkdir machine
+cd machine
+wget "https://gitlab.com/api/v4/projects/giomasce%2Fdqib/jobs/artifacts/master/download?job=convert_riscv64-virt" -O debian-rv64.zip
+
+unzip ./debian-rv64.zip
+
+# Grab the URL from https://packages.debian.org/sid/u-boot-qemu
+wget "http://ftp.us.debian.org/debian/pool/main/u/u-boot/u-boot-qemu_2025.01-3.1_all.deb" -O u-boot-qemu.deb
+mkdir u-boot-qemu
+cd u-boot-qemu
+ar -x ../u-boot-qemu.deb
+tar xvf data.tar.xz
+cp ./usr/lib/u-boot/qemu-riscv64_smode/uboot.elf ./uboot.elf
+
+qemu-img create -o backing_file=./dqib_riscv64-virt/image.qcow2,backing_fmt=qcow2 -f qcow2 overlay.qcow2
+