Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dylib open/call/close io functions, initial ffi api #394

Merged
merged 8 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ fn main() {
println!("cargo:rerun-if-changed=src/hvm.c");
println!("cargo:rerun-if-changed=src/run.cu");
println!("cargo:rerun-if-changed=src/hvm.cu");
println!("cargo:rustc-link-arg=-rdynamic");

match cc::Build::new()
.file("src/run.c")
Expand Down
220 changes: 220 additions & 0 deletions src/hvm.cuh
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
#ifndef hvm_cuh_INCLUDED
#define hvm_cuh_INCLUDED

#include <math.h>
#include <stdint.h>

// Types
// -----

typedef uint8_t bool;
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef unsigned long long int u64;
typedef int32_t i32;
typedef float f32;
typedef double f64;

// Local Types
typedef u8 Tag; // Tag ::= 3-bit (rounded up to u8)
typedef u32 Val; // Val ::= 29-bit (rounded up to u32)
typedef u32 Port; // Port ::= Tag + Val (fits a u32)
typedef u64 Pair; // Pair ::= Port + Port (fits a u64)

// Numbs
typedef u32 Numb; // Numb ::= 29-bit (rounded up to u32)

// Tags
const Tag VAR = 0x0; // variable
const Tag REF = 0x1; // reference
const Tag ERA = 0x2; // eraser
const Tag NUM = 0x3; // number
const Tag CON = 0x4; // constructor
const Tag DUP = 0x5; // duplicator
const Tag OPR = 0x6; // operator
const Tag SWI = 0x7; // switch

// Numbers
static const f32 U24_MAX = (f32) (1 << 24) - 1;
static const f32 U24_MIN = 0.0;
static const f32 I24_MAX = (f32) (1 << 23) - 1;
static const f32 I24_MIN = (f32) (i32) ((-1u) << 23);
const Tag TY_SYM = 0x00;
const Tag TY_U24 = 0x01;
const Tag TY_I24 = 0x02;
const Tag TY_F24 = 0x03;
const Tag OP_ADD = 0x04;
const Tag OP_SUB = 0x05;
const Tag FP_SUB = 0x06;
const Tag OP_MUL = 0x07;
const Tag OP_DIV = 0x08;
const Tag FP_DIV = 0x09;
const Tag OP_REM = 0x0A;
const Tag FP_REM = 0x0B;
const Tag OP_EQ = 0x0C;
const Tag OP_NEQ = 0x0D;
const Tag OP_LT = 0x0E;
const Tag OP_GT = 0x0F;
const Tag OP_AND = 0x10;
const Tag OP_OR = 0x11;
const Tag OP_XOR = 0x12;
const Tag OP_SHL = 0x13;
const Tag FP_SHL = 0x14;
const Tag OP_SHR = 0x15;
const Tag FP_SHR = 0x16;

typedef struct GNet GNet;

// Debugger
// --------

// Port: Constructor and Getters
// -----------------------------

static inline Port new_port(Tag tag, Val val) {
return (val << 3) | tag;
}

static inline Tag get_tag(Port port) {
return port & 7;
}

static inline Val get_val(Port port) {
return port >> 3;
}

// Pair: Constructor and Getters
// -----------------------------

static inline const Pair new_pair(Port fst, Port snd) {
return ((u64)snd << 32) | fst;
}

static inline Port get_fst(Pair pair) {
return pair & 0xFFFFFFFF;
}

static inline Port get_snd(Pair pair) {
return pair >> 32;
}

// Utils
// -----

// Swaps two ports.
static inline void swap(Port *a, Port *b) {
Port x = *a; *a = *b; *b = x;
}

static inline u32 min(u32 a, u32 b) {
return (a < b) ? a : b;
}

static inline f32 clamp(f32 x, f32 min, f32 max) {
const f32 t = x < min ? min : x;
return (t > max) ? max : t;
}

// Numbs
// -----

// Constructor and getters for SYM (operation selector)
static inline Numb new_sym(u32 val) {
return (val << 5) | TY_SYM;
}

static inline u32 get_sym(Numb word) {
return (word >> 5);
}

// Constructor and getters for U24 (unsigned 24-bit integer)
static inline Numb new_u24(u32 val) {
return (val << 5) | TY_U24;
}

static inline u32 get_u24(Numb word) {
return word >> 5;
}

// Constructor and getters for I24 (signed 24-bit integer)
static inline Numb new_i24(i32 val) {
return ((u32)val << 5) | TY_I24;
}

static inline i32 get_i24(Numb word) {
return ((i32)word) << 3 >> 8;
}

// Constructor and getters for F24 (24-bit float)
static inline Numb new_f24(float val) {
u32 bits = *(u32*)&val;
u32 shifted_bits = bits >> 8;
u32 lost_bits = bits & 0xFF;
// round ties to even
shifted_bits += (!isnan(val)) & ((lost_bits - ((lost_bits >> 7) & !shifted_bits)) >> 7);
// ensure NaNs don't become infinities
shifted_bits |= isnan(val);
return (shifted_bits << 5) | TY_F24;
}

static inline float get_f24(Numb word) {
u32 bits = (word << 3) & 0xFFFFFF00;
return *(float*)&bits;
}

static inline Tag get_typ(Numb word) {
return word & 0x1F;
}

static inline bool is_num(Numb word) {
return get_typ(word) >= TY_U24 && get_typ(word) <= TY_F24;
}

static inline bool is_cast(Numb word) {
return get_typ(word) == TY_SYM && get_sym(word) >= TY_U24 && get_sym(word) <= TY_F24;
}

// Partial application
static inline Numb partial(Numb a, Numb b) {
return (b & ~0x1F) | get_sym(a);
}

// Readback
// ---------

// Readback: Tuples
typedef struct Tup {
u32 elem_len;
Port elem_buf[8];
} Tup;

// Reads a tuple of `size` elements from `port`.
// Tuples are con nodes nested to the right auxilliary port,
// For example, `(CON a (CON b (CON c)))` is a 3-tuple (a, b, c).
extern Tup gnet_readback_tup(GNet* gnet, Port port, u32 size);

typedef struct Str {
u32 text_len;
char text_buf[256];
} Str;

// Reads a constructor-encoded string (of length at most 255 characters),
// into a null-terminated `Str`.
extern Str gnet_readback_str(GNet* gnet, Port port);

typedef struct Bytes {
u32 len;
char *buf;
} Bytes;

// Reads a constructor-encoded string (of length at most 256 characters),
// into a `Bytes`. The returned `Bytes` is not null terminated.
extern Bytes gnet_readback_bytes(GNet* net, Port port);

// Creates a construtor-encoded string of arbitrary length from the
// provided `bytes`. This string can be consumed on the HVM-side. This
// will return an `ERA` if nodes cannot be allocated.
extern Port gnet_inject_bytes(GNet* net, Bytes *bytes);

#endif // hvm_cuh_INCLUDED
Loading
Loading