diff --git a/ext/integer128.nim b/ext/integer128.nim new file mode 100644 index 0000000..c44a9f3 --- /dev/null +++ b/ext/integer128.nim @@ -0,0 +1,378 @@ +{.emit:"typedef __uint128_t NU128; typedef __int128_t NI128;".} + +# Capacity of 42 because it seems +# reasonable that the number will fit. +# If it doesn't, nim will just allocate +# more memory for us anyway +const STRING_CAPACITY = 42 + +type + s128* {.importc: "NI128"} = object + high: int64 + low: uint64 + + u128* {.importc: "NU128"} = object + high, low: uint64 + + helperInt128 = object + hi: int64 + lo: uint64 + + helperUInt128 = object + hi: uint64 + lo: uint64 + +proc toHelper(val: s128): helperInt128 = + (cast[ptr helperInt128](unsafeAddr val))[] + +proc lo*(val: s128): uint64 = + val.toHelper().lo + +proc hi*(val: s128): int64 = + val.toHelper().hi + +proc toInt128(val: helperInt128): s128 = + (cast[ptr s128](unsafeAddr val))[] + +proc toHelper(val: u128): helperUInt128 = + (cast[ptr helperUInt128](unsafeAddr val))[] + +proc lo*(val: u128): uint64 = + val.toHelper().lo + +proc hi*(val: u128): uint64 = + val.toHelper().hi + +proc toUInt128(val: helperUInt128): u128 = + (cast[ptr u128](unsafeAddr val))[] + +proc newInt128*(hi: int64, lo: uint64): s128 = + let r = helperInt128(hi: hi, lo: lo) + return r.toInt128() + +proc newUInt128*(hi: uint64, lo: uint64): u128 = + let r = helperUInt128(hi: hi, lo: lo) + return r.toUInt128() + +proc toUInt128(val: s128): u128 = + newUInt128(val.hi.uint64, val.lo) + +converter intToInt128*(val: int): s128 = + newInt128(0, val.uint64) + +converter intToUInt128*(val: int): u128 = + newUInt128(0, val.uint64) + +proc `<`*(val1: u128, val2: u128): bool = + let lhs = val1.toHelper() + let rhs = val2.toHelper() + + if (lhs.hi < rhs.hi): + return true + if (rhs.hi < lhs.hi): + return false + if (lhs.lo < rhs.lo): + return true + return false + +proc `<`*(val1: s128, val2: s128): bool = + let lhs = val1.toHelper() + let rhs = val2.toHelper() + + if (lhs.hi < rhs.hi): + return true + if (rhs.hi < lhs.hi): + return false + if (lhs.lo < rhs.lo): + return true + return false + +proc `>=`*(val1: s128, val2: s128): bool = + let lhs = val1.toHelper() + let rhs = val2.toHelper() + + if lhs.hi == rhs.hi and lhs.lo == rhs.lo: + return true + + if lhs.hi > rhs.hi: + return true + if rhs.hi > lhs.hi: + return false + + if lhs.lo > rhs.lo: + return true + return false + +proc `>=`*(val1: u128, val2: u128): bool = + let lhs = val1.toHelper() + let rhs = val2.toHelper() + + if lhs.hi == rhs.hi and lhs.lo == rhs.lo: + return true + + if lhs.hi > rhs.hi: + return true + if rhs.hi > lhs.hi: + return false + + if lhs.lo > rhs.lo: + return true + return false + +proc `>`*(val1: s128, val2: s128): bool = + let lhs = val1.toHelper() + let rhs = val2.toHelper() + + if (lhs.hi < rhs.hi): + return true + if (rhs.hi < lhs.hi): + return false + if (lhs.lo < rhs.lo): + return true + return false + +proc `>`*(val1: u128, val2: u128): bool = + let lhs = val1.toHelper() + let rhs = val2.toHelper() + + if (lhs.hi < rhs.hi): + return true + if (rhs.hi < lhs.hi): + return false + if (lhs.lo < rhs.lo): + return true + return false + +proc `<=`*(val1: s128, val2: s128): bool = + let lhs = val1.toHelper() + let rhs = val2.toHelper() + + if lhs.hi == rhs.hi and lhs.lo == rhs.lo: + return true + + if lhs.hi < rhs.hi: + return true + if rhs.hi < lhs.hi: + return false + if lhs.lo < rhs.lo: + return true + return false + +proc `<=`*(val1: u128, val2: u128): bool = + let lhs = val1.toHelper() + let rhs = val2.toHelper() + + if lhs.hi == rhs.hi and lhs.lo == rhs.lo: + return true + + if lhs.hi < rhs.hi: + return true + if rhs.hi < lhs.hi: + return false + if lhs.lo < rhs.lo: + return true + return false + +proc `!=`*(val1: s128, val2: s128): bool = + let lhs = val1.toHelper() + let rhs = val2.toHelper() + return (lhs.hi != rhs.hi) or (lhs.lo != rhs.lo) + +proc `!=`*(val1: u128, val2: u128): bool = + let lhs = val1.toHelper() + let rhs = val2.toHelper() + return (lhs.hi != rhs.hi) or (lhs.lo != rhs.lo) + +proc `==`*(val1: s128, val2: s128): bool = + let lhs = val1.tohelper() + let rhs = val2.tohelper() + if lhs.hi != rhs.hi: + return false + if lhs.lo != rhs.lo: + return false + return true + +proc `==`*(val1: u128, val2: u128): bool = + let lhs = val1.tohelper() + let rhs = val2.tohelper() + if lhs.hi != rhs.hi: + return false + if lhs.lo != rhs.lo: + return false + return true + +proc `+`*(val1, val2: s128): s128 = + let lhs = val1.toHelper() + let rhs = val2.toHelper() + + var res = result.toHelper() + + res.hi = lhs.hi + rhs.hi + + res.lo = lhs.lo + rhs.lo + if res.lo < rhs.lo: + res.hi.inc() + result = res.toInt128() + +proc `+`*(val1, val2: u128): u128 = + let lhs = val1.toHelper() + let rhs = val2.toHelper() + + var res = result.toHelper() + + res.hi = lhs.hi + rhs.hi + + res.lo = lhs.lo + rhs.lo + if res.lo < rhs.lo: + res.hi.inc() + result = res.toUInt128() + +proc `-`*(val: s128): s128 = + var res = val.toHelper() + res.hi = not res.hi + res.lo = not res.lo + res.lo += 1 + if res.lo == 0: + res.hi += 1 + + result = res.toInt128() + +proc `-`*(val: u128): s128 = + var res = newInt128(val.hi.int64, val.lo).toHelper() + + res.hi = not res.hi + res.lo = not res.lo + res.lo += 1 + if res.lo == 0: + res.hi += 1 + + result = res.toInt128() + +proc `-`*(val1, val2: s128): s128 = + let lhs = val1.toHelper() + let rhs = val2.toHelper() + + var res = result.toHelper() + + res.hi = lhs.hi - rhs.hi + res.lo = lhs.lo - rhs.lo + if res.lo > lhs.lo: + res.hi.dec() + + result = res.toInt128() + +proc `-`*(val1, val2: u128): s128 = + let lhs = val1.toHelper() + let rhs = val2.toHelper() + + var res = result.toHelper() + + res.hi = (lhs.hi - rhs.hi).int64 + res.lo = lhs.lo - rhs.lo + if res.lo > lhs.lo: + res.hi.dec() + + result = res.toInt128() + +proc `$`*(val: s128): string = + var v = val + + if v == 0: + return "0" + + var str = newStringOfCap(STRING_CAPACITY) + + var + p10 = 1.s128 + temp: s128 + num_digits = 0 + going = 1 + digit = 0 + + if v < 0: + str.add('-') + v = -v + + while (p10 <= v and going > 0): + p10 = p10 + p10 + if p10 < 0: + going = 0 + temp = p10 + p10 = p10 + p10 + if p10 < 0: + going = 0 + p10 = p10 + p10 + if p10 < 0: + going = 0 + p10 = p10 + temp + if p10 < 0: + going = 0 + num_digits.inc + + while num_digits > 0: + num_digits -= 1 + p10 = 1 + for i in 0..= p10): + v = v - p10 + digit.inc + str.add(char(48 + digit)) + + result = str + +proc `$`*(val: u128): string = + var v = val + + if v == 0: + return "0" + + var str = newStringOfCap(STRING_CAPACITY) + + var + p10 = 1.u128 + temp: u128 + num_digits = 0 + going = 1 + digit = 0 + + while (p10 <= v and going > 0): + p10 = p10 + p10 + if p10 < 0: + going = 0 + temp = p10 + p10 = p10 + p10 + if p10 < 0: + going = 0 + p10 = p10 + p10 + if p10 < 0: + going = 0 + p10 = p10 + temp + if p10 < 0: + going = 0 + num_digits.inc + + while num_digits > 0: + num_digits -= 1 + p10 = 1 + for i in 0..= p10): + v = (v - p10).toUInt128() + digit.inc + str.add(char(48 + digit)) + + result = str + diff --git a/libnx.nimble b/libnx.nimble new file mode 100644 index 0000000..b8f0b69 --- /dev/null +++ b/libnx.nimble @@ -0,0 +1,20 @@ +# Package + +version = "0.1.0" +author = "Joey Payne" +description = "Nintendo Switch library libnx for Nim." +license = "MIT" + +srcDir = "src" + +# Deps +requires "nim >= 0.18.0", "https://github.com/jyapayne/nimgenEx@#head" + +task setup, "Download and generate": + exec "nimgen libnxGen.cfg" + +before install: + setupTask() + +task test, "Run tests": + exec "nim c -r tests/test.nim" diff --git a/libnxGen.cfg b/libnxGen.cfg new file mode 100644 index 0000000..086e953 --- /dev/null +++ b/libnxGen.cfg @@ -0,0 +1,302 @@ +[n.global] +output="src/libnx" +c_compiler="aarch64-none-elf-gcc" +cpp_compiler="aarch64-none-elf-g++" +filter=lock + +[n.include] +src/libnx/nx/include +src/libnx/nx/include/switch +src/libnx/nx/include/switch/arm +src/libnx/nx/include/switch/kernel +src/libnx/nx/include/switch/services +src/libnx/nx/include/switch/audio +src/libnx/nx/include/switch/gfx +src/libnx/nx/include/switch/runtime +src/libnx/nx/include/switch/runtime/util +src/libnx/nx/include/switch/runtime/devices +/opt/devkitpro/devkitA64/aarch64-none-elf/include/ + +[n.exclude] +src/libnx/nim.cfg + +[n.prepare] +gitremote = "https://github.com/switchbrew/libnx" +gitsparse = """ +nx/include/* +nx/source/* +nx/external/bsd/* +""" + +[n.after] +wildcard = ".nim" +search = "_Bool" +replace = "bool" + +search.u8 = "u8" +replace.u8 = "uint8" + +search.u16 = "u16" +replace.u16 = "uint16" + +search.u32 = "u32" +replace.u32 = "uint32" + +search.u64 = "u64" +replace.u64 = "uint64" + +search.lib = " src/libnx" +replace.lib = " libnx" + +search.timport = "../types" +replace.timport = "libnx/types" + +search.kimport = "../kernel/" +replace.kimport = "libnx/" + +search.servimport = "../services/" +replace.servimport = "libnx/" + +search.resimport = "../result" +replace.resimport = "libnx/result" + +search.armimport = "../arm/" +replace.armimport = "libnx/" + +search.lock = "_LOCK" +replace.lock = "LOCK" + +search.cdecl = "stdcall" +replace.cdecl = "cdecl" + +[src/libnx/nim.cfg] +create = """ +--path:"../" +""" + +[result.h] +defines = true + +[hid.h] +defines = true +search.static_assert = "static_assert" +replace.static_assert = "// static_assert" + +[ipc.h] +defines = true +execute = "vim -es +'g/^static inline.*{/norm f{d%r;' -es +%print -es +q! $file" + +[tls.h] +execute = "vim -es +'g/^static inline.*{/norm f{d%r;' -es +%print -es +q! $file" + +[sm.h] +execute = "vim -es +'g/^static inline.*{/norm f{d%r;' -es +%print -es +q! $file" + +[shmem.h] +execute = "vim -es +'g/^static inline.*{/norm f{d%r;' -es +%print -es +q! $file" + +[condvar.h] +execute = "vim -es +'g/^static inline.*/norm jd%$$a;' -es +%print -es +q! $file" + +[romfs_dev.h] +execute = "vim -es +'g/^static inline.*/norm jd%$$a;' -es +%print -es +q! $file" +search = "romfs_" +replace = "Romfs_" + +[gfx.h] +defines = true +execute = "vim -es +'g/^static inline.*{/norm f{d%r;' -es +%print -es +q! $file" + +[ioctl.h] +defines = true +search = "_NV_" +replace = "UNV_" + +search.nv = "__nv_" +replace.nv = "DUnv_" + +[svc.h] +search = "PACKED" +replace = "" + +search.noreturn = "NORETURN" +replace.noreturn = "" + +defines=true +execute = "vim -es +'g/^static inline.*{/norm f{d%r;' -es +%print -es +q! $file" + +[switch.h] +preprocess = true +defines = true +recurse = true +compile = "src/libnx/nx/source" + +[types.nim] +search.o = " uint8*" +prepend.o = """ + u8* = uint8 + u16* = uint16 + u32* = uint32 + u64* = uint64 + int8_t* = int8 + int16_t* = int16 + int32_t* = int32 + int64_t* = int64 + ssize_t* = int +""" + +search.s128 = " s128* = __int128_t" +replace.s128 = "" + +search.u128 = " u128* = __uint128_t" +replace.u128 = "" + +search.uint8 = "uint8* = uint8_t" +replace.uint8 = "uint8_t* = uint8" + +search.uint16 = "uint16* = uint16_t" +replace.uint16 = "uint16_t* = uint16" + +search.uint32 = "uint32* = uint32_t" +replace.uint32 = "uint32_t* = uint32" + +search.uint64 = "uint64* = uint64_t" +replace.uint64 = "uint64_t* = uint64" + +search.import = "type\n" +prepend.import = """ +include integer128 +template BIT*(n): auto = (1.uint shl n) +""" + +[svc.nim] + +search.import = "type\n" +prepend.import = """ +import libnx/types +""" + +search.permx = "Perm_X = BIT(2), ## /< Execute permission." +replace.permx = "Perm_Rw = Perm_R.int or Perm_W.int, ## /< Read/write permissions." + +search.permrw = "Perm_Rw = Perm_R or Perm_W, ## /< Read/write permissions." +replace.permrw = "Perm_X = BIT(2), ## /< Execute permission." + +search.permrx = "Perm_Rx = Perm_R or Perm_X, ## /< Read/execute permissions." +replace.permrx = "Perm_Rx = Perm_R.int or Perm_X.int, ## /< Read/execute permissions." + +[shmem.nim] +search.import = "type\n" +prepend.import = """ +import libnx/svc +""" + +[nacp.nim] +search.t = "type" +prepend.t = """ +import libnx/types +""" + +[lock.nim] +search.flock_t = " __lock_t" +replace.flock_t = " DUlock_t" + +search.nlock_t = "= __lock_t" +replace.nlock_t = "= DUlock_t" + +search.import = "type" +prepend.import = """ +import libnx/types +""" + +search.proc_under = "proc __" +replace.proc_under = "proc DU" + +[ipc.nim] +search.o = "UINT32_MAX" +replace.o = "uint32.high" + +search.import = "import\n" +append.import = """ + libnx/types, +""" + +[audin.nim] +search.o = "import " +prepend.o = """ +import libnx/types +""" + +[audout.nim] +search.o = "import " +prepend.o = """ +import libnx/types +""" + +[hid.nim] +search.o = """ KEY_JOYCON_RIGHT = BIT(0), KEY_JOYCON_DOWN = BIT(1), KEY_JOYCON_UP = BIT(2), KEY_JOYCON_LEFT = BIT( + 3),""" +replace.o = "" + +search.key_left = "KEY_LEFT = KEY_DLEFT or KEY_LSTICK_LEFT or KEY_RSTICK_LEFT, ## /< D-Pad Left or Sticks Left" +replace.key_left = "" +search.key_rstick_up = " KEY_RSTICK_UP" +prepend.key_rstick_up = """ + KEY_LEFT = KEY_DLEFT.int or KEY_LSTICK_LEFT.int or KEY_RSTICK_LEFT.int, ## /< D-Pad Left or Sticks Left +""" + +search.key_right = " KEY_RIGHT = KEY_DRIGHT or KEY_LSTICK_RIGHT or KEY_RSTICK_RIGHT ## /< D-Pad Right or Sticks Right" +replace.key_right = "" +search.key_rstick_down = " KEY_RSTICK_DOWN" +prepend.key_rstick_down = """ + KEY_RIGHT = KEY_DRIGHT.int or KEY_LSTICK_RIGHT.int or KEY_RSTICK_RIGHT.int ## /< D-Pad Right or Sticks Right +""" + +search.key_up = " KEY_UP = KEY_DUP or KEY_LSTICK_UP or KEY_RSTICK_UP, ## /< D-Pad Up or Sticks Up" +replace.key_up = "" +search.key_rstick_right = " KEY_RSTICK_RIGHT" +prepend.key_rstick_right = """ + KEY_UP = KEY_DUP.int or KEY_LSTICK_UP.int or KEY_RSTICK_UP.int, ## /< D-Pad Up or Sticks Up +""" + +search.key_down = " KEY_DOWN = KEY_DDOWN or KEY_LSTICK_DOWN or KEY_RSTICK_DOWN, ## /< D-Pad Down or Sticks Down" +replace.key_down = "" +search.key_sl = " KEY_SL" +prepend.key_sl = """ + KEY_DOWN = KEY_DDOWN.int or KEY_LSTICK_DOWN.int or KEY_RSTICK_DOWN.int, ## /< D-Pad Down or Sticks Down +""" + +[nifm.nim] +search.o = "import libnx" +prepend.o = """ +import libnx/types +""" + +[set.nim] +search.o = "import libnx" +prepend.o = """ +import libnx/types +""" + +[parcel.nim] +search.o = "import libnx" +prepend.o = """ +import libnx/types +""" + +[fs_dev.nim] +search.o = "import libnx" +prepend.o = """ +import libnx/types +""" + +[buffer_producer.nim] +search.o = "import libnx" +prepend.o = """ +import libnx/types +import libnx/binder +""" + +[nxlink.nim] +search.o = "var __nxlink" +replace.o = "var DUnxlink"