use crate::{spec::{Bindgen, Binding}, set_current_binding, reset_current_binding};
use super::{Code, verbose_println };
pub fn generate_binding(bindgen: &Bindgen, binding: &Binding) -> Code {
verbose_println(format!("Generating binding for {}", binding.name));
set_current_binding(binding.name.clone());
let mut code = String::new();
verbose_println("Adding attributes: inline(never), no_mangle");
code.push_str("#[inline(never)]\n");
code.push_str("#[no_mangle]\n");
let doc = format!(
r#"Calls the Function "{name}" with the arguments "{args}"."#,
name = binding.name,
args = binding
.args
.iter()
.map(|a| a.name.clone())
.collect::<Vec<String>>()
.join(", ")
);
verbose_println(format!("Adding documentation: {}", doc));
code.push_str(format!("#[doc = {:?}]\n", doc).as_str());
verbose_println(format!("Starting function definition for {}", binding.name));
code.push_str(format!("pub unsafe extern \"C\" fn {}(\n", binding.name).as_str());
for arg in &binding.args {
verbose_println(format!(
"Generating argument {} of type {}",
arg.name, arg.ty
));
code.push_str(format!("{name}: {ty},\n", name = arg.name, ty = arg.ty).as_str());
}
verbose_println("Closing function definition");
code.push_str(format!(") -> {}\n{{\n", binding.ret).as_str());
verbose_println("Generating inline assembly");
code.push_str(generate_inline_asm(bindgen, binding).as_str());
verbose_println("Finalizing function");
code.push_str(
format!(
"return _ret & 0x{:x} }}\n",
(bindgen.function_sig.map(|m| (m as u32) << 16).unwrap_or(0) | binding.offset as u32)
)
.as_str(),
);
verbose_println("Binding generation complete");
reset_current_binding();
code
}
pub fn generate_inline_asm(bindgen: &Bindgen, binding: &Binding) -> Code {
verbose_println(format!("Generating inline assembly for {}", binding.name));
let mut code = format!("let mut _ret: {};\n", binding.ret);
verbose_println("Adding assembly code");
code.push_str("::core::arch::asm!(\n");
verbose_println(format!(
"Adding interrupt number: 0x{:x}",
bindgen.interrupt_number
));
code.push_str(format!("\"int 0x{:x}\",\n", bindgen.interrupt_number).as_str());
let binding_number =
bindgen.function_sig.map(|m| (m as u32) << 16).unwrap_or(0) | binding.offset as u32;
verbose_println(format!(
"Adding function register: {:?}",
bindgen.function_register
));
code.push_str(
format!(
"in({:?}) 0x{:x},\n",
bindgen.function_register, binding_number
)
.as_str(),
);
for arg in &binding.args {
verbose_println(format!(
"Adding argument: {}, register: {:?}",
arg.name, arg.reg
));
code.push_str(format!("in({:?}) {},\n", arg.reg, arg.name).as_str());
}
verbose_println(format!(
"Adding lateout register: {:?}",
bindgen.function_register
));
code.push_str(format!("lateout({:?}) _ret,\n", bindgen.function_register).as_str());
verbose_println("Adding options: nostack, nomem, raw");
code.push_str("options(nostack, nomem, raw)\n");
verbose_println("Closing assembly code");
code.push_str(");\n");
verbose_println("Inline assembly generation complete");
code
}