159 lines
3.2 KiB
Lua
159 lines
3.2 KiB
Lua
local bit = require('bit')
|
|
local ffi = require('ffi')
|
|
|
|
local unsign_i64 = ffi.typeof('uint64_t')
|
|
|
|
local div = {}
|
|
|
|
local le = {}
|
|
local lt = {}
|
|
local ge = {}
|
|
local gt = {}
|
|
|
|
local band = {}
|
|
local bor = {}
|
|
local bxor = {}
|
|
local bnot = {}
|
|
|
|
local shl = {}
|
|
local shr = {}
|
|
|
|
local extend = {}
|
|
local wrap = {}
|
|
|
|
local load = {}
|
|
local store = {}
|
|
|
|
-- Helper functions
|
|
local function unsign_i32(x)
|
|
if x < 0 then x = x + 0x100000000 end
|
|
|
|
return x
|
|
end
|
|
|
|
local function rip_u64(x) return bit.band(bit.rshift(x, 32), 0xFFFFFFFF), bit.band(x, 0xFFFFFFFF) end
|
|
|
|
local function merge_u64(hi, lo) return bit.bor(bit.lshift(hi, 32), lo) end
|
|
|
|
-- Runtime functions
|
|
local function grow_page_num(memory, num)
|
|
local old = memory.min
|
|
local new = old + num
|
|
|
|
if memory.max and new > memory.max then
|
|
return -1
|
|
else
|
|
memory.min = new
|
|
|
|
return old
|
|
end
|
|
end
|
|
|
|
function div.i32(lhs, rhs)
|
|
if rhs == 0 then error('division by zero') end
|
|
|
|
return math.floor(lhs / rhs)
|
|
end
|
|
|
|
function le.u32(lhs, rhs) return unsign_i32(lhs) <= unsign_i32(rhs) and 1 or 0 end
|
|
|
|
function lt.u32(lhs, rhs) return unsign_i32(lhs) < unsign_i32(rhs) and 1 or 0 end
|
|
|
|
function ge.u32(lhs, rhs) return unsign_i32(lhs) >= unsign_i32(rhs) and 1 or 0 end
|
|
|
|
function gt.u32(lhs, rhs) return unsign_i32(lhs) > unsign_i32(rhs) and 1 or 0 end
|
|
|
|
function le.u64(lhs, rhs) return unsign_i64(lhs) <= unsign_i64(rhs) and 1 or 0 end
|
|
|
|
function lt.u64(lhs, rhs) return unsign_i64(lhs) < unsign_i64(rhs) and 1 or 0 end
|
|
|
|
function ge.u64(lhs, rhs) return unsign_i64(lhs) >= unsign_i64(rhs) and 1 or 0 end
|
|
|
|
function gt.u64(lhs, rhs) return unsign_i64(lhs) > unsign_i64(rhs) and 1 or 0 end
|
|
|
|
band.i32 = bit.band
|
|
bor.i32 = bit.bor
|
|
bxor.i32 = bit.bxor
|
|
bnot.i32 = bit.bnot
|
|
band.i64 = bit.band
|
|
bor.i64 = bit.bor
|
|
bxor.i64 = bit.bxor
|
|
bnot.i64 = bit.bnot
|
|
|
|
shl.u32 = bit.lshift
|
|
shr.u32 = bit.rshift
|
|
shl.i32 = bit.lshift
|
|
shr.i32 = bit.rshift
|
|
shl.u64 = bit.lshift
|
|
shr.u64 = bit.rshift
|
|
shl.i64 = bit.lshift
|
|
shr.i64 = bit.rshift
|
|
|
|
extend.i32_u64 = ffi.typeof('int64_t')
|
|
|
|
wrap.i64_i32 = ffi.typeof('int32_t')
|
|
|
|
function load.i32(memory, addr)
|
|
if addr % 4 ~= 0 then error('unaligned read') end
|
|
|
|
return memory.data[addr / 4] or 0
|
|
end
|
|
|
|
function load.i32_u8(memory, addr)
|
|
local value = load.i32(memory, addr)
|
|
|
|
return bit.band(value, 0xFF)
|
|
end
|
|
|
|
function load.i64(memory, addr)
|
|
if addr % 4 ~= 0 then error('unaligned read') end
|
|
|
|
local hi = memory.data[addr / 4 + 1] or 0
|
|
local lo = memory.data[addr / 4] or 0
|
|
|
|
return merge_u64(hi, lo)
|
|
end
|
|
|
|
function store.i32(memory, addr, value)
|
|
if addr % 4 ~= 0 then error('unaligned write') end
|
|
|
|
memory.data[addr / 4] = value
|
|
end
|
|
|
|
function store.i32_n8(memory, addr, value)
|
|
if addr % 4 ~= 0 then error('unaligned write') end
|
|
|
|
local old = bit.band(memory.data[addr / 4] or 0, 0xFFFFFF00)
|
|
local new = bit.band(value, 0xFF)
|
|
|
|
memory.data[addr / 4] = bit.bor(old, new)
|
|
end
|
|
|
|
function store.i64(memory, addr, value)
|
|
if addr % 4 ~= 0 then error('unaligned write') end
|
|
|
|
local hi, lo = rip_u64(value)
|
|
|
|
memory.data[addr / 4] = lo
|
|
memory.data[addr / 4 + 1] = hi
|
|
end
|
|
|
|
return {
|
|
grow_page_num = grow_page_num,
|
|
div = div,
|
|
le = le,
|
|
lt = lt,
|
|
ge = ge,
|
|
gt = gt,
|
|
band = band,
|
|
bor = bor,
|
|
bxor = bxor,
|
|
bnot = bnot,
|
|
shl = shl,
|
|
shr = shr,
|
|
extend = extend,
|
|
wrap = wrap,
|
|
load = load,
|
|
store = store,
|
|
}
|