From 142adb1a6ccb7d37831c48e99a066440efcd8c87 Mon Sep 17 00:00:00 2001 From: Dmitrii Fedorov Date: Thu, 24 Sep 2026 11:47:12 -0300 Subject: [PATCH] fix(specs): make 36 specs compile under the current t27 compiler These .t27 files failed to parse, so the t27 compiler produced no target for them and the Queen board (t27.ai/queen, Specs) listed them as Broken. The syntax is translated to t27 (Zig/Rust idioms, old test style, typos such as 'expect(a;);', stray braces); declarations, tests, invariants, benches, assertions and constants are kept. Every file now passes all seven targets (c, js, rust, ts, verilog, verilog_hir, zig) of the compiler built from gHashTag/t27 master a103752, and t27c gen / gen-c / gen-rust / gen-verilog. Co-Authored-By: Claude Opus 5.5 --- specs/fpga/avs_controller_48.t27 | 211 ++++----- specs/fpga/avs_controller_96.t27 | 221 +++++----- specs/fpga/avs_reconf.t27 | 213 ++++----- specs/fpga/dfs_gate.t27 | 221 +++++----- specs/fpga/drowsy_ret.t27 | 311 +++++++------- specs/fpga/fbb_active_path.t27 | 280 ++++++------ specs/fpga/fp8_e4m3.t27 | 459 ++++++++++---------- specs/fpga/fp8_e5m2.t27 | 621 ++++++++++++++------------- specs/fpga/gf128.t27 | 9 +- specs/fpga/gf16_to_fp16.t27 | 210 ++++----- specs/fpga/gf16_to_posit16.t27 | 243 +++++------ specs/fpga/gf256.t27 | 32 +- specs/fpga/gf32_to_fp32.t27 | 245 ++++++----- specs/fpga/holo_mux_x4.t27 | 210 ++++----- specs/fpga/int4.t27 | 59 ++- specs/fpga/int8.t27 | 141 ++++-- specs/fpga/lane_l_precheck.t27 | 187 ++++---- specs/fpga/lut_npu_81_entry.t27 | 155 +++---- specs/fpga/nf4.t27 | 34 +- specs/fpga/null_pe.t27 | 227 +++++----- specs/fpga/posit16.t27 | 376 ++++++++-------- specs/fpga/purkinje_thermal_gate.t27 | 259 ++++++----- specs/fpga/sparse_mask.t27 | 275 ++++++------ specs/fpga/sparse_skip.t27 | 222 +++++----- specs/fpga/spec_exit.t27 | 191 ++++---- specs/fpga/stoch_round.t27 | 269 ++++++------ specs/fpga/subth_clk.t27 | 160 +++---- specs/numeric/formats.t27 | 78 ++-- specs/numeric/gf128.t27 | 113 +++-- specs/numeric/gf256.t27 | 166 +++---- specs/numeric/gf64.t27 | 394 ++++++++--------- specs/numeric/goldenfloat_family.t27 | 25 +- specs/numeric/int4.t27 | 429 +++++++++--------- specs/numeric/int8.t27 | 595 +++++++++++++------------ specs/numeric/nf4.t27 | 459 ++++++++++---------- specs/numeric/tri_net_formats.t27 | 44 +- 36 files changed, 4279 insertions(+), 4065 deletions(-) diff --git a/specs/fpga/avs_controller_48.t27 b/specs/fpga/avs_controller_48.t27 index c528b27..916b688 100644 --- a/specs/fpga/avs_controller_48.t27 +++ b/specs/fpga/avs_controller_48.t27 @@ -64,6 +64,14 @@ pub const AvsStatus = struct { fault_code : u8, } +// Named form of the anonymous `struct { opcode, level, reserved }` that +// decode_avs_48_cmd returns (same fields, same types). +pub const Avs48Cmd = struct { + opcode : u8, + level : u8, + reserved : u8, +} + pub const AvsConfig = struct { mode : AvsMode, min_mv : u16, @@ -131,7 +139,7 @@ pub fn avs_voltage_in_hysteresis(current_mv: u16, target_mv: u16, hysteresis_mv: // avs_should_adjust(current_mv: u16, target_mv: u16, hysteresis_mv: u16) -> bool // Check if voltage should be adjusted pub fn avs_should_adjust(current_mv: u16, target_mv: u16, hysteresis_mv: u16) -> bool { - return not avs_voltage_in_hysteresis(current_mv, target_mv, hysteresis_mv); + return !avs_voltage_in_hysteresis(current_mv, target_mv, hysteresis_mv); } // ============================================================================ @@ -284,7 +292,7 @@ pub fn avs_control_pin_for_bit(bit_index: u8) -> u8 { // encode_avs_48_cmd(opcode: u8, level: u8, reserved: u8) -> u16 // Encode AVS 48-pin command -pub fn encode_avs_48_cmd(opcode: u8, level: u8, reserved: u8) u16 { +pub fn encode_avs_48_cmd(opcode: u8, level: u8, reserved: u8) -> u16 { // Format: [OP:8][LEVEL:6][RES:2] const op_field : u16 = @as(u16, opcode) << 8; const level_field : u16 = @as(u16, level & 0x3F) << 2; @@ -294,11 +302,11 @@ pub fn encode_avs_48_cmd(opcode: u8, level: u8, reserved: u8) u16 { // decode_avs_48_cmd(encoded: u16) -> struct { opcode: u8, level: u8, reserved: u8 } // Decode AVS 48-pin command -pub fn decode_avs_48_cmd(encoded: u16) -> struct { opcode: u8, level: u8, reserved: u8 } { +pub fn decode_avs_48_cmd(encoded: u16) -> Avs48Cmd { const opcode : u8 = @as(u8, @truncate((encoded >> 8) & 0xFF)); const level : u8 = @as(u8, @truncate((encoded >> 2) & 0x3F)); const reserved : u8 = @as(u8, @truncate(encoded & 0x03)); - return .{ .opcode = opcode, .level = level, .reserved = reserved }; + return Avs48Cmd{ .opcode = opcode, .level = level, .reserved = reserved }; } // ============================================================================ @@ -306,204 +314,203 @@ pub fn decode_avs_48_cmd(encoded: u16) -> struct { opcode: u8, level: u8, reserv // ============================================================================ test "pins_48_constant" { - try std.testing.expect(PINS_48 == 48); + assert(PINS_48 == 48); } test "voltage_constants" { - try std.testing.expect(VOLTAGE_MIN_MV == 800); - try std.testing.expect(VOLTAGE_MAX_MV == 1200); - try std.testing.expect(VOLTAGE_STEP_MV == 10); - try std.testing.expect(VOLTAGE_LEVELS == 41); + assert(VOLTAGE_MIN_MV == 800); + assert(VOLTAGE_MAX_MV == 1200); + assert(VOLTAGE_STEP_MV == 10); + assert(VOLTAGE_LEVELS == 41); } test "target_voltage_constant" { - try std.testing.expect(TARGET_MV == 1000); + assert(TARGET_MV == 1000); } test "control_pin_constants" { - try std.testing.expect(CONTROL_PIN_OFFSET == 16); - try std.testing.expect(CONTROL_PIN_COUNT == 6); + assert(CONTROL_PIN_OFFSET == 16); + assert(CONTROL_PIN_COUNT == 6); } test "avs_voltage_from_level_zero" { - try std.testing.expect(avs_voltage_from_level(0) == VOLTAGE_MIN_MV); + assert(avs_voltage_from_level(0) == VOLTAGE_MIN_MV); } test "avs_voltage_from_level_max" { - given max_level = VOLTAGE_LEVELS - 1 - try std.testing.expect(avs_voltage_from_level(max_level) == VOLTAGE_MAX_MV); + const max_level = VOLTAGE_LEVELS - 1; + assert(avs_voltage_from_level(max_level) == VOLTAGE_MAX_MV); } test "avs_voltage_from_level_target" { - given level = avs_level_from_voltage(TARGET_MV) - try std.testing.expect(avs_voltage_from_level(level) == TARGET_MV); + const level = avs_level_from_voltage(TARGET_MV); + assert(avs_voltage_from_level(level) == TARGET_MV); } test "avs_level_from_voltage_min" { - try std.testing.expect(avs_level_from_voltage(VOLTAGE_MIN_MV) == 0); + assert(avs_level_from_voltage(VOLTAGE_MIN_MV) == 0); } test "avs_level_from_voltage_max" { - try std.testing.expect(avs_level_from_voltage(VOLTAGE_MAX_MV) == VOLTAGE_LEVELS - 1); + assert(avs_level_from_voltage(VOLTAGE_MAX_MV) == VOLTAGE_LEVELS - 1); } test "avs_level_from_voltage_clamp_low" { - try std.testing.expect(avs_level_from_voltage(700) == 0); + assert(avs_level_from_voltage(700) == 0); } test "avs_level_from_voltage_clamp_high" { - try std.testing.expect(avs_level_from_voltage(1500) == VOLTAGE_LEVELS - 1); + assert(avs_level_from_voltage(1500) == VOLTAGE_LEVELS - 1); } test "avs_control_code_from_level_zero" { - try std.testing.expect(avs_control_code_from_level(0) == 0); + assert(avs_control_code_from_level(0) == 0); } test "avs_control_code_from_level_max" { - given code = avs_control_code_from_level(63) - try std.testing.expect(code == 63); + const code = avs_control_code_from_level(63); + assert(code == 63); } test "avs_control_code_from_level_clamp" { - given code = avs_control_code_from_level(100) - try std.testing.expect(code == 36 // 100 & 0x3F); + const code = avs_control_code_from_level(100); + assert(code == 36); // 100 & 0x3F } test "avs_level_from_control_code_roundtrip" { - given level = 20 - try std.testing.expect(code = avs_control_code_from_level(level)); - try std.testing.expect(decoded = avs_level_from_control_code(code)); - try std.testing.expect(decoded == level); + const level = 20; + const code = avs_control_code_from_level(level); + const decoded = avs_level_from_control_code(code); + assert(decoded == level); } test "avs_voltage_valid_in_range" { - try std.testing.expect(avs_voltage_valid(900) == true); - try std.testing.expect(avs_voltage_valid(1000) == true); - try std.testing.expect(avs_voltage_valid(1100) == true); + assert(avs_voltage_valid(900) == true); + assert(avs_voltage_valid(1000) == true); + assert(avs_voltage_valid(1100) == true); } test "avs_voltage_valid_out_of_range" { - try std.testing.expect(avs_voltage_valid(700) == false); - try std.testing.expect(avs_voltage_valid(1300) == false); + assert(avs_voltage_valid(700) == false); + assert(avs_voltage_valid(1300) == false); } test "avs_voltage_in_hysteresis_true" { - try std.testing.expect(avs_voltage_in_hysteresis(1000, 1000, 20) == true); - try std.testing.expect(avs_voltage_in_hysteresis(1015, 1000, 20) == true); - try std.testing.expect(avs_voltage_in_hysteresis(985, 1000, 20) == true); + assert(avs_voltage_in_hysteresis(1000, 1000, 20) == true); + assert(avs_voltage_in_hysteresis(1015, 1000, 20) == true); + assert(avs_voltage_in_hysteresis(985, 1000, 20) == true); } test "avs_voltage_in_hysteresis_false" { - try std.testing.expect(avs_voltage_in_hysteresis(1050, 1000, 20) == false); - try std.testing.expect(avs_voltage_in_hysteresis(950, 1000, 20) == false); + assert(avs_voltage_in_hysteresis(1050, 1000, 20) == false); + assert(avs_voltage_in_hysteresis(950, 1000, 20) == false); } test "avs_should_adjust_false_in_hysteresis" { - try std.testing.expect(avs_should_adjust(1010, 1000, 20) == false); + assert(avs_should_adjust(1010, 1000, 20) == false); } test "avs_should_adjust_true_out_of_hysteresis" { - try std.testing.expect(avs_should_adjust(1050, 1000, 20) == true); + assert(avs_should_adjust(1050, 1000, 20) == true); } test "avs_config_init_structure" { - given config = avs_config_init() - try std.testing.expect(config.mode == AvsMode.automatic); - try std.testing.expect(config.target_mv == TARGET_MV); - try std.testing.expect(config.hysteresis_mv == HYSTERESIS_MV); + const config = avs_config_init(); + assert(config.mode == AvsMode.automatic); + assert(config.target_mv == TARGET_MV); + assert(config.hysteresis_mv == HYSTERESIS_MV); } test "avs_config_manual_structure" { - given config = avs_config_manual(900) - try std.testing.expect(config.mode == AvsMode.manual); - try std.testing.expect(config.target_mv == 900); + const config = avs_config_manual(900); + assert(config.mode == AvsMode.manual); + assert(config.target_mv == 900); } test "avs_config_adaptive_structure" { - given config = avs_config_adaptive(850, 1150) - try std.testing.expect(config.mode == AvsMode.adaptive); - try std.testing.expect(config.min_mv == 850); - try std.testing.expect(config.max_mv == 1150); + const config = avs_config_adaptive(850, 1150); + assert(config.mode == AvsMode.adaptive); + assert(config.min_mv == 850); + assert(config.max_mv == 1150); } test "avs_status_init_structure" { - given status = avs_status_init() - try std.testing.expect(status.state == AvsState.disabled); - try std.testing.expect(status.current_mv == VOLTAGE_MIN_MV); + const status = avs_status_init(); + assert(status.state == AvsState.disabled); + assert(status.current_mv == VOLTAGE_MIN_MV); } test "avs_status_enable" { - given status = avs_status_init() - try std.testing.expect(config = avs_config_init()); - try std.testing.expect(result = avs_status_enable(status, config)); - try std.testing.expect(result.state == AvsState.enabled); - try std.testing.expect(result.mode == AvsMode.automatic); + const status = avs_status_init(); + const config = avs_config_init(); + const result = avs_status_enable(status, config); + assert(result.state == AvsState.enabled); + assert(result.mode == AvsMode.automatic); } test "avs_status_adjust" { - given status = avs_status_init() - try std.testing.expect(result = avs_status_adjust(status, 10)); - try std.testing.expect(result.state == AvsState.adjusting); - try std.testing.expect(result.level == 10); + const status = avs_status_init(); + const result = avs_status_adjust(status, 10); + assert(result.state == AvsState.adjusting); + assert(result.level == 10); } test "avs_status_settled" { - given status = avs_status_init() - try std.testing.expect(result = avs_status_settled(status, 1000)); - try std.testing.expect(result.state == AvsState.settled); - try std.testing.expect(result.current_mv == 1000); + const status = avs_status_init(); + const result = avs_status_settled(status, 1000); + assert(result.state == AvsState.settled); + assert(result.current_mv == 1000); } test "avs_status_fault" { - given status = avs_status_init() - try std.testing.expect(result = avs_status_fault(status, 1)); - try std.testing.expect(result.state == AvsState.fault); - try std.testing.expect(result.fault_code == 1); + const status = avs_status_init(); + const result = avs_status_fault(status, 1); + assert(result.state == AvsState.fault); + assert(result.fault_code == 1); } test "avs_control_pins_start" { - try std.testing.expect(avs_control_pins_start() == CONTROL_PIN_OFFSET); + assert(avs_control_pins_start() == CONTROL_PIN_OFFSET); } test "avs_control_pins_end" { - try std.testing.expect(avs_control_pins_end() == CONTROL_PIN_OFFSET + CONTROL_PIN_COUNT - 1); + assert(avs_control_pins_end() == CONTROL_PIN_OFFSET + CONTROL_PIN_COUNT - 1); } test "avs_is_control_pin_true" { - try std.testing.expect(avs_is_control_pin(16) == true); - try std.testing.expect(avs_is_control_pin(21) == true); + assert(avs_is_control_pin(16) == true); + assert(avs_is_control_pin(21) == true); } test "avs_is_control_pin_false" { - try std.testing.expect(avs_is_control_pin(15) == false); - try std.testing.expect(avs_is_control_pin(22) == false); + assert(avs_is_control_pin(15) == false); + assert(avs_is_control_pin(22) == false); } test "avs_control_pin_for_bit" { - try std.testing.expect(avs_control_pin_for_bit(0) == CONTROL_PIN_OFFSET); - try std.testing.expect(avs_control_pin_for_bit(5) == CONTROL_PIN_OFFSET + 5); + assert(avs_control_pin_for_bit(0) == CONTROL_PIN_OFFSET); + assert(avs_control_pin_for_bit(5) == CONTROL_PIN_OFFSET + 5); } test "avs_control_pin_for_bit_clamp" { - try std.testing.expect(avs_control_pin_for_bit(10) == CONTROL_PIN_OFFSET); + assert(avs_control_pin_for_bit(10) == CONTROL_PIN_OFFSET); } test "encode_avs_48_cmd" { - given encoded = encode_avs_48_cmd(0x10, 20, 0) - try std.testing.expect((encoded >> 8) == 0x10); + const encoded = encode_avs_48_cmd(0x10, 20, 0); + assert((encoded >> 8) == 0x10); } test "decode_avs_48_cmd" { - given decoded = decode_avs_48_cmd(0x1050) - try std.testing.expect(decoded.opcode == 0x10); - try std.testing.expect(decoded.level == 20); + const decoded = decode_avs_48_cmd(0x1050); + assert(decoded.opcode == 0x10); + assert(decoded.level == 20); } // ============================================================================ // Invariants // ============================================================================ -} invariant voltage_range_positive assert VOLTAGE_MIN_MV > 0 and VOLTAGE_MAX_MV > VOLTAGE_MIN_MV @@ -511,7 +518,7 @@ invariant voltage_step_positive assert VOLTAGE_STEP_MV > 0 invariant voltage_levels_calculated - try std.testing.expect(VOLTAGE_LEVELS == ((VOLTAGE_MAX_MV - VOLTAGE_MIN_MV) / VOLTAGE_STEP_MV) + 1); + assert VOLTAGE_LEVELS == ((VOLTAGE_MAX_MV - VOLTAGE_MIN_MV) / VOLTAGE_STEP_MV) + 1 invariant target_voltage_in_range assert avs_voltage_valid(TARGET_MV) @@ -527,36 +534,36 @@ invariant control_pin_count_six invariant avs_voltage_from_level_roundtrip given level = 15 - try std.testing.expect(voltage = avs_voltage_from_level(level)); - try std.testing.expect(result_level = avs_level_from_voltage(voltage)); - try std.testing.expect(result_level == level); + and voltage = avs_voltage_from_level(level) + and result_level = avs_level_from_voltage(voltage) + then result_level == level invariant avs_voltage_in_hysteresis_exact - try std.testing.expect(avs_voltage_in_hysteresis(TARGET_MV, TARGET_MV, 0) == true); + assert avs_voltage_in_hysteresis(TARGET_MV, TARGET_MV, 0) == true invariant avs_should_adjust_false_at_exact_target - try std.testing.expect(avs_should_adjust(TARGET_MV, TARGET_MV, HYSTERESIS_MV) == false); + assert avs_should_adjust(TARGET_MV, TARGET_MV, HYSTERESIS_MV) == false invariant avs_status_init_disabled given status = avs_status_init() - try std.testing.expect(status.state == AvsState.disabled); + then status.state == AvsState.disabled invariant avs_status_enable_sets_mode given status = avs_status_init() - try std.testing.expect(config = avs_config_manual(950)); - try std.testing.expect(result = avs_status_enable(status, config)); - try std.testing.expect(result.mode == AvsMode.manual); + and config = avs_config_manual(950) + and result = avs_status_enable(status, config) + then result.mode == AvsMode.manual invariant avs_status_adjust_changes_level given status = avs_status_init() - try std.testing.expect(result = avs_status_adjust(status, 25)); - try std.testing.expect(result.level == 25); + and result = avs_status_adjust(status, 25) + then result.level == 25 invariant avs_is_control_pin_monotonic - try std.testing.expect(avs_control_pin_for_bit(3) > avs_control_pin_for_bit(2)); + assert avs_control_pin_for_bit(3) > avs_control_pin_for_bit(2) invariant avs_control_pin_for_bit_start_at_offset - try std.testing.expect(avs_control_pin_for_bit(0) == CONTROL_PIN_OFFSET); + assert avs_control_pin_for_bit(0) == CONTROL_PIN_OFFSET // ============================================================================ // Benchmarks diff --git a/specs/fpga/avs_controller_96.t27 b/specs/fpga/avs_controller_96.t27 index 16b47c6..cdbcaa1 100644 --- a/specs/fpga/avs_controller_96.t27 +++ b/specs/fpga/avs_controller_96.t27 @@ -83,6 +83,14 @@ pub const AvsStatus = struct { calibration_complete : bool, } +// Named form of the anonymous `struct { opcode, level, channel }` that +// decode_avs_96_cmd returns (same fields, same types). +pub const Avs96Cmd = struct { + opcode : u8, + level : u8, + channel : u8, +} + pub const AvsConfig = struct { mode : AvsMode, min_mv : u16, @@ -150,7 +158,7 @@ pub fn avs_voltage_in_hysteresis(current_mv: u16, target_mv: u16, hysteresis_mv: // avs_should_adjust(current_mv: u16, target_mv: u16, hysteresis_mv: u16) -> bool // Check if voltage should be adjusted pub fn avs_should_adjust(current_mv: u16, target_mv: u16, hysteresis_mv: u16) -> bool { - return not avs_voltage_in_hysteresis(current_mv, target_mv, hysteresis_mv); + return !avs_voltage_in_hysteresis(current_mv, target_mv, hysteresis_mv); } // ============================================================================ @@ -385,7 +393,7 @@ pub fn avs_control_pin_for_bit(bit_index: u8, channel: AvsChannel) -> u8 { // encode_avs_96_cmd(opcode: u8, level: u8, channel: u8) -> u16 // Encode AVS 96-pin command -pub fn encode_avs_96_cmd(opcode: u8, level: u8, channel: u8) u16 { +pub fn encode_avs_96_cmd(opcode: u8, level: u8, channel: u8) -> u16 { // Format: [OP:8][LEVEL:7][CHANNEL:1] const op_field : u16 = @as(u16, opcode) << 8; const level_field : u16 = @as(u16, level & 0x7F) << 1; @@ -395,11 +403,11 @@ pub fn encode_avs_96_cmd(opcode: u8, level: u8, channel: u8) u16 { // decode_avs_96_cmd(encoded: u16) -> struct { opcode: u8, level: u8, channel: u8 } // Decode AVS 96-pin command -pub fn decode_avs_96_cmd(encoded: u16) -> struct { opcode: u8, level: u8, channel: u8 } { +pub fn decode_avs_96_cmd(encoded: u16) -> Avs96Cmd { const opcode : u8 = @as(u8, @truncate((encoded >> 8) & 0xFF)); const level : u8 = @as(u8, @truncate((encoded >> 1) & 0x7F)); const channel : u8 = @as(u8, @truncate(encoded & 0x01)); - return .{ .opcode = opcode, .level = level, .channel = channel }; + return Avs96Cmd{ .opcode = opcode, .level = level, .channel = channel }; } // ============================================================================ @@ -407,23 +415,23 @@ pub fn decode_avs_96_cmd(encoded: u16) -> struct { opcode: u8, level: u8, channe // ============================================================================ test "pins_96_constant" { - try std.testing.expect(PINS_96 == 96); + assert(PINS_96 == 96); } test "voltage_constants" { - try std.testing.expect(VOLTAGE_MIN_MV == 700); - try std.testing.expect(VOLTAGE_MAX_MV == 1300); - try std.testing.expect(VOLTAGE_STEP_MV == 5); - try std.testing.expect(VOLTAGE_LEVELS == 121); + assert(VOLTAGE_MIN_MV == 700); + assert(VOLTAGE_MAX_MV == 1300); + assert(VOLTAGE_STEP_MV == 5); + assert(VOLTAGE_LEVELS == 121); } test "target_voltage_constant" { - try std.testing.expect(TARGET_MV == 1000); + assert(TARGET_MV == 1000); } test "control_pin_constants" { - try std.testing.expect(CONTROL_PIN_OFFSET == 64); - try std.testing.expect(CONTROL_PIN_COUNT == 7); + assert(CONTROL_PIN_OFFSET == 64); + assert(CONTROL_PIN_COUNT == 7); } test "dual_channel_constant" { @@ -431,202 +439,201 @@ test "dual_channel_constant" { } test "avs_voltage_from_level_zero" { - try std.testing.expect(avs_voltage_from_level(0) == VOLTAGE_MIN_MV); + assert(avs_voltage_from_level(0) == VOLTAGE_MIN_MV); } test "avs_voltage_from_level_max" { - given max_level = VOLTAGE_LEVELS - 1 - try std.testing.expect(avs_voltage_from_level(max_level) == VOLTAGE_MAX_MV); + const max_level = VOLTAGE_LEVELS - 1; + assert(avs_voltage_from_level(max_level) == VOLTAGE_MAX_MV); } test "avs_level_from_voltage_target" { - given level = avs_level_from_voltage(TARGET_MV) - try std.testing.expect(avs_voltage_from_level(level) == TARGET_MV); + const level = avs_level_from_voltage(TARGET_MV); + assert(avs_voltage_from_level(level) == TARGET_MV); } test "avs_level_from_voltage_clamp_low" { - try std.testing.expect(avs_level_from_voltage(600) == 0); + assert(avs_level_from_voltage(600) == 0); } test "avs_level_from_voltage_clamp_high" { - try std.testing.expect(avs_level_from_voltage(1500) == VOLTAGE_LEVELS - 1); + assert(avs_level_from_voltage(1500) == VOLTAGE_LEVELS - 1); } test "avs_control_code_from_level_max" { - given code = avs_control_code_from_level(127) - try std.testing.expect(code == 127); + const code = avs_control_code_from_level(127); + assert(code == 127); } test "avs_control_code_from_level_clamp" { - given code = avs_control_code_from_level(200) - try std.testing.expect(code == 72 // 200 & 0x7F); + const code = avs_control_code_from_level(200); + assert(code == 72); // 200 & 0x7F } test "avs_level_from_control_code_roundtrip" { - given level = 50 - try std.testing.expect(code = avs_control_code_from_level(level)); - try std.testing.expect(decoded = avs_level_from_control_code(code)); - try std.testing.expect(decoded == level); + const level = 50; + const code = avs_control_code_from_level(level); + const decoded = avs_level_from_control_code(code); + assert(decoded == level); } test "avs_voltage_valid_in_range" { - try std.testing.expect(avs_voltage_valid(750) == true); - try std.testing.expect(avs_voltage_valid(1000) == true); - try std.testing.expect(avs_voltage_valid(1250) == true); + assert(avs_voltage_valid(750) == true); + assert(avs_voltage_valid(1000) == true); + assert(avs_voltage_valid(1250) == true); } test "avs_voltage_valid_out_of_range" { - try std.testing.expect(avs_voltage_valid(600) == false); - try std.testing.expect(avs_voltage_valid(1400) == false); + assert(avs_voltage_valid(600) == false); + assert(avs_voltage_valid(1400) == false); } test "avs_voltage_in_hysteresis_true" { - try std.testing.expect(avs_voltage_in_hysteresis(1000, 1000, 15) == true); - try std.testing.expect(avs_voltage_in_hysteresis(1010, 1000, 15) == true); - try std.testing.expect(avs_voltage_in_hysteresis(990, 1000, 15) == true); + assert(avs_voltage_in_hysteresis(1000, 1000, 15) == true); + assert(avs_voltage_in_hysteresis(1010, 1000, 15) == true); + assert(avs_voltage_in_hysteresis(990, 1000, 15) == true); } test "avs_voltage_in_hysteresis_false" { - try std.testing.expect(avs_voltage_in_hysteresis(1030, 1000, 15) == false); - try std.testing.expect(avs_voltage_in_hysteresis(970, 1000, 15) == false); + assert(avs_voltage_in_hysteresis(1030, 1000, 15) == false); + assert(avs_voltage_in_hysteresis(970, 1000, 15) == false); } test "avs_config_init_structure" { - given config = avs_config_init() - try std.testing.expect(config.mode == AvsMode.automatic); - try std.testing.expect(config.target_mv == TARGET_MV); - try std.testing.expect(config.enable_dual_channel == false); + const config = avs_config_init(); + assert(config.mode == AvsMode.automatic); + assert(config.target_mv == TARGET_MV); + assert(config.enable_dual_channel == false); } test "avs_config_dual_structure" { - given config = avs_config_dual(950, 1050) - try std.testing.expect(config.mode == AvsMode.dual_independent); - try std.testing.expect(config.enable_dual_channel == true); + const config = avs_config_dual(950, 1050); + assert(config.mode == AvsMode.dual_independent); + assert(config.enable_dual_channel == true); } test "avs_channel_init_structure" { - given channel = avs_channel_init(AvsChannel.channel0) - try std.testing.expect(channel.channel == AvsChannel.channel0); - try std.testing.expect(channel.enabled == false); + const channel = avs_channel_init(AvsChannel.channel0); + assert(channel.channel == AvsChannel.channel0); + assert(channel.enabled == false); } test "avs_channel_enable" { - given channel = avs_channel_init(AvsChannel.channel0) - try std.testing.expect(result = avs_channel_enable(channel, 950)); - try std.testing.expect(result.enabled == true); - try std.testing.expect(result.target_mv == 950); + const channel = avs_channel_init(AvsChannel.channel0); + const result = avs_channel_enable(channel, 950); + assert(result.enabled == true); + assert(result.target_mv == 950); } test "avs_channel_adjust" { - given channel = avs_channel_init(AvsChannel.channel0) - try std.testing.expect(result = avs_channel_adjust(channel, 30)); - try std.testing.expect(result.level == 30); + const channel = avs_channel_init(AvsChannel.channel0); + const result = avs_channel_adjust(channel, 30); + assert(result.level == 30); } test "avs_status_init_structure" { - given status = avs_status_init() - try std.testing.expect(status.state == AvsState.disabled); - try std.testing.expect(status.calibration_complete == false); + const status = avs_status_init(); + assert(status.state == AvsState.disabled); + assert(status.calibration_complete == false); } test "avs_status_enable" { - given status = avs_status_init() - try std.testing.expect(config = avs_config_init()); - try std.testing.expect(result = avs_status_enable(status, config)); - try std.testing.expect(result.state == AvsState.enabled); - try std.testing.expect(result.channel0.enabled == true); + const status = avs_status_init(); + const config = avs_config_init(); + const result = avs_status_enable(status, config); + assert(result.state == AvsState.enabled); + assert(result.channel0.enabled == true); } test "avs_status_enable_dual" { - given status = avs_status_init() - try std.testing.expect(config = avs_config_dual(950, 1050)); - try std.testing.expect(result = avs_status_enable(status, config)); - try std.testing.expect(result.channel0.enabled == true); - try std.testing.expect(result.channel1.enabled == true); + const status = avs_status_init(); + const config = avs_config_dual(950, 1050); + const result = avs_status_enable(status, config); + assert(result.channel0.enabled == true); + assert(result.channel1.enabled == true); } test "avs_status_calibrate" { - given status = avs_status_init() - try std.testing.expect(result = avs_status_calibrate(status)); - try std.testing.expect(result.state == AvsState.calibrating); - try std.testing.expect(result.calibration_complete == false); + const status = avs_status_init(); + const result = avs_status_calibrate(status); + assert(result.state == AvsState.calibrating); + assert(result.calibration_complete == false); } test "avs_status_calibration_complete" { - given status = avs_status_init() - try std.testing.expect(result = avs_status_calibration_complete(status)); - try std.testing.expect(result.calibration_complete == true); + const status = avs_status_init(); + const result = avs_status_calibration_complete(status); + assert(result.calibration_complete == true); } test "avs_control_pins_start" { - try std.testing.expect(avs_control_pins_start() == CONTROL_PIN_OFFSET); + assert(avs_control_pins_start() == CONTROL_PIN_OFFSET); } test "avs_control_pins_end" { - try std.testing.expect(avs_control_pins_end() == CONTROL_PIN_OFFSET + CONTROL_PIN_COUNT - 1); + assert(avs_control_pins_end() == CONTROL_PIN_OFFSET + CONTROL_PIN_COUNT - 1); } test "avs_control_pins_secondary_start" { - try std.testing.expect(avs_control_pins_secondary_start() == CONTROL_PIN_OFFSET + CONTROL_PIN_COUNT); + assert(avs_control_pins_secondary_start() == CONTROL_PIN_OFFSET + CONTROL_PIN_COUNT); } test "avs_is_control_pin_primary_true" { - try std.testing.expect(avs_is_control_pin_primary(64) == true); - try std.testing.expect(avs_is_control_pin_primary(70) == true); + assert(avs_is_control_pin_primary(64) == true); + assert(avs_is_control_pin_primary(70) == true); } test "avs_is_control_pin_primary_false" { - try std.testing.expect(avs_is_control_pin_primary(63) == false); - try std.testing.expect(avs_is_control_pin_primary(71) == false); + assert(avs_is_control_pin_primary(63) == false); + assert(avs_is_control_pin_primary(71) == false); } test "avs_is_control_pin_secondary_true" { - try std.testing.expect(avs_is_control_pin_secondary(71) == true); - try std.testing.expect(avs_is_control_pin_secondary(77) == true); + assert(avs_is_control_pin_secondary(71) == true); + assert(avs_is_control_pin_secondary(77) == true); } test "avs_is_control_pin_secondary_false" { - try std.testing.expect(avs_is_control_pin_secondary(70) == false); - try std.testing.expect(avs_is_control_pin_secondary(78) == false); + assert(avs_is_control_pin_secondary(70) == false); + assert(avs_is_control_pin_secondary(78) == false); } test "avs_is_control_pin_true" { - try std.testing.expect(avs_is_control_pin(64) == true); - try std.testing.expect(avs_is_control_pin(75) == true); + assert(avs_is_control_pin(64) == true); + assert(avs_is_control_pin(75) == true); } test "avs_is_control_pin_false" { - try std.testing.expect(avs_is_control_pin(63) == false); - try std.testing.expect(avs_is_control_pin(78) == false); + assert(avs_is_control_pin(63) == false); + assert(avs_is_control_pin(78) == false); } test "avs_control_pin_for_bit_primary" { - try std.testing.expect(avs_control_pin_for_bit(0, AvsChannel.channel0) == CONTROL_PIN_OFFSET); - try std.testing.expect(avs_control_pin_for_bit(6, AvsChannel.channel0) == CONTROL_PIN_OFFSET + 6); + assert(avs_control_pin_for_bit(0, AvsChannel.channel0) == CONTROL_PIN_OFFSET); + assert(avs_control_pin_for_bit(6, AvsChannel.channel0) == CONTROL_PIN_OFFSET + 6); } test "avs_control_pin_for_bit_secondary" { - try std.testing.expect(avs_control_pin_for_bit(0, AvsChannel.channel1) == avs_control_pins_secondary_start()); - try std.testing.expect(avs_control_pin_for_bit(6, AvsChannel.channel1) == avs_control_pins_secondary_start() + 6); + assert(avs_control_pin_for_bit(0, AvsChannel.channel1) == avs_control_pins_secondary_start()); + assert(avs_control_pin_for_bit(6, AvsChannel.channel1) == avs_control_pins_secondary_start() + 6); } test "encode_avs_96_cmd" { - given encoded = encode_avs_96_cmd(0x20, 30, 1) - try std.testing.expect((encoded >> 8) == 0x20); + const encoded = encode_avs_96_cmd(0x20, 30, 1); + assert((encoded >> 8) == 0x20); } test "decode_avs_96_cmd" { - given decoded = decode_avs_96_cmd(0x203D) - try std.testing.expect(decoded.opcode == 0x20); - try std.testing.expect(decoded.level == 30); - try std.testing.expect(decoded.channel == 1); + const decoded = decode_avs_96_cmd(0x203D); + assert(decoded.opcode == 0x20); + assert(decoded.level == 30); + assert(decoded.channel == 1); } // ============================================================================ // Invariants // ============================================================================ -} invariant voltage_range_positive assert VOLTAGE_MIN_MV > 0 and VOLTAGE_MAX_MV > VOLTAGE_MIN_MV @@ -634,7 +641,7 @@ invariant voltage_step_positive assert VOLTAGE_STEP_MV > 0 invariant voltage_levels_calculated - try std.testing.expect(VOLTAGE_LEVELS == ((VOLTAGE_MAX_MV - VOLTAGE_MIN_MV) / VOLTAGE_STEP_MV) + 1); + assert VOLTAGE_LEVELS == ((VOLTAGE_MAX_MV - VOLTAGE_MIN_MV) / VOLTAGE_STEP_MV) + 1 invariant target_voltage_in_range assert avs_voltage_valid(TARGET_MV) @@ -650,25 +657,25 @@ invariant dual_channel_enabled invariant avs_status_init_disabled given status = avs_status_init() - try std.testing.expect(status.state == AvsState.disabled); + then status.state == AvsState.disabled invariant avs_status_calibrate_sets_state given status = avs_status_init() - try std.testing.expect(result = avs_status_calibrate(status)); - try std.testing.expect(result.state == AvsState.calibrating); + and result = avs_status_calibrate(status) + then result.state == AvsState.calibrating invariant avs_is_control_pin_primary_excludes_secondary given pin = 70 // Last primary pin assert avs_is_control_pin_primary(pin) == true - try std.testing.expect(avs_is_control_pin_secondary(pin) == false); + then avs_is_control_pin_secondary(pin) == false invariant avs_is_control_pin_secondary_excludes_primary given pin = 71 // First secondary pin assert avs_is_control_pin_secondary(pin) == true - try std.testing.expect(avs_is_control_pin_primary(pin) == false); + then avs_is_control_pin_primary(pin) == false invariant avs_control_pin_for_bit_monotonic - try std.testing.expect(avs_control_pin_for_bit(3, AvsChannel.channel0) < avs_control_pin_for_bit(4, AvsChannel.channel0)); + assert avs_control_pin_for_bit(3, AvsChannel.channel0) < avs_control_pin_for_bit(4, AvsChannel.channel0) invariant avs_config_dual_enables_both_channels given config = avs_config_dual(950, 1050) diff --git a/specs/fpga/avs_reconf.t27 b/specs/fpga/avs_reconf.t27 index 61d90cf..6281592 100644 --- a/specs/fpga/avs_reconf.t27 +++ b/specs/fpga/avs_reconf.t27 @@ -187,10 +187,12 @@ pub fn avs_reconf_freq_valid(freq_khz: u32) -> bool { // avs_reconf_config_valid(config: ReconfConfig) -> bool // Check if config is valid pub fn avs_reconf_config_valid(config: ReconfConfig) -> bool { + // `and` continuation lines restored (they had been rewritten as + // `try std.testing.expect(...)` statements after the return). return avs_reconf_voltage_valid(config.voltage_mv) - try std.testing.expect(avs_reconf_freq_valid(config.freq_khz)); - try std.testing.expect(config.min_voltage_mv < config.max_voltage_mv); - try std.testing.expect(config.min_freq_khz < config.max_freq_khz;); + and avs_reconf_freq_valid(config.freq_khz) + and config.min_voltage_mv < config.max_voltage_mv + and config.min_freq_khz < config.max_freq_khz; } // ============================================================================ @@ -393,204 +395,203 @@ pub fn decode_avs_reconf_cmd(encoded: u32) -> struct { op: u8, param1: u16, para // ============================================================================ test "reconf_opcode_base" { - try std.testing.expect(RECONF_OPCODE_BASE == 0xF0); + assert(RECONF_OPCODE_BASE == 0xF0); } test "reconf_op_constants" { - try std.testing.expect(RECONF_OP_SET_VOLTAGE == 0); - try std.testing.expect(RECONF_OP_SET_FREQUENCY == 1); - try std.testing.expect(RECONF_OP_SET_MODE == 2); - try std.testing.expect(RECONF_OP_CALIBRATE == 7); + assert(RECONF_OP_SET_VOLTAGE == 0); + assert(RECONF_OP_SET_FREQUENCY == 1); + assert(RECONF_OP_SET_MODE == 2); + assert(RECONF_OP_CALIBRATE == 7); } test "reconf_mode_constants" { - try std.testing.expect(RECONF_MODE_MANUAL == 0); - try std.testing.expect(RECONF_MODE_PERFORMANCE == 2); - try std.testing.expect(RECONF_MODE_POWER_SAVING == 3); - try std.testing.expect(RECONF_MODE_ADAPTIVE == 4); + assert(RECONF_MODE_MANUAL == 0); + assert(RECONF_MODE_PERFORMANCE == 2); + assert(RECONF_MODE_POWER_SAVING == 3); + assert(RECONF_MODE_ADAPTIVE == 4); } test "reconf_state_constants" { - try std.testing.expect(RECONF_STATE_IDLE == 0); - try std.testing.expect(RECONF_STATE_BUSY == 1); - try std.testing.expect(RECONF_STATE_ERROR == 2); + assert(RECONF_STATE_IDLE == 0); + assert(RECONF_STATE_BUSY == 1); + assert(RECONF_STATE_ERROR == 2); } test "voltage_freq_constants" { - try std.testing.expect(VOLTAGE_MIN_MV == 700); - try std.testing.expect(VOLTAGE_MAX_MV == 1300); - try std.testing.expect(FREQ_MIN_KHZ == 10000); - try std.testing.expect(FREQ_MAX_KHZ == 200000); + assert(VOLTAGE_MIN_MV == 700); + assert(VOLTAGE_MAX_MV == 1300); + assert(FREQ_MIN_KHZ == 10000); + assert(FREQ_MAX_KHZ == 200000); } test "avs_reconf_config_init_structure" { - given config = avs_reconf_config_init() - try std.testing.expect(config.mode == ReconfMode.manual); - try std.testing.expect(config.voltage_mv == 1000); - try std.testing.expect(config.freq_khz == 100000); + const config = avs_reconf_config_init(); + assert(config.mode == ReconfMode.manual); + assert(config.voltage_mv == 1000); + assert(config.freq_khz == 100000); } test "avs_reconf_config_performance_structure" { - given config = avs_reconf_config_performance() - try std.testing.expect(config.mode == ReconfMode.performance); - try std.testing.expect(config.voltage_mv == VOLTAGE_MAX_MV); - try std.testing.expect(config.auto_scale == true); + const config = avs_reconf_config_performance(); + assert(config.mode == ReconfMode.performance); + assert(config.voltage_mv == VOLTAGE_MAX_MV); + assert(config.auto_scale == true); } test "avs_reconf_config_power_saving_structure" { - given config = avs_reconf_config_power_saving() - try std.testing.expect(config.mode == ReconfMode.power_saving); - try std.testing.expect(config.voltage_mv < 1000); - try std.testing.expect(config.auto_scale == true); + const config = avs_reconf_config_power_saving(); + assert(config.mode == ReconfMode.power_saving); + assert(config.voltage_mv < 1000); + assert(config.auto_scale == true); } test "avs_reconf_config_adaptive_structure" { - given config = avs_reconf_config_adaptive() - try std.testing.expect(config.mode == ReconfMode.adaptive); - try std.testing.expect(config.auto_scale == true); + const config = avs_reconf_config_adaptive(); + assert(config.mode == ReconfMode.adaptive); + assert(config.auto_scale == true); } test "avs_reconf_voltage_valid_true" { - try std.testing.expect(avs_reconf_voltage_valid(800) == true); - try std.testing.expect(avs_reconf_voltage_valid(1000) == true); - try std.testing.expect(avs_reconf_voltage_valid(1200) == true); + assert(avs_reconf_voltage_valid(800) == true); + assert(avs_reconf_voltage_valid(1000) == true); + assert(avs_reconf_voltage_valid(1200) == true); } test "avs_reconf_voltage_valid_false" { - try std.testing.expect(avs_reconf_voltage_valid(600) == false); - try std.testing.expect(avs_reconf_voltage_valid(1400) == false); + assert(avs_reconf_voltage_valid(600) == false); + assert(avs_reconf_voltage_valid(1400) == false); } test "avs_reconf_freq_valid_true" { - try std.testing.expect(avs_reconf_freq_valid(20000) == true); - try std.testing.expect(avs_reconf_freq_valid(100000) == true); - try std.testing.expect(avs_reconf_freq_valid(150000) == true); + assert(avs_reconf_freq_valid(20000) == true); + assert(avs_reconf_freq_valid(100000) == true); + assert(avs_reconf_freq_valid(150000) == true); } test "avs_reconf_freq_valid_false" { - try std.testing.expect(avs_reconf_freq_valid(5000) == false); - try std.testing.expect(avs_reconf_freq_valid(300000) == false); + assert(avs_reconf_freq_valid(5000) == false); + assert(avs_reconf_freq_valid(300000) == false); } test "avs_reconf_config_valid_true" { - given config = avs_reconf_config_init() - try std.testing.expect(avs_reconf_config_valid(config) == true); + const config = avs_reconf_config_init(); + assert(avs_reconf_config_valid(config) == true); } test "avs_reconf_config_valid_false" { - given config = ReconfConfig{.mode = ReconfMode.manual, .voltage_mv = 600, .freq_khz = 100000, .auto_scale = false, .min_voltage_mv = 700, .max_voltage_mv = 1300, .min_freq_khz = 10000, .max_freq_khz = 200000} - try std.testing.expect(avs_reconf_config_valid(config) == false); + const config = ReconfConfig{.mode = ReconfMode.manual, .voltage_mv = 600, .freq_khz = 100000, .auto_scale = false, .min_voltage_mv = 700, .max_voltage_mv = 1300, .min_freq_khz = 10000, .max_freq_khz = 200000}; + assert(avs_reconf_config_valid(config) == false); } test "avs_reconf_status_init_structure" { - given status = avs_reconf_status_init() - try std.testing.expect(status.state == ReconfState.idle); - try std.testing.expect(status.current_voltage_mv == VOLTAGE_MIN_MV); + const status = avs_reconf_status_init(); + assert(status.state == ReconfState.idle); + assert(status.current_voltage_mv == VOLTAGE_MIN_MV); } test "avs_reconf_status_start_op" { - given status = avs_reconf_status_init() - try std.testing.expect(result = avs_reconf_status_start_op(status, ReconfOp.set_voltage)); - try std.testing.expect(result.state == ReconfState.busy); - try std.testing.expect(result.last_op == ReconfOp.set_voltage); + const status = avs_reconf_status_init(); + const result = avs_reconf_status_start_op(status, ReconfOp.set_voltage); + assert(result.state == ReconfState.busy); + assert(result.last_op == ReconfOp.set_voltage); } test "avs_reconf_status_complete_success" { - given status = avs_reconf_status_init() - try std.testing.expect(result = avs_reconf_result_success(1000)); - try std.testing.expect(new_status = avs_reconf_status_complete(status, result)); - try std.testing.expect(new_status.state == ReconfState.idle); - try std.testing.expect(new_status.error_code == 0); + const status = avs_reconf_status_init(); + const result = avs_reconf_result_success(1000); + const new_status = avs_reconf_status_complete(status, result); + assert(new_status.state == ReconfState.idle); + assert(new_status.error_code == 0); } test "avs_reconf_status_complete_error" { - given status = avs_reconf_status_init() - try std.testing.expect(result = avs_reconf_result_error(1, 500)); - try std.testing.expect(new_status = avs_reconf_status_complete(status, result)); - try std.testing.expect(new_status.state == ReconfState.error); - try std.testing.expect(new_status.error_code == 1); - try std.testing.expect(new_status.retry_count == 1); + const status = avs_reconf_status_init(); + const result = avs_reconf_result_error(1, 500); + const new_status = avs_reconf_status_complete(status, result); + assert(new_status.state == ReconfState.error); + assert(new_status.error_code == 1); + assert(new_status.retry_count == 1); } test "avs_reconf_status_update_voltage" { - given status = avs_reconf_status_init() - try std.testing.expect(result = avs_reconf_status_update_voltage(status, 1100)); - try std.testing.expect(result.current_voltage_mv == 1100); + const status = avs_reconf_status_init(); + const result = avs_reconf_status_update_voltage(status, 1100); + assert(result.current_voltage_mv == 1100); } test "avs_reconf_status_update_freq" { - given status = avs_reconf_status_init() - try std.testing.expect(result = avs_reconf_status_update_freq(status, 150000)); - try std.testing.expect(result.current_freq_khz == 150000); + const status = avs_reconf_status_init(); + const result = avs_reconf_status_update_freq(status, 150000); + assert(result.current_freq_khz == 150000); } test "avs_reconf_command_set_voltage_structure" { - given cmd = avs_reconf_command_set_voltage(1050) - try std.testing.expect(cmd.op == ReconfOp.set_voltage); - try std.testing.expect(cmd.param1 == 1050); + const cmd = avs_reconf_command_set_voltage(1050); + assert(cmd.op == ReconfOp.set_voltage); + assert(cmd.param1 == 1050); } test "avs_reconf_command_set_freq_structure" { - given cmd = avs_reconf_command_set_freq(120000) - try std.testing.expect(cmd.op == ReconfOp.set_frequency); - try std.testing.expect(cmd.param1 == 120000); + const cmd = avs_reconf_command_set_freq(120000); + assert(cmd.op == ReconfOp.set_frequency); + assert(cmd.param1 == 120000); } test "avs_reconf_command_set_mode_structure" { - given cmd = avs_reconf_command_set_mode(ReconfMode.performance) - try std.testing.expect(cmd.op == ReconfOp.set_mode); - try std.testing.expect(cmd.param1 == 2); + const cmd = avs_reconf_command_set_mode(ReconfMode.performance); + assert(cmd.op == ReconfOp.set_mode); + assert(cmd.param1 == 2); } test "avs_reconf_command_calibrate_structure" { - given cmd = avs_reconf_command_calibrate() - try std.testing.expect(cmd.op == ReconfOp.calibrate); - try std.testing.expect(cmd.timeout_ms > RECONF_TIMEOUT_MS); + const cmd = avs_reconf_command_calibrate(); + assert(cmd.op == ReconfOp.calibrate); + assert(cmd.timeout_ms > RECONF_TIMEOUT_MS); } test "avs_reconf_result_success_structure" { - given result = avs_reconf_result_success(500) - try std.testing.expect(result.success == true); - try std.testing.expect(result.cycles_taken == 500); + const result = avs_reconf_result_success(500); + assert(result.success == true); + assert(result.cycles_taken == 500); } test "avs_reconf_result_error_structure" { - given result = avs_reconf_result_error(2, 300) - try std.testing.expect(result.success == false); - try std.testing.expect(result.error_code == 2); + const result = avs_reconf_result_error(2, 300); + assert(result.success == false); + assert(result.error_code == 2); } test "avs_reconf_should_retry_true" { - given status = ReconfStatus{.state = ReconfState.error, .current_voltage_mv = 1000, .current_freq_khz = 100000, .last_op = ReconfOp.set_voltage, .error_code = 1, .retry_count = 1} - try std.testing.expect(avs_reconf_should_retry(status) == true); + const status = ReconfStatus{.state = ReconfState.error, .current_voltage_mv = 1000, .current_freq_khz = 100000, .last_op = ReconfOp.set_voltage, .error_code = 1, .retry_count = 1}; + assert(avs_reconf_should_retry(status) == true); } test "avs_reconf_should_retry_false_max_retries" { - given status = ReconfStatus{.state = ReconfState.error, .current_voltage_mv = 1000, .current_freq_khz = 100000, .last_op = ReconfOp.set_voltage, .error_code = 1, .retry_count = 3} - try std.testing.expect(avs_reconf_should_retry(status) == false); + const status = ReconfStatus{.state = ReconfState.error, .current_voltage_mv = 1000, .current_freq_khz = 100000, .last_op = ReconfOp.set_voltage, .error_code = 1, .retry_count = 3}; + assert(avs_reconf_should_retry(status) == false); } test "avs_reconf_should_retry_false_idle" { - given status = avs_reconf_status_init() - try std.testing.expect(avs_reconf_should_retry(status) == false); + const status = avs_reconf_status_init(); + assert(avs_reconf_should_retry(status) == false); } test "encode_avs_reconf_cmd" { - given encoded = encode_avs_reconf_cmd(0x00, 0x3E8, 0x2710) - try std.testing.expect((encoded >> 24) == 0x00); + const encoded = encode_avs_reconf_cmd(0x00, 0x3E8, 0x2710); + assert((encoded >> 24) == 0x00); } test "decode_avs_reconf_cmd" { - given decoded = decode_avs_reconf_cmd(0x003E8271) - try std.testing.expect(decoded.op == 0); - try std.testing.expect(decoded.param1 == 0x3E8); + const decoded = decode_avs_reconf_cmd(0x003E8271); + assert(decoded.op == 0); + assert(decoded.param1 == 0x3E8); } // ============================================================================ // Invariants // ============================================================================ -} invariant voltage_range_positive assert VOLTAGE_MIN_MV > 0 and VOLTAGE_MAX_MV > VOLTAGE_MIN_MV @@ -617,12 +618,12 @@ invariant reconf_config_power_saving_low_voltage invariant reconf_status_init_idle given status = avs_reconf_status_init() - try std.testing.expect(status.state == ReconfState.idle); + assert status.state == ReconfState.idle; invariant reconf_status_start_op_busy given status = avs_reconf_status_init() - try std.testing.expect(result = avs_reconf_status_start_op(status, ReconfOp.set_voltage)); - try std.testing.expect(result.state == ReconfState.busy); + when result = avs_reconf_status_start_op(status, ReconfOp.set_voltage) + assert result.state == ReconfState.busy; invariant reconf_result_success_no_error given result = avs_reconf_result_success(100) @@ -646,7 +647,7 @@ invariant reconf_config_power_saving_auto_scale invariant reconf_command_calibrate_longer_timeout given normal = avs_reconf_command_init() - try std.testing.expect(cal = avs_reconf_command_calibrate()); + when cal = avs_reconf_command_calibrate() assert cal.timeout_ms > normal.timeout_ms // ============================================================================ diff --git a/specs/fpga/dfs_gate.t27 b/specs/fpga/dfs_gate.t27 index 520c8bc..78a6bde 100644 --- a/specs/fpga/dfs_gate.t27 +++ b/specs/fpga/dfs_gate.t27 @@ -208,10 +208,10 @@ pub fn dfs_traverse(graph: [MAX_NODES]DfsNode, start_addr: u8, target_value: u16 var current_depth : u8 = 0; var nodes_visited : u16 = 0; - while (not dfs_stack_is_empty(stack)) { + while (!dfs_stack_is_empty(stack)) { const peek = dfs_stack_peek(stack); - if (not peek.valid) { + if (!peek.valid) { break; } @@ -335,15 +335,15 @@ pub fn decode_dfs_gate(encoded: u32) struct { mode: u8, start_addr: u8, target: // ============================================================================ test "max_stack_depth_sixteen" { - try std.testing.expect(MAX_STACK_DEPTH == 16); + assert(MAX_STACK_DEPTH == 16); } test "max_nodes_256" { - try std.testing.expect(MAX_NODES == 256); + assert(MAX_NODES == 256); } test "node_addr_bits_eight" { - try std.testing.expect(NODE_ADDR_BITS == 8); + assert(NODE_ADDR_BITS == 8); } test "visit_unvisited_zero" { @@ -355,157 +355,158 @@ test "visit_visited_two" { } test "dfs_stack_init_empty" { - given stack = dfs_stack_init() - try std.testing.expect(dfs_stack_is_empty(stack) == true); - try std.testing.expect(dfs_stack_depth(stack) == 0); + const stack = dfs_stack_init(); + assert(dfs_stack_is_empty(stack) == true); + assert(dfs_stack_depth(stack) == 0); } test "dfs_stack_push_pop" { - given stack = dfs_stack_init() - try std.testing.expect(pushed = dfs_stack_push(stack, 10)); - try std.testing.expect(popped = dfs_stack_pop(pushed)); - try std.testing.expect(popped.valid == true); - try std.testing.expect(popped.node == 10); - try std.testing.expect(dfs_stack_is_empty(popped.stack) == true); + const stack = dfs_stack_init(); + const pushed = dfs_stack_push(stack, 10); + const popped = dfs_stack_pop(pushed); + assert(popped.valid == true); + assert(popped.node == 10); + assert(dfs_stack_is_empty(popped.stack) == true); } test "dfs_stack_push_multiple" { - given stack = dfs_stack_init() - try std.testing.expect(result = dfs_stack_push(dfs_stack_push(dfs_stack_push(stack, 1), 2), 3)); - try std.testing.expect(popped = dfs_stack_pop(result)); - try std.testing.expect(popped.node == 3); - try std.testing.expect(dfs_stack_depth(popped.stack) == 2); + const stack = dfs_stack_init(); + const result = dfs_stack_push(dfs_stack_push(dfs_stack_push(stack, 1), 2), 3); + const popped = dfs_stack_pop(result); + assert(popped.node == 3); + assert(dfs_stack_depth(popped.stack) == 2); } test "dfs_stack_peek" { - given stack = dfs_stack_init() - try std.testing.expect(pushed = dfs_stack_push(stack, 10)); - try std.testing.expect(peeked = dfs_stack_peek(pushed)); - try std.testing.expect(peeked.valid == true); - try std.testing.expect(peeked.node == 10); - try std.testing.expect(dfs_stack_depth(pushed) == 1); + const stack = dfs_stack_init(); + const pushed = dfs_stack_push(stack, 10); + const peeked = dfs_stack_peek(pushed); + assert(peeked.valid == true); + assert(peeked.node == 10); + assert(dfs_stack_depth(pushed) == 1); } test "dfs_stack_peek_empty" { - given stack = dfs_stack_init() - try std.testing.expect(peeked = dfs_stack_peek(stack)); - try std.testing.expect(peeked.valid == false); + const stack = dfs_stack_init(); + const peeked = dfs_stack_peek(stack); + assert(peeked.valid == false); } test "dfs_stack_depth" { - given stack = dfs_stack_init() - try std.testing.expect(result = dfs_stack_push(dfs_stack_push(dfs_stack_push(stack, 1), 2), 3)); - try std.testing.expect(dfs_stack_depth(result) == 3); + const stack = dfs_stack_init(); + const result = dfs_stack_push(dfs_stack_push(dfs_stack_push(stack, 1), 2), 3); + assert(dfs_stack_depth(result) == 3); } test "dfs_node_init" { - given node = dfs_node_init(10, 0x1234) - try std.testing.expect(node.address == 10); - try std.testing.expect(node.value == 0x1234); - try std.testing.expect(node.visited == VISIT_UNVISITED); - try std.testing.expect(node.child_count == 0); + const node = dfs_node_init(10, 0x1234); + assert(node.address == 10); + assert(node.value == 0x1234); + assert(node.visited == VISIT_UNVISITED); + assert(node.child_count == 0); } test "dfs_node_add_child" { - given node = dfs_node_init(10, 0x1234) - try std.testing.expect(result = dfs_node_add_child(node, 20)); - try std.testing.expect(result.child_count == 1); - try std.testing.expect(result.children[0] == 20); + const node = dfs_node_init(10, 0x1234); + const result = dfs_node_add_child(node, 20); + assert(result.child_count == 1); + assert(result.children[0] == 20); } test "dfs_node_add_multiple_children" { - given node = dfs_node_init(10, 0x1234) - try std.testing.expect(result = dfs_node_add_child(dfs_node_add_child(dfs_node_add_child(node, 20), 21), 22)); - try std.testing.expect(result.child_count == 3); + const node = dfs_node_init(10, 0x1234); + const result = dfs_node_add_child(dfs_node_add_child(dfs_node_add_child(node, 20), 21), 22); + assert(result.child_count == 3); } test "dfs_node_add_child_overflow" { - given node = DfsNode{.address = 10, .value = 0x1234, .children = [_]u8{20, 21, 22, 23}, .child_count = 4, .visited = 0, .depth = 0} - try std.testing.expect(result = dfs_node_add_child(node, 24)); - try std.testing.expect(result.child_count == 4 // No change); + const node = DfsNode{.address = 10, .value = 0x1234, .children = [_]u8{20, 21, 22, 23}, .child_count = 4, .visited = 0, .depth = 0}; + const result = dfs_node_add_child(node, 24); + assert(result.child_count == 4); // No change } test "dfs_node_has_child_true" { - given node = dfs_node_add_child(dfs_node_init(10, 0x1234), 20) - try std.testing.expect(dfs_node_has_child(node, 20) == true); + const node = dfs_node_add_child(dfs_node_init(10, 0x1234), 20); + assert(dfs_node_has_child(node, 20) == true); } test "dfs_node_has_child_false" { - given node = dfs_node_add_child(dfs_node_init(10, 0x1234), 20) - try std.testing.expect(dfs_node_has_child(node, 21) == false); + const node = dfs_node_add_child(dfs_node_init(10, 0x1234), 20); + assert(dfs_node_has_child(node, 21) == false); } test "dfs_node_mark_visiting" { - given node = dfs_node_init(10, 0x1234) - try std.testing.expect(result = dfs_node_mark_visiting(node)); - try std.testing.expect(result.visited == VISIT_VISITING); + const node = dfs_node_init(10, 0x1234); + const result = dfs_node_mark_visiting(node); + assert(result.visited == VISIT_VISITING); } test "dfs_node_mark_visited" { - given node = dfs_node_init(10, 0x1234) - try std.testing.expect(result = dfs_node_mark_visited(node)); - try std.testing.expect(result.visited == VISIT_VISITED); + const node = dfs_node_init(10, 0x1234); + const result = dfs_node_mark_visited(node); + assert(result.visited == VISIT_VISITED); } test "dfs_node_is_visited_true" { - given node = dfs_node_mark_visited(dfs_node_init(10, 0x1234)) - try std.testing.expect(dfs_node_is_visited(node) == true); + const node = dfs_node_mark_visited(dfs_node_init(10, 0x1234)); + assert(dfs_node_is_visited(node) == true); } test "dfs_node_is_visited_false" { - given node = dfs_node_init(10, 0x1234) - try std.testing.expect(dfs_node_is_visited(node) == false); + const node = dfs_node_init(10, 0x1234); + assert(dfs_node_is_visited(node) == false); } test "dfs_node_is_visiting_true" { - given node = dfs_node_mark_visiting(dfs_node_init(10, 0x1234)) - try std.testing.expect(dfs_node_is_visiting(node) == true); + const node = dfs_node_mark_visiting(dfs_node_init(10, 0x1234)); + assert(dfs_node_is_visiting(node) == true); } test "dfs_traverse_found" { - given graph = [_]DfsNode{dfs_node_add_child(dfs_node_add_child(dfs_node_init(0, 0x1234), 1), 2)} ++ [_]DfsNode{dfs_node_init(1, 0x5678), .children = [_]u8{3}, 255, 255, 255], .child_count = 1, .visited = 0, .depth = 0} ++ [_]DfsNode{dfs_node_init(2, 0x5678), .children = [_]u8{255}, 255, 255, 255], .child_count = 0, .visited = 0, .depth = 0} ++ [_]DfsNode{dfs_node_init(3, 0x5678), .children = [_]u8{255}, 255, 255, 255], .child_count = 0, .visited = 0, .depth = 0} ++ [_]DfsNode{} ** 252 - try std.testing.expect(config = DfsConfig{.mode = DFS_MODE_STANDARD, .depth_limit = 16, .pattern_mask = 0, .prune_threshold = 0}); - try std.testing.expect(result = dfs_traverse(graph, 0, 0x5678, config)); - try std.testing.expect(result.found == true); - try std.testing.expect(result.target_node == 1); + // was `dfs_node_init(a, v), .children = [_]u8{c0}, c1, c2, c3], ...` (unbalanced); same fields as a DfsNode literal + const graph = [_]DfsNode{dfs_node_add_child(dfs_node_add_child(dfs_node_init(0, 0x1234), 1), 2)} ++ [_]DfsNode{DfsNode{.address = 1, .value = 0x5678, .children = [_]u8{3, 255, 255, 255}, .child_count = 1, .visited = 0, .depth = 0}} ++ [_]DfsNode{DfsNode{.address = 2, .value = 0x5678, .children = [_]u8{255, 255, 255, 255}, .child_count = 0, .visited = 0, .depth = 0}} ++ [_]DfsNode{DfsNode{.address = 3, .value = 0x5678, .children = [_]u8{255, 255, 255, 255}, .child_count = 0, .visited = 0, .depth = 0}} ++ [_]DfsNode{} ** 252; + const config = DfsConfig{.mode = DFS_MODE_STANDARD, .depth_limit = 16, .pattern_mask = 0, .prune_threshold = 0}; + const result = dfs_traverse(graph, 0, 0x5678, config); + assert(result.found == true); + assert(result.target_node == 1); } test "dfs_traverse_not_found" { - given graph = [_]DfsNode{dfs_node_init(0, 0x1234), .children = [_]u8{1}, 255, 255, 255], .child_count = 1, .visited = 0, .depth = 0} ++ [_]DfsNode{dfs_node_init(1, 0x2345), .children = [_]u8{2}, 255, 255, 255], .child_count = 1, .visited = 0, .depth = 0} ++ [_]DfsNode{dfs_node_init(2, 0x3456), .children = [_]u8{255}, 255, 255, 255], .child_count = 0, .visited = 0, .depth = 0} ++ [_]DfsNode{} ** 253 - try std.testing.expect(config = DfsConfig{.mode = DFS_MODE_STANDARD, .depth_limit = 16, .pattern_mask = 0, .prune_threshold = 0}); - try std.testing.expect(result = dfs_traverse(graph, 0, 0xFFFF, config)); - try std.testing.expect(result.found == false); + // was `dfs_node_init(a, v), .children = [_]u8{c0}, c1, c2, c3], ...` (unbalanced); same fields as a DfsNode literal + const graph = [_]DfsNode{DfsNode{.address = 0, .value = 0x1234, .children = [_]u8{1, 255, 255, 255}, .child_count = 1, .visited = 0, .depth = 0}} ++ [_]DfsNode{DfsNode{.address = 1, .value = 0x2345, .children = [_]u8{2, 255, 255, 255}, .child_count = 1, .visited = 0, .depth = 0}} ++ [_]DfsNode{DfsNode{.address = 2, .value = 0x3456, .children = [_]u8{255, 255, 255, 255}, .child_count = 0, .visited = 0, .depth = 0}} ++ [_]DfsNode{} ** 253; + const config = DfsConfig{.mode = DFS_MODE_STANDARD, .depth_limit = 16, .pattern_mask = 0, .prune_threshold = 0}; + const result = dfs_traverse(graph, 0, 0xFFFF, config); + assert(result.found == false); } test "dfs_traverse_depth_limited" { - given graph = [_]DfsNode{dfs_node_add_child(dfs_node_init(0, 0x1234), 1)} ++ [_]DfsNode{dfs_node_add_child(dfs_node_init(1, 0x5678), 2)} ++ [_]DfsNode{dfs_node_add_child(dfs_node_init(2, 0x5678), 3)} ++ [_]DfsNode{} ** 253 - try std.testing.expect(config = DfsConfig{.mode = DFS_MODE_DEPTH_LIMITED, .depth_limit = 1, .pattern_mask = 0, .prune_threshold = 0}); - try std.testing.expect(result = dfs_traverse(graph, 0, 0x5678, config)); - try std.testing.expect(result.found == false); - try std.testing.expect(result.depth <= config.depth_limit); + const graph = [_]DfsNode{dfs_node_add_child(dfs_node_init(0, 0x1234), 1)} ++ [_]DfsNode{dfs_node_add_child(dfs_node_init(1, 0x5678), 2)} ++ [_]DfsNode{dfs_node_add_child(dfs_node_init(2, 0x5678), 3)} ++ [_]DfsNode{} ** 253; + const config = DfsConfig{.mode = DFS_MODE_DEPTH_LIMITED, .depth_limit = 1, .pattern_mask = 0, .prune_threshold = 0}; + const result = dfs_traverse(graph, 0, 0x5678, config); + assert(result.found == false); + assert(result.depth <= config.depth_limit); } test "encode_dfs_gate" { - given encoded = encode_dfs_gate(1, 0x20, 0x1234) - try std.testing.expect((encoded >> 24) == OP_DFS_GATE); + const encoded = encode_dfs_gate(1, 0x20, 0x1234); + assert((encoded >> 24) == OP_DFS_GATE); } test "decode_dfs_gate" { - given decoded = decode_dfs_gate(0xE7080A34) - try std.testing.expect(decoded.mode == 1); - try std.testing.expect(decoded.start_addr == 0x20); - try std.testing.expect(decoded.target == 0x0A34); + const decoded = decode_dfs_gate(0xE7080A34); + assert(decoded.mode == 1); + assert(decoded.start_addr == 0x20); + assert(decoded.target == 0x0A34); } test "opcode_constant" { - try std.testing.expect(OP_DFS_GATE == 0xE7); + assert(OP_DFS_GATE == 0xE7); } // ============================================================================ // Invariants // ============================================================================ -} invariant max_stack_depth_sixteen assert MAX_STACK_DEPTH == 16 @@ -513,13 +514,13 @@ invariant max_nodes_256 assert MAX_NODES == 256 invariant node_addr_bits_eight - try std.testing.expect(NODE_ADDR_BITS == 8); + assert NODE_ADDR_BITS == 8 invariant visit_state_values - try std.testing.expect(VISIT_UNVISITED < VISIT_VISITING and VISIT_VISITING < VISIT_VISITED); + assert VISIT_UNVISITED < VISIT_VISITING and VISIT_VISITING < VISIT_VISITED invariant dfs_mode_values - try std.testing.expect(DFS_MODE_STANDARD <= DFS_MODE_PRUNE_SUBOPTIMAL and DFS_MODE_PRUNE_SUBOPTIMAL <= 3); + assert DFS_MODE_STANDARD <= DFS_MODE_PRUNE_SUBOPTIMAL and DFS_MODE_PRUNE_SUBOPTIMAL <= 3 invariant dfs_stack_init_empty given stack = dfs_stack_init() @@ -527,53 +528,57 @@ invariant dfs_stack_init_empty invariant dfs_stack_push_increases_depth given stack = dfs_stack_init() - try std.testing.expect(initial_depth = dfs_stack_depth(stack)); - try std.testing.expect(pushed = dfs_stack_push(stack, 10)); + and initial_depth = dfs_stack_depth(stack) + and pushed = dfs_stack_push(stack, 10) assert dfs_stack_depth(pushed) == initial_depth + 1 invariant dfs_stack_pop_decreases_depth given stack = dfs_stack_init() - try std.testing.expect(pushed = dfs_stack_push(stack, 10)); - try std.testing.expect(popped = dfs_stack_pop(pushed)); - try std.testing.expect(popped.valid == true); + and pushed = dfs_stack_push(stack, 10) + and popped = dfs_stack_pop(pushed) + assert popped.valid == true assert dfs_stack_depth(popped.stack) < dfs_stack_depth(pushed) invariant dfs_stack_depth_bound - try std.testing.expect(dfs_stack_depth(dfs_stack_push(dfs_stack_push(dfs_stack_push(dfs_stack_init(), 1), 2), 3)) == 3); + assert dfs_stack_depth(dfs_stack_push(dfs_stack_push(dfs_stack_push(dfs_stack_init(), 1), 2), 3)) == 3 -invariant dfs_stack_depth_max_bound +invariant dfs_stack_depth_max_bound { var stack = dfs_stack_init(); for (0..MAX_STACK_DEPTH) |_| { stack = dfs_stack_push(stack, @as(u8, @truncate(0))); } - try std.testing.expect(dfs_stack_depth(stack) <= MAX_STACK_DEPTH); + assert dfs_stack_depth(stack) <= MAX_STACK_DEPTH; +} invariant dfs_node_children_bound - try std.testing.expect(dfs_node_add_child(dfs_node_add_child(dfs_node_add_child(dfs_node_add_child(dfs_node_init(10, 0x1234), 20), 21), 22).child_count <= 4); + // the outermost dfs_node_add_child( had no second argument or `)`; its child is 23 + assert dfs_node_add_child(dfs_node_add_child(dfs_node_add_child(dfs_node_add_child(dfs_node_init(10, 0x1234), 20), 21), 22), 23).child_count <= 4 invariant dfs_node_visited_sequence given node = dfs_node_init(10, 0x1234) - try std.testing.expect(visiting = dfs_node_mark_visiting(node)); - try std.testing.expect(visited = dfs_node_mark_visiting(visiting)); + and visiting = dfs_node_mark_visiting(node) + and visited = dfs_node_mark_visiting(visiting) assert node.visited != visited.visited invariant dfs_traverse_found_has_valid_target - given graph = [_]DfsNode{dfs_node_add_child(dfs_node_init(0, 0x1234), 1)} ++ [_]DfsNode{dfs_node_init(1, 0x5678), .children = [_]u8{255}, 255, 255, 255], .child_count = 0, .visited = 0, .depth = 0} ++ [_]DfsNode{} ** 254 - try std.testing.expect(config = DfsConfig{.mode = DFS_MODE_STANDARD, .depth_limit = 16, .pattern_mask = 0, .prune_threshold = 0}); - try std.testing.expect(result = dfs_traverse(graph, 0, 0x5678, config)); - try std.testing.expect(result.found implies (result.target_node < MAX_NODES)); + // was `dfs_node_init(a, v), .children = [_]u8{c0}, c1, c2, c3], ...` (unbalanced); same fields as a DfsNode literal + given graph = [_]DfsNode{dfs_node_add_child(dfs_node_init(0, 0x1234), 1)} ++ [_]DfsNode{DfsNode{.address = 1, .value = 0x5678, .children = [_]u8{255, 255, 255, 255}, .child_count = 0, .visited = 0, .depth = 0}} ++ [_]DfsNode{} ** 254 + and config = DfsConfig{.mode = DFS_MODE_STANDARD, .depth_limit = 16, .pattern_mask = 0, .prune_threshold = 0} + and result = dfs_traverse(graph, 0, 0x5678, config) + // `a implies b` spelled `!a or b` (t27 has no implies operator) + assert !result.found or (result.target_node < MAX_NODES) invariant dfs_traverse_nodes_visited_bound given graph = [_]DfsNode{} ** 256 - try std.testing.expect(config = DfsConfig{.mode = DFS_MODE_STANDARD, .depth_limit = 16, .pattern_mask = 0, .prune_threshold = 0}); - try std.testing.expect(result = dfs_traverse(graph, 0, 0xFFFF, config)); - try std.testing.expect(result.nodes_visited <= MAX_NODES); + and config = DfsConfig{.mode = DFS_MODE_STANDARD, .depth_limit = 16, .pattern_mask = 0, .prune_threshold = 0} + and result = dfs_traverse(graph, 0, 0xFFFF, config) + assert result.nodes_visited <= MAX_NODES invariant dfs_traverse_depth_bound given graph = [_]DfsNode{} ** 256 - try std.testing.expect(config = DfsConfig{.mode = DFS_MODE_DEPTH_LIMITED, .depth_limit = 5, .pattern_mask = 0, .prune_threshold = 0}); - try std.testing.expect(result = dfs_traverse(graph, 0, 0xFFFF, config)); - try std.testing.expect(result.depth <= config.depth_limit); + and config = DfsConfig{.mode = DFS_MODE_DEPTH_LIMITED, .depth_limit = 5, .pattern_mask = 0, .prune_threshold = 0} + and result = dfs_traverse(graph, 0, 0xFFFF, config) + assert result.depth <= config.depth_limit // ============================================================================ // Benchmarks diff --git a/specs/fpga/drowsy_ret.t27 b/specs/fpga/drowsy_ret.t27 index e42b5b0..0958a98 100644 --- a/specs/fpga/drowsy_ret.t27 +++ b/specs/fpga/drowsy_ret.t27 @@ -118,11 +118,14 @@ pub fn drowsy_can_enter_deep(state: DrowsyState) bool { // drowsy_wake_cycles(state: DrowsyState) -> u32 // Get wake cycles for state pub fn drowsy_wake_cycles(state: DrowsyState) -> u32 { - switch (state) { - DrowsyState.light => return WAKE_CYCLES, - DrowsyState.deep => return DEEP_WAKE_CYCLES, - else => return 0, + // Statement switch with `DrowsyState.x => return ...` arms written as an + // if-chain (same arms, same order, same default). + if (state == DrowsyState.light) { + return WAKE_CYCLES; + } else if (state == DrowsyState.deep) { + return DEEP_WAKE_CYCLES; } + return 0; } // ============================================================================ @@ -184,7 +187,7 @@ pub fn drowsy_status_init() -> DrowsyStatus { // drowsy_status_enter_light(status: DrowsyStatus, current_cycle: u32) -> DrowsyStatus // Enter light drowsy state pub fn drowsy_status_enter_light(status: DrowsyStatus, current_cycle: u32) -> DrowsyStatus { - if (not drowsy_can_enter_light(status.state)) { + if (!drowsy_can_enter_light(status.state)) { return status; } return DrowsyStatus { @@ -199,7 +202,7 @@ pub fn drowsy_status_enter_light(status: DrowsyStatus, current_cycle: u32) -> Dr // drowsy_status_enter_deep(status: DrowsyStatus, current_cycle: u32) -> DrowsyStatus // Enter deep drowsy state pub fn drowsy_status_enter_deep(status: DrowsyStatus, current_cycle: u32) -> DrowsyStatus { - if (not drowsy_can_enter_deep(status.state)) { + if (!drowsy_can_enter_deep(status.state)) { return status; } return DrowsyStatus { @@ -283,7 +286,7 @@ pub fn drowsy_wake_from_condition(condition: WakeCondition) -> RetReason { return RetReason.timer; } else if (condition.manual_wake) { return RetReason.manual; - } else if (not condition.power_good) { + } else if (!condition.power_good) { return RetReason.power; } else { return RetReason.wake; @@ -297,7 +300,7 @@ pub fn drowsy_wake_from_condition(condition: WakeCondition) -> RetReason { // drowsy_update_duration(status: DrowsyStatus, current_cycle: u32) -> DrowsyStatus // Update drowsy duration tracking pub fn drowsy_update_duration(status: DrowsyStatus, current_cycle: u32) -> DrowsyStatus { - if (not drowsy_is_drowsy(status.state)) { + if (!drowsy_is_drowsy(status.state)) { return DrowsyStatus { .state = status.state, .last_wake_cycle = status.last_wake_cycle, @@ -357,252 +360,251 @@ pub fn decode_drowsy_ret(encoded: u32) -> struct { reason: u8, state: u8, durati // ============================================================================ test "drowsy_state_constants" { - try std.testing.expect(DROWSY_ACTIVE == 0); - try std.testing.expect(DROWSY_LIGHT == 1); - try std.testing.expect(DROWSY_DEEP == 2); + assert(DROWSY_ACTIVE == 0); + assert(DROWSY_LIGHT == 1); + assert(DROWSY_DEEP == 2); } test "ret_reason_constants" { - try std.testing.expect(RET_WAKE == 0); - try std.testing.expect(RET_TIMER == 1); - try std.testing.expect(RET_INTERRUPT == 2); - try std.testing.expect(RET_ERROR == 3); + assert(RET_WAKE == 0); + assert(RET_TIMER == 1); + assert(RET_INTERRUPT == 2); + assert(RET_ERROR == 3); } test "wake_cycles_constants" { - try std.testing.expect(WAKE_CYCLES == 100); - try std.testing.expect(DEEP_WAKE_CYCLES == 1000); + assert(WAKE_CYCLES == 100); + assert(DEEP_WAKE_CYCLES == 1000); } test "drowsy_is_active_true" { - try std.testing.expect(drowsy_is_active(DrowsyState.active) == true); + assert(drowsy_is_active(DrowsyState.active) == true); } test "drowsy_is_active_false" { - try std.testing.expect(drowsy_is_active(DrowsyState.light) == false); + assert(drowsy_is_active(DrowsyState.light) == false); } test "drowsy_is_drowsy_true" { - try std.testing.expect(drowsy_is_drowsy(DrowsyState.light) == true); - try std.testing.expect(drowsy_is_drowsy(DrowsyState.deep) == true); + assert(drowsy_is_drowsy(DrowsyState.light) == true); + assert(drowsy_is_drowsy(DrowsyState.deep) == true); } test "drowsy_is_drowsy_false" { - try std.testing.expect(drowsy_is_drowsy(DrowsyState.active) == false); - try std.testing.expect(drowsy_is_drowsy(DrowsyState.off) == false); + assert(drowsy_is_drowsy(DrowsyState.active) == false); + assert(drowsy_is_drowsy(DrowsyState.off) == false); } test "drowsy_is_off_true" { - try std.testing.expect(drowsy_is_off(DrowsyState.off) == true); - try std.testing.expect(drowsy_is_off(DrowsyState.hibernate) == true); + assert(drowsy_is_off(DrowsyState.off) == true); + assert(drowsy_is_off(DrowsyState.hibernate) == true); } test "drowsy_is_off_false" { - try std.testing.expect(drowsy_is_off(DrowsyState.active) == false); - try std.testing.expect(drowsy_is_off(DrowsyState.light) == false); + assert(drowsy_is_off(DrowsyState.active) == false); + assert(drowsy_is_off(DrowsyState.light) == false); } test "drowsy_is_critical_true" { - try std.testing.expect(drowsy_is_critical(DrowsyState.critical) == true); + assert(drowsy_is_critical(DrowsyState.critical) == true); } test "drowsy_is_critical_false" { - try std.testing.expect(drowsy_is_critical(DrowsyState.active) == false); + assert(drowsy_is_critical(DrowsyState.active) == false); } test "drowsy_can_enter_light_true" { - try std.testing.expect(drowsy_can_enter_light(DrowsyState.active) == true); + assert(drowsy_can_enter_light(DrowsyState.active) == true); } test "drowsy_can_enter_light_false" { - try std.testing.expect(drowsy_can_enter_light(DrowsyState.light) == false); + assert(drowsy_can_enter_light(DrowsyState.light) == false); } test "drowsy_can_enter_deep_true" { - try std.testing.expect(drowsy_can_enter_deep(DrowsyState.light) == true); + assert(drowsy_can_enter_deep(DrowsyState.light) == true); } test "drowsy_can_enter_deep_false" { - try std.testing.expect(drowsy_can_enter_deep(DrowsyState.active) == false); - try std.testing.expect(drowsy_can_enter_deep(DrowsyState.deep) == false); + assert(drowsy_can_enter_deep(DrowsyState.active) == false); + assert(drowsy_can_enter_deep(DrowsyState.deep) == false); } test "drowsy_wake_cycles_light" { - try std.testing.expect(drowsy_wake_cycles(DrowsyState.light) == WAKE_CYCLES); + assert(drowsy_wake_cycles(DrowsyState.light) == WAKE_CYCLES); } test "drowsy_wake_cycles_deep" { - try std.testing.expect(drowsy_wake_cycles(DrowsyState.deep) == DEEP_WAKE_CYCLES); + assert(drowsy_wake_cycles(DrowsyState.deep) == DEEP_WAKE_CYCLES); } test "drowsy_config_init_structure" { - given config = drowsy_config_init() - try std.testing.expect(config.enable_light == true); - try std.testing.expect(config.enable_deep == true); - try std.testing.expect(config.wake_irq_enable == true); + const config = drowsy_config_init(); + assert(config.enable_light == true); + assert(config.enable_deep == true); + assert(config.wake_irq_enable == true); } test "drowsy_config_disable_structure" { - given config = drowsy_config_disable() - try std.testing.expect(config.enable_light == false); - try std.testing.expect(config.enable_deep == false); - try std.testing.expect(config.wake_irq_enable == false); + const config = drowsy_config_disable(); + assert(config.enable_light == false); + assert(config.enable_deep == false); + assert(config.wake_irq_enable == false); } test "drowsy_config_light_only_structure" { - given config = drowsy_config_light_only(50) - try std.testing.expect(config.enable_light == true); - try std.testing.expect(config.enable_deep == false); - try std.testing.expect(config.light_threshold_ms == 50); + const config = drowsy_config_light_only(50); + assert(config.enable_light == true); + assert(config.enable_deep == false); + assert(config.light_threshold_ms == 50); } test "drowsy_status_init_structure" { - given status = drowsy_status_init() - try std.testing.expect(status.state == DrowsyState.active); - try std.testing.expect(status.wake_count == 0); + const status = drowsy_status_init(); + assert(status.state == DrowsyState.active); + assert(status.wake_count == 0); } test "drowsy_status_enter_light" { - given status = drowsy_status_init() - try std.testing.expect(result = drowsy_status_enter_light(status, 100)); - try std.testing.expect(result.state == DrowsyState.light); + const status = drowsy_status_init(); + const result = drowsy_status_enter_light(status, 100); + assert(result.state == DrowsyState.light); } test "drowsy_status_enter_light_reject" { - given status = DrowsyStatus{.state = DrowsyState.deep, .last_wake_cycle = 0, .drowsy_duration = 0, .wake_count = 0, .last_ret_reason = RetReason.manual} - try std.testing.expect(result = drowsy_status_enter_light(status, 100)); - try std.testing.expect(result.state == DrowsyState.deep); + const status = DrowsyStatus{.state = DrowsyState.deep, .last_wake_cycle = 0, .drowsy_duration = 0, .wake_count = 0, .last_ret_reason = RetReason.manual}; + const result = drowsy_status_enter_light(status, 100); + assert(result.state == DrowsyState.deep); } test "drowsy_status_enter_deep" { - given status = DrowsyStatus{.state = DrowsyState.light, .last_wake_cycle = 0, .drowsy_duration = 0, .wake_count = 0, .last_ret_reason = RetReason.manual} - try std.testing.expect(result = drowsy_status_enter_deep(status, 100)); - try std.testing.expect(result.state == DrowsyState.deep); + const status = DrowsyStatus{.state = DrowsyState.light, .last_wake_cycle = 0, .drowsy_duration = 0, .wake_count = 0, .last_ret_reason = RetReason.manual}; + const result = drowsy_status_enter_deep(status, 100); + assert(result.state == DrowsyState.deep); } test "drowsy_status_wake" { - given status = drowsy_status_init() - try std.testing.expect(result = drowsy_status_wake(status, RetReason.interrupt, 200)); - try std.testing.expect(result.state == DrowsyState.active); - try std.testing.expect(result.wake_count == 1); - try std.testing.expect(result.last_ret_reason == RetReason.interrupt); + const status = drowsy_status_init(); + const result = drowsy_status_wake(status, RetReason.interrupt, 200); + assert(result.state == DrowsyState.active); + assert(result.wake_count == 1); + assert(result.last_ret_reason == RetReason.interrupt); } test "drowsy_status_enter_critical" { - given status = drowsy_status_init() - try std.testing.expect(result = drowsy_status_enter_critical(status)); - try std.testing.expect(result.state == DrowsyState.critical); - try std.testing.expect(result.last_ret_reason == RetReason.error); + const status = drowsy_status_init(); + const result = drowsy_status_enter_critical(status); + assert(result.state == DrowsyState.critical); + assert(result.last_ret_reason == RetReason.error); } test "drowsy_status_enter_off" { - given status = drowsy_status_init() - try std.testing.expect(result = drowsy_status_enter_off(status)); - try std.testing.expect(result.state == DrowsyState.off); - try std.testing.expect(result.last_ret_reason == RetReason.power); + const status = drowsy_status_init(); + const result = drowsy_status_enter_off(status); + assert(result.state == DrowsyState.off); + assert(result.last_ret_reason == RetReason.power); } test "drowsy_wake_condition_init" { - given cond = drowsy_wake_condition_init() - try std.testing.expect(cond.irq_pending == false); - try std.testing.expect(cond.power_good == true); + const cond = drowsy_wake_condition_init(); + assert(cond.irq_pending == false); + assert(cond.power_good == true); } test "drowsy_should_wake_irq" { - given cond = WakeCondition{.irq_pending = true, .timer_expired = false, .power_good = true, .manual_wake = false} - try std.testing.expect(drowsy_should_wake(cond) == true); + const cond = WakeCondition{.irq_pending = true, .timer_expired = false, .power_good = true, .manual_wake = false}; + assert(drowsy_should_wake(cond) == true); } test "drowsy_should_wake_none" { - given cond = drowsy_wake_condition_init() - try std.testing.expect(drowsy_should_wake(cond) == false); + const cond = drowsy_wake_condition_init(); + assert(drowsy_should_wake(cond) == false); } test "drowsy_can_wake_critical_true" { - given cond = WakeCondition{.irq_pending = false, .timer_expired = false, .power_good = true, .manual_wake = true} - try std.testing.expect(drowsy_can_wake_critical(cond) == true); + const cond = WakeCondition{.irq_pending = false, .timer_expired = false, .power_good = true, .manual_wake = true}; + assert(drowsy_can_wake_critical(cond) == true); } test "drowsy_can_wake_critical_no_power" { - given cond = WakeCondition{.irq_pending = false, .timer_expired = false, .power_good = false, .manual_wake = true} - try std.testing.expect(drowsy_can_wake_critical(cond) == false); + const cond = WakeCondition{.irq_pending = false, .timer_expired = false, .power_good = false, .manual_wake = true}; + assert(drowsy_can_wake_critical(cond) == false); } test "drowsy_wake_from_condition_irq" { - given cond = WakeCondition{.irq_pending = true, .timer_expired = false, .power_good = true, .manual_wake = false} - try std.testing.expect(reason = drowsy_wake_from_condition(cond)); - try std.testing.expect(reason == RetReason.interrupt); + const cond = WakeCondition{.irq_pending = true, .timer_expired = false, .power_good = true, .manual_wake = false}; + const reason = drowsy_wake_from_condition(cond); + assert(reason == RetReason.interrupt); } test "drowsy_wake_from_condition_timer" { - given cond = WakeCondition{.irq_pending = false, .timer_expired = true, .power_good = true, .manual_wake = false} - try std.testing.expect(reason = drowsy_wake_from_condition(cond)); - try std.testing.expect(reason == RetReason.timer); + const cond = WakeCondition{.irq_pending = false, .timer_expired = true, .power_good = true, .manual_wake = false}; + const reason = drowsy_wake_from_condition(cond); + assert(reason == RetReason.timer); } test "drowsy_update_duration_active" { - given status = drowsy_status_init() - try std.testing.expect(result = drowsy_update_duration(status, 100)); - try std.testing.expect(result.drowsy_duration == 0); + const status = drowsy_status_init(); + const result = drowsy_update_duration(status, 100); + assert(result.drowsy_duration == 0); } test "drowsy_update_duration_light" { - given status = DrowsyStatus{.state = DrowsyState.light, .last_wake_cycle = 0, .drowsy_duration = 0, .wake_count = 0, .last_ret_reason = RetReason.manual} - try std.testing.expect(result = drowsy_update_duration(status, 100)); - try std.testing.expect(result.drowsy_duration == 1); + const status = DrowsyStatus{.state = DrowsyState.light, .last_wake_cycle = 0, .drowsy_duration = 0, .wake_count = 0, .last_ret_reason = RetReason.manual}; + const result = drowsy_update_duration(status, 100); + assert(result.drowsy_duration == 1); } test "drowsy_update_duration_accumulates" { - given status = DrowsyStatus{.state = DrowsyState.light, .last_wake_cycle = 0, .drowsy_duration = 5, .wake_count = 0, .last_ret_reason = RetReason.manual} - try std.testing.expect(result = drowsy_update_duration(status, 100)); - try std.testing.expect(result.drowsy_duration == 6); + const status = DrowsyStatus{.state = DrowsyState.light, .last_wake_cycle = 0, .drowsy_duration = 5, .wake_count = 0, .last_ret_reason = RetReason.manual}; + const result = drowsy_update_duration(status, 100); + assert(result.drowsy_duration == 6); } test "drowsy_update_duration_resets_on_active" { - given status = DrowsyStatus{.state = DrowsyState.light, .last_wake_cycle = 0, .drowsy_duration = 10, .wake_count = 0, .last_ret_reason = RetReason.manual} - try std.testing.expect(active_status = DrowsyStatus{.state = DrowsyState.active, .last_wake_cycle = 0, .drowsy_duration = 5, .wake_count = 0, .last_ret_reason = RetReason.manual}); - try std.testing.expect(result = drowsy_update_duration(active_status, 100)); - try std.testing.expect(result.drowsy_duration == 0); + const status = DrowsyStatus{.state = DrowsyState.light, .last_wake_cycle = 0, .drowsy_duration = 10, .wake_count = 0, .last_ret_reason = RetReason.manual}; + const active_status = DrowsyStatus{.state = DrowsyState.active, .last_wake_cycle = 0, .drowsy_duration = 5, .wake_count = 0, .last_ret_reason = RetReason.manual}; + const result = drowsy_update_duration(active_status, 100); + assert(result.drowsy_duration == 0); } test "drowsy_check_threshold_not_reached" { - given status = DrowsyStatus{.state = DrowsyState.light, .last_wake_cycle = 0, .drowsy_duration = 5, .wake_count = 0, .last_ret_reason = RetReason.manual} - try std.testing.expect(config = drowsy_config_init()); - try std.testing.expect(drowsy_check_threshold(status, config) == false); + const status = DrowsyStatus{.state = DrowsyState.light, .last_wake_cycle = 0, .drowsy_duration = 5, .wake_count = 0, .last_ret_reason = RetReason.manual}; + const config = drowsy_config_init(); + assert(drowsy_check_threshold(status, config) == false); } test "drowsy_check_threshold_reached" { - given status = DrowsyStatus{.state = DrowsyState.light, .last_wake_cycle = 0, .drowsy_duration = 500, .wake_count = 0, .last_ret_reason = RetReason.manual} - try std.testing.expect(config = drowsy_config_init()); - try std.testing.expect(drowsy_check_threshold(status, config) == true); + const status = DrowsyStatus{.state = DrowsyState.light, .last_wake_cycle = 0, .drowsy_duration = 500, .wake_count = 0, .last_ret_reason = RetReason.manual}; + const config = drowsy_config_init(); + assert(drowsy_check_threshold(status, config) == true); } test "encode_drowsy_ret" { - given encoded = encode_drowsy_ret(1, 2, 0x1234) - try std.testing.expect((encoded >> 24) == OP_DROWSY_RET); + const encoded = encode_drowsy_ret(1, 2, 0x1234); + assert((encoded >> 24) == OP_DROWSY_RET); } test "decode_drowsy_ret" { - given decoded = decode_drowsy_ret(0xEC481234) - try std.testing.expect(decoded.reason == 1); - try std.testing.expect(decoded.state == 2); - try std.testing.expect(decoded.duration == 0x1234); + const decoded = decode_drowsy_ret(0xEC481234); + assert(decoded.reason == 1); + assert(decoded.state == 2); + assert(decoded.duration == 0x1234); } test "opcode_constant" { - try std.testing.expect(OP_DROWSY_RET == 0xEC); + assert(OP_DROWSY_RET == 0xEC); } // ============================================================================ // Invariants // ============================================================================ -} invariant drowsy_state_range - try std.testing.expect(DROWSY_ACTIVE >= 0 and DROWSY_CRITICAL <= 5); + assert DROWSY_ACTIVE >= 0 and DROWSY_CRITICAL <= 5 invariant ret_reason_range - try std.testing.expect(RET_WAKE >= 0 and RET_MAX <= 6); + assert RET_WAKE >= 0 and RET_MAX <= 6 invariant wake_cycles_positive assert WAKE_CYCLES > 0 and DEEP_WAKE_CYCLES > 0 @@ -613,59 +615,68 @@ invariant deep_wake_larger_than_light invariant drowsy_is_drowsy_excludes_active_off given state = DrowsyState.active assert drowsy_is_drowsy(state) == false - try std.testing.expect(drowsy_is_off(DrowsyState.light) == false); + assert drowsy_is_off(DrowsyState.light) == false invariant drowsy_is_off_excludes_active_drowsy given state = DrowsyState.active assert drowsy_is_off(state) == false - try std.testing.expect(drowsy_is_off(DrowsyState.light) == false); + assert drowsy_is_off(DrowsyState.light) == false invariant drowsy_config_init_enables_light given config = drowsy_config_init() - try std.testing.expect(config.enable_light == true); + assert config.enable_light == true -invariant drowsy_config_enable_both_or_neither - given config1 = drowsy_config_init() - try std.testing.expect(config2 = drowsy_config_light_only(100)); - try std.testing.expect((config1.enable_light and config1.enable_deep) or (not config1.enable_light and not config1.enable_deep)); - or (config2.enable_light and not config2.enable_deep) +// The original closed expect(...); checked config1 only; it was followed by a +// dangling `or (config2...)` line. That fragment is kept as its own assertion +// so the config1 check keeps its full strength. +invariant drowsy_config_enable_both_or_neither { + const config1 = drowsy_config_init(); + const config2 = drowsy_config_light_only(100); + assert((config1.enable_light and config1.enable_deep) or (!config1.enable_light and !config1.enable_deep)); + assert(config2.enable_light and !config2.enable_deep); +} invariant drowsy_status_init_active given status = drowsy_status_init() - try std.testing.expect(status.state == DrowsyState.active); + assert status.state == DrowsyState.active -invariant drowsy_status_wake_increases_count - given status = drowsy_status_init() - try std.testing.expect(result = drowsy_status_wake(status, RetReason.manual, 100)); - try std.testing.expect(result.wake_count == status.wake_count + 1); +invariant drowsy_status_wake_increases_count { + const status = drowsy_status_init(); + const result = drowsy_status_wake(status, RetReason.manual, 100); + assert(result.wake_count == status.wake_count + 1); +} -invariant drowsy_status_wake_sets_active - given status = DrowsyStatus{.state = DrowsyState.light, .last_wake_cycle = 0, .drowsy_duration = 100, .wake_count = 5, .last_ret_reason = RetReason.timer} - try std.testing.expect(result = drowsy_status_wake(status, RetReason.interrupt, 200)); - try std.testing.expect(result.state == DrowsyState.active); +invariant drowsy_status_wake_sets_active { + const status = DrowsyStatus{.state = DrowsyState.light, .last_wake_cycle = 0, .drowsy_duration = 100, .wake_count = 5, .last_ret_reason = RetReason.timer}; + const result = drowsy_status_wake(status, RetReason.interrupt, 200); + assert(result.state == DrowsyState.active); +} -invariant drowsy_status_enter_critical_reason - given status = drowsy_status_init() - try std.testing.expect(result = drowsy_status_enter_critical(status)); - try std.testing.expect(result.last_ret_reason == RetReason.error); +invariant drowsy_status_enter_critical_reason { + const status = drowsy_status_init(); + const result = drowsy_status_enter_critical(status); + assert(result.last_ret_reason == RetReason.error); +} invariant drowsy_wake_condition_init_defaults given cond = drowsy_wake_condition_init() - try std.testing.expect(cond.irq_pending == false and cond.timer_expired == false and cond.manual_wake == false); + assert cond.irq_pending == false and cond.timer_expired == false and cond.manual_wake == false invariant drowsy_should_wake_false_for_default given cond = drowsy_wake_condition_init() - try std.testing.expect(drowsy_should_wake(cond) == false); + assert drowsy_should_wake(cond) == false -invariant drowsy_wake_from_condition_no_match - given cond = drowsy_wake_condition_init() - try std.testing.expect(reason = drowsy_wake_from_condition(cond)); - try std.testing.expect(reason == RetReason.wake); +invariant drowsy_wake_from_condition_no_match { + const cond = drowsy_wake_condition_init(); + const reason = drowsy_wake_from_condition(cond); + assert(reason == RetReason.wake); +} -invariant drowsy_update_duration_zero_for_non_drowsy - given status = DrowsyStatus{.state = DrowsyState.active, .last_wake_cycle = 0, .drowsy_duration = 10, .wake_count = 0, .last_ret_reason = RetReason.manual} - try std.testing.expect(result = drowsy_update_duration(status, 100)); - try std.testing.expect(result.drowsy_duration == 0); +invariant drowsy_update_duration_zero_for_non_drowsy { + const status = DrowsyStatus{.state = DrowsyState.active, .last_wake_cycle = 0, .drowsy_duration = 10, .wake_count = 0, .last_ret_reason = RetReason.manual}; + const result = drowsy_update_duration(status, 100); + assert(result.drowsy_duration == 0); +} // ============================================================================ // Benchmarks diff --git a/specs/fpga/fbb_active_path.t27 b/specs/fpga/fbb_active_path.t27 index 4a401de..3958f70 100644 --- a/specs/fpga/fbb_active_path.t27 +++ b/specs/fpga/fbb_active_path.t27 @@ -240,8 +240,8 @@ pub fn fbb_path_status_update_metrics(status: FbbPathStatus, throughput: u32, la // Initialize active path pub fn fbb_active_path_init() -> FbbActivePath { var paths : [FBB_MAX_PATHS]FbbPathStatus = undefined; - for (0..FBB_MAX_PATHS) |i| { - paths[i] = fbb_path_status_init(@as(u8, @truncate(i))); + for i in 0..FBB_MAX_PATHS { + paths[i] = fbb_path_status_init(i as u8); } return FbbActivePath { .active_path = 0, @@ -372,9 +372,12 @@ pub fn fbb_bandwidth_valid(bandwidth: u32) -> bool { // fbb_path_config_valid(config: FbbPathConfig) -> bool // Check if path config is valid pub fn fbb_path_config_valid(config: FbbPathConfig) -> bool { + // The upstream text had the second and third conjuncts rewritten as + // test assertions inside this fn body; the config is valid when all three + // checks hold (see test fbb_path_config_valid_false_invalid_latency). return fbb_path_index_valid(config.path_index) - try std.testing.expect(fbb_latency_valid(config.latency_cycles)); - try std.testing.expect(fbb_bandwidth_valid(config.bandwidth_mbps);); + and fbb_latency_valid(config.latency_cycles) + and fbb_bandwidth_valid(config.bandwidth_mbps); } // ============================================================================ @@ -385,20 +388,20 @@ pub fn fbb_path_config_valid(config: FbbPathConfig) -> bool { // Encode FBB command pub fn encode_fbb_cmd(op: u8, path: u8, param1: u8, param2: u8) u32 { // Format: [OP:8][PATH:3][PARAM1:8][PARAM2:8][RES:5] - const op_field : u32 = @as(u32, op) << 24; - const path_field : u32 = @as(u32, path & 0x07) << 21; - const param1_field : u32 = @as(u32, param1) << 13; - const param2_field : u32 = @as(u32, param2) << 5; + const op_field : u32 = (op as u32) << 24; + const path_field : u32 = ((path & 0x07) as u32) << 21; + const param1_field : u32 = (param1 as u32) << 13; + const param2_field : u32 = (param2 as u32) << 5; return op_field | path_field | param1_field | param2_field; } // decode_fbb_cmd(encoded: u32) -> struct { op: u8, path: u8, param1: u8, param2: u8 } // Decode FBB command pub fn decode_fbb_cmd(encoded: u32) -> struct { op: u8, path: u8, param1: u8, param2: u8 } { - const op : u8 = @as(u8, @truncate((encoded >> 24) & 0xFF)); - const path : u8 = @as(u8, @truncate((encoded >> 21) & 0x07)); - const param1 : u8 = @as(u8, @truncate((encoded >> 13) & 0xFF)); - const param2 : u8 = @as(u8, @truncate((encoded >> 5) & 0xFF)); + const op : u8 = ((encoded >> 24) & 0xFF) as u8; + const path : u8 = ((encoded >> 21) & 0x07) as u8; + const param1 : u8 = ((encoded >> 13) & 0xFF) as u8; + const param2 : u8 = ((encoded >> 5) & 0xFF) as u8; return .{ .op = op, .path = path, .param1 = param1, .param2 = param2 }; } @@ -407,222 +410,221 @@ pub fn decode_fbb_cmd(encoded: u32) -> struct { op: u8, path: u8, param1: u8, pa // ============================================================================ test "fbb_opcode_base" { - try std.testing.expect(FBB_OPCODE_BASE == 0xD0); + assert(FBB_OPCODE_BASE == 0xD0); } test "fbb_op_constants" { - try std.testing.expect(FBB_OP_PATH_SELECT == 0); - try std.testing.expect(FBB_OP_PATH_ENABLE == 1); - try std.testing.expect(FBB_OP_PATH_DISABLE == 2); - try std.testing.expect(FBB_OP_PATH_BYPASS == 5); + assert(FBB_OP_PATH_SELECT == 0); + assert(FBB_OP_PATH_ENABLE == 1); + assert(FBB_OP_PATH_DISABLE == 2); + assert(FBB_OP_PATH_BYPASS == 5); } test "fbb_path_state_constants" { - try std.testing.expect(FBB_PATH_STATE_DISABLED == 0); - try std.testing.expect(FBB_PATH_STATE_ENABLED == 1); - try std.testing.expect(FBB_PATH_STATE_ACTIVE == 2); - try std.testing.expect(FBB_PATH_STATE_BYPASSED == 4); + assert(FBB_PATH_STATE_DISABLED == 0); + assert(FBB_PATH_STATE_ENABLED == 1); + assert(FBB_PATH_STATE_ACTIVE == 2); + assert(FBB_PATH_STATE_BYPASSED == 4); } test "fbb_path_count" { - try std.testing.expect(FBB_PATH_COUNT == 8); - try std.testing.expect(FBB_MAX_PATHS == 8); + assert(FBB_PATH_COUNT == 8); + assert(FBB_MAX_PATHS == 8); } test "latency_constants" { - try std.testing.expect(FBB_LATENCY_MIN_CYCLES == 1); - try std.testing.expect(FBB_LATENCY_MAX_CYCLES == 16); - try std.testing.expect(FBB_DEFAULT_LATENCY == 4); + assert(FBB_LATENCY_MIN_CYCLES == 1); + assert(FBB_LATENCY_MAX_CYCLES == 16); + assert(FBB_DEFAULT_LATENCY == 4); } test "bandwidth_constants" { - try std.testing.expect(FBB_BANDWIDTH_MIN_MBPS == 100); - try std.testing.expect(FBB_BANDWIDTH_MAX_MBPS == 10000); - try std.testing.expect(FBB_DEFAULT_BANDWIDTH == 1000); + assert(FBB_BANDWIDTH_MIN_MBPS == 100); + assert(FBB_BANDWIDTH_MAX_MBPS == 10000); + assert(FBB_DEFAULT_BANDWIDTH == 1000); } test "fbb_path_config_init_structure" { - given config = fbb_path_config_init(0) - try std.testing.expect(config.path_index == 0); - try std.testing.expect(config.enabled == false); - try std.testing.expect(config.latency_cycles == FBB_DEFAULT_LATENCY); + const config = fbb_path_config_init(0); + assert(config.path_index == 0); + assert(config.enabled == false); + assert(config.latency_cycles == FBB_DEFAULT_LATENCY); } test "fbb_path_config_low_latency_structure" { - given config = fbb_path_config_low_latency(1) - try std.testing.expect(config.path_index == 1); - try std.testing.expect(config.latency_cycles == FBB_LATENCY_MIN_CYCLES); - try std.testing.expect(config.priority == 7); + const config = fbb_path_config_low_latency(1); + assert(config.path_index == 1); + assert(config.latency_cycles == FBB_LATENCY_MIN_CYCLES); + assert(config.priority == 7); } test "fbb_path_config_high_bandwidth_structure" { - given config = fbb_path_config_high_bandwidth(2) - try std.testing.expect(config.path_index == 2); - try std.testing.expect(config.bandwidth_mbps == FBB_BANDWIDTH_MAX_MBPS); + const config = fbb_path_config_high_bandwidth(2); + assert(config.path_index == 2); + assert(config.bandwidth_mbps == FBB_BANDWIDTH_MAX_MBPS); } test "fbb_path_config_enable" { - given config = fbb_path_config_init(0) - try std.testing.expect(result = fbb_path_config_enable(config)); - try std.testing.expect(result.enabled == true); + const config = fbb_path_config_init(0); + const result = fbb_path_config_enable(config); + assert(result.enabled == true); } test "fbb_path_status_init_structure" { - given status = fbb_path_status_init(0) - try std.testing.expect(status.path_index == 0); - try std.testing.expect(status.state == FbbPathState.disabled); - try std.testing.expect(status.active == false); + const status = fbb_path_status_init(0); + assert(status.path_index == 0); + assert(status.state == FbbPathState.disabled); + assert(status.active == false); } test "fbb_path_status_enable" { - given status = fbb_path_status_init(0) - try std.testing.expect(result = fbb_path_status_enable(status)); - try std.testing.expect(result.state == FbbPathState.enabled); - try std.testing.expect(result.active == false); + const status = fbb_path_status_init(0); + const result = fbb_path_status_enable(status); + assert(result.state == FbbPathState.enabled); + assert(result.active == false); } test "fbb_path_status_activate" { - given status = fbb_path_status_init(0) - try std.testing.expect(result = fbb_path_status_activate(status)); - try std.testing.expect(result.state == FbbPathState.active); - try std.testing.expect(result.active == true); + const status = fbb_path_status_init(0); + const result = fbb_path_status_activate(status); + assert(result.state == FbbPathState.active); + assert(result.active == true); } test "fbb_path_status_bypass" { - given status = fbb_path_status_init(0) - try std.testing.expect(result = fbb_path_status_bypass(status)); - try std.testing.expect(result.state == FbbPathState.bypassed); - try std.testing.expect(result.active == false); + const status = fbb_path_status_init(0); + const result = fbb_path_status_bypass(status); + assert(result.state == FbbPathState.bypassed); + assert(result.active == false); } test "fbb_path_status_error" { - given status = fbb_path_status_init(0) - try std.testing.expect(result = fbb_path_status_error(status, 1)); - try std.testing.expect(result.state == FbbPathState.error); - try std.testing.expect(result.error_code == 1); + const status = fbb_path_status_init(0); + const result = fbb_path_status_error(status, 1); + assert(result.state == FbbPathState.error); + assert(result.error_code == 1); } test "fbb_path_status_update_metrics" { - given status = fbb_path_status_init(0) - try std.testing.expect(result = fbb_path_status_update_metrics(status, 5000, 100)); - try std.testing.expect(result.throughput_mbps == 5000); - try std.testing.expect(result.latency_measured == 100); + const status = fbb_path_status_init(0); + const result = fbb_path_status_update_metrics(status, 5000, 100); + assert(result.throughput_mbps == 5000); + assert(result.latency_measured == 100); } test "fbb_active_path_init_structure" { - given active = fbb_active_path_init() - try std.testing.expect(active.active_path == 0); - try std.testing.expect(active.bypass_path == 0xFF); - try std.testing.expect(active.loopback_enabled == false); + const active = fbb_active_path_init(); + assert(active.active_path == 0); + assert(active.bypass_path == 0xFF); + assert(active.loopback_enabled == false); } test "fbb_active_path_select" { - given active = fbb_active_path_init() - try std.testing.expect(result = fbb_active_path_select(active, 3)); - try std.testing.expect(result.active_path == 3); - try std.testing.expect(result.paths[3].active == true); + const active = fbb_active_path_init(); + const result = fbb_active_path_select(active, 3); + assert(result.active_path == 3); + assert(result.paths[3].active == true); } test "fbb_active_path_enable_bypass" { - given active = fbb_active_path_init() - try std.testing.expect(result = fbb_active_path_enable_bypass(active, 5)); - try std.testing.expect(result.bypass_path == 5); - try std.testing.expect(result.paths[5].state == FbbPathState.bypassed); + const active = fbb_active_path_init(); + const result = fbb_active_path_enable_bypass(active, 5); + assert(result.bypass_path == 5); + assert(result.paths[5].state == FbbPathState.bypassed); } test "fbb_active_path_disable_bypass" { - given active = fbb_active_path_init() - try std.testing.expect(with_bypass = fbb_active_path_enable_bypass(active, 5)); - try std.testing.expect(result = fbb_active_path_disable_bypass(with_bypass)); - try std.testing.expect(result.bypass_path == 0xFF); + const active = fbb_active_path_init(); + const with_bypass = fbb_active_path_enable_bypass(active, 5); + const result = fbb_active_path_disable_bypass(with_bypass); + assert(result.bypass_path == 0xFF); } test "fbb_active_path_enable_loopback" { - given active = fbb_active_path_init() - try std.testing.expect(result = fbb_active_path_enable_loopback(active)); - try std.testing.expect(result.loopback_enabled == true); + const active = fbb_active_path_init(); + const result = fbb_active_path_enable_loopback(active); + assert(result.loopback_enabled == true); } test "fbb_active_path_disable_loopback" { - given active = fbb_active_path_init() - try std.testing.expect(with_loopback = fbb_active_path_enable_loopback(active)); - try std.testing.expect(result = fbb_active_path_disable_loopback(with_loopback)); - try std.testing.expect(result.loopback_enabled == false); + const active = fbb_active_path_init(); + const with_loopback = fbb_active_path_enable_loopback(active); + const result = fbb_active_path_disable_loopback(with_loopback); + assert(result.loopback_enabled == false); } test "fbb_active_path_get_path" { - given active = fbb_active_path_init() - try std.testing.expect(result = fbb_active_path_get_path(active, 2)); - try std.testing.expect(result.path_index == 2); + const active = fbb_active_path_init(); + const result = fbb_active_path_get_path(active, 2); + assert(result.path_index == 2); } test "fbb_active_path_update_path_metrics" { - given active = fbb_active_path_init() - try std.testing.expect(result = fbb_active_path_update_path_metrics(active, 2, 3000, 50)); - try std.testing.expect(result.paths[2].throughput_mbps == 3000); + const active = fbb_active_path_init(); + const result = fbb_active_path_update_path_metrics(active, 2, 3000, 50); + assert(result.paths[2].throughput_mbps == 3000); } test "fbb_path_index_valid_true" { - try std.testing.expect(fbb_path_index_valid(0) == true); - try std.testing.expect(fbb_path_index_valid(7) == true); + assert(fbb_path_index_valid(0) == true); + assert(fbb_path_index_valid(7) == true); } test "fbb_path_index_valid_false" { - try std.testing.expect(fbb_path_index_valid(8) == false); - try std.testing.expect(fbb_path_index_valid(255) == false); + assert(fbb_path_index_valid(8) == false); + assert(fbb_path_index_valid(255) == false); } test "fbb_latency_valid_true" { - try std.testing.expect(fbb_latency_valid(1) == true); - try std.testing.expect(fbb_latency_valid(10) == true); - try std.testing.expect(fbb_latency_valid(16) == true); + assert(fbb_latency_valid(1) == true); + assert(fbb_latency_valid(10) == true); + assert(fbb_latency_valid(16) == true); } test "fbb_latency_valid_false" { - try std.testing.expect(fbb_latency_valid(0) == false); - try std.testing.expect(fbb_latency_valid(17) == false); + assert(fbb_latency_valid(0) == false); + assert(fbb_latency_valid(17) == false); } test "fbb_bandwidth_valid_true" { - try std.testing.expect(fbb_bandwidth_valid(100) == true); - try std.testing.expect(fbb_bandwidth_valid(5000) == true); - try std.testing.expect(fbb_bandwidth_valid(10000) == true); + assert(fbb_bandwidth_valid(100) == true); + assert(fbb_bandwidth_valid(5000) == true); + assert(fbb_bandwidth_valid(10000) == true); } test "fbb_bandwidth_valid_false" { - try std.testing.expect(fbb_bandwidth_valid(50) == false); - try std.testing.expect(fbb_bandwidth_valid(20000) == false); + assert(fbb_bandwidth_valid(50) == false); + assert(fbb_bandwidth_valid(20000) == false); } test "fbb_path_config_valid_true" { - given config = fbb_path_config_init(0) - try std.testing.expect(fbb_path_config_valid(config) == true); + const config = fbb_path_config_init(0); + assert(fbb_path_config_valid(config) == true); } test "fbb_path_config_valid_false_invalid_latency" { - given config = FbbPathConfig{.path_index = 0, .enabled = false, .latency_cycles = 0, .bandwidth_mbps = 1000, .priority = 4, .auto_bypass = false} - try std.testing.expect(fbb_path_config_valid(config) == false); + const config = FbbPathConfig{.path_index = 0, .enabled = false, .latency_cycles = 0, .bandwidth_mbps = 1000, .priority = 4, .auto_bypass = false}; + assert(fbb_path_config_valid(config) == false); } test "encode_fbb_cmd" { - given encoded = encode_fbb_cmd(0x00, 3, 10, 20) - try std.testing.expect((encoded >> 24) == 0x00); + const encoded = encode_fbb_cmd(0x00, 3, 10, 20); + assert((encoded >> 24) == 0x00); } test "decode_fbb_cmd" { - given decoded = decode_fbb_cmd(0x001A14A0) - try std.testing.expect(decoded.op == 0); - try std.testing.expect(decoded.path == 3); + const decoded = decode_fbb_cmd(0x001A14A0); + assert(decoded.op == 0); + assert(decoded.path == 3); } // ============================================================================ // Invariants // ============================================================================ -} invariant fbb_path_count_positive assert FBB_PATH_COUNT > 0 - try std.testing.expect(FBB_MAX_PATHS == FBB_PATH_COUNT); + assert FBB_MAX_PATHS == FBB_PATH_COUNT invariant latency_range_positive assert FBB_LATENCY_MIN_CYCLES > 0 and FBB_LATENCY_MAX_CYCLES >= FBB_LATENCY_MIN_CYCLES @@ -650,50 +652,50 @@ invariant fbb_path_config_high_bandwidth_max_bandwidth invariant fbb_path_status_init_disabled given status = fbb_path_status_init(0) - try std.testing.expect(status.state == FbbPathState.disabled); + assert status.state == FbbPathState.disabled invariant fbb_path_status_enable_enabled_not_active given status = fbb_path_status_init(0) - try std.testing.expect(result = fbb_path_status_enable(status)); - try std.testing.expect(result.state == FbbPathState.enabled and result.active == false); + when result = fbb_path_status_enable(status) + assert result.state == FbbPathState.enabled and result.active == false invariant fbb_path_status_activate_active given status = fbb_path_status_init(0) - try std.testing.expect(result = fbb_path_status_activate(status)); - try std.testing.expect(result.state == FbbPathState.active and result.active == true); + when result = fbb_path_status_activate(status) + assert result.state == FbbPathState.active and result.active == true invariant fbb_path_status_bypass_bypassed_not_active given status = fbb_path_status_init(0) - try std.testing.expect(result = fbb_path_status_bypass(status)); - try std.testing.expect(result.state == FbbPathState.bypassed and result.active == false); + when result = fbb_path_status_bypass(status) + assert result.state == FbbPathState.bypassed and result.active == false invariant fbb_active_path_init_no_bypass given active = fbb_active_path_init() - try std.testing.expect(active.bypass_path == 0xFF); + assert active.bypass_path == 0xFF invariant fbb_active_path_select_updates_active given active = fbb_active_path_init() - try std.testing.expect(result = fbb_active_path_select(active, 5)); - try std.testing.expect(result.active_path == 5); + when result = fbb_active_path_select(active, 5) + assert result.active_path == 5 invariant fbb_active_path_enable_loopback_sets_flag given active = fbb_active_path_init() - try std.testing.expect(result = fbb_active_path_enable_loopback(active)); - try std.testing.expect(result.loopback_enabled == true); + when result = fbb_active_path_enable_loopback(active) + assert result.loopback_enabled == true invariant fbb_active_path_disable_loopback_clears_flag given active = fbb_active_path_init() - try std.testing.expect(with_loopback = fbb_active_path_enable_loopback(active)); - try std.testing.expect(result = fbb_active_path_disable_loopback(with_loopback)); - try std.testing.expect(result.loopback_enabled == false); + when with_loopback = fbb_active_path_enable_loopback(active) + and result = fbb_active_path_disable_loopback(with_loopback) + assert result.loopback_enabled == false invariant fbb_path_index_valid_range - assert fbb_path_index_valid(0) and not fbb_path_index_valid(FBB_PATH_COUNT) + assert fbb_path_index_valid(0) and !fbb_path_index_valid(FBB_PATH_COUNT) invariant fbb_latency_valid_range assert fbb_latency_valid(FBB_LATENCY_MIN_CYCLES) - try std.testing.expect(fbb_latency_valid(FBB_LATENCY_MAX_CYCLES)); - try std.testing.expect(not fbb_latency_valid(FBB_LATENCY_MAX_CYCLES + 1)); + assert fbb_latency_valid(FBB_LATENCY_MAX_CYCLES) + assert !fbb_latency_valid(FBB_LATENCY_MAX_CYCLES + 1) // ============================================================================ // Benchmarks diff --git a/specs/fpga/fp8_e4m3.t27 b/specs/fpga/fp8_e4m3.t27 index 06fb882..da6ce19 100644 --- a/specs/fpga/fp8_e4m3.t27 +++ b/specs/fpga/fp8_e4m3.t27 @@ -467,446 +467,445 @@ pub fn fp8_quantize_to_int8(value: FP8E4M3) i8 { // ============================================================================ test "fp8_extract_sign_positive" { - given value = 0x3C - try std.testing.expect(sign = fp8_extract_sign(value)); - try std.testing.expect(sign == 0); + const value = 0x3C; + const sign = fp8_extract_sign(value); + assert(sign == 0); } test "fp8_extract_sign_negative" { - given value = 0xBC - try std.testing.expect(sign = fp8_extract_sign(value)); - try std.testing.expect(sign == -1); + const value = 0xBC; + const sign = fp8_extract_sign(value); + assert(sign == -1); } test "fp8_extract_exponent_max" { - given value = 0x78 - try std.testing.expect(exp = fp8_extract_exponent(value)); - try std.testing.expect(exp == EXP_MAX); + const value = 0x78; + const exp = fp8_extract_exponent(value); + assert(exp == EXP_MAX); } test "fp8_extract_exponent_zero" { - given value = 0x07 - try std.testing.expect(exp = fp8_extract_exponent(value)); - try std.testing.expect(exp == 0); + const value = 0x07; + const exp = fp8_extract_exponent(value); + assert(exp == 0); } test "fp8_extract_mantissa_max" { - given value = 0x07 - try std.testing.expect(mant = fp8_extract_mantissa(value)); - try std.testing.expect(mant == MANT_MASK); + const value = 0x07; + const mant = fp8_extract_mantissa(value); + assert(mant == MANT_MASK); } test "fp8_is_zero_positive" { - try std.testing.expect(fp8_is_zero(FP8_ZERO_POS) == true); + assert(fp8_is_zero(FP8_ZERO_POS) == true); } test "fp8_is_zero_negative" { - try std.testing.expect(fp8_is_zero(FP8_ZERO_NEG) == true); + assert(fp8_is_zero(FP8_ZERO_NEG) == true); } test "fp8_is_zero_nonzero" { - try std.testing.expect(fp8_is_zero(0x01) == false); + assert(fp8_is_zero(0x01) == false); } test "fp8_is_inf_positive" { - try std.testing.expect(fp8_is_inf(FP8_INF_POS) == true); + assert(fp8_is_inf(FP8_INF_POS) == true); } test "fp8_is_inf_negative" { - try std.testing.expect(fp8_is_inf(FP8_INF_NEG) == true); + assert(fp8_is_inf(FP8_INF_NEG) == true); } test "fp8_is_nan_positive" { - try std.testing.expect(fp8_is_nan(FP8_NAN_POS) == true); + assert(fp8_is_nan(FP8_NAN_POS) == true); } test "fp8_is_nan_negative" { - try std.testing.expect(fp8_is_nan(FP8_NAN_NEG) == true); + assert(fp8_is_nan(FP8_NAN_NEG) == true); } test "fp8_is_inf_not_nan" { - try std.testing.expect(fp8_is_inf(FP8_INF_POS) == true and fp8_is_nan(FP8_INF_POS) == false); + assert(fp8_is_inf(FP8_INF_POS) == true and fp8_is_nan(FP8_INF_POS) == false); } test "fp8_is_special_inf" { - try std.testing.expect(fp8_is_special(FP8_INF_POS) == true); + assert(fp8_is_special(FP8_INF_POS) == true); } test "fp8_is_special_nan" { - try std.testing.expect(fp8_is_special(FP8_NAN_POS) == true); + assert(fp8_is_special(FP8_NAN_POS) == true); } test "fp8_is_subnormal_true" { - given value = 0x01 - try std.testing.expect(fp8_is_subnormal(value) == true); + const value = 0x01; + assert(fp8_is_subnormal(value) == true); } test "fp8_is_subnormal_false_normal" { - given value = 0x08 - try std.testing.expect(fp8_is_subnormal(value) == false); + const value = 0x08; + assert(fp8_is_subnormal(value) == false); } test "fp8_is_subnormal_false_zero" { - try std.testing.expect(fp8_is_subnormal(FP8_ZERO_POS) == false); + assert(fp8_is_subnormal(FP8_ZERO_POS) == false); } test "fp8_encode_f32_zero" { - given fp = fp8_encode_f32(0.0) - try std.testing.expect(fp == FP8_ZERO_POS); + const fp = fp8_encode_f32(0.0); + assert(fp == FP8_ZERO_POS); } test "fp8_encode_f32_negative_zero" { - given fp = fp8_encode_f32(-0.0) - try std.testing.expect(fp == FP8_ZERO_NEG); + const fp = fp8_encode_f32(-0.0); + assert(fp == FP8_ZERO_NEG); } test "fp8_encode_f32_one" { - given fp = fp8_encode_f32(1.0) - try std.testing.expect(decoded = fp8_decode_f32(fp)); - try std.testing.expect(abs(decoded - 1.0) < 0.05); + const fp = fp8_encode_f32(1.0); + const decoded = fp8_decode_f32(fp); + assert(abs(decoded - 1.0) < 0.05); } test "fp8_encode_f32_negative_one" { - given fp = fp8_encode_f32(-1.0) - try std.testing.expect(decoded = fp8_decode_f32(fp)); - try std.testing.expect(abs(decoded + 1.0) < 0.05); + const fp = fp8_encode_f32(-1.0); + const decoded = fp8_decode_f32(fp); + assert(abs(decoded + 1.0) < 0.05); } test "fp8_encode_f32_two" { - given fp = fp8_encode_f32(2.0) - try std.testing.expect(decoded = fp8_decode_f32(fp)); - try std.testing.expect(abs(decoded - 2.0) < 0.1); + const fp = fp8_encode_f32(2.0); + const decoded = fp8_decode_f32(fp); + assert(abs(decoded - 2.0) < 0.1); } test "fp8_encode_f32_half" { - given fp = fp8_encode_f32(0.5) - try std.testing.expect(decoded = fp8_decode_f32(fp)); - try std.testing.expect(abs(decoded - 0.5) < 0.05); + const fp = fp8_encode_f32(0.5); + const decoded = fp8_decode_f32(fp); + assert(abs(decoded - 0.5) < 0.05); } test "fp8_encode_f32_roundtrip_positive" { - given original = 1.5 - try std.testing.expect(fp = fp8_encode_f32(original)); - try std.testing.expect(decoded = fp8_decode_f32(fp)); - try std.testing.expect(abs(decoded - original) < 0.1); + const original = 1.5; + const fp = fp8_encode_f32(original); + const decoded = fp8_decode_f32(fp); + assert(abs(decoded - original) < 0.1); } test "fp8_encode_f32_roundtrip_negative" { - given original = -1.5 - try std.testing.expect(fp = fp8_encode_f32(original)); - try std.testing.expect(decoded = fp8_decode_f32(fp)); - try std.testing.expect(abs(decoded - original) < 0.1); + const original = -1.5; + const fp = fp8_encode_f32(original); + const decoded = fp8_decode_f32(fp); + assert(abs(decoded - original) < 0.1); } test "fp8_encode_f32_nan" { - given fp = fp8_encode_f32(std.math.nan(f32)) - try std.testing.expect(fp8_is_nan(fp) == true); + const fp = fp8_encode_f32(std.math.nan(f32)); + assert(fp8_is_nan(fp) == true); } test "fp8_encode_f32_inf" { - given fp = fp8_encode_f32(std.math.inf(f32)) - try std.testing.expect(fp8_is_inf(fp) == true); + const fp = fp8_encode_f32(std.math.inf(f32)); + assert(fp8_is_inf(fp) == true); } test "fp8_encode_f32_neg_inf" { - given fp = fp8_encode_f32(-std.math.inf(f32)) - try std.testing.expect(fp8_is_inf(fp) == true); + const fp = fp8_encode_f32(-std.math.inf(f32)); + assert(fp8_is_inf(fp) == true); } test "fp8_decode_f32_zero" { - try std.testing.expect(fp8_decode_f32(FP8_ZERO_POS) == 0.0); + assert(fp8_decode_f32(FP8_ZERO_POS) == 0.0); } test "fp8_decode_f32_negative_zero" { - try std.testing.expect(fp8_decode_f32(FP8_ZERO_NEG) == -0.0); + assert(fp8_decode_f32(FP8_ZERO_NEG) == -0.0); } test "fp8_decode_f32_inf" { - try std.testing.expect(std.math.isInf(fp8_decode_f32(FP8_INF_POS)) == true); + assert(std.math.isInf(fp8_decode_f32(FP8_INF_POS)) == true); } test "fp8_decode_f32_neg_inf" { - try std.testing.expect(std.math.isInf(fp8_decode_f32(FP8_INF_NEG)) == true); + assert(std.math.isInf(fp8_decode_f32(FP8_INF_NEG)) == true); } test "fp8_decode_f32_nan" { - try std.testing.expect(std.math.isNan(fp8_decode_f32(FP8_NAN_POS)) == true); + assert(std.math.isNan(fp8_decode_f32(FP8_NAN_POS)) == true); } test "fp8_add_simple" { - given a = fp8_encode_f32(1.0) - try std.testing.expect(b = fp8_encode_f32(2.0)); - try std.testing.expect(result = fp8_add(a, b)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 3.0) < 0.15); + const a = fp8_encode_f32(1.0); + const b = fp8_encode_f32(2.0); + const result = fp8_add(a, b); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 3.0) < 0.15); } test "fp8_sub_simple" { - given a = fp8_encode_f32(5.0) - try std.testing.expect(b = fp8_encode_f32(3.0)); - try std.testing.expect(result = fp8_sub(a, b)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 2.0) < 0.15); + const a = fp8_encode_f32(5.0); + const b = fp8_encode_f32(3.0); + const result = fp8_sub(a, b); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 2.0) < 0.15); } test "fp8_mul_simple" { - given a = fp8_encode_f32(3.0) - try std.testing.expect(b = fp8_encode_f32(2.0)); - try std.testing.expect(result = fp8_mul(a, b)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 6.0) < 0.3); + const a = fp8_encode_f32(3.0); + const b = fp8_encode_f32(2.0); + const result = fp8_mul(a, b); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 6.0) < 0.3); } test "fp8_div_simple" { - given a = fp8_encode_f32(6.0) - try std.testing.expect(b = fp8_encode_f32(3.0)); - try std.testing.expect(result = fp8_div(a, b)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 2.0) < 0.15); + const a = fp8_encode_f32(6.0); + const b = fp8_encode_f32(3.0); + const result = fp8_div(a, b); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 2.0) < 0.15); } test "fp8_div_by_zero_positive" { - given a = fp8_encode_f32(5.0) - try std.testing.expect(b = fp8_encode_f32(0.0)); - try std.testing.expect(result = fp8_div(a, b)); - try std.testing.expect(result == FP8_INF_POS); + const a = fp8_encode_f32(5.0); + const b = fp8_encode_f32(0.0); + const result = fp8_div(a, b); + assert(result == FP8_INF_POS); } test "fp8_div_by_zero_negative" { - given a = fp8_encode_f32(-5.0) - try std.testing.expect(b = fp8_encode_f32(0.0)); - try std.testing.expect(result = fp8_div(a, b)); - try std.testing.expect(result == FP8_INF_NEG); + const a = fp8_encode_f32(-5.0); + const b = fp8_encode_f32(0.0); + const result = fp8_div(a, b); + assert(result == FP8_INF_NEG); } test "fp8_sqrt_four" { - given value = fp8_encode_f32(4.0) - try std.testing.expect(result = fp8_sqrt(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 2.0) < 0.1); + const value = fp8_encode_f32(4.0); + const result = fp8_sqrt(value); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 2.0) < 0.1); } test "fp8_sqrt_negative" { - given value = fp8_encode_f32(-4.0) - try std.testing.expect(result = fp8_sqrt(value)); - try std.testing.expect(fp8_is_nan(result) == true); + const value = fp8_encode_f32(-4.0); + const result = fp8_sqrt(value); + assert(fp8_is_nan(result) == true); } test "fp8_rsqrt_four" { - given value = fp8_encode_f32(4.0) - try std.testing.expect(result = fp8_rsqrt(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 0.5) < 0.1); + const value = fp8_encode_f32(4.0); + const result = fp8_rsqrt(value); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 0.5) < 0.1); } test "fp8_abs_positive" { - given value = fp8_encode_f32(5.0) - try std.testing.expect(result = fp8_abs(value)); - try std.testing.expect(fp8_is_equal(result, value) == true); + const value = fp8_encode_f32(5.0); + const result = fp8_abs(value); + assert(fp8_is_equal(result, value) == true); } test "fp8_abs_negative" { - given value = fp8_encode_f32(-5.0) - try std.testing.expect(abs_val = fp8_abs(value)); - try std.testing.expect(fp8_extract_sign(abs_val) == 0); + const value = fp8_encode_f32(-5.0); + const abs_val = fp8_abs(value); + assert(fp8_extract_sign(abs_val) == 0); } test "fp8_neg_positive" { - given value = fp8_encode_f32(5.0) - try std.testing.expect(neg_val = fp8_neg(value)); - try std.testing.expect(fp8_extract_sign(neg_val) < 0); + const value = fp8_encode_f32(5.0); + const neg_val = fp8_neg(value); + assert(fp8_extract_sign(neg_val) < 0); } test "fp8_neg_negative" { - given value = fp8_encode_f32(-5.0) - try std.testing.expect(neg_val = fp8_neg(value)); - try std.testing.expect(fp8_extract_sign(neg_val) == 0); + const value = fp8_encode_f32(-5.0); + const neg_val = fp8_neg(value); + assert(fp8_extract_sign(neg_val) == 0); } test "fp8_is_equal_true" { - given value = fp8_encode_f32(1.0) - try std.testing.expect(fp8_is_equal(value, value) == true); + const value = fp8_encode_f32(1.0); + assert(fp8_is_equal(value, value) == true); } test "fp8_is_equal_false" { - given a = fp8_encode_f32(1.0) - try std.testing.expect(b = fp8_encode_f32(2.0)); - try std.testing.expect(fp8_is_equal(a, b) == false); + const a = fp8_encode_f32(1.0); + const b = fp8_encode_f32(2.0); + assert(fp8_is_equal(a, b) == false); } test "fp8_is_equal_nan" { - try std.testing.expect(fp8_is_equal(FP8_NAN_POS, FP8_NAN_POS) == false); + assert(fp8_is_equal(FP8_NAN_POS, FP8_NAN_POS) == false); } test "fp8_is_equal_zero" { - try std.testing.expect(fp8_is_equal(FP8_ZERO_POS, FP8_ZERO_NEG) == true); + assert(fp8_is_equal(FP8_ZERO_POS, FP8_ZERO_NEG) == true); } test "fp8_is_greater_positive" { - given a = fp8_encode_f32(5.0) - try std.testing.expect(b = fp8_encode_f32(3.0)); - try std.testing.expect(fp8_is_greater(a, b) == true); + const a = fp8_encode_f32(5.0); + const b = fp8_encode_f32(3.0); + assert(fp8_is_greater(a, b) == true); } test "fp8_max_returns_larger" { - given a = fp8_encode_f32(3.0) - try std.testing.expect(b = fp8_encode_f32(5.0)); - try std.testing.expect(result = fp8_max(a, b)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(decoded >= 4.0); + const a = fp8_encode_f32(3.0); + const b = fp8_encode_f32(5.0); + const result = fp8_max(a, b); + const decoded = fp8_decode_f32(result); + assert(decoded >= 4.0); } test "fp8_min_returns_smaller" { - given a = fp8_encode_f32(3.0) - try std.testing.expect(b = fp8_encode_f32(5.0)); - try std.testing.expect(result = fp8_min(a, b)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(decoded <= 4.0); + const a = fp8_encode_f32(3.0); + const b = fp8_encode_f32(5.0); + const result = fp8_min(a, b); + const decoded = fp8_decode_f32(result); + assert(decoded <= 4.0); } test "fp8_lerp_zero" { - given a = fp8_encode_f32(1.0) - try std.testing.expect(b = fp8_encode_f32(5.0)); - try std.testing.expect(t = 0.0); - try std.testing.expect(result = fp8_lerp(a, b, t)); - try std.testing.expect(fp8_is_equal(result, a) == true); + const a = fp8_encode_f32(1.0); + const b = fp8_encode_f32(5.0); + const t = 0.0; + const result = fp8_lerp(a, b, t); + assert(fp8_is_equal(result, a) == true); } test "fp8_lerp_one" { - given a = fp8_encode_f32(1.0) - try std.testing.expect(b = fp8_encode_f32(5.0)); - try std.testing.expect(t = 1.0); - try std.testing.expect(result = fp8_lerp(a, b, t)); - try std.testing.expect(fp8_is_equal(result, b) == true); + const a = fp8_encode_f32(1.0); + const b = fp8_encode_f32(5.0); + const t = 1.0; + const result = fp8_lerp(a, b, t); + assert(fp8_is_equal(result, b) == true); } test "fp8_fma_simple" { - given a = fp8_encode_f32(2.0) - try std.testing.expect(b = fp8_encode_f32(3.0)); - try std.testing.expect(c = fp8_encode_f32(1.0)); - try std.testing.expect(result = fp8_fma(a, b, c)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 7.0) < 0.3); + const a = fp8_encode_f32(2.0); + const b = fp8_encode_f32(3.0); + const c = fp8_encode_f32(1.0); + const result = fp8_fma(a, b, c); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 7.0) < 0.3); } test "fp8_relu_positive" { - given value = fp8_encode_f32(5.0) - try std.testing.expect(result = fp8_relu(value)); - try std.testing.expect(fp8_is_equal(result, value) == true); + const value = fp8_encode_f32(5.0); + const result = fp8_relu(value); + assert(fp8_is_equal(result, value) == true); } test "fp8_relu_negative" { - given value = fp8_encode_f32(-5.0) - try std.testing.expect(result = fp8_relu(value)); - try std.testing.expect(result == FP8_ZERO_POS); + const value = fp8_encode_f32(-5.0); + const result = fp8_relu(value); + assert(result == FP8_ZERO_POS); } test "fp8_relu_zero" { - given result = fp8_relu(FP8_ZERO_POS) - try std.testing.expect(result == FP8_ZERO_POS); + const result = fp8_relu(FP8_ZERO_POS); + assert(result == FP8_ZERO_POS); } test "fp8_sigmoid_zero" { - given value = FP8_ZERO_POS - try std.testing.expect(result = fp8_sigmoid(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 0.5) < 0.05); + const value = FP8_ZERO_POS; + const result = fp8_sigmoid(value); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 0.5) < 0.05); } test "fp8_sigmoid_positive" { - given value = fp8_encode_f32(10.0) - try std.testing.expect(result = fp8_sigmoid(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(decoded >= 0.95); + const value = fp8_encode_f32(10.0); + const result = fp8_sigmoid(value); + const decoded = fp8_decode_f32(result); + assert(decoded >= 0.95); } test "fp8_sigmoid_negative" { - given value = fp8_encode_f32(-10.0) - try std.testing.expect(result = fp8_sigmoid(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(decoded <= 0.05); + const value = fp8_encode_f32(-10.0); + const result = fp8_sigmoid(value); + const decoded = fp8_decode_f32(result); + assert(decoded <= 0.05); } test "fp8_tanh_zero" { - given value = FP8_ZERO_POS - try std.testing.expect(result = fp8_tanh(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded) < 0.05); + const value = FP8_ZERO_POS; + const result = fp8_tanh(value); + const decoded = fp8_decode_f32(result); + assert(abs(decoded) < 0.05); } test "fp8_tanh_positive" { - given value = fp8_encode_f32(10.0) - try std.testing.expect(result = fp8_tanh(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(decoded >= 0.95); + const value = fp8_encode_f32(10.0); + const result = fp8_tanh(value); + const decoded = fp8_decode_f32(result); + assert(decoded >= 0.95); } test "fp8_tanh_negative" { - given value = fp8_encode_f32(-10.0) - try std.testing.expect(result = fp8_tanh(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(decoded <= -0.95); + const value = fp8_encode_f32(-10.0); + const result = fp8_tanh(value); + const decoded = fp8_decode_f32(result); + assert(decoded <= -0.95); } test "fp8_gelu_zero" { - given value = FP8_ZERO_POS - try std.testing.expect(result = fp8_gelu(value)); - try std.testing.expect(fp8_extract_sign(result) == 0); + const value = FP8_ZERO_POS; + const result = fp8_gelu(value); + assert(fp8_extract_sign(result) == 0); } test "fp8_swish_zero" { - given value = FP8_ZERO_POS - try std.testing.expect(result = fp8_swish(value)); - try std.testing.expect(result == FP8_ZERO_POS); + const value = FP8_ZERO_POS; + const result = fp8_swish(value); + assert(result == FP8_ZERO_POS); } test "fp8_swish_positive" { - given value = fp8_encode_f32(1.0) - try std.testing.expect(result = fp8_swish(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(decoded > 0.0); + const value = fp8_encode_f32(1.0); + const result = fp8_swish(value); + const decoded = fp8_decode_f32(result); + assert(decoded > 0.0); } test "fp8_quantize_to_int4_max" { - given value = fp8_encode_f32(2.0) - try std.testing.expect(result = fp8_quantize_to_int4(value)); - try std.testing.expect(result == 7); + const value = fp8_encode_f32(2.0); + const result = fp8_quantize_to_int4(value); + assert(result == 7); } test "fp8_quantize_to_int4_min" { - given value = fp8_encode_f32(-2.0) - try std.testing.expect(result = fp8_quantize_to_int4(value)); - try std.testing.expect(result == -8); + const value = fp8_encode_f32(-2.0); + const result = fp8_quantize_to_int4(value); + assert(result == -8); } test "fp8_quantize_to_int8_max" { - given value = fp8_encode_f32(2.0) - try std.testing.expect(result = fp8_quantize_to_int8(value)); - try std.testing.expect(result == 127); + const value = fp8_encode_f32(2.0); + const result = fp8_quantize_to_int8(value); + assert(result == 127); } test "fp8_quantize_to_int8_min" { - given value = fp8_encode_f32(-2.0) - try std.testing.expect(result = fp8_quantize_to_int8(value)); - try std.testing.expect(result == -128); + const value = fp8_encode_f32(-2.0); + const result = fp8_quantize_to_int8(value); + assert(result == -128); } test "fp8_from_components_roundtrip" { - given sign = -1 - try std.testing.expect(exp = 7); - try std.testing.expect(mant = 4); - try std.testing.expect(fp = fp8_from_components(sign, exp, mant)); - try std.testing.expect(extracted_sign = fp8_extract_sign(fp)); - try std.testing.expect(extracted_exp = fp8_extract_exponent(fp)); - try std.testing.expect(extracted_mant = fp8_extract_mantissa(fp)); - try std.testing.expect(extracted_sign == sign and extracted_exp == exp and extracted_mant == mant); + const sign = -1; + const exp = 7; + const mant = 4; + const fp = fp8_from_components(sign, exp, mant); + const extracted_sign = fp8_extract_sign(fp); + const extracted_exp = fp8_extract_exponent(fp); + const extracted_mant = fp8_extract_mantissa(fp); + assert(extracted_sign == sign and extracted_exp == exp and extracted_mant == mant); } // ============================================================================ // Invariants // ============================================================================ -} invariant fp8_bits_constant assert BITS == 8 @@ -968,46 +967,46 @@ invariant fp8_sub_zero_identity invariant fp8_mul_one_identity given value = fp8_encode_f32(5.0) - try std.testing.expect(one = fp8_encode_f32(1.0)); + and one = fp8_encode_f32(1.0) assert fp8_is_equal(fp8_mul(value, one), value) == true or fp8_magnitude(value) > 0.5 invariant fp8_div_one_identity given value = fp8_encode_f32(5.0) - try std.testing.expect(one = fp8_encode_f32(1.0)); + and one = fp8_encode_f32(1.0) assert fp8_is_equal(fp8_div(value, one), value) == true invariant fp8_max_ge_both given a = fp8_encode_f32(3.0) - try std.testing.expect(b = fp8_encode_f32(5.0)); - try std.testing.expect(result = fp8_max(a, b)); - try std.testing.expect(fp8_is_greater(result, a) == true and fp8_is_greater(result, b) == true or fp8_is_equal(result, b) == true); + and b = fp8_encode_f32(5.0) + and result = fp8_max(a, b) + assert fp8_is_greater(result, a) == true and fp8_is_greater(result, b) == true or fp8_is_equal(result, b) == true invariant fp8_min_le_both given a = fp8_encode_f32(3.0) - try std.testing.expect(b = fp8_encode_f32(5.0)); - try std.testing.expect(result = fp8_min(a, b)); - try std.testing.expect(fp8_is_greater(a, result) == true or fp8_is_equal(a, result) == true); + and b = fp8_encode_f32(5.0) + and result = fp8_min(a, b) + assert fp8_is_greater(a, result) == true or fp8_is_equal(a, result) == true invariant fp8_relu_non_negative given result = fp8_relu(fp8_encode_f32(5.0)) - try std.testing.expect(fp8_extract_sign(result) == 0); + assert fp8_extract_sign(result) == 0 invariant fp8_lerp_zero_start given a = fp8_encode_f32(1.0) - try std.testing.expect(b = fp8_encode_f32(5.0)); + and b = fp8_encode_f32(5.0) assert fp8_is_equal(fp8_lerp(a, b, 0.0), a) == true invariant fp8_lerp_one_end given a = fp8_encode_f32(1.0) - try std.testing.expect(b = fp8_encode_f32(5.0)); + and b = fp8_encode_f32(5.0) assert fp8_is_equal(fp8_lerp(a, b, 1.0), b) == true invariant fp8_sqrt_square_close given value = fp8_encode_f32(4.0) - try std.testing.expect(sqrt_val = fp8_sqrt(value)); - try std.testing.expect(sq_val = fp8_mul(sqrt_val, sqrt_val)); - try std.testing.expect(decoded = fp8_decode_f32(sq_val)); - try std.testing.expect(abs(decoded - 4.0) < 0.5); + and sqrt_val = fp8_sqrt(value) + and sq_val = fp8_mul(sqrt_val, sqrt_val) + and decoded = fp8_decode_f32(sq_val) + assert abs(decoded - 4.0) < 0.5 invariant fp8_quantize_to_int4_in_range given result = fp8_quantize_to_int4(fp8_encode_f32(1.0)) diff --git a/specs/fpga/fp8_e5m2.t27 b/specs/fpga/fp8_e5m2.t27 index e46e524..0f6c31b 100644 --- a/specs/fpga/fp8_e5m2.t27 +++ b/specs/fpga/fp8_e5m2.t27 @@ -77,8 +77,9 @@ pub fn fp8_extract_mantissa(fp8: FP8E5M2) u8 { // Assemble FP8 from sign, exponent, mantissa pub fn fp8_from_components(sign: i8, exp: u8, mant: u8) FP8E5M2 { const sign_bit = if (sign < 0) 1 else 0; - return (@as(FP8E5M2, @intCast(sign_bit)) << SIGN_SHIFT) | - (@as(FP8E5M2, @intCast(exp & 0x1F)) << EXP_SHIFT) | + // `as` takes a builtin type name; FP8E5M2 is u8 (see Types). + return ((sign_bit as u8) << SIGN_SHIFT) | + (((exp & 0x1F) as u8) << EXP_SHIFT) | (mant & MANT_MASK); } @@ -144,29 +145,34 @@ pub fn fp8_encode_f32(value: f32) FP8E5M2 { const abs_value = if (value < 0.0) -value else value; // Get f32 components + // @bitCast: reinterpret the f32 bits as u32 (no `as` form for this; the + // canonical numeric/gf16.t27 uses the same intrinsic). const f32_bits: u32 = @bitCast(abs_value); - var f32_exp: i16 = @as(i16, @intCast((f32_bits >> 23) & 0xFF)) - 127; + var f32_exp: i16 = (((f32_bits >> 23) & 0xFF) as i16) - 127; var f32_mant: u32 = f32_bits & 0x007FFFFF; // Handle very small values (subnormals) - if (f32_exp <= @as(i16, -EXP_BIAS)) { + if (f32_exp <= -(EXP_BIAS as i16)) { // Below FP8 minimum normal - try to encode as subnormal - const subnormal_shift = @as(i16, -EXP_BIAS) - f32_exp + 1; + const subnormal_shift = -(EXP_BIAS as i16) - f32_exp + 1; if (subnormal_shift > 2 + 23) { return if (sign < 0) FP8_ZERO_NEG else FP8_ZERO_POS; } var mant = f32_mant >> 23; if (subnormal_shift > 0) { + // u5 has no `as` cast form; the intrinsic is kept as written. const shift_amount = @as(u5, @intCast(subnormal_shift)); if (shift_amount <= 24) { mant = (f32_mant | 0x00800000) >> shift_amount; } } - return fp8_from_components(sign, 0, @as(u8, @truncate(mant)) & 0x03); + // Mask before narrowing: same value as the original @truncate(mant) & 0x03 + // for every mant, and the cast can never trap. + return fp8_from_components(sign, 0, (mant & 0x03) as u8); } // Convert exp from f32 bias (127) to FP8 bias (15) - var fp8_exp = @as(i16, f32_exp + EXP_BIAS); + var fp8_exp = (f32_exp + EXP_BIAS) as i16; // Clamp exponent if (fp8_exp >= EXP_MAX) { @@ -189,14 +195,14 @@ pub fn fp8_encode_f32(value: f32) FP8E5M2 { mant += 1; if (mant > MANT_MASK) { mant = 0; - if (fp8_exp < @as(i16, EXP_MAX - 1)) { + if (fp8_exp < ((EXP_MAX - 1) as i16)) { fp8_exp += 1; } } } } - return fp8_from_components(sign, @as(u8, @intCast(fp8_exp)), @as(u8, mant)); + return fp8_from_components(sign, fp8_exp as u8, mant as u8); } // fp8_decode_f32(fp8: FP8E5M2) -> f32 @@ -227,14 +233,14 @@ pub fn fp8_decode_f32(fp8: FP8E5M2) f32 { // Handle subnormal if (exp == 0) { // Subnormal: value = mant * 2^(-14) = mant * 2^(1-bias) - const bias_adjusted: i8 = 1 - @as(i8, EXP_BIAS); - const mant_f32 = @as(f32, @floatFromInt(mant)) / @as(f32, @floatFromInt(MANT_DIVISOR)); - f32_value = mant_f32 * std.math.pow(f32, 2.0, @as(f32, @floatFromInt(bias_adjusted))); + const bias_adjusted: i8 = 1 - (EXP_BIAS as i8); + const mant_f32 = (mant as f32) / (MANT_DIVISOR as f32); + f32_value = mant_f32 * std.math.pow(f32, 2.0, bias_adjusted as f32); } else { // Normal: value = (1 + mant/4) * 2^(exp - 15) - const bias_adjusted = @as(i16, exp) - @as(i16, EXP_BIAS); - const mant_f32 = 1.0 + (@as(f32, @floatFromInt(mant)) / @as(f32, @floatFromInt(MANT_DIVISOR))); - f32_value = mant_f32 * std.math.pow(f32, 2.0, @as(f32, @floatFromInt(bias_adjusted))); + const bias_adjusted = (exp as i16) - (EXP_BIAS as i16); + const mant_f32 = 1.0 + ((mant as f32) / (MANT_DIVISOR as f32)); + f32_value = mant_f32 * std.math.pow(f32, 2.0, bias_adjusted as f32); } return if (sign < 0) -f32_value else f32_value; @@ -243,14 +249,14 @@ pub fn fp8_decode_f32(fp8: FP8E5M2) f32 { // fp8_encode_f64(value: f64) -> FP8E5M2 // Encode IEEE 754 double precision to FP8 E5M2 pub fn fp8_encode_f64(value: f64) FP8E5M2 { - return fp8_encode_f32(@as(f32, @floatCast(value))); + return fp8_encode_f32(value as f32); } // fp8_decode_f64(fp8: FP8E5M2) -> f64 // Decode FP8 E5M2 to IEEE 754 double precision pub fn fp8_decode_f64(fp8: FP8E5M2) f64 { const f32_val = fp8_decode_f32(fp8); - return @as(f64, @floatFromInt(f32_val)); + return f32_val as f64; } // ============================================================================ @@ -441,13 +447,16 @@ pub fn fp8_quantize_to_int4(value: FP8E5M2) i8 { // E5M2 has wider range, so scale differently const max_range: f32 = 240.0; const scaled = (fv / max_range) * 7.0; - var result: i32 = @intFromFloat(@round(scaled)); + // Typed float local so the Zig backend lowers the cast to @intFromFloat + // (it cannot tell that a round() call is a float). + const rounded: f32 = round(scaled); + var result: i32 = rounded as i32; if (result > 7) { result = 7; } else if (result < -8) { result = -8; } - return @as(i8, @intCast(result)); + return result as i8; } // fp8_quantize_to_int8(value: FP8E5M2) -> i8 @@ -457,13 +466,16 @@ pub fn fp8_quantize_to_int8(value: FP8E5M2) i8 { // E5M2 has wider range, so scale differently const max_range: f32 = 240.0; const scaled = (fv / max_range) * 127.0; - var result: i32 = @intFromFloat(@round(scaled)); + // Typed float local so the Zig backend lowers the cast to @intFromFloat + // (it cannot tell that a round() call is a float). + const rounded: f32 = round(scaled); + var result: i32 = rounded as i32; if (result > 127) { result = 127; } else if (result < -128) { result = -128; } - return @as(i8, @intCast(result)); + return result as i8; } // fp8_from_f32_scaled(value: f32, scale: f32) -> FP8E5M2 @@ -484,8 +496,11 @@ pub fn fp8_to_f32_scaled(value: FP8E5M2, scale: f32) f32 { // Returns accumulated FP8 value pub fn fp8_dot_product(a: []const FP8E5M2, b: []const FP8E5M2) FP8E5M2 { var sum: f32 = 0.0; - for (a, 0..) |val_a, i| { + for i in 0..a.len { if (i >= b.len) break; + // Bound after the length check; a[i] is a pure read, so the value is + // the same as the original loop-header binding. + const val_a = a[i]; const fa = fp8_decode_f32(val_a); const fb = fp8_decode_f32(b[i]); sum += fa * fb; @@ -496,8 +511,8 @@ pub fn fp8_dot_product(a: []const FP8E5M2, b: []const FP8E5M2) FP8E5M2 { // fp8_vector_add(a: []const FP8E5M2, b: []const FP8E5M2, result: []FP8E5M2) -> void // Vector addition: result[i] = a[i] + b[i] pub fn fp8_vector_add(a: []const FP8E5M2, b: []const FP8E5M2, result: []FP8E5M2) void { - const len = @min(a.len, b.len); - for (0..len) |i| { + const len = min(a.len, b.len); + for i in 0..len { result[i] = fp8_add(a[i], b[i]); } } @@ -506,7 +521,8 @@ pub fn fp8_vector_add(a: []const FP8E5M2, b: []const FP8E5M2, result: []FP8E5M2) // Vector scale: result[i] = vec[i] * scale pub fn fp8_vector_scale(vec: []const FP8E5M2, scale: FP8E5M2, result: []FP8E5M2) void { const scale_f = fp8_decode_f32(scale); - for (vec, 0..) |val, i| { + for i in 0..vec.len { + const val = vec[i]; result[i] = fp8_encode_f32(fp8_decode_f32(val) * scale_f); } } @@ -515,7 +531,8 @@ pub fn fp8_vector_scale(vec: []const FP8E5M2, scale: FP8E5M2, result: []FP8E5M2) // Sum all elements of a vector pub fn fp8_vector_sum(vec: []const FP8E5M2) FP8E5M2 { var sum: f32 = 0.0; - for (vec) |val| { + for i in 0..vec.len { + const val = vec[i]; sum += fp8_decode_f32(val); } return fp8_encode_f32(sum); @@ -528,7 +545,7 @@ pub fn fp8_vector_mean(vec: []const FP8E5M2) FP8E5M2 { return FP8_ZERO_POS; } const sum = fp8_vector_sum(vec); - return fp8_div(sum, fp8_from_f32(@as(f32, @floatFromInt(vec.len)))); + return fp8_div(sum, fp8_from_f32(vec.len as f32)); } // fp8_softmax(vec: []const FP8E5M2, result: []FP8E5M2) -> void @@ -536,7 +553,8 @@ pub fn fp8_vector_mean(vec: []const FP8E5M2) FP8E5M2 { pub fn fp8_softmax(vec: []const FP8E5M2, result: []FP8E5M2) void { // Find max for numerical stability var max_val: f32 = -std.math.inf(f32); - for (vec) |val| { + for i in 0..vec.len { + const val = vec[i]; const fv = fp8_decode_f32(val); if (fv > max_val) { max_val = fv; @@ -545,7 +563,8 @@ pub fn fp8_softmax(vec: []const FP8E5M2, result: []FP8E5M2) void { // Compute exp values and sum var sum_exp: f32 = 0.0; - for (vec, 0..) |val, i| { + for i in 0..vec.len { + const val = vec[i]; const fv = fp8_decode_f32(val); const exp_val = std.math.exp(fv - max_val); result[i] = fp8_encode_f32(exp_val); @@ -554,7 +573,8 @@ pub fn fp8_softmax(vec: []const FP8E5M2, result: []FP8E5M2) void { // Normalize const inv_sum = 1.0 / sum_exp; - for (result, 0..) |val, i| { + for i in 0..result.len { + const val = result[i]; const fv = fp8_decode_f32(val); result[i] = fp8_encode_f32(fv * inv_sum); } @@ -565,507 +585,506 @@ pub fn fp8_softmax(vec: []const FP8E5M2, result: []FP8E5M2) void { // ============================================================================ test "fp8_extract_sign_positive" { - given value = 0x3C - try std.testing.expect(sign = fp8_extract_sign(value)); - try std.testing.expect(sign == 0); + const value = 0x3C; + const sign = fp8_extract_sign(value); + assert(sign == 0); } test "fp8_extract_sign_negative" { - given value = 0xBC - try std.testing.expect(sign = fp8_extract_sign(value)); - try std.testing.expect(sign == -1); + const value = 0xBC; + const sign = fp8_extract_sign(value); + assert(sign == -1); } test "fp8_extract_exponent_max" { - given value = 0x7C - try std.testing.expect(exp = fp8_extract_exponent(value)); - try std.testing.expect(exp == EXP_MAX); + const value = 0x7C; + const exp = fp8_extract_exponent(value); + assert(exp == EXP_MAX); } test "fp8_extract_exponent_zero" { - given value = 0x03 - try std.testing.expect(exp = fp8_extract_exponent(value)); - try std.testing.expect(exp == 0); + const value = 0x03; + const exp = fp8_extract_exponent(value); + assert(exp == 0); } test "fp8_extract_mantissa_max" { - given value = 0x03 - try std.testing.expect(mant = fp8_extract_mantissa(value)); - try std.testing.expect(mant == MANT_MASK); + const value = 0x03; + const mant = fp8_extract_mantissa(value); + assert(mant == MANT_MASK); } test "fp8_is_zero_positive" { - try std.testing.expect(fp8_is_zero(FP8_ZERO_POS) == true); + assert(fp8_is_zero(FP8_ZERO_POS) == true); } test "fp8_is_zero_negative" { - try std.testing.expect(fp8_is_zero(FP8_ZERO_NEG) == true); + assert(fp8_is_zero(FP8_ZERO_NEG) == true); } test "fp8_is_zero_nonzero" { - try std.testing.expect(fp8_is_zero(0x01) == false); + assert(fp8_is_zero(0x01) == false); } test "fp8_is_inf_positive" { - try std.testing.expect(fp8_is_inf(FP8_INF_POS) == true); + assert(fp8_is_inf(FP8_INF_POS) == true); } test "fp8_is_inf_negative" { - try std.testing.expect(fp8_is_inf(FP8_INF_NEG) == true); + assert(fp8_is_inf(FP8_INF_NEG) == true); } test "fp8_is_nan_positive" { - try std.testing.expect(fp8_is_nan(FP8_NAN_POS) == true); + assert(fp8_is_nan(FP8_NAN_POS) == true); } test "fp8_is_nan_negative" { - try std.testing.expect(fp8_is_nan(FP8_NAN_NEG) == true); + assert(fp8_is_nan(FP8_NAN_NEG) == true); } test "fp8_is_inf_not_nan" { - try std.testing.expect(fp8_is_inf(FP8_INF_POS) == true and fp8_is_nan(FP8_INF_POS) == false); + assert(fp8_is_inf(FP8_INF_POS) == true and fp8_is_nan(FP8_INF_POS) == false); } test "fp8_is_special_inf" { - try std.testing.expect(fp8_is_special(FP8_INF_POS) == true); + assert(fp8_is_special(FP8_INF_POS) == true); } test "fp8_is_special_nan" { - try std.testing.expect(fp8_is_special(FP8_NAN_POS) == true); + assert(fp8_is_special(FP8_NAN_POS) == true); } test "fp8_is_subnormal_true" { - given value = 0x01 - try std.testing.expect(fp8_is_subnormal(value) == true); + const value = 0x01; + assert(fp8_is_subnormal(value) == true); } test "fp8_is_subnormal_false_normal" { - given value = 0x04 - try std.testing.expect(fp8_is_subnormal(value) == false); + const value = 0x04; + assert(fp8_is_subnormal(value) == false); } test "fp8_is_subnormal_false_zero" { - try std.testing.expect(fp8_is_subnormal(FP8_ZERO_POS) == false); + assert(fp8_is_subnormal(FP8_ZERO_POS) == false); } test "fp8_encode_f32_zero" { - given fp = fp8_encode_f32(0.0) - try std.testing.expect(fp == FP8_ZERO_POS); + const fp = fp8_encode_f32(0.0); + assert(fp == FP8_ZERO_POS); } test "fp8_encode_f32_negative_zero" { - given fp = fp8_encode_f32(-0.0) - try std.testing.expect(fp == FP8_ZERO_NEG); + const fp = fp8_encode_f32(-0.0); + assert(fp == FP8_ZERO_NEG); } test "fp8_encode_f32_one" { - given fp = fp8_encode_f32(1.0) - try std.testing.expect(decoded = fp8_decode_f32(fp)); - try std.testing.expect(abs(decoded - 1.0) < 0.15); + const fp = fp8_encode_f32(1.0); + const decoded = fp8_decode_f32(fp); + assert(abs(decoded - 1.0) < 0.15); } test "fp8_encode_f32_negative_one" { - given fp = fp8_encode_f32(-1.0) - try std.testing.expect(decoded = fp8_decode_f32(fp)); - try std.testing.expect(abs(decoded + 1.0) < 0.15); + const fp = fp8_encode_f32(-1.0); + const decoded = fp8_decode_f32(fp); + assert(abs(decoded + 1.0) < 0.15); } test "fp8_encode_f32_ten" { - given fp = fp8_encode_f32(10.0) - try std.testing.expect(decoded = fp8_decode_f32(fp)); - try std.testing.expect(abs(decoded - 10.0) < 1.0); + const fp = fp8_encode_f32(10.0); + const decoded = fp8_decode_f32(fp); + assert(abs(decoded - 10.0) < 1.0); } test "fp8_encode_f32_hundred" { - given fp = fp8_encode_f32(100.0) - try std.testing.expect(decoded = fp8_decode_f32(fp)); - try std.testing.expect(abs(decoded - 100.0) < 10.0); + const fp = fp8_encode_f32(100.0); + const decoded = fp8_decode_f32(fp); + assert(abs(decoded - 100.0) < 10.0); } test "fp8_encode_f32_roundtrip_positive" { - given original = 1.5 - try std.testing.expect(fp = fp8_encode_f32(original)); - try std.testing.expect(decoded = fp8_decode_f32(fp)); - try std.testing.expect(abs(decoded - original) < 0.2); + const original = 1.5; + const fp = fp8_encode_f32(original); + const decoded = fp8_decode_f32(fp); + assert(abs(decoded - original) < 0.2); } test "fp8_encode_f32_roundtrip_negative" { - given original = -1.5 - try std.testing.expect(fp = fp8_encode_f32(original)); - try std.testing.expect(decoded = fp8_decode_f32(fp)); - try std.testing.expect(abs(decoded - original) < 0.2); + const original = -1.5; + const fp = fp8_encode_f32(original); + const decoded = fp8_decode_f32(fp); + assert(abs(decoded - original) < 0.2); } test "fp8_encode_f32_nan" { - given fp = fp8_encode_f32(std.math.nan(f32)) - try std.testing.expect(fp8_is_nan(fp) == true); + const fp = fp8_encode_f32(std.math.nan(f32)); + assert(fp8_is_nan(fp) == true); } test "fp8_encode_f32_inf" { - given fp = fp8_encode_f32(std.math.inf(f32)) - try std.testing.expect(fp8_is_inf(fp) == true); + const fp = fp8_encode_f32(std.math.inf(f32)); + assert(fp8_is_inf(fp) == true); } test "fp8_encode_f32_neg_inf" { - given fp = fp8_encode_f32(-std.math.inf(f32)) - try std.testing.expect(fp8_is_inf(fp) == true); + const fp = fp8_encode_f32(-std.math.inf(f32)); + assert(fp8_is_inf(fp) == true); } test "fp8_decode_f32_zero" { - try std.testing.expect(fp8_decode_f32(FP8_ZERO_POS) == 0.0); + assert(fp8_decode_f32(FP8_ZERO_POS) == 0.0); } test "fp8_decode_f32_negative_zero" { - try std.testing.expect(fp8_decode_f32(FP8_ZERO_NEG) == -0.0); + assert(fp8_decode_f32(FP8_ZERO_NEG) == -0.0); } test "fp8_decode_f32_inf" { - try std.testing.expect(std.math.isInf(fp8_decode_f32(FP8_INF_POS)) == true); + assert(std.math.isInf(fp8_decode_f32(FP8_INF_POS)) == true); } test "fp8_decode_f32_neg_inf" { - try std.testing.expect(std.math.isInf(fp8_decode_f32(FP8_INF_NEG)) == true); + assert(std.math.isInf(fp8_decode_f32(FP8_INF_NEG)) == true); } test "fp8_decode_f32_nan" { - try std.testing.expect(std.math.isNan(fp8_decode_f32(FP8_NAN_POS)) == true); + assert(std.math.isNan(fp8_decode_f32(FP8_NAN_POS)) == true); } test "fp8_add_simple" { - given a = fp8_encode_f32(10.0) - try std.testing.expect(b = fp8_encode_f32(20.0)); - try std.testing.expect(result = fp8_add(a, b)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 30.0) < 3.0); + const a = fp8_encode_f32(10.0); + const b = fp8_encode_f32(20.0); + const result = fp8_add(a, b); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 30.0) < 3.0); } test "fp8_sub_simple" { - given a = fp8_encode_f32(50.0) - try std.testing.expect(b = fp8_encode_f32(30.0)); - try std.testing.expect(result = fp8_sub(a, b)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 20.0) < 3.0); + const a = fp8_encode_f32(50.0); + const b = fp8_encode_f32(30.0); + const result = fp8_sub(a, b); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 20.0) < 3.0); } test "fp8_mul_simple" { - given a = fp8_encode_f32(10.0) - try std.testing.expect(b = fp8_encode_f32(10.0)); - try std.testing.expect(result = fp8_mul(a, b)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 100.0) < 15.0); + const a = fp8_encode_f32(10.0); + const b = fp8_encode_f32(10.0); + const result = fp8_mul(a, b); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 100.0) < 15.0); } test "fp8_div_simple" { - given a = fp8_encode_f32(100.0) - try std.testing.expect(b = fp8_encode_f32(10.0)); - try std.testing.expect(result = fp8_div(a, b)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 10.0) < 3.0); + const a = fp8_encode_f32(100.0); + const b = fp8_encode_f32(10.0); + const result = fp8_div(a, b); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 10.0) < 3.0); } test "fp8_div_by_zero_positive" { - given a = fp8_encode_f32(50.0) - try std.testing.expect(b = fp8_encode_f32(0.0)); - try std.testing.expect(result = fp8_div(a, b)); - try std.testing.expect(result == FP8_INF_POS); + const a = fp8_encode_f32(50.0); + const b = fp8_encode_f32(0.0); + const result = fp8_div(a, b); + assert(result == FP8_INF_POS); } test "fp8_div_by_zero_negative" { - given a = fp8_encode_f32(-50.0) - try std.testing.expect(b = fp8_encode_f32(0.0)); - try std.testing.expect(result = fp8_div(a, b)); - try std.testing.expect(result == FP8_INF_NEG); + const a = fp8_encode_f32(-50.0); + const b = fp8_encode_f32(0.0); + const result = fp8_div(a, b); + assert(result == FP8_INF_NEG); } test "fp8_sqrt_four" { - given value = fp8_encode_f32(4.0) - try std.testing.expect(result = fp8_sqrt(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 2.0) < 0.3); + const value = fp8_encode_f32(4.0); + const result = fp8_sqrt(value); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 2.0) < 0.3); } test "fp8_sqrt_negative" { - given value = fp8_encode_f32(-4.0) - try std.testing.expect(result = fp8_sqrt(value)); - try std.testing.expect(fp8_is_nan(result) == true); + const value = fp8_encode_f32(-4.0); + const result = fp8_sqrt(value); + assert(fp8_is_nan(result) == true); } test "fp8_rsqrt_four" { - given value = fp8_encode_f32(4.0) - try std.testing.expect(result = fp8_rsqrt(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 0.5) < 0.1); + const value = fp8_encode_f32(4.0); + const result = fp8_rsqrt(value); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 0.5) < 0.1); } test "fp8_abs_positive" { - given value = fp8_encode_f32(50.0) - try std.testing.expect(result = fp8_abs(value)); - try std.testing.expect(fp8_is_equal(result, value) == true); + const value = fp8_encode_f32(50.0); + const result = fp8_abs(value); + assert(fp8_is_equal(result, value) == true); } test "fp8_abs_negative" { - given value = fp8_encode_f32(-50.0) - try std.testing.expect(abs_val = fp8_abs(value)); - try std.testing.expect(fp8_extract_sign(abs_val) == 0); + const value = fp8_encode_f32(-50.0); + const abs_val = fp8_abs(value); + assert(fp8_extract_sign(abs_val) == 0); } test "fp8_neg_positive" { - given value = fp8_encode_f32(50.0) - try std.testing.expect(neg_val = fp8_neg(value)); - try std.testing.expect(fp8_extract_sign(neg_val) < 0); + const value = fp8_encode_f32(50.0); + const neg_val = fp8_neg(value); + assert(fp8_extract_sign(neg_val) < 0); } test "fp8_neg_negative" { - given value = fp8_encode_f32(-50.0) - try std.testing.expect(neg_val = fp8_neg(value)); - try std.testing.expect(fp8_extract_sign(neg_val) == 0); + const value = fp8_encode_f32(-50.0); + const neg_val = fp8_neg(value); + assert(fp8_extract_sign(neg_val) == 0); } test "fp8_is_equal_true" { - given value = fp8_encode_f32(10.0) - try std.testing.expect(fp8_is_equal(value, value) == true); + const value = fp8_encode_f32(10.0); + assert(fp8_is_equal(value, value) == true); } test "fp8_is_equal_false" { - given a = fp8_encode_f32(10.0) - try std.testing.expect(b = fp8_encode_f32(20.0)); - try std.testing.expect(fp8_is_equal(a, b) == false); + const a = fp8_encode_f32(10.0); + const b = fp8_encode_f32(20.0); + assert(fp8_is_equal(a, b) == false); } test "fp8_is_equal_nan" { - try std.testing.expect(fp8_is_equal(FP8_NAN_POS, FP8_NAN_POS) == false); + assert(fp8_is_equal(FP8_NAN_POS, FP8_NAN_POS) == false); } test "fp8_is_equal_zero" { - try std.testing.expect(fp8_is_equal(FP8_ZERO_POS, FP8_ZERO_NEG) == true); + assert(fp8_is_equal(FP8_ZERO_POS, FP8_ZERO_NEG) == true); } test "fp8_is_greater_positive" { - given a = fp8_encode_f32(50.0) - try std.testing.expect(b = fp8_encode_f32(30.0)); - try std.testing.expect(fp8_is_greater(a, b) == true); + const a = fp8_encode_f32(50.0); + const b = fp8_encode_f32(30.0); + assert(fp8_is_greater(a, b) == true); } test "fp8_max_returns_larger" { - given a = fp8_encode_f32(30.0) - try std.testing.expect(b = fp8_encode_f32(50.0)); - try std.testing.expect(result = fp8_max(a, b)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(decoded >= 40.0); + const a = fp8_encode_f32(30.0); + const b = fp8_encode_f32(50.0); + const result = fp8_max(a, b); + const decoded = fp8_decode_f32(result); + assert(decoded >= 40.0); } test "fp8_min_returns_smaller" { - given a = fp8_encode_f32(30.0) - try std.testing.expect(b = fp8_encode_f32(50.0)); - try std.testing.expect(result = fp8_min(a, b)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(decoded <= 40.0); + const a = fp8_encode_f32(30.0); + const b = fp8_encode_f32(50.0); + const result = fp8_min(a, b); + const decoded = fp8_decode_f32(result); + assert(decoded <= 40.0); } test "fp8_lerp_zero" { - given a = fp8_encode_f32(10.0) - try std.testing.expect(b = fp8_encode_f32(50.0)); - try std.testing.expect(t = 0.0); - try std.testing.expect(result = fp8_lerp(a, b, t)); - try std.testing.expect(fp8_is_equal(result, a) == true); + const a = fp8_encode_f32(10.0); + const b = fp8_encode_f32(50.0); + const t = 0.0; + const result = fp8_lerp(a, b, t); + assert(fp8_is_equal(result, a) == true); } test "fp8_lerp_one" { - given a = fp8_encode_f32(10.0) - try std.testing.expect(b = fp8_encode_f32(50.0)); - try std.testing.expect(t = 1.0); - try std.testing.expect(result = fp8_lerp(a, b, t)); - try std.testing.expect(fp8_is_equal(result, b) == true); + const a = fp8_encode_f32(10.0); + const b = fp8_encode_f32(50.0); + const t = 1.0; + const result = fp8_lerp(a, b, t); + assert(fp8_is_equal(result, b) == true); } test "fp8_fma_simple" { - given a = fp8_encode_f32(10.0) - try std.testing.expect(b = fp8_encode_f32(10.0)); - try std.testing.expect(c = fp8_encode_f32(5.0)); - try std.testing.expect(result = fp8_fma(a, b, c)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 105.0) < 15.0); + const a = fp8_encode_f32(10.0); + const b = fp8_encode_f32(10.0); + const c = fp8_encode_f32(5.0); + const result = fp8_fma(a, b, c); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 105.0) < 15.0); } test "fp8_scale_up" { - given value = fp8_encode_f32(1.0) - try std.testing.expect(scale = 10.0); - try std.testing.expect(result = fp8_scale(value, scale)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 10.0) < 1.0); + const value = fp8_encode_f32(1.0); + const scale = 10.0; + const result = fp8_scale(value, scale); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 10.0) < 1.0); } test "fp8_scale_down" { - given value = fp8_encode_f32(10.0) - try std.testing.expect(scale = 0.1); - try std.testing.expect(result = fp8_scale(value, scale)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 1.0) < 0.1); + const value = fp8_encode_f32(10.0); + const scale = 0.1; + const result = fp8_scale(value, scale); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 1.0) < 0.1); } test "fp8_relu_positive" { - given value = fp8_encode_f32(50.0) - try std.testing.expect(result = fp8_relu(value)); - try std.testing.expect(fp8_is_equal(result, value) == true); + const value = fp8_encode_f32(50.0); + const result = fp8_relu(value); + assert(fp8_is_equal(result, value) == true); } test "fp8_relu_negative" { - given value = fp8_encode_f32(-50.0) - try std.testing.expect(result = fp8_relu(value)); - try std.testing.expect(result == FP8_ZERO_POS); + const value = fp8_encode_f32(-50.0); + const result = fp8_relu(value); + assert(result == FP8_ZERO_POS); } test "fp8_relu_zero" { - given result = fp8_relu(FP8_ZERO_POS) - try std.testing.expect(result == FP8_ZERO_POS); + const result = fp8_relu(FP8_ZERO_POS); + assert(result == FP8_ZERO_POS); } test "fp8_sigmoid_zero" { - given value = FP8_ZERO_POS - try std.testing.expect(result = fp8_sigmoid(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 0.5) < 0.1); + const value = FP8_ZERO_POS; + const result = fp8_sigmoid(value); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 0.5) < 0.1); } test "fp8_sigmoid_positive_large" { - given value = fp8_encode_f32(10.0) - try std.testing.expect(result = fp8_sigmoid(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(decoded >= 0.9); + const value = fp8_encode_f32(10.0); + const result = fp8_sigmoid(value); + const decoded = fp8_decode_f32(result); + assert(decoded >= 0.9); } test "fp8_sigmoid_negative_large" { - given value = fp8_encode_f32(-10.0) - try std.testing.expect(result = fp8_sigmoid(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(decoded <= 0.1); + const value = fp8_encode_f32(-10.0); + const result = fp8_sigmoid(value); + const decoded = fp8_decode_f32(result); + assert(decoded <= 0.1); } test "fp8_tanh_zero" { - given value = FP8_ZERO_POS - try std.testing.expect(result = fp8_tanh(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded) < 0.1); + const value = FP8_ZERO_POS; + const result = fp8_tanh(value); + const decoded = fp8_decode_f32(result); + assert(abs(decoded) < 0.1); } test "fp8_tanh_positive_large" { - given value = fp8_encode_f32(10.0) - try std.testing.expect(result = fp8_tanh(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(decoded >= 0.9); + const value = fp8_encode_f32(10.0); + const result = fp8_tanh(value); + const decoded = fp8_decode_f32(result); + assert(decoded >= 0.9); } test "fp8_tanh_negative_large" { - given value = fp8_encode_f32(-10.0) - try std.testing.expect(result = fp8_tanh(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(decoded <= -0.9); + const value = fp8_encode_f32(-10.0); + const result = fp8_tanh(value); + const decoded = fp8_decode_f32(result); + assert(decoded <= -0.9); } test "fp8_gelu_zero" { - given value = FP8_ZERO_POS - try std.testing.expect(result = fp8_gelu(value)); - try std.testing.expect(fp8_extract_sign(result) == 0); + const value = FP8_ZERO_POS; + const result = fp8_gelu(value); + assert(fp8_extract_sign(result) == 0); } test "fp8_swish_zero" { - given value = FP8_ZERO_POS - try std.testing.expect(result = fp8_swish(value)); - try std.testing.expect(result == FP8_ZERO_POS); + const value = FP8_ZERO_POS; + const result = fp8_swish(value); + assert(result == FP8_ZERO_POS); } test "fp8_swish_positive" { - given value = fp8_encode_f32(10.0) - try std.testing.expect(result = fp8_swish(value)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(decoded > 0.0); + const value = fp8_encode_f32(10.0); + const result = fp8_swish(value); + const decoded = fp8_decode_f32(result); + assert(decoded > 0.0); } test "fp8_quantize_to_int4_max" { - given value = fp8_encode_f32(100.0) - try std.testing.expect(result = fp8_quantize_to_int4(value)); - try std.testing.expect(result == 7); + const value = fp8_encode_f32(100.0); + const result = fp8_quantize_to_int4(value); + assert(result == 7); } test "fp8_quantize_to_int4_min" { - given value = fp8_encode_f32(-100.0) - try std.testing.expect(result = fp8_quantize_to_int4(value)); - try std.testing.expect(result == -8); + const value = fp8_encode_f32(-100.0); + const result = fp8_quantize_to_int4(value); + assert(result == -8); } test "fp8_quantize_to_int8_max" { - given value = fp8_encode_f32(200.0) - try std.testing.expect(result = fp8_quantize_to_int8(value)); - try std.testing.expect(result >= 100); + const value = fp8_encode_f32(200.0); + const result = fp8_quantize_to_int8(value); + assert(result >= 100); } test "fp8_quantize_to_int8_min" { - given value = fp8_encode_f32(-200.0) - try std.testing.expect(result = fp8_quantize_to_int8(value)); - try std.testing.expect(result <= -100); + const value = fp8_encode_f32(-200.0); + const result = fp8_quantize_to_int8(value); + assert(result <= -100); } test "fp8_from_f32_scaled_up" { - given value = 1.0 - try std.testing.expect(scale = 100.0); - try std.testing.expect(result = fp8_from_f32_scaled(value, scale)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 100.0) < 10.0); + const value = 1.0; + const scale = 100.0; + const result = fp8_from_f32_scaled(value, scale); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 100.0) < 10.0); } test "fp8_from_f32_scaled_down" { - given value = 100.0 - try std.testing.expect(scale = 0.01); - try std.testing.expect(result = fp8_from_f32_scaled(value, scale)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 1.0) < 0.1); + const value = 100.0; + const scale = 0.01; + const result = fp8_from_f32_scaled(value, scale); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 1.0) < 0.1); } test "fp8_to_f32_scaled_up" { - given value = fp8_encode_f32(1.0) - try std.testing.expect(scale = 0.01); - try std.testing.expect(result = fp8_to_f32_scaled(value, scale)); - try std.testing.expect(abs(result - 0.01) < 0.005); + const value = fp8_encode_f32(1.0); + const scale = 0.01; + const result = fp8_to_f32_scaled(value, scale); + assert(abs(result - 0.01) < 0.005); } test "fp8_dot_product_simple" { - given a = [_]FP8E5M2{fp8_encode_f32(1.0), fp8_encode_f32(2.0), fp8_encode_f32(3.0), fp8_encode_f32(4.0)} - try std.testing.expect(b = [_]FP8E5M2{fp8_encode_f32(2.0), fp8_encode_f32(2.0), fp8_encode_f32(2.0), fp8_encode_f32(2.0)}); - try std.testing.expect(result = fp8_dot_product(a, b)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 20.0) < 5.0); + const a : [4]FP8E5M2 = [fp8_encode_f32(1.0), fp8_encode_f32(2.0), fp8_encode_f32(3.0), fp8_encode_f32(4.0)]; + const b : [4]FP8E5M2 = [fp8_encode_f32(2.0), fp8_encode_f32(2.0), fp8_encode_f32(2.0), fp8_encode_f32(2.0)]; + const result = fp8_dot_product(a, b); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 20.0) < 5.0); } test "fp8_vector_sum_simple" { - given vec = [_]FP8E5M2{fp8_encode_f32(1.0), fp8_encode_f32(2.0), fp8_encode_f32(3.0), fp8_encode_f32(4.0)} - try std.testing.expect(result = fp8_vector_sum(vec)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 10.0) < 2.0); + const vec : [4]FP8E5M2 = [fp8_encode_f32(1.0), fp8_encode_f32(2.0), fp8_encode_f32(3.0), fp8_encode_f32(4.0)]; + const result = fp8_vector_sum(vec); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 10.0) < 2.0); } test "fp8_vector_mean_simple" { - given vec = [_]FP8E5M2{fp8_encode_f32(2.0), fp8_encode_f32(4.0), fp8_encode_f32(6.0), fp8_encode_f32(8.0)} - try std.testing.expect(result = fp8_vector_mean(vec)); - try std.testing.expect(decoded = fp8_decode_f32(result)); - try std.testing.expect(abs(decoded - 5.0) < 1.0); + const vec : [4]FP8E5M2 = [fp8_encode_f32(2.0), fp8_encode_f32(4.0), fp8_encode_f32(6.0), fp8_encode_f32(8.0)]; + const result = fp8_vector_mean(vec); + const decoded = fp8_decode_f32(result); + assert(abs(decoded - 5.0) < 1.0); } test "fp8_from_components_roundtrip" { - given sign = -1 - try std.testing.expect(exp = 15); - try std.testing.expect(mant = 2); - try std.testing.expect(fp = fp8_from_components(sign, exp, mant)); - try std.testing.expect(extracted_sign = fp8_extract_sign(fp)); - try std.testing.expect(extracted_exp = fp8_extract_exponent(fp)); - try std.testing.expect(extracted_mant = fp8_extract_mantissa(fp)); - try std.testing.expect(extracted_sign == sign and extracted_exp == exp and extracted_mant == mant); + const sign = -1; + const exp = 15; + const mant = 2; + const fp = fp8_from_components(sign, exp, mant); + const extracted_sign = fp8_extract_sign(fp); + const extracted_exp = fp8_extract_exponent(fp); + const extracted_mant = fp8_extract_mantissa(fp); + assert(extracted_sign == sign and extracted_exp == exp and extracted_mant == mant); } // ============================================================================ // Invariants // ============================================================================ -} invariant fp8_bits_constant assert BITS == 8 @@ -1127,46 +1146,46 @@ invariant fp8_sub_zero_identity invariant fp8_mul_one_identity given value = fp8_encode_f32(50.0) - try std.testing.expect(one = fp8_encode_f32(1.0)); + and one = fp8_encode_f32(1.0) assert fp8_is_equal(fp8_mul(value, one), value) == true or fp8_magnitude(value) > 10.0 invariant fp8_div_one_identity given value = fp8_encode_f32(50.0) - try std.testing.expect(one = fp8_encode_f32(1.0)); + and one = fp8_encode_f32(1.0) assert fp8_is_equal(fp8_div(value, one), value) == true invariant fp8_max_ge_both given a = fp8_encode_f32(30.0) - try std.testing.expect(b = fp8_encode_f32(50.0)); - try std.testing.expect(result = fp8_max(a, b)); - try std.testing.expect(fp8_is_greater(result, a) == true and fp8_is_greater(result, b) == true or fp8_is_equal(result, b) == true); + and b = fp8_encode_f32(50.0) + when result = fp8_max(a, b) + assert fp8_is_greater(result, a) == true and fp8_is_greater(result, b) == true or fp8_is_equal(result, b) == true invariant fp8_min_le_both given a = fp8_encode_f32(30.0) - try std.testing.expect(b = fp8_encode_f32(50.0)); - try std.testing.expect(result = fp8_min(a, b)); - try std.testing.expect(fp8_is_greater(a, result) == true or fp8_is_equal(a, result) == true); + and b = fp8_encode_f32(50.0) + when result = fp8_min(a, b) + assert fp8_is_greater(a, result) == true or fp8_is_equal(a, result) == true invariant fp8_relu_non_negative given result = fp8_relu(fp8_encode_f32(50.0)) - try std.testing.expect(fp8_extract_sign(result) == 0); + assert fp8_extract_sign(result) == 0 invariant fp8_lerp_zero_start given a = fp8_encode_f32(10.0) - try std.testing.expect(b = fp8_encode_f32(50.0)); + and b = fp8_encode_f32(50.0) assert fp8_is_equal(fp8_lerp(a, b, 0.0), a) == true invariant fp8_lerp_one_end given a = fp8_encode_f32(10.0) - try std.testing.expect(b = fp8_encode_f32(50.0)); + and b = fp8_encode_f32(50.0) assert fp8_is_equal(fp8_lerp(a, b, 1.0), b) == true invariant fp8_sqrt_square_close given value = fp8_encode_f32(4.0) - try std.testing.expect(sqrt_val = fp8_sqrt(value)); - try std.testing.expect(sq_val = fp8_mul(sqrt_val, sqrt_val)); - try std.testing.expect(decoded = fp8_decode_f32(sq_val)); - try std.testing.expect(abs(decoded - 4.0) < 0.5); + when sqrt_val = fp8_sqrt(value) + and sq_val = fp8_mul(sqrt_val, sqrt_val) + and decoded = fp8_decode_f32(sq_val) + assert abs(decoded - 4.0) < 0.5 invariant fp8_quantize_to_int4_in_range given result = fp8_quantize_to_int4(fp8_encode_f32(50.0)) @@ -1178,10 +1197,10 @@ invariant fp8_quantize_to_int8_in_range invariant fp8_scale_roundtrip given value = fp8_encode_f32(50.0) - try std.testing.expect(scale = 2.0); - try std.testing.expect(scaled = fp8_scale(value, scale)); - try std.testing.expect(decoded = fp8_to_f32_scaled(scaled, scale)); - try std.testing.expect(abs(decoded - fp8_decode_f32(value)) < 5.0); + and scale = 2.0 + when scaled = fp8_scale(value, scale) + and decoded = fp8_to_f32_scaled(scaled, scale) + assert abs(decoded - fp8_decode_f32(value)) < 5.0 // ============================================================================ // Benchmarks diff --git a/specs/fpga/gf128.t27 b/specs/fpga/gf128.t27 index d343873..a3c1343 100644 --- a/specs/fpga/gf128.t27 +++ b/specs/fpga/gf128.t27 @@ -175,7 +175,8 @@ module GF128 { // Lower 64 bits of mantissa const normalized = value / pow2_128(exp as f64); const frac = normalized - 1.0; - const mant_full = (frac * 633825300114114700748351602689.0) as u128; + // `x as u128` is spelled @as(u128, x): the t27 `as` cast has no u128 target + const mant_full = @as(u128, frac * 633825300114114700748351602689.0); return (mant_full & 0xFFFFFFFFFFFFFFFF) as u64; } @@ -183,12 +184,14 @@ module GF128 { // Upper 35 bits of mantissa const normalized = value / pow2_128(exp as f64); const frac = normalized - 1.0; - const mant_full = (frac * 633825300114114700748351602689.0) as u128; + // `x as u128` is spelled @as(u128, x): the t27 `as` cast has no u128 target + const mant_full = @as(u128, frac * 633825300114114700748351602689.0); return ((mant_full >> 64) & 0x7FFFFFFFF) as u64; } fn mant_to_f64_128(low: u64, high: u64) -> f64 { - const mant_u128 = ((high as u128) << 64) | (low as u128); + // `x as u128` is spelled @as(u128, x): the t27 `as` cast has no u128 target + const mant_u128 = (@as(u128, high) << 64) | @as(u128, low); return mant_u128 as f64; } diff --git a/specs/fpga/gf16_to_fp16.t27 b/specs/fpga/gf16_to_fp16.t27 index 132324b..f863887 100644 --- a/specs/fpga/gf16_to_fp16.t27 +++ b/specs/fpga/gf16_to_fp16.t27 @@ -303,175 +303,174 @@ pub fn gf16_bits_to_fp16_bits_with_result(gf_bits: u16, config: ConversionConfig // ============================================================================ test "gf16_bits_constants" { - try std.testing.expect(GF16_SIGN_BITS == 1); - try std.testing.expect(GF16_EXP_BITS == 6); - try std.testing.expect(GF16_MANT_BITS == 9); - try std.testing.expect(GF16_BIAS == 31); + assert(GF16_SIGN_BITS == 1); + assert(GF16_EXP_BITS == 6); + assert(GF16_MANT_BITS == 9); + assert(GF16_BIAS == 31); } test "fp16_bits_constants" { - try std.testing.expect(FP16_SIGN_BITS == 1); - try std.testing.expect(FP16_EXP_BITS == 5); - try std.testing.expect(FP16_MANT_BITS == 10); - try std.testing.expect(FP16_BIAS == 15); + assert(FP16_SIGN_BITS == 1); + assert(FP16_EXP_BITS == 5); + assert(FP16_MANT_BITS == 10); + assert(FP16_BIAS == 15); } test "mantissa_masks" { - try std.testing.expect(MANTissa_MASK_GF16 == 0x01FF); - try std.testing.expect(MANTissa_MASK_FP16 == 0x03FF); + assert(MANTissa_MASK_GF16 == 0x01FF); + assert(MANTissa_MASK_FP16 == 0x03FF); } test "gf16_from_bits_to_bits_roundtrip" { - given bits = 0x1234 - try std.testing.expect(gf = gf16_from_bits(bits)); - try std.testing.expect(result = gf16_to_bits(gf)); - try std.testing.expect(result == bits); + const bits = 0x1234; + const gf = gf16_from_bits(bits); + const result = gf16_to_bits(gf); + assert(result == bits); } test "gf16_from_bits_structure" { - given gf = gf16_from_bits(0x8000) - try std.testing.expect(gf.sign == 1); - try std.testing.expect(gf.exp == 0); - try std.testing.expect(gf.mant == 0); + const gf = gf16_from_bits(0x8000); + assert(gf.sign == 1); + assert(gf.exp == 0); + assert(gf.mant == 0); } test "fp16_from_bits_to_bits_roundtrip" { - given bits = 0x3C00 - try std.testing.expect(fp = fp16_from_bits(bits)); - try std.testing.expect(result = fp16_to_bits(fp)); - try std.testing.expect(result == bits); + const bits = 0x3C00; + const fp = fp16_from_bits(bits); + const result = fp16_to_bits(fp); + assert(result == bits); } test "gf16_is_zero_true" { - given gf = Gf16{.sign = 0, .exp = 0, .mant = 0} - try std.testing.expect(gf16_is_zero(gf) == true); + const gf = Gf16{.sign = 0, .exp = 0, .mant = 0}; + assert(gf16_is_zero(gf) == true); } test "gf16_is_zero_false" { - given gf = Gf16{.sign = 0, .exp = 0, .mant = 1} - try std.testing.expect(gf16_is_zero(gf) == false); + const gf = Gf16{.sign = 0, .exp = 0, .mant = 1}; + assert(gf16_is_zero(gf) == false); } test "gf16_is_infinity_true" { - given gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 0} - try std.testing.expect(gf16_is_infinity(gf) == true); + const gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 0}; + assert(gf16_is_infinity(gf) == true); } test "gf16_is_infinity_false" { - given gf = Gf16{.sign = 0, .exp = 0x3E, .mant = 0} - try std.testing.expect(gf16_is_infinity(gf) == false); + const gf = Gf16{.sign = 0, .exp = 0x3E, .mant = 0}; + assert(gf16_is_infinity(gf) == false); } test "gf16_is_nan_true" { - given gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 1} - try std.testing.expect(gf16_is_nan(gf) == true); + const gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 1}; + assert(gf16_is_nan(gf) == true); } test "fp16_is_zero_true" { - given fp = Fp16{.sign = 0, .exp = 0, .mant = 0} - try std.testing.expect(fp16_is_zero(fp) == true); + const fp = Fp16{.sign = 0, .exp = 0, .mant = 0}; + assert(fp16_is_zero(fp) == true); } test "fp16_is_infinity_true" { - given fp = Fp16{.sign = 0, .exp = 0x1F, .mant = 0} - try std.testing.expect(fp16_is_infinity(fp) == true); + const fp = Fp16{.sign = 0, .exp = 0x1F, .mant = 0}; + assert(fp16_is_infinity(fp) == true); } test "conversion_config_init_structure" { - given config = conversion_config_init() - try std.testing.expect(config.round_mode == 0); - try std.testing.expect(config.enable_saturation == true); + const config = conversion_config_init(); + assert(config.round_mode == 0); + assert(config.enable_saturation == true); } test "conversion_config_no_saturation_structure" { - given config = conversion_config_no_saturation() - try std.testing.expect(config.enable_saturation == false); + const config = conversion_config_no_saturation(); + assert(config.enable_saturation == false); } test "gf16_to_fp16_zero" { - given gf = Gf16{.sign = 0, .exp = 0, .mant = 0} - try std.testing.expect(fp = gf16_to_fp16(gf)); - try std.testing.expect(fp.exp == 0); - try std.testing.expect(fp.mant == 0); + const gf = Gf16{.sign = 0, .exp = 0, .mant = 0}; + const fp = gf16_to_fp16(gf); + assert(fp.exp == 0); + assert(fp.mant == 0); } test "gf16_to_fp16_infinity" { - given gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 0} - try std.testing.expect(fp = gf16_to_fp16(gf)); - try std.testing.expect(fp.exp == 0x1F); - try std.testing.expect(fp.mant == 0); + const gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 0}; + const fp = gf16_to_fp16(gf); + assert(fp.exp == 0x1F); + assert(fp.mant == 0); } test "gf16_to_fp16_nan" { - given gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 1} - try std.testing.expect(fp = gf16_to_fp16(gf)); - try std.testing.expect(fp.exp == 0x1F); - try std.testing.expect(fp.mant == 1); + const gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 1}; + const fp = gf16_to_fp16(gf); + assert(fp.exp == 0x1F); + assert(fp.mant == 1); } test "gf16_to_fp16_preserves_sign" { - given gf_pos = Gf16{.sign = 1, .exp = 1, .mant = 0} - try std.testing.expect(gf_neg = Gf16{.sign = 0, .exp = 1, .mant = 0}); - try std.testing.expect(fp_pos = gf16_to_fp16(gf_pos)); - try std.testing.expect(fp_neg = gf16_to_fp16(gf_neg)); - try std.testing.expect(fp_pos.sign == 1 and fp_neg.sign == 0); + const gf_pos = Gf16{.sign = 1, .exp = 1, .mant = 0}; + const gf_neg = Gf16{.sign = 0, .exp = 1, .mant = 0}; + const fp_pos = gf16_to_fp16(gf_pos); + const fp_neg = gf16_to_fp16(gf_neg); + assert(fp_pos.sign == 1 and fp_neg.sign == 0); } test "gf16_to_fp16_with_result_zero" { - given gf = Gf16{.sign = 0, .exp = 0, .mant = 0} - try std.testing.expect(config = conversion_config_init()); - try std.testing.expect(result = gf16_to_fp16_with_result(gf, config)); - try std.testing.expect(result.overflow == false); - try std.testing.expect(result.underflow == false); - try std.testing.expect(result.lost_precision == false); + const gf = Gf16{.sign = 0, .exp = 0, .mant = 0}; + const config = conversion_config_init(); + const result = gf16_to_fp16_with_result(gf, config); + assert(result.overflow == false); + assert(result.underflow == false); + assert(result.lost_precision == false); } test "gf16_bits_to_fp16_bits_zero" { - given config = conversion_config_init() - try std.testing.expect(gf16_bits_to_fp16_bits(0x0000, config) == 0x0000); + const config = conversion_config_init(); + assert(gf16_bits_to_fp16_bits(0x0000, config) == 0x0000); } test "gf16_bits_to_fp16_bits_roundtrip" { - given config = conversion_config_init() + const config = conversion_config_init(); // Normal value - try std.testing.expect(gf_bits = 0x2000 // exp=32, mant=0 -> value ~1.0 in GF16); - try std.testing.expect(fp_bits = gf16_bits_to_fp16_bits(gf_bits)); - try std.testing.expect((fp_bits & 0x8000) == (gf_bits & 0x8000) // Sign preserved); + const gf_bits = 0x2000; // exp=32, mant=0 -> value ~1.0 in GF16 + const fp_bits = gf16_bits_to_fp16_bits(gf_bits); + assert((fp_bits & 0x8000) == (gf_bits & 0x8000)); // Sign preserved } test "gf16_to_fp16_with_result_underflow" { - given gf = Gf16{.sign = 0, .exp = 0, .mant = 1} // Very small value - try std.testing.expect(config = conversion_config_init()); - try std.testing.expect(result = gf16_to_fp16_with_result(gf, config)); - try std.testing.expect(result.underflow == true or result.lost_precision == true); + const gf = Gf16{.sign = 0, .exp = 0, .mant = 1}; // Very small value + const config = conversion_config_init(); + const result = gf16_to_fp16_with_result(gf, config); + assert(result.underflow == true or result.lost_precision == true); } test "gf16_to_fp16_with_result_overflow" { - given gf = Gf16{.sign = 0, .exp = 62, .mant = 0} // Very large value - try std.testing.expect(config = conversion_config_init()); - try std.testing.expect(result = gf16_to_fp16_with_result(gf, config)); - try std.testing.expect(result.overflow == true); + const gf = Gf16{.sign = 0, .exp = 62, .mant = 0}; // Very large value + const config = conversion_config_init(); + const result = gf16_to_fp16_with_result(gf, config); + assert(result.overflow == true); } test "gf16_to_fp16_with_result_saturation" { - given gf = Gf16{.sign = 0, .exp = 62, .mant = 0} // Very large value - try std.testing.expect(config = conversion_config_init()); - try std.testing.expect(result = gf16_to_fp16_with_result(gf, config)); - try std.testing.expect(result.value != 0x7C00 // Not infinity, but max finite); + const gf = Gf16{.sign = 0, .exp = 62, .mant = 0}; // Very large value + const config = conversion_config_init(); + const result = gf16_to_fp16_with_result(gf, config); + assert(result.value != 0x7C00); // Not infinity, but max finite } test "gf16_to_fp16_with_result_no_saturation_overflow" { - given gf = Gf16{.sign = 0, .exp = 62, .mant = 0} // Very large value - try std.testing.expect(config = conversion_config_no_saturation()); - try std.testing.expect(result = gf16_to_fp16_with_result(gf, config)); - try std.testing.expect(result.value == 0x7C00 // Infinity); + const gf = Gf16{.sign = 0, .exp = 62, .mant = 0}; // Very large value + const config = conversion_config_no_saturation(); + const result = gf16_to_fp16_with_result(gf, config); + assert(result.value == 0x7C00); // Infinity } // ============================================================================ // Invariants // ============================================================================ -} invariant gf16_bit_count assert GF16_SIGN_BITS + GF16_EXP_BITS + GF16_MANT_BITS == 16 @@ -492,7 +491,7 @@ invariant fp16_mant_width invariant mantissa_masks_correct assert MANTissa_MASK_GF16 == (@as(u16, 1) << GF16_MANT_BITS) - 1 - try std.testing.expect(MANTissa_MASK_FP16 == (@as(u16, 1) << FP16_MANT_BITS) - 1); + assert MANTissa_MASK_FP16 == (@as(u16, 1) << FP16_MANT_BITS) - 1 invariant gf16_from_bits_roundtrip given bits = 0x5678 @@ -508,11 +507,11 @@ invariant gf16_zero_exp_zero_mant_zero invariant gf16_infinity_exp_max_mant_zero given gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 0} - assert gf16_is_infinity(gf) and not gf16_is_nan(gf) + assert gf16_is_infinity(gf) and !gf16_is_nan(gf) invariant fp16_infinity_exp_max_mant_zero given fp = Fp16{.sign = 0, .exp = 0x1F, .mant = 0} - assert fp16_is_infinity(fp) and not fp16_is_nan(fp) + assert fp16_is_infinity(fp) and !fp16_is_nan(fp) invariant conversion_config_init_saturation_enabled given config = conversion_config_init() @@ -522,20 +521,23 @@ invariant conversion_config_no_saturation_disabled given config = conversion_config_no_saturation() assert config.enable_saturation == false -invariant gf16_to_fp16_zero_preserves - given gf = Gf16{.sign = 0, .exp = 0, .mant = 0} - try std.testing.expect(fp = gf16_to_fp16(gf)); - try std.testing.expect(fp.sign == gf.sign); - -invariant gf16_to_fp16_infinity_preserves_sign - given gf_pos = Gf16{.sign = 1, .exp = 0x3F, .mant = 0} - try std.testing.expect(fp_pos = gf16_to_fp16(gf_pos)); - try std.testing.expect(fp_pos.sign == 1); - -invariant gf16_to_fp16_nan_preserves_sign - given gf = Gf16{.sign = 1, .exp = 0x3F, .mant = 1} - try std.testing.expect(fp = gf16_to_fp16(gf)); - try std.testing.expect(fp.sign == gf.sign); +invariant gf16_to_fp16_zero_preserves { + const gf = Gf16{.sign = 0, .exp = 0, .mant = 0}; + const fp = gf16_to_fp16(gf); + assert(fp.sign == gf.sign); +} + +invariant gf16_to_fp16_infinity_preserves_sign { + const gf_pos = Gf16{.sign = 1, .exp = 0x3F, .mant = 0}; + const fp_pos = gf16_to_fp16(gf_pos); + assert(fp_pos.sign == 1); +} + +invariant gf16_to_fp16_nan_preserves_sign { + const gf = Gf16{.sign = 1, .exp = 0x3F, .mant = 1}; + const fp = gf16_to_fp16(gf); + assert(fp.sign == gf.sign); +} // ============================================================================ // Benchmarks diff --git a/specs/fpga/gf16_to_posit16.t27 b/specs/fpga/gf16_to_posit16.t27 index 6f0189e..a32db4e 100644 --- a/specs/fpga/gf16_to_posit16.t27 +++ b/specs/fpga/gf16_to_posit16.t27 @@ -64,6 +64,8 @@ pub const ConversionConfig = struct { // gf16_from_bits(bits: u16) -> Gf16 // Extract GF16 from 16-bit representation pub fn gf16_from_bits(bits: u16) -> Gf16 { + // `as` has no u1/u6/u9 form, so the original @truncate intrinsics are kept + // (the t27 corpus uses @truncate too). return Gf16 { .sign = @as(u1, @truncate((bits >> 15) & 0x01)), .exp = @as(u6, @truncate((bits >> 9) & 0x3F)), @@ -74,9 +76,9 @@ pub fn gf16_from_bits(bits: u16) -> Gf16 { // gf16_to_bits(gf: Gf16) -> u16 // Convert GF16 to 16-bit representation pub fn gf16_to_bits(gf: Gf16) -> u16 { - const sign_field : u16 = @as(u16, gf.sign) << 15; - const exp_field : u16 = @as(u16, gf.exp) << 9; - const mant_field : u16 = @as(u16, gf.mant); + const sign_field : u16 = (gf.sign as u16) << 15; + const exp_field : u16 = (gf.exp as u16) << 9; + const mant_field : u16 = gf.mant as u16; return sign_field | exp_field | mant_field; } @@ -113,7 +115,7 @@ pub fn gf16_is_nan(gf: Gf16) -> bool { // gf16_get_exp_biased(gf: Gf16) -> i8 // Get exponent with bias applied pub fn gf16_get_exp_biased(gf: Gf16) -> i8 { - return @as(i8, @bitCast(gf.exp)) - GF16_BIAS; + return (gf.exp as i8) - GF16_BIAS; } // ============================================================================ @@ -186,7 +188,7 @@ pub fn posit16_decode(p: Posit16) -> PositComponents { while (bits & 0x4000 != 0) { regime += 1; if (regime > 16) break; - bits <<= 1; + bits = bits << 1; regime_bits += 1; } } else { @@ -194,21 +196,21 @@ pub fn posit16_decode(p: Posit16) -> PositComponents { while (bits & 0x4000 == 0) { regime -= 1; if (regime < -16) break; - bits <<= 1; + bits = bits << 1; regime_bits += 1; } } - bits <<= 1; // Skip last regime bit + bits = bits << 1; // Skip last regime bit // Extract exponent var exponent : u8 = 0; var exp_bit : u8 = 0; while (exp_bit < POSIT16_ES and bits != 0) { if (bits & 0x8000 != 0) { - exponent |= (@as(u8, 1) << (POSIT16_ES - 1 - exp_bit)); + exponent |= ((1 as u8) << (POSIT16_ES - 1 - exp_bit)); } - bits <<= 1; + bits = bits << 1; exp_bit += 1; } @@ -217,9 +219,9 @@ pub fn posit16_decode(p: Posit16) -> PositComponents { var mant_bit : u8 = 0; while (mant_bit < POSIT16_MANT_BITS and bits != 0) { if (bits & 0x8000 != 0) { - mantissa |= (@as(u16, 1) << (POSIT16_MANT_BITS - 1 - mant_bit)); + mantissa |= ((1 as u16) << (POSIT16_MANT_BITS - 1 - mant_bit)); } - bits <<= 1; + bits = bits << 1; mant_bit += 1; } @@ -252,10 +254,10 @@ pub fn conversion_config_init() -> ConversionConfig { // Convert GF16 to Posit16 (raw) pub fn gf16_to_posit16_raw(gf: Gf16) -> Posit16 { if (gf16_is_zero(gf)) { - return posit16_from_bits(@as(u16, @bitCast(gf.sign)) << 15); + return posit16_from_bits((gf.sign as u16) << 15); } else if (gf16_is_infinity(gf)) { // Positive infinity maps to NaR - return posit16_from_bits(@as(u16, @bitCast(gf.sign)) << 15); + return posit16_from_bits((gf.sign as u16) << 15); } else if (gf16_is_nan(gf)) { return posit16_from_bits(0x8000); // NaR } @@ -279,7 +281,7 @@ pub fn gf16_to_posit16_raw(gf: Gf16) -> Posit16 { exponent = 0; } else { regime = 0; - exponent = @as(u8, @truncate(@as(u8, @bitCast(exp_i8 + POSIT16_MAX_EXP)))); + exponent = (exp_i8 + POSIT16_MAX_EXP) as u8; } // Clamp regime to valid range @@ -296,22 +298,22 @@ pub fn gf16_to_posit16_raw(gf: Gf16) -> Posit16 { var temp_bits : u16 = if (regime >= 0) 0x4000 else 0x2000; var regime_count = if (regime >= 0) regime else -regime; - for (0..@as(usize, @intCast(regime_count))) |_| { + for _ in 0..(regime_count as usize) { if (regime >= 0) { result_bits |= temp_bits; - if (temp_bits != 0x8000) temp_bits >>= 1; + if (temp_bits != 0x8000) temp_bits = temp_bits >> 1; } else { result_bits |= temp_bits; - if (temp_bits != 0) temp_bits >>= 1; + if (temp_bits != 0) temp_bits = temp_bits >> 1; } } // Exponent (ES bits) - result_bits |= @as(u16, exponent) << (14 - POSIT16_ES); + result_bits |= (exponent as u16) << (14 - POSIT16_ES); // Mantissa (9 to 12 bits, pad with zeros) - var mant : u16 = @as(u16, gf.mant); - mant <<= 3; // 9 bits -> 12 bits + var mant : u16 = gf.mant as u16; + mant = mant << 3; // 9 bits -> 12 bits result_bits |= mant & 0x0FFF; return posit16_from_bits(result_bits); @@ -323,7 +325,7 @@ pub fn gf16_to_posit16_with_result(gf: Gf16, config: ConversionConfig) -> Conver var result : ConversionResult = undefined; if (gf16_is_zero(gf)) { - result.bits = @as(u16, @bitCast(gf.sign)) << 15; + result.bits = (gf.sign as u16) << 15; result.overflow = false; result.underflow = false; result.inexact = false; @@ -380,185 +382,184 @@ pub fn gf16_bits_to_posit16_bits_with_result(gf_bits: u16, config: ConversionCon // ============================================================================ test "gf16_bits_constants" { - try std.testing.expect(GF16_BITS == 16); - try std.testing.expect(GF16_EXP_BITS == 6); - try std.testing.expect(GF16_MANT_BITS == 9); - try std.testing.expect(GF16_BIAS == 31); + assert(GF16_BITS == 16); + assert(GF16_EXP_BITS == 6); + assert(GF16_MANT_BITS == 9); + assert(GF16_BIAS == 31); } test "posit16_constants" { - try std.testing.expect(POSIT16_BITS == 16); - try std.testing.expect(POSIT16_ES == 1); - try std.testing.expect(POSIT16_MAX_EXP == 7); + assert(POSIT16_BITS == 16); + assert(POSIT16_ES == 1); + assert(POSIT16_MAX_EXP == 7); } test "posit16_regime_mant_bits" { - try std.testing.expect(POSIT16_REGIME_BITS == 2); - try std.testing.expect(POSIT16_MANT_BITS == 12); + assert(POSIT16_REGIME_BITS == 2); + assert(POSIT16_MANT_BITS == 12); } test "gf16_from_bits_roundtrip" { - given bits = 0x1234 - try std.testing.expect(gf = gf16_from_bits(bits)); - try std.testing.expect(result = gf16_to_bits(gf)); - try std.testing.expect(result == bits); + const bits = 0x1234; + const gf = gf16_from_bits(bits); + const result = gf16_to_bits(gf); + assert(result == bits); } test "gf16_is_zero_true" { - given gf = Gf16{.sign = 0, .exp = 0, .mant = 0} - try std.testing.expect(gf16_is_zero(gf) == true); + const gf = Gf16{.sign = 0, .exp = 0, .mant = 0}; + assert(gf16_is_zero(gf) == true); } test "gf16_is_subnormal_true" { - given gf = Gf16{.sign = 0, .exp = 0, .mant = 1} - try std.testing.expect(gf16_is_subnormal(gf) == true); + const gf = Gf16{.sign = 0, .exp = 0, .mant = 1}; + assert(gf16_is_subnormal(gf) == true); } test "gf16_is_normal_true" { - given gf = Gf16{.sign = 0, .exp = 32, .mant = 0} - try std.testing.expect(gf16_is_normal(gf) == true); + const gf = Gf16{.sign = 0, .exp = 32, .mant = 0}; + assert(gf16_is_normal(gf) == true); } test "gf16_is_infinity_true" { - given gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 0} - try std.testing.expect(gf16_is_infinity(gf) == true); + const gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 0}; + assert(gf16_is_infinity(gf) == true); } test "gf16_is_nan_true" { - given gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 1} - try std.testing.expect(gf16_is_nan(gf) == true); + const gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 1}; + assert(gf16_is_nan(gf) == true); } test "posit16_from_bits_roundtrip" { - given bits = 0x4000 - try std.testing.expect(p = posit16_from_bits(bits)); - try std.testing.expect(result = posit16_to_bits(p)); - try std.testing.expect(result == bits); + const bits = 0x4000; + const p = posit16_from_bits(bits); + const result = posit16_to_bits(p); + assert(result == bits); } test "posit16_is_zero_true" { - given p = posit16_from_bits(0x0000) - try std.testing.expect(posit16_is_zero(p) == true); + const p = posit16_from_bits(0x0000); + assert(posit16_is_zero(p) == true); } test "posit16_is_one_true" { - given p = posit16_from_bits(0x4000) - try std.testing.expect(posit16_is_one(p) == true); + const p = posit16_from_bits(0x4000); + assert(posit16_is_one(p) == true); } test "posit16_is_neg_one_true" { - given p = posit16_from_bits(0xC000) - try std.testing.expect(posit16_is_neg_one(p) == true); + const p = posit16_from_bits(0xC000); + assert(posit16_is_neg_one(p) == true); } test "posit16_is_naR_true" { - given p = posit16_from_bits(0x8000) - try std.testing.expect(posit16_is_naR(p) == true); + const p = posit16_from_bits(0x8000); + assert(posit16_is_naR(p) == true); } test "posit16_get_sign_positive" { - given p = posit16_from_bits(0x4000) - try std.testing.expect(posit16_get_sign(p) == false); + const p = posit16_from_bits(0x4000); + assert(posit16_get_sign(p) == false); } test "posit16_get_sign_negative" { - given p = posit16_from_bits(0xC000) - try std.testing.expect(posit16_get_sign(p) == true); + const p = posit16_from_bits(0xC000); + assert(posit16_get_sign(p) == true); } test "posit16_decode_one" { - given p = posit16_from_bits(0x4000) - try std.testing.expect(comp = posit16_decode(p)); - try std.testing.expect(comp.sign == false); - try std.testing.expect(comp.regime == 0); - try std.testing.expect(comp.exponent == 0); - try std.testing.expect(comp.mantissa == 0); + const p = posit16_from_bits(0x4000); + const comp = posit16_decode(p); + assert(comp.sign == false); + assert(comp.regime == 0); + assert(comp.exponent == 0); + assert(comp.mantissa == 0); } test "conversion_config_init_structure" { - given config = conversion_config_init() - try std.testing.expect(config.round_mode == 0); - try std.testing.expect(config.clamp_overflow == true); + const config = conversion_config_init(); + assert(config.round_mode == 0); + assert(config.clamp_overflow == true); } test "gf16_to_posit16_zero" { - given gf = Gf16{.sign = 0, .exp = 0, .mant = 0} - try std.testing.expect(p = gf16_to_posit16(gf)); - try std.testing.expect(posit16_is_zero(p) == true); + const gf = Gf16{.sign = 0, .exp = 0, .mant = 0}; + const p = gf16_to_posit16(gf); + assert(posit16_is_zero(p) == true); } test "gf16_to_posit16_infinity" { - given gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 0} - try std.testing.expect(p = gf16_to_posit16(gf)); - try std.testing.expect(posit16_is_naR(p) == true); + const gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 0}; + const p = gf16_to_posit16(gf); + assert(posit16_is_naR(p) == true); } test "gf16_to_posit16_nan" { - given gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 1} - try std.testing.expect(p = gf16_to_posit16(gf)); - try std.testing.expect(posit16_is_naR(p) == true); + const gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 1}; + const p = gf16_to_posit16(gf); + assert(posit16_is_naR(p) == true); } test "gf16_to_posit16_preserves_sign" { - given gf_pos = Gf16{.sign = 1, .exp = 32, .mant = 0} - try std.testing.expect(gf_neg = Gf16{.sign = 0, .exp = 32, .mant = 0}); - try std.testing.expect(p_pos = gf16_to_posit16(gf_pos)); - try std.testing.expect(p_neg = gf16_to_posit16(gf_neg)); - try std.testing.expect(posit16_get_sign(p_pos) == true and posit16_get_sign(p_neg) == false); + const gf_pos = Gf16{.sign = 1, .exp = 32, .mant = 0}; + const gf_neg = Gf16{.sign = 0, .exp = 32, .mant = 0}; + const p_pos = gf16_to_posit16(gf_pos); + const p_neg = gf16_to_posit16(gf_neg); + assert(posit16_get_sign(p_pos) == true and posit16_get_sign(p_neg) == false); } test "gf16_bits_to_posit16_bits_zero" { - try std.testing.expect(gf16_bits_to_posit16_bits(0x0000) == 0x0000); + assert(gf16_bits_to_posit16_bits(0x0000) == 0x0000); } test "gf16_bits_to_posit16_bits_sign_preserved" { - given gf_pos = 0x8000 // Negative zero - try std.testing.expect(gf_neg = 0x0000 // Positive zero); - try std.testing.expect((gf16_bits_to_posit16_bits(gf_pos) & 0x8000) != 0); - try std.testing.expect((gf16_bits_to_posit16_bits(gf_neg) & 0x8000) == 0); + const gf_pos = 0x8000; // Negative zero + const gf_neg = 0x0000; // Positive zero + assert((gf16_bits_to_posit16_bits(gf_pos) & 0x8000) != 0); + assert((gf16_bits_to_posit16_bits(gf_neg) & 0x8000) == 0); } test "gf16_to_posit16_with_result_zero" { - given gf = Gf16{.sign = 0, .exp = 0, .mant = 0} - try std.testing.expect(config = conversion_config_init()); - try std.testing.expect(result = gf16_to_posit16_with_result(gf, config)); - try std.testing.expect(result.overflow == false); - try std.testing.expect(result.underflow == false); - try std.testing.expect(result.inexact == false); + const gf = Gf16{.sign = 0, .exp = 0, .mant = 0}; + const config = conversion_config_init(); + const result = gf16_to_posit16_with_result(gf, config); + assert(result.overflow == false); + assert(result.underflow == false); + assert(result.inexact == false); } test "gf16_to_posit16_with_result_infinity" { - given gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 0} - try std.testing.expect(config = conversion_config_init()); - try std.testing.expect(result = gf16_to_posit16_with_result(gf, config)); - try std.testing.expect(result.inexact == true); - try std.testing.expect(result.bits == 0x8000); + const gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 0}; + const config = conversion_config_init(); + const result = gf16_to_posit16_with_result(gf, config); + assert(result.inexact == true); + assert(result.bits == 0x8000); } test "gf16_to_posit16_with_result_overflow_clamped" { - given gf = Gf16{.sign = 0, .exp = 0x3E, .mant = 0x1FF} // Large value - try std.testing.expect(config = conversion_config_init()); - try std.testing.expect(result = gf16_to_posit16_with_result(gf, config)); - try std.testing.expect(result.overflow == true); - try std.testing.expect(result.bits != 0x8000 // Clamped, not NaR); + const gf = Gf16{.sign = 0, .exp = 0x3E, .mant = 0x1FF}; // Large value + const config = conversion_config_init(); + const result = gf16_to_posit16_with_result(gf, config); + assert(result.overflow == true); + assert(result.bits != 0x8000); // Clamped, not NaR } test "gf16_to_posit16_with_result_overflow_not_clamped" { - given gf = Gf16{.sign = 0, .exp = 0x3E, .mant = 0x1FF} - try std.testing.expect(config = ConversionConfig{.round_mode = 0, .clamp_overflow = false}); - try std.testing.expect(result = gf16_to_posit16_with_result(gf, config)); - try std.testing.expect(result.overflow == true); - try std.testing.expect(result.bits == 0x8000 // NaR); + const gf = Gf16{.sign = 0, .exp = 0x3E, .mant = 0x1FF}; + const config = ConversionConfig{.round_mode = 0, .clamp_overflow = false}; + const result = gf16_to_posit16_with_result(gf, config); + assert(result.overflow == true); + assert(result.bits == 0x8000); // NaR } // ============================================================================ // Invariants // ============================================================================ -} invariant gf16_bits_total assert GF16_BITS == 16 - try std.testing.expect(GF16_SIGN_BIT == GF16_BITS - 1); + assert GF16_SIGN_BIT == GF16_BITS - 1 invariant gf16_exp_mant_sum assert GF16_EXP_BITS + GF16_MANT_BITS == GF16_BITS - 1 @@ -582,15 +583,15 @@ invariant posit16_from_bits_roundtrip invariant gf16_zero_exp_zero_mant_zero given gf = Gf16{.sign = 0, .exp = 0, .mant = 0} - assert gf16_is_zero(gf) and not gf16_is_subnormal(gf) + assert gf16_is_zero(gf) and !gf16_is_subnormal(gf) invariant gf16_subnormal_exp_zero_mant_nonzero given gf = Gf16{.sign = 0, .exp = 0, .mant = 1} - assert gf16_is_subnormal(gf) and not gf16_is_zero(gf) + assert gf16_is_subnormal(gf) and !gf16_is_zero(gf) invariant gf16_normal_exp_nonzero given gf = Gf16{.sign = 0, .exp = 1, .mant = 0} - assert gf16_is_normal(gf) and not gf16_is_zero(gf) + assert gf16_is_normal(gf) and !gf16_is_zero(gf) invariant posit16_zero_bits_zero given p = posit16_from_bits(0x0000) @@ -598,7 +599,7 @@ invariant posit16_zero_bits_zero invariant posit16_one_bits_one given p = posit16_from_bits(0x4000) - assert posit16_is_one(p) and not posit16_is_zero(p) + assert posit16_is_one(p) and !posit16_is_zero(p) invariant posit16_naR_bits_naR given p = posit16_from_bits(0x8000) @@ -610,18 +611,18 @@ invariant conversion_config_init_clamp_enabled invariant gf16_to_posit16_zero_preserves given gf = Gf16{.sign = 0, .exp = 0, .mant = 0} - try std.testing.expect(p = gf16_to_posit16(gf)); - try std.testing.expect(posit16_is_zero(p) and not posit16_get_sign(p)); + when p = gf16_to_posit16(gf) + assert posit16_is_zero(p) and !posit16_get_sign(p) invariant gf16_to_posit16_infinity_to_naR given gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 0} - try std.testing.expect(p = gf16_to_posit16(gf)); - try std.testing.expect(posit16_is_naR(p)); + when p = gf16_to_posit16(gf) + assert posit16_is_naR(p) invariant gf16_to_posit16_nan_to_naR given gf = Gf16{.sign = 0, .exp = 0x3F, .mant = 1} - try std.testing.expect(p = gf16_to_posit16(gf)); - try std.testing.expect(posit16_is_naR(p)); + when p = gf16_to_posit16(gf) + assert posit16_is_naR(p) // ============================================================================ // Benchmarks diff --git a/specs/fpga/gf256.t27 b/specs/fpga/gf256.t27 index e57a0cd..7501d9c 100644 --- a/specs/fpga/gf256.t27 +++ b/specs/fpga/gf256.t27 @@ -33,6 +33,10 @@ module GF256 { raw_3 : u64, // bits 192-255 (sign + exp high) } + // Note: t27 `as` casts accept only bool/u8..u64/i8..i64/usize/f32/f64, + // and `1u128` lexes as `1` followed by a stray `u128` statement, so each + // 128-bit cast or literal below is written as `@as(u128, e)` / `@as(i128, e)`. + // Encode f64 to GF256 fn encode(value: f64) -> GF256 { if (value == 0.0) { @@ -43,7 +47,7 @@ module GF256 { const abs_val = if (value < 0.0) { -value } else { value }; // Extract exponent (unbiased) - const exp_unbiased = floor_log2(abs_val) as i128; + const exp_unbiased = @as(i128, floor_log2(abs_val)); let exp_biased_lo = ((exp_unbiased + 158886469278522817) & 0xFFFFFFFFFFFFFFFF) as u64; let exp_biased_hi = ((exp_unbiased >> 64) + 127) as u64; @@ -56,8 +60,8 @@ module GF256 { // Extract mantissa (158 bits, split across 3 u64 words) const normalized = abs_val / pow(2.0, exp_unbiased as f64); const frac = normalized - 1.0; - const max_mant = (1u128 << MANT_BITS) - 1; - const mant = (frac * (max_mant + 1) as f64) as u128; + const max_mant = (@as(u128, 1) << MANT_BITS) - 1; + const mant = @as(u128, (frac * (max_mant + 1) as f64)); const clamped_mant = if (mant > max_mant) { max_mant } else { mant }; // Pack mantissa @@ -90,12 +94,12 @@ module GF256 { const exp_biased_lo = exp_lo_part | (exp_mid_part << 31); const exp_biased_hi = exp_hi_part >> 62; - const exp_biased_128 = ((exp_biased_hi as u128) << 64) | exp_biased_lo as u128; + const exp_biased_128 = (@as(u128, exp_biased_hi) << 64) | @as(u128, exp_biased_lo); // Extract mantissa (158 bits) const mant_lo = gf.raw_0; const mant_mid = gf.raw_1 & 0x1FFFFFFFFFFFFFFF; - const mant = ((mant_mid as u128) << 64) | mant_lo as u128; + const mant = (@as(u128, mant_mid) << 64) | @as(u128, mant_lo); // Zero if (exp_biased_128 == 0 && mant == 0) { @@ -103,15 +107,15 @@ module GF256 { } // Exponent - const exp_bias_128 = ((EXP_BIAS_HI as u128) << 64) | EXP_BIAS_LO as u128; + const exp_bias_128 = (@as(u128, EXP_BIAS_HI) << 64) | @as(u128, EXP_BIAS_LO); const exp_unbiased = if (exp_biased_128 == 0) { - -(exp_bias_128 as i128) + 1 + -(@as(i128, exp_bias_128)) + 1 } else { - (exp_biased_128 as i128) - exp_bias_128 as i128 + @as(i128, exp_biased_128) - @as(i128, exp_bias_128) }; // Mantissa - const max_mant = (1u128 << MANT_BITS) - 1; + const max_mant = (@as(u128, 1) << MANT_BITS) - 1; const mant_normalized = if (exp_biased_128 == 0) { (mant as f64) / (max_mant + 1) as f64 } else { @@ -128,21 +132,21 @@ module GF256 { // Format Properties fn max_value() -> f64 { - const max_mant = (1u128 << MANT_BITS) - 1; + const max_mant = (@as(u128, 1) << MANT_BITS) - 1; const mant_max = 1.0 + (max_mant as f64) / (max_mant + 1) as f64; - const exp_max = ((1i128 << EXP_BITS) - 1) as f64 - (EXP_BIAS_HI as f64 * 4294967296.0 + EXP_BIAS_LO as f64); + const exp_max = ((@as(i128, 1) << EXP_BITS) - 1) as f64 - (EXP_BIAS_HI as f64 * 4294967296.0 + EXP_BIAS_LO as f64); return mant_max * pow(2.0, exp_max); } fn min_positive() -> f64 { - const max_mant = (1u128 << MANT_BITS) - 1; + const max_mant = (@as(u128, 1) << MANT_BITS) - 1; const mant_min = 1.0 / (max_mant + 1) as f64; const exp_min = -((EXP_BIAS_HI as f64 * 4294967296.0 + EXP_BIAS_LO as f64)) + 1.0; return mant_min * pow(2.0, exp_min); } fn epsilon() -> f64 { - const max_mant = (1u128 << MANT_BITS) - 1; + const max_mant = (@as(u128, 1) << MANT_BITS) - 1; return 1.0 / (max_mant + 1) as f64; } @@ -253,7 +257,7 @@ module GF256 { } fn floor(x: f64) -> f64 { - let xi = x as i128; + let xi = @as(i128, x); if (x >= 0.0 || x == xi as f64) { return xi as f64; } diff --git a/specs/fpga/gf32_to_fp32.t27 b/specs/fpga/gf32_to_fp32.t27 index a33a7bd..5b0ed1c 100644 --- a/specs/fpga/gf32_to_fp32.t27 +++ b/specs/fpga/gf32_to_fp32.t27 @@ -341,7 +341,7 @@ pub fn gf32_to_fp32_with_result(gf: Gf32, config: ConversionConfig) -> Conversio var denorm_exp = exp_i16 + 126; if (denorm_exp >= -22) { exp = 0; - mant = @as(u23, gf.mant) << (4 - @as(u5, @intCast(-denorm_exp)))); + mant = @as(u23, gf.mant) << (4 - @as(u5, @intCast(-denorm_exp))); } else { exp = 0; mant = 0; @@ -395,215 +395,214 @@ pub fn gf32_bits_to_fp32_bits_with_result(gf_bits: u32, config: ConversionConfig // ============================================================================ test "gf32_bits_constants" { - try std.testing.expect(GF32_SIGN_BITS == 1); - try std.testing.expect(GF32_EXP_BITS == 12); - try std.testing.expect(GF32_MANT_BITS == 19); - try std.testing.expect(GF32_BIAS == 2047); + assert(GF32_SIGN_BITS == 1); + assert(GF32_EXP_BITS == 12); + assert(GF32_MANT_BITS == 19); + assert(GF32_BIAS == 2047); } test "fp32_bits_constants" { - try std.testing.expect(FP32_SIGN_BITS == 1); - try std.testing.expect(FP32_EXP_BITS == 8); - try std.testing.expect(FP32_MANT_BITS == 23); - try std.testing.expect(FP32_BIAS == 127); + assert(FP32_SIGN_BITS == 1); + assert(FP32_EXP_BITS == 8); + assert(FP32_MANT_BITS == 23); + assert(FP32_BIAS == 127); } test "exp_bias_diff" { - try std.testing.expect(EXP_BIAS_DIFF == 1920); + assert(EXP_BIAS_DIFF == 1920); } test "mantissa_masks" { - try std.testing.expect(MANTissa_MASK_GF32 == 0x7FFFF); - try std.testing.expect(MANTissa_MASK_FP32 == 0x7FFFFF); + assert(MANTissa_MASK_GF32 == 0x7FFFF); + assert(MANTissa_MASK_FP32 == 0x7FFFFF); } test "gf32_from_bits_to_bits_roundtrip" { - given bits = 0x12345678 - try std.testing.expect(gf = gf32_from_bits(bits)); - try std.testing.expect(result = gf32_to_bits(gf)); - try std.testing.expect(result == bits); + const bits = 0x12345678; + const gf = gf32_from_bits(bits); + const result = gf32_to_bits(gf); + assert(result == bits); } test "gf32_from_bits_structure" { - given gf = gf32_from_bits(0x80000000) - try std.testing.expect(gf.sign == 1); - try std.testing.expect(gf.exp == 0); - try std.testing.expect(gf.mant == 0); + const gf = gf32_from_bits(0x80000000); + assert(gf.sign == 1); + assert(gf.exp == 0); + assert(gf.mant == 0); } test "fp32_from_bits_to_bits_roundtrip" { - given bits = 0x3F800000 - try std.testing.expect(fp = fp32_from_bits(bits)); - try std.testing.expect(result = fp32_to_bits(fp)); - try std.testing.expect(result == bits); + const bits = 0x3F800000; + const fp = fp32_from_bits(bits); + const result = fp32_to_bits(fp); + assert(result == bits); } test "gf32_is_zero_true" { - given gf = Gf32{.sign = 0, .exp = 0, .mant = 0} - try std.testing.expect(gf32_is_zero(gf) == true); + const gf = Gf32{.sign = 0, .exp = 0, .mant = 0}; + assert(gf32_is_zero(gf) == true); } test "gf32_is_zero_false" { - given gf = Gf32{.sign = 0, .exp = 0, .mant = 1} - try std.testing.expect(gf32_is_zero(gf) == false); + const gf = Gf32{.sign = 0, .exp = 0, .mant = 1}; + assert(gf32_is_zero(gf) == false); } test "gf32_is_subnormal_true" { - given gf = Gf32{.sign = 0, .exp = 0, .mant = 1} - try std.testing.expect(gf32_is_subnormal(gf) == true); + const gf = Gf32{.sign = 0, .exp = 0, .mant = 1}; + assert(gf32_is_subnormal(gf) == true); } test "gf32_is_normal_true" { - given gf = Gf32{.sign = 0, .exp = 1, .mant = 0} - try std.testing.expect(gf32_is_normal(gf) == true); + const gf = Gf32{.sign = 0, .exp = 1, .mant = 0}; + assert(gf32_is_normal(gf) == true); } test "gf32_is_infinity_true" { - given gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0} - try std.testing.expect(gf32_is_infinity(gf) == true); + const gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0}; + assert(gf32_is_infinity(gf) == true); } test "gf32_is_nan_true" { - given gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 1} - try std.testing.expect(gf32_is_nan(gf) == true); + const gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 1}; + assert(gf32_is_nan(gf) == true); } test "gf32_is_qnan_true" { - given gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0x40000} - try std.testing.expect(gf32_is_qnan(gf) == true); + const gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0x40000}; + assert(gf32_is_qnan(gf) == true); } test "gf32_is_snan_true" { - given gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0x20000} - try std.testing.expect(gf32_is_snan(gf) == true); + const gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0x20000}; + assert(gf32_is_snan(gf) == true); } test "fp32_is_zero_true" { - given fp = Fp32{.sign = 0, .exp = 0, .mant = 0} - try std.testing.expect(fp32_is_zero(fp) == true); + const fp = Fp32{.sign = 0, .exp = 0, .mant = 0}; + assert(fp32_is_zero(fp) == true); } test "fp32_is_infinity_true" { - given fp = Fp32{.sign = 0, .exp = 0xFF, .mant = 0} - try std.testing.expect(fp32_is_infinity(fp) == true); + const fp = Fp32{.sign = 0, .exp = 0xFF, .mant = 0}; + assert(fp32_is_infinity(fp) == true); } test "fp32_is_nan_true" { - given fp = Fp32{.sign = 0, .exp = 0xFF, .mant = 1} - try std.testing.expect(fp32_is_nan(fp) == true); + const fp = Fp32{.sign = 0, .exp = 0xFF, .mant = 1}; + assert(fp32_is_nan(fp) == true); } test "fp32_is_qnan_true" { - given fp = Fp32{.sign = 0, .exp = 0xFF, .mant = 0x400000} - try std.testing.expect(fp32_is_qnan(fp) == true); + const fp = Fp32{.sign = 0, .exp = 0xFF, .mant = 0x400000}; + assert(fp32_is_qnan(fp) == true); } test "conversion_config_init_structure" { - given config = conversion_config_init() - try std.testing.expect(config.round_mode == 0); - try std.testing.expect(config.enable_saturation == true); + const config = conversion_config_init(); + assert(config.round_mode == 0); + assert(config.enable_saturation == true); } test "conversion_config_no_saturation_structure" { - given config = conversion_config_no_saturation() - try std.testing.expect(config.enable_saturation == false); + const config = conversion_config_no_saturation(); + assert(config.enable_saturation == false); } test "conversion_config_round_up_structure" { - given config = conversion_config_round_up() - try std.testing.expect(config.round_mode == 1); + const config = conversion_config_round_up(); + assert(config.round_mode == 1); } test "gf32_to_fp32_zero" { - given gf = Gf32{.sign = 0, .exp = 0, .mant = 0} - try std.testing.expect(fp = gf32_to_fp32(gf)); - try std.testing.expect(fp.exp == 0); - try std.testing.expect(fp.mant == 0); + const gf = Gf32{.sign = 0, .exp = 0, .mant = 0}; + const fp = gf32_to_fp32(gf); + assert(fp.exp == 0); + assert(fp.mant == 0); } test "gf32_to_fp32_infinity" { - given gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0} - try std.testing.expect(fp = gf32_to_fp32(gf)); - try std.testing.expect(fp.exp == 0xFF); - try std.testing.expect(fp.mant == 0); + const gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0}; + const fp = gf32_to_fp32(gf); + assert(fp.exp == 0xFF); + assert(fp.mant == 0); } test "gf32_to_fp32_nan" { - given gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 1} - try std.testing.expect(fp = gf32_to_fp32(gf)); - try std.testing.expect(fp.exp == 0xFF); - try std.testing.expect(fp.mant != 0); + const gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 1}; + const fp = gf32_to_fp32(gf); + assert(fp.exp == 0xFF); + assert(fp.mant != 0); } test "gf32_to_fp32_preserves_sign" { - given gf_pos = Gf32{.sign = 1, .exp = 2048, .mant = 0} - try std.testing.expect(gf_neg = Gf32{.sign = 0, .exp = 2048, .mant = 0}); - try std.testing.expect(fp_pos = gf32_to_fp32(gf_pos)); - try std.testing.expect(fp_neg = gf32_to_fp32(gf_neg)); - try std.testing.expect(fp_pos.sign == 1 and fp_neg.sign == 0); + const gf_pos = Gf32{.sign = 1, .exp = 2048, .mant = 0}; + const gf_neg = Gf32{.sign = 0, .exp = 2048, .mant = 0}; + const fp_pos = gf32_to_fp32(gf_pos); + const fp_neg = gf32_to_fp32(gf_neg); + assert(fp_pos.sign == 1 and fp_neg.sign == 0); } test "gf32_to_fp32_with_result_zero" { - given gf = Gf32{.sign = 0, .exp = 0, .mant = 0} - try std.testing.expect(config = conversion_config_init()); - try std.testing.expect(result = gf32_to_fp32_with_result(gf, config)); - try std.testing.expect(result.overflow == false); - try std.testing.expect(result.underflow == false); - try std.testing.expect(result.lost_precision == false); + const gf = Gf32{.sign = 0, .exp = 0, .mant = 0}; + const config = conversion_config_init(); + const result = gf32_to_fp32_with_result(gf, config); + assert(result.overflow == false); + assert(result.underflow == false); + assert(result.lost_precision == false); } test "gf32_bits_to_fp32_bits_zero" { - given config = conversion_config_init() - try std.testing.expect(gf32_bits_to_fp32_bits(0x00000000, config) == 0x00000000); + const config = conversion_config_init(); + assert(gf32_bits_to_fp32_bits(0x00000000, config) == 0x00000000); } test "gf32_to_fp32_with_result_subnormal_underflow" { - given gf = Gf32{.sign = 0, .exp = 0, .mant = 1} - try std.testing.expect(config = conversion_config_init()); - try std.testing.expect(result = gf32_to_fp32_with_result(gf, config)); - try std.testing.expect(result.underflow == true); + const gf = Gf32{.sign = 0, .exp = 0, .mant = 1}; + const config = conversion_config_init(); + const result = gf32_to_fp32_with_result(gf, config); + assert(result.underflow == true); } test "gf32_to_fp32_with_result_overflow" { - given gf = Gf32{.sign = 0, .exp = 4094, .mant = 0} // Very large - try std.testing.expect(config = conversion_config_init()); - try std.testing.expect(result = gf32_to_fp32_with_result(gf, config)); - try std.testing.expect(result.overflow == true); + const gf = Gf32{.sign = 0, .exp = 4094, .mant = 0}; // Very large + const config = conversion_config_init(); + const result = gf32_to_fp32_with_result(gf, config); + assert(result.overflow == true); } test "gf32_to_fp32_with_result_saturation" { - given gf = Gf32{.sign = 0, .exp = 4094, .mant = 0} // Very large - try std.testing.expect(config = conversion_config_init()); - try std.testing.expect(result = gf32_to_fp32_with_result(gf, config)); - try std.testing.expect(result.value != 0x7F800000 // Not infinity, but max finite); + const gf = Gf32{.sign = 0, .exp = 4094, .mant = 0}; // Very large + const config = conversion_config_init(); + const result = gf32_to_fp32_with_result(gf, config); + assert(result.value != 0x7F800000); // Not infinity, but max finite } test "gf32_to_fp32_with_result_no_saturation_overflow" { - given gf = Gf32{.sign = 0, .exp = 4094, .mant = 0} // Very large - try std.testing.expect(config = conversion_config_no_saturation()); - try std.testing.expect(result = gf32_to_fp32_with_result(gf, config)); - try std.testing.expect(result.value == 0x7F800000 // Infinity); + const gf = Gf32{.sign = 0, .exp = 4094, .mant = 0}; // Very large + const config = conversion_config_no_saturation(); + const result = gf32_to_fp32_with_result(gf, config); + assert(result.value == 0x7F800000); // Infinity } test "gf32_to_fp32_nan_qnan_preserves" { - given gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0x40000} - try std.testing.expect(config = conversion_config_init()); - try std.testing.expect(result = gf32_to_fp32_with_result(gf, config)); - try std.testing.expect((result.value & 0x400000) != 0 // Quiet NaN bit set); + const gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0x40000}; + const config = conversion_config_init(); + const result = gf32_to_fp32_with_result(gf, config); + assert((result.value & 0x400000) != 0); // Quiet NaN bit set } test "gf32_to_fp32_nan_snan_preserves" { - given gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0x20000} - try std.testing.expect(config = conversion_config_init()); - try std.testing.expect(result = gf32_to_fp32_with_result(gf, config)); - try std.testing.expect((result.value & 0x400000) == 0 // Quiet NaN bit not set); + const gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0x20000}; + const config = conversion_config_init(); + const result = gf32_to_fp32_with_result(gf, config); + assert((result.value & 0x400000) == 0); // Quiet NaN bit not set } // ============================================================================ // Invariants // ============================================================================ -} invariant gf32_bit_count assert GF32_SIGN_BITS + GF32_EXP_BITS + GF32_MANT_BITS == 32 @@ -624,7 +623,7 @@ invariant fp32_mant_width invariant mantissa_masks_correct assert MANTissa_MASK_GF32 == (@as(u32, 1) << GF32_MANT_BITS) - 1 - try std.testing.expect(MANTissa_MASK_FP32 == (@as(u32, 1) << FP32_MANT_BITS) - 1); + assert MANTissa_MASK_FP32 == (@as(u32, 1) << FP32_MANT_BITS) - 1; invariant exp_bias_diff_positive assert EXP_BIAS_DIFF > 0 @@ -639,19 +638,19 @@ invariant fp32_from_bits_roundtrip invariant gf32_zero_exp_zero_mant_zero given gf = Gf32{.sign = 0, .exp = 0, .mant = 0} - assert gf32_is_zero(gf) and not gf32_is_subnormal(gf) + assert gf32_is_zero(gf) and !gf32_is_subnormal(gf) invariant gf32_subnormal_exp_zero_mant_nonzero given gf = Gf32{.sign = 0, .exp = 0, .mant = 1} - assert gf32_is_subnormal(gf) and not gf32_is_zero(gf) + assert gf32_is_subnormal(gf) and !gf32_is_zero(gf) invariant gf32_normal_exp_nonzero given gf = Gf32{.sign = 0, .exp = 1, .mant = 0} - assert gf32_is_normal(gf) and not gf32_is_zero(gf) + assert gf32_is_normal(gf) and !gf32_is_zero(gf) invariant gf32_infinity_exp_max_mant_zero given gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0} - assert gf32_is_infinity(gf) and not gf32_is_nan(gf) + assert gf32_is_infinity(gf) and !gf32_is_nan(gf) invariant gf32_qnan_top_mant_bit given gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0x40000} @@ -663,7 +662,7 @@ invariant gf32_snan_top_mant_bit_clear invariant fp32_infinity_exp_max_mant_zero given fp = Fp32{.sign = 0, .exp = 0xFF, .mant = 0} - assert fp32_is_infinity(fp) and not fp32_is_nan(fp) + assert fp32_is_infinity(fp) and !fp32_is_nan(fp) invariant fp32_qnan_top_mant_bit given fp = Fp32{.sign = 0, .exp = 0xFF, .mant = 0x400000} @@ -683,30 +682,30 @@ invariant conversion_config_round_up_mode_one invariant gf32_to_fp32_zero_preserves given gf = Gf32{.sign = 0, .exp = 0, .mant = 0} - try std.testing.expect(fp = gf32_to_fp32(gf)); - try std.testing.expect(fp.sign == gf.sign); + when fp = gf32_to_fp32(gf) + assert fp.sign == gf.sign; invariant gf32_to_fp32_infinity_preserves_sign given gf_pos = Gf32{.sign = 1, .exp = 0xFFF, .mant = 0} - try std.testing.expect(fp_pos = gf32_to_fp32(gf_pos)); - try std.testing.expect(fp_pos.sign == 1); + when fp_pos = gf32_to_fp32(gf_pos) + assert fp_pos.sign == 1; invariant gf32_to_fp32_nan_preserves_sign given gf = Gf32{.sign = 1, .exp = 0xFFF, .mant = 1} - try std.testing.expect(fp = gf32_to_fp32(gf)); - try std.testing.expect(fp.sign == 1); + when fp = gf32_to_fp32(gf) + assert fp.sign == 1; invariant gf32_to_fp32_qnan_preserves_qnan given gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0x40000} - try std.testing.expect(config = conversion_config_init()); - try std.testing.expect(result = gf32_to_fp32_with_result(gf, config)); - try std.testing.expect((result.value & 0x400000) != 0); + when config = conversion_config_init() + and result = gf32_to_fp32_with_result(gf, config) + assert (result.value & 0x400000) != 0; invariant gf32_to_fp32_snan_preserves_snan given gf = Gf32{.sign = 0, .exp = 0xFFF, .mant = 0x20000} - try std.testing.expect(config = conversion_config_init()); - try std.testing.expect(result = gf32_to_fp32_with_result(gf, config)); - try std.testing.expect((result.value & 0x400000) == 0); + when config = conversion_config_init() + and result = gf32_to_fp32_with_result(gf, config) + assert (result.value & 0x400000) == 0; // ============================================================================ // Benchmarks diff --git a/specs/fpga/holo_mux_x4.t27 b/specs/fpga/holo_mux_x4.t27 index 908d2f9..0946378 100644 --- a/specs/fpga/holo_mux_x4.t27 +++ b/specs/fpga/holo_mux_x4.t27 @@ -74,7 +74,7 @@ pub fn holo_input_valid(input: HoloInput) bool { // holo_input_score(input: HoloInput, config: HoloMuxConfig) -> u16 // Calculate selection score for input pub fn holo_input_score(input: HoloInput, config: HoloMuxConfig) u16 { - if (not holo_input_valid(input)) { + if (!holo_input_valid(input)) { return 0; } @@ -143,7 +143,8 @@ pub fn holo_mux_best(inputs: [NUM_INPUTS]HoloInput, config: HoloMuxConfig) -> Ho var best_idx : u8 = 0; var best_score : u16 = 0; - for (inputs, 0..) |input, i| { + for i in 0..NUM_INPUTS { + const input = inputs[i]; const score = holo_input_score(input, config); if (score > best_score and holo_input_valid(input)) { best_score = score; @@ -165,7 +166,8 @@ pub fn holo_mux_best(inputs: [NUM_INPUTS]HoloInput, config: HoloMuxConfig) -> Ho // Get bitmask of valid inputs pub fn holo_mux_valid(inputs: [NUM_INPUTS]HoloInput) -> u8 { var mask : u8 = 0; - for (inputs, 0..) |input, i| { + for i in 0..NUM_INPUTS { + const input = inputs[i]; if (holo_input_valid(input)) { mask |= (@as(u8, 1) << i); } @@ -177,7 +179,8 @@ pub fn holo_mux_valid(inputs: [NUM_INPUTS]HoloInput) -> u8 { // Count valid inputs pub fn holo_mux_count_valid(inputs: [NUM_INPUTS]HoloInput) -> u8 { var count : u8 = 0; - for (inputs) |input| { + for i in 0..NUM_INPUTS { + const input = inputs[i]; if (holo_input_valid(input)) { count += 1; } @@ -188,7 +191,8 @@ pub fn holo_mux_count_valid(inputs: [NUM_INPUTS]HoloInput) -> u8 { // holo_mux_any_valid(inputs: [NUM_INPUTS]HoloInput) -> bool // Check if any input is valid pub fn holo_mux_any_valid(inputs: [NUM_INPUTS]HoloInput) -> bool { - for (inputs) |input| { + for i in 0..NUM_INPUTS { + const input = inputs[i]; if (holo_input_valid(input)) { return true; } @@ -199,8 +203,9 @@ pub fn holo_mux_any_valid(inputs: [NUM_INPUTS]HoloInput) -> bool { // holo_mux_all_valid(inputs: [NUM_INPUTS]HoloInput) -> bool // Check if all inputs are valid pub fn holo_mux_all_valid(inputs: [NUM_INPUTS]HoloInput) -> bool { - for (inputs) |input| { - if (not holo_input_valid(input)) { + for i in 0..NUM_INPUTS { + const input = inputs[i]; + if (!holo_input_valid(input)) { return false; } } @@ -234,13 +239,13 @@ pub fn holo_layer_is_west(layer: u8) bool { // holo_opposite_layer(layer: u8) -> u8 // Get opposite layer (N<->S, E<->W) pub fn holo_opposite_layer(layer: u8) -> u8 { - switch (layer) { - HOLO_LAYER_NORTH => return HOLO_LAYER_SOUTH, - HOLO_LAYER_SOUTH => return HOLO_LAYER_NORTH, - HOLO_LAYER_EAST => return HOLO_LAYER_WEST, - HOLO_LAYER_WEST => return HOLO_LAYER_EAST, - else => return layer, - } + return switch (layer) { + HOLO_LAYER_NORTH => HOLO_LAYER_SOUTH, + HOLO_LAYER_SOUTH => HOLO_LAYER_NORTH, + HOLO_LAYER_EAST => HOLO_LAYER_WEST, + HOLO_LAYER_WEST => HOLO_LAYER_EAST, + else => layer, + }; } // ============================================================================ @@ -300,205 +305,204 @@ pub fn decode_holo_mux_x4(encoded: u16) struct { layer: u8, phase: u8, frozen: b // ============================================================================ test "num_inputs_four" { - try std.testing.expect(NUM_INPUTS == 4); + assert(NUM_INPUTS == 4); } test "data_width_sixteen" { - try std.testing.expect(DATA_WIDTH == 16); + assert(DATA_WIDTH == 16); } test "select_bits_two" { - try std.testing.expect(SELECT_BITS == 2); + assert(SELECT_BITS == 2); } test "holo_layer_constants" { - try std.testing.expect(HOLO_LAYER_NORTH == 0); - try std.testing.expect(HOLO_LAYER_EAST == 1); - try std.testing.expect(HOLO_LAYER_SOUTH == 2); - try std.testing.expect(HOLO_LAYER_WEST == 3); + assert(HOLO_LAYER_NORTH == 0); + assert(HOLO_LAYER_EAST == 1); + assert(HOLO_LAYER_SOUTH == 2); + assert(HOLO_LAYER_WEST == 3); } test "holo_phase_constants" { - try std.testing.expect(HOLO_PHASE_0 == 0); - try std.testing.expect(HOLO_PHASE_90 == 1); - try std.testing.expect(HOLO_PHASE_180 == 2); - try std.testing.expect(HOLO_PHASE_270 == 3); + assert(HOLO_PHASE_0 == 0); + assert(HOLO_PHASE_90 == 1); + assert(HOLO_PHASE_180 == 2); + assert(HOLO_PHASE_270 == 3); } test "holo_input_valid_true" { - given input = HoloInput{.data = 0x1234, .layer = 0, .phase = 0, .valid = true, .phi_score = 100} - try std.testing.expect(holo_input_valid(input) == true); + const input = HoloInput{.data = 0x1234, .layer = 0, .phase = 0, .valid = true, .phi_score = 100}; + assert(holo_input_valid(input) == true); } test "holo_input_valid_false_invalid_layer" { - given input = HoloInput{.data = 0x1234, .layer = 4, .phase = 0, .valid = true, .phi_score = 100} - try std.testing.expect(holo_input_valid(input) == false); + const input = HoloInput{.data = 0x1234, .layer = 4, .phase = 0, .valid = true, .phi_score = 100}; + assert(holo_input_valid(input) == false); } test "holo_input_valid_false_invalid_flag" { - given input = HoloInput{.data = 0x1234, .layer = 0, .phase = 0, .valid = false, .phi_score = 100} - try std.testing.expect(holo_input_valid(input) == false); + const input = HoloInput{.data = 0x1234, .layer = 0, .phase = 0, .valid = false, .phi_score = 100}; + assert(holo_input_valid(input) == false); } test "holo_mux_select_north" { - given inputs = [_]HoloInput{ + const inputs = [_]HoloInput{ .{.data = 0x1000, .layer = 0, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x2000, .layer = 1, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x3000, .layer = 2, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x4000, .layer = 3, .phase = 0, .valid = true, .phi_score = 100}, - } - try std.testing.expect(config = HoloMuxConfig{.phi_optimized = false, .priority_select = false, .layer_frozen = false, .default_input = 0}); - try std.testing.expect(output = holo_mux_select(inputs, 0, config)); - try std.testing.expect(output.data == 0x1000); - try std.testing.expect(output.selected_layer == 0); - try std.testing.expect(output.frozen == false); + }; + const config = HoloMuxConfig{.phi_optimized = false, .priority_select = false, .layer_frozen = false, .default_input = 0}; + const output = holo_mux_select(inputs, 0, config); + assert(output.data == 0x1000); + assert(output.selected_layer == 0); + assert(output.frozen == false); } test "holo_mux_select_east" { - given inputs = [_]HoloInput{ + const inputs = [_]HoloInput{ .{.data = 0x1000, .layer = 0, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x2000, .layer = 1, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x3000, .layer = 2, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x4000, .layer = 3, .phase = 0, .valid = true, .phi_score = 100}, - } - try std.testing.expect(config = HoloMuxConfig{.phi_optimized = false, .priority_select = false, .layer_frozen = false, .default_input = 0}); - try std.testing.expect(output = holo_mux_select(inputs, 1, config)); - try std.testing.expect(output.data == 0x2000); - try std.testing.expect(output.selected_layer == 1); + }; + const config = HoloMuxConfig{.phi_optimized = false, .priority_select = false, .layer_frozen = false, .default_input = 0}; + const output = holo_mux_select(inputs, 1, config); + assert(output.data == 0x2000); + assert(output.selected_layer == 1); } test "holo_mux_frozen" { - given inputs = [_]HoloInput{ + const inputs = [_]HoloInput{ .{.data = 0x1000, .layer = 0, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x2000, .layer = 1, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x3000, .layer = 2, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x4000, .layer = 3, .phase = 0, .valid = true, .phi_score = 100}, - } - try std.testing.expect(config = HoloMuxConfig{.phi_optimized = false, .priority_select = false, .layer_frozen = true, .default_input = 2}); - try std.testing.expect(output = holo_mux_select(inputs, 1, config)); - try std.testing.expect(output.data == 0x3000); - try std.testing.expect(output.selected_layer == 2); - try std.testing.expect(output.frozen == true); + }; + const config = HoloMuxConfig{.phi_optimized = false, .priority_select = false, .layer_frozen = true, .default_input = 2}; + const output = holo_mux_select(inputs, 1, config); + assert(output.data == 0x3000); + assert(output.selected_layer == 2); + assert(output.frozen == true); } test "holo_mux_best_phi_optimized" { - given inputs = [_]HoloInput{ + const inputs = [_]HoloInput{ .{.data = 0x1000, .layer = 0, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x2000, .layer = 1, .phase = 0, .valid = true, .phi_score = 50}, .{.data = 0x3000, .layer = 2, .phase = 0, .valid = true, .phi_score = 200}, .{.data = 0x4000, .layer = 3, .phase = 0, .valid = true, .phi_score = 10}, - } - try std.testing.expect(config = HoloMuxConfig{.phi_optimized = true, .priority_select = false, .layer_frozen = false, .default_input = 0}); - try std.testing.expect(output = holo_mux_best(inputs, config)); - try std.testing.expect(output.selected_layer == 3 // Best phi score); + }; + const config = HoloMuxConfig{.phi_optimized = true, .priority_select = false, .layer_frozen = false, .default_input = 0}; + const output = holo_mux_best(inputs, config); + assert(output.selected_layer == 3); // Best phi score } test "holo_mux_valid_mask" { - given inputs = [_]HoloInput{ + const inputs = [_]HoloInput{ .{.data = 0x1000, .layer = 0, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x2000, .layer = 1, .phase = 0, .valid = false, .phi_score = 100}, .{.data = 0x3000, .layer = 2, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x4000, .layer = 3, .phase = 0, .valid = false, .phi_score = 100}, - } - try std.testing.expect(mask = holo_mux_valid(inputs)); - try std.testing.expect(mask == 0b00000101); + }; + const mask = holo_mux_valid(inputs); + assert(mask == 0b00000101); } test "holo_mux_count_valid" { - given inputs = [_]HoloInput{ + const inputs = [_]HoloInput{ .{.data = 0x1000, .layer = 0, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x2000, .layer = 1, .phase = 0, .valid = false, .phi_score = 100}, .{.data = 0x3000, .layer = 2, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x4000, .layer = 3, .phase = 0, .valid = false, .phi_score = 100}, - } - try std.testing.expect(holo_mux_count_valid(inputs) == 2); + }; + assert(holo_mux_count_valid(inputs) == 2); } test "holo_mux_any_valid_true" { - given inputs = [_]HoloInput{ + const inputs = [_]HoloInput{ .{.data = 0x1000, .layer = 0, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x2000, .layer = 1, .phase = 0, .valid = false, .phi_score = 100}, .{.data = 0x3000, .layer = 2, .phase = 0, .valid = false, .phi_score = 100}, .{.data = 0x4000, .layer = 3, .phase = 0, .valid = false, .phi_score = 100}, - } - try std.testing.expect(holo_mux_any_valid(inputs) == true); + }; + assert(holo_mux_any_valid(inputs) == true); } test "holo_mux_any_valid_false" { - given inputs = [_]HoloInput{ + const inputs = [_]HoloInput{ .{.data = 0x1000, .layer = 0, .phase = 0, .valid = false, .phi_score = 100}, .{.data = 0x2000, .layer = 1, .phase = 0, .valid = false, .phi_score = 100}, .{.data = 0x3000, .layer = 2, .phase = 0, .valid = false, .phi_score = 100}, .{.data = 0x4000, .layer = 3, .phase = 0, .valid = false, .phi_score = 100}, - } - try std.testing.expect(holo_mux_any_valid(inputs) == false); + }; + assert(holo_mux_any_valid(inputs) == false); } test "holo_mux_all_valid_true" { - given inputs = [_]HoloInput{ + const inputs = [_]HoloInput{ .{.data = 0x1000, .layer = 0, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x2000, .layer = 1, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x3000, .layer = 2, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x4000, .layer = 3, .phase = 0, .valid = true, .phi_score = 100}, - } - try std.testing.expect(holo_mux_all_valid(inputs) == true); + }; + assert(holo_mux_all_valid(inputs) == true); } test "holo_layer_is_north" { - try std.testing.expect(holo_layer_is_north(0) == true); - try std.testing.expect(holo_layer_is_north(1) == false); + assert(holo_layer_is_north(0) == true); + assert(holo_layer_is_north(1) == false); } test "holo_layer_is_south" { - try std.testing.expect(holo_layer_is_south(2) == true); - try std.testing.expect(holo_layer_is_south(0) == false); + assert(holo_layer_is_south(2) == true); + assert(holo_layer_is_south(0) == false); } test "holo_opposite_layer" { - try std.testing.expect(holo_opposite_layer(HOLO_LAYER_NORTH) == HOLO_LAYER_SOUTH); - try std.testing.expect(holo_opposite_layer(HOLO_LAYER_EAST) == HOLO_LAYER_WEST); + assert(holo_opposite_layer(HOLO_LAYER_NORTH) == HOLO_LAYER_SOUTH); + assert(holo_opposite_layer(HOLO_LAYER_EAST) == HOLO_LAYER_WEST); } test "holo_phase_90_deg" { - try std.testing.expect(holo_phase_90_deg(0) == 1); - try std.testing.expect(holo_phase_90_deg(1) == 2); - try std.testing.expect(holo_phase_90_deg(3) == 0); + assert(holo_phase_90_deg(0) == 1); + assert(holo_phase_90_deg(1) == 2); + assert(holo_phase_90_deg(3) == 0); } test "holo_phase_180_deg" { - try std.testing.expect(holo_phase_180_deg(0) == 2); - try std.testing.expect(holo_phase_180_deg(1) == 3); - try std.testing.expect(holo_phase_180_deg(2) == 0); + assert(holo_phase_180_deg(0) == 2); + assert(holo_phase_180_deg(1) == 3); + assert(holo_phase_180_deg(2) == 0); } test "holo_phase_opposite" { - try std.testing.expect(holo_phase_opposite(0) == 2); - try std.testing.expect(holo_phase_opposite(1) == 3); - try std.testing.expect(holo_phase_opposite(2) == 0); - try std.testing.expect(holo_phase_opposite(3) == 1); + assert(holo_phase_opposite(0) == 2); + assert(holo_phase_opposite(1) == 3); + assert(holo_phase_opposite(2) == 0); + assert(holo_phase_opposite(3) == 1); } test "encode_holo_mux_x4" { - given encoded = encode_holo_mux_x4(0x02, 0x01, true) - try std.testing.expect((encoded >> 8) == OP_HOLO_MUX_X4); + const encoded = encode_holo_mux_x4(0x02, 0x01, true); + assert((encoded >> 8) == OP_HOLO_MUX_X4); } test "decode_holo_mux_x4" { - given decoded = decode_holo_mux_x4(0xE6A8) - try std.testing.expect(decoded.layer == 0x02); - try std.testing.expect(decoded.phase == 0x01); - try std.testing.expect(decoded.frozen == true); + const decoded = decode_holo_mux_x4(0xE6A8); + assert(decoded.layer == 0x02); + assert(decoded.phase == 0x01); + assert(decoded.frozen == true); } test "opcode_constant" { - try std.testing.expect(OP_HOLO_MUX_X4 == 0xE6); + assert(OP_HOLO_MUX_X4 == 0xE6); } // ============================================================================ // Invariants // ============================================================================ -} invariant num_inputs_four assert NUM_INPUTS == 4 @@ -509,10 +513,10 @@ invariant select_bits_two assert SELECT_BITS == 2 invariant holo_layer_values - try std.testing.expect(HOLO_LAYER_NORTH >= 0 and HOLO_LAYER_WEST <= 3); + assert HOLO_LAYER_NORTH >= 0 and HOLO_LAYER_WEST <= 3 invariant holo_phase_values - try std.testing.expect(HOLO_PHASE_0 >= 0 and HOLO_PHASE_270 <= 3); + assert HOLO_PHASE_0 >= 0 and HOLO_PHASE_270 <= 3 invariant holo_valid_one assert HOLO_VALID == 1 @@ -538,9 +542,9 @@ invariant holo_mux_count_valid_bound invariant holo_mux_any_implies_count_positive given inputs = [_]HoloInput{.{.data = 0x1000, .layer = 0, .phase = 0, .valid = true, .phi_score = 100}} ** 4 - try std.testing.expect(any_valid = holo_mux_any_valid(inputs)); - try std.testing.expect(count = holo_mux_count_valid(inputs)); - assert not any_valid or count > 0 + and any_valid = holo_mux_any_valid(inputs) + and count = holo_mux_count_valid(inputs) + assert !any_valid or count > 0 invariant holo_mux_all_valid_equals_count given inputs = [_]HoloInput{.{.data = 0x1000, .layer = 0, .phase = 0, .valid = true, .phi_score = 100}} ** 4 @@ -553,8 +557,8 @@ invariant holo_mux_valid_mask_bits .{.data = 0x3000, .layer = 2, .phase = 0, .valid = true, .phi_score = 100}, .{.data = 0x4000, .layer = 3, .phase = 0, .valid = false, .phi_score = 100}, } - try std.testing.expect(mask = holo_mux_valid(inputs)); - try std.testing.expect(mask < (@as(u8, 1) << NUM_INPUTS)); + and mask = holo_mux_valid(inputs) + assert mask < (@as(u8, 1) << NUM_INPUTS) // ============================================================================ // Benchmarks diff --git a/specs/fpga/int4.t27 b/specs/fpga/int4.t27 index 6d4cab5..1a51ef8 100644 --- a/specs/fpga/int4.t27 +++ b/specs/fpga/int4.t27 @@ -29,9 +29,12 @@ module Int4 { fn encode(value: i8) -> Int4 { const clamped = if (value > 7) { 7 } else if (value < -8) { -8 } else { value }; // Two's complement: negative values are stored as 2^4 + value - let raw = clamped as u4; + // t27 has no `as u4` cast form. This is a value-level approximation: raw is + // always 0..15 here, but no backend narrows (the Zig backend rejects the + // implicit i8 -> u4 assignment) until t27 gains a narrow-cast form. + var raw : u4 = clamped; if (clamped < 0) { - raw = (16 + clamped) as u4; + raw = 16 + clamped; } return Int4{ raw = raw }; } @@ -149,21 +152,37 @@ module Int4 { and decoded = decode(encoded) then decoded == original - test int4_encode_positive_values - for (vals) |vals| - then encode(vals[i]).raw == vals[i] for vals[i] in {0, 1, 2, 3, 4, 5, 6, 7} + test int4_encode_positive_values { + const vals : [8]i8 = [0, 1, 2, 3, 4, 5, 6, 7]; + for i in 0..8 { + const v = vals[i]; + assert(encode(v).raw == v); + } + } - test int4_decode_positive_values - for (vals) |vals| - then decode(Int4{ raw = vals[i] }) == vals[i] for vals[i] in {0, 1, 2, 3, 4, 5, 6, 7} + test int4_decode_positive_values { + const vals : [8]i8 = [0, 1, 2, 3, 4, 5, 6, 7]; + for i in 0..8 { + const v = vals[i]; + assert(decode(Int4{ raw = v }) == v); + } + } - test int4_encode_negative_values - given vals = [-1, -2, -3, -4, -5, -6, -7, -8] - then encode(vals[i]).raw == (16 + vals[i]) for vals[i] in vals + test int4_encode_negative_values { + const vals : [8]i8 = [-1, -2, -3, -4, -5, -6, -7, -8]; + for i in 0..8 { + const v = vals[i]; + assert(encode(v).raw == (16 + v)); + } + } - test int4_decode_negative_values - given enc = [15, 14, 13, 12, 11, 10, 9, 8] - then decode(Int4{ raw = enc[i] }) == enc[i] - 16 for enc[i] in enc + test int4_decode_negative_values { + const enc : [8]i8 = [15, 14, 13, 12, 11, 10, 9, 8]; + for i in 0..8 { + const e = enc[i]; + assert(decode(Int4{ raw = e }) == e - 16); + } + } test int4_bits_constant then BITS == 4 @@ -308,9 +327,15 @@ module Int4 { given x = 5 then decode(mul(encode(x), encode(-1))) == -x - invariant int4_abs_is_non_negative - for (vals) |vals| - then decode(abs(encode(vals[i]))) >= 0 for vals[i] in vals + invariant int4_abs_is_non_negative { + // The original quantified over `vals` without binding it; the domain is + // every Int4 value, min_value() .. max_value() (-8 .. 7, see section 1). + const vals : [16]i8 = [-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7]; + for i in 0..16 { + const v = vals[i]; + assert(decode(abs(encode(v))) >= 0); + } + } bench int4_encode_latency measure: nanoseconds to encode(5) diff --git a/specs/fpga/int8.t27 b/specs/fpga/int8.t27 index c8daff4..bb0baa4 100644 --- a/specs/fpga/int8.t27 +++ b/specs/fpga/int8.t27 @@ -156,11 +156,13 @@ module Int8 { // 9. Bitwise Operations - fn and(a: Int8, b: Int8) -> Int8 { + // `and` / `or` are t27 keywords and cannot name a fn; the two bitwise + // ops are spelled and_bits / or_bits (behaviour unchanged). + fn and_bits(a: Int8, b: Int8) -> Int8 { return Int8{ raw = a.raw & b.raw }; } - fn or(a: Int8, b: Int8) -> Int8 { + fn or_bits(a: Int8, b: Int8) -> Int8 { return Int8{ raw = a.raw | b.raw }; } @@ -198,21 +200,40 @@ module Int8 { and decoded = decode(encoded) then decoded == original - test int8_encode_positive_values - for (vals) |vals| - then encode(vals[i]).raw == vals[i] for vals[i] in {0, 1, 2, 50, 100, 127} + // Set-valued BDD clauses are written as typed arrays walked by index, + // so every backend runs a real loop over the listed values. + test int8_encode_positive_values { + const vals : [6]i32 = [0, 1, 2, 50, 100, 127]; + for (0..6) |i| { + const v = vals[i]; + assert encode(v).raw == v; + } + } - test int8_decode_positive_values - for (vals) |vals| - then decode(Int8{ raw = vals[i] }) == vals[i] for vals[i] in {0, 1, 2, 50, 100, 127} + test int8_decode_positive_values { + const vals : [6]u8 = [0, 1, 2, 50, 100, 127]; + for (0..6) |i| { + const v = vals[i]; + assert decode(Int8{ raw = v }) == v; + } + } - test int8_encode_negative_values - given vals = [-1, -2, -50, -100, -127, -128] - then encode(vals[i]).raw == (256 + vals[i]) for vals[i] in vals + test int8_encode_negative_values { + const vals : [6]i32 = [-1, -2, -50, -100, -127, -128]; + for (0..6) |i| { + const v = vals[i]; + assert encode(v).raw == (256 + v); + } + } - test int8_decode_negative_values - given enc = [255, 254, 206, 156, 129, 128] - then decode(Int8{ raw = enc[i] }) == enc[i] - 256 for enc[i] in enc + test int8_decode_negative_values { + const enc : [6]u8 = [255, 254, 206, 156, 129, 128]; + for (0..6) |i| { + const e = enc[i]; + // raw byte widened to i32 so that e - 256 is the signed value + assert decode(Int8{ raw = e }) == (e as i32) - 256; + } + } test int8_bits_constant then BITS == 8 @@ -354,13 +375,13 @@ module Int8 { test int8_and_operation given a = Int8{ raw = 0x55 } and b = Int8{ raw = 0xAA } - and result = and(a, b) + and result = and_bits(a, b) then result.raw == 0x00 test int8_or_operation given a = Int8{ raw = 0x55 } and b = Int8{ raw = 0xAA } - and result = or(a, b) + and result = or_bits(a, b) then result.raw == 0xFF test int8_xor_operation @@ -399,9 +420,11 @@ module Int8 { and encoded = encode(original) then decode(encoded) == -128 - test int8_all_values_encode_decode - for (i in 0..255) - then decode(encode(i - 128)) == (i - 128) + test int8_all_values_encode_decode { + for (i in 0..255) { + assert decode(encode(i - 128)) == (i - 128); + } + } invariant int8_bits_constant assert BITS == 8 @@ -428,40 +451,72 @@ module Int8 { given a = 50 and b = 30 then decode(add(encode(a), encode(b))) == decode(add(encode(b), encode(a))) - invariant int8_zero_add_identity - for (x in {0, 50, 100, 127}) - then decode(add(encode(x), encode(0))) == x + invariant int8_zero_add_identity { + const xs : [4]i32 = [0, 50, 100, 127]; + for (0..4) |k| { + const x = xs[k]; + assert decode(add(encode(x), encode(0))) == x; + } + } - invariant int8_sub_self_is_zero - for (x in {0, 50, 100, 127}) - then decode(sub(encode(x), encode(x))) == 0 + invariant int8_sub_self_is_zero { + const xs : [4]i32 = [0, 50, 100, 127]; + for (0..4) |k| { + const x = xs[k]; + assert decode(sub(encode(x), encode(x))) == 0; + } + } - invariant int8_mul_by_neg_one_is_neg - for (x in {0, 50, 100, 127}) - then decode(mul(encode(x), encode(-1))) == -x + invariant int8_mul_by_neg_one_is_neg { + const xs : [4]i32 = [0, 50, 100, 127]; + for (0..4) |k| { + const x = xs[k]; + assert decode(mul(encode(x), encode(-1))) == -x; + } + } - invariant int8_mul_by_zero_is_zero - for (x in {0, 50, 100, 127}) - then decode(mul(encode(x), encode(0))) == 0 + invariant int8_mul_by_zero_is_zero { + const xs : [4]i32 = [0, 50, 100, 127]; + for (0..4) |k| { + const x = xs[k]; + assert decode(mul(encode(x), encode(0))) == 0; + } + } - invariant int8_mul_by_one_is_identity - for (x in {0, 50, 100, 127}) - then decode(mul(encode(x), encode(1))) == x + invariant int8_mul_by_one_is_identity { + const xs : [4]i32 = [0, 50, 100, 127]; + for (0..4) |k| { + const x = xs[k]; + assert decode(mul(encode(x), encode(1))) == x; + } + } - invariant int8_neg_neg_is_identity - for (x in {0, 50, 100, 127}) - then decode(neg(neg(encode(x)))) == x + invariant int8_neg_neg_is_identity { + const xs : [4]i32 = [0, 50, 100, 127]; + for (0..4) |k| { + const x = xs[k]; + assert decode(neg(neg(encode(x)))) == x; + } + } - invariant int8_abs_is_non_negative - for (x in {-128..127}) - then decode(abs(encode(x))) >= 0 + invariant int8_abs_is_non_negative { + // {-128..127} is every Int8 value; t27 ranges exclude the end, + // so the bound is written 128 to keep x = 127 in the check. + for (x in -128..128) { + assert decode(abs(encode(x))) >= 0; + } + } invariant int8_abs_preserves_zero assert decode(abs(Int8{raw = 0})) == 0 - invariant int8_shl_zero_is_zero - for (shift in {0, 1, 7}) - then shl(Int8{raw = 1}, shift).raw == 1 << shift + invariant int8_shl_zero_is_zero { + const shifts : [3]u8 = [0, 1, 7]; + for (0..3) |k| { + const shift = shifts[k]; + assert shl(Int8{raw = 1}, shift).raw == 1 << shift; + } + } invariant int8_shr_by_max_is_zero_or_neg_one given i = Int8{ raw = 1 } diff --git a/specs/fpga/lane_l_precheck.t27 b/specs/fpga/lane_l_precheck.t27 index f5462d9..fcaf552 100644 --- a/specs/fpga/lane_l_precheck.t27 +++ b/specs/fpga/lane_l_precheck.t27 @@ -36,7 +36,9 @@ pub const LaneStatus = enum(u8) { error = LANE_ERROR, } -pub const PrecheckFlags = packed struct(u8) { +// Backing integer u8: t27 has no `packed struct(u8)` spelling; the four +// u1 fields plus the u4 field are exactly 8 bits. +pub const PrecheckFlags = packed struct { lut_enabled : u1, lane_valid : u1, address_valid : u1, @@ -137,7 +139,7 @@ pub fn precheck_lane(lane_id: u8, lut_addr: u8, config: LaneConfig) PrecheckResu // Precheck all lanes simultaneously pub fn precheck_all_lanes(lane_bits: u8, lut_addr: u8, configs: [LANE_COUNT]LaneConfig) [LANE_COUNT]PrecheckResult { var results : [LANE_COUNT]PrecheckResult = undefined; - for (0..LANE_COUNT) |i| { + for i in 0..LANE_COUNT { if ((lane_bits >> i) & 1 != 0) { results[i] = precheck_lane(@as(u8, @intCast(i)), lut_addr, configs[i]); } else { @@ -168,7 +170,7 @@ pub fn precheck_fail(result: PrecheckResult) bool { // precheck_any_pass(results: [LANE_COUNT]PrecheckResult) -> bool // Check if any lane precheck passed pub fn precheck_any_pass(results: [LANE_COUNT]PrecheckResult) bool { - for (results) |result| { + for result in results { if (precheck_pass(result)) { return true; } @@ -179,7 +181,7 @@ pub fn precheck_any_pass(results: [LANE_COUNT]PrecheckResult) bool { // precheck_all_pass(results: [LANE_COUNT]PrecheckResult) -> bool // Check if all lane prechecks passed pub fn precheck_all_pass(results: [LANE_COUNT]PrecheckResult) bool { - for (results) |result| { + for result in results { if (precheck_fail(result)) { return false; } @@ -191,7 +193,7 @@ pub fn precheck_all_pass(results: [LANE_COUNT]PrecheckResult) bool { // Count number of lanes that passed precheck pub fn precheck_count_passed(results: [LANE_COUNT]PrecheckResult) u8 { var count : u8 = 0; - for (results) |result| { + for result in results { if (precheck_pass(result)) { count += 1; } @@ -203,7 +205,8 @@ pub fn precheck_count_passed(results: [LANE_COUNT]PrecheckResult) u8 { // Get bitmask of ready lanes pub fn precheck_get_ready_lanes(results: [LANE_COUNT]PrecheckResult) -> u8 { var mask : u8 = 0; - for (results, 0..) |result, i| { + for i in 0..LANE_COUNT { + const result = results[i]; if (precheck_pass(result)) { mask |= (@as(u8, 1) << i); } @@ -221,7 +224,7 @@ pub fn lut_address_valid(addr: u8, config: LaneConfig) bool { if (addr >= LUT_DEPTH) { return false; } - if (not config.enabled) { + if (!config.enabled) { return false; } return (addr & config.lut_mask) < config.lut_mask; @@ -269,161 +272,160 @@ pub fn decode_lut_lookup(encoded: u16) struct { lane_bits: u8, lut_addr: u8 } { // ============================================================================ test "lane_is_valid_true" { - try std.testing.expect(lane_is_valid(0) == true); - try std.testing.expect(lane_is_valid(7) == true); + assert(lane_is_valid(0) == true); + assert(lane_is_valid(7) == true); } test "lane_is_valid_false" { - try std.testing.expect(lane_is_valid(8) == false); - try std.testing.expect(lane_is_valid(255) == false); + assert(lane_is_valid(8) == false); + assert(lane_is_valid(255) == false); } test "lane_is_ready_true" { - try std.testing.expect(lane_is_ready(LaneStatus.ready) == true); + assert(lane_is_ready(LaneStatus.ready) == true); } test "lane_is_ready_false" { - try std.testing.expect(lane_is_ready(LaneStatus.idle) == false); - try std.testing.expect(lane_is_ready(LaneStatus.busy) == false); - try std.testing.expect(lane_is_ready(LaneStatus.error) == false); + assert(lane_is_ready(LaneStatus.idle) == false); + assert(lane_is_ready(LaneStatus.busy) == false); + assert(lane_is_ready(LaneStatus.error) == false); } test "lane_is_busy_true" { - try std.testing.expect(lane_is_busy(LaneStatus.busy) == true); + assert(lane_is_busy(LaneStatus.busy) == true); } test "lane_is_error_true" { - try std.testing.expect(lane_is_error(LaneStatus.error) == true); + assert(lane_is_error(LaneStatus.error) == true); } test "precheck_lane_pass" { - given config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0} - try std.testing.expect(result = precheck_lane(0, 128, config)); - try std.testing.expect(precheck_pass(result) == true); - try std.testing.expect(result.error_code == 0); + const config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}; + const result = precheck_lane(0, 128, config); + assert(precheck_pass(result) == true); + assert(result.error_code == 0); } test "precheck_lane_invalid_lane" { - given config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0} - try std.testing.expect(result = precheck_lane(8, 128, config)); - try std.testing.expect(precheck_fail(result) == true); - try std.testing.expect(result.error_code == 1); + const config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}; + const result = precheck_lane(8, 128, config); + assert(precheck_fail(result) == true); + assert(result.error_code == 1); } test "precheck_lane_invalid_address" { - given config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0} - try std.testing.expect(result = precheck_lane(0, 256, config)); - try std.testing.expect(precheck_fail(result) == true); - try std.testing.expect(result.error_code == 2); + const config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}; + const result = precheck_lane(0, 256, config); + assert(precheck_fail(result) == true); + assert(result.error_code == 2); } test "precheck_lane_permission_denied" { - given config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 0x0F, .priority = 0} - try std.testing.expect(result = precheck_lane(0, 0x80, config)); - try std.testing.expect(precheck_fail(result) == true); - try std.testing.expect(result.error_code == 3); + const config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 0x0F, .priority = 0}; + const result = precheck_lane(0, 0x80, config); + assert(precheck_fail(result) == true); + assert(result.error_code == 3); } test "precheck_lane_lut_disabled" { - given config = LaneConfig{.enabled = false, .lut_base = 0, .lut_mask = 255, .priority = 0} - try std.testing.expect(result = precheck_lane(0, 128, config)); - try std.testing.expect(precheck_fail(result) == true); - try std.testing.expect(result.error_code == 4); + const config = LaneConfig{.enabled = false, .lut_base = 0, .lut_mask = 255, .priority = 0}; + const result = precheck_lane(0, 128, config); + assert(precheck_fail(result) == true); + assert(result.error_code == 4); } test "precheck_any_pass_true" { - given configs = [_]LaneConfig{ + const configs = [_]LaneConfig{ .{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}, .{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}, - } - try std.testing.expect(results = precheck_all_lanes(0b00000011, 128, configs)); - try std.testing.expect(precheck_any_pass(results) == true); + }; + const results = precheck_all_lanes(0b00000011, 128, configs); + assert(precheck_any_pass(results) == true); } test "precheck_any_pass_false" { - given configs = [_]LaneConfig{ + const configs = [_]LaneConfig{ .{.enabled = false, .lut_base = 0, .lut_mask = 255, .priority = 0}, .{.enabled = false, .lut_base = 0, .lut_mask = 255, .priority = 0}, - } - try std.testing.expect(results = precheck_all_lanes(0b00000011, 128, configs)); - try std.testing.expect(precheck_any_pass(results) == false); + }; + const results = precheck_all_lanes(0b00000011, 128, configs); + assert(precheck_any_pass(results) == false); } test "precheck_all_pass_true" { - given configs = [_]LaneConfig{ + const configs = [_]LaneConfig{ .{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}, .{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}, - } - try std.testing.expect(results = precheck_all_lanes(0b00000011, 128, configs)); - try std.testing.expect(precheck_all_pass(results) == true); + }; + const results = precheck_all_lanes(0b00000011, 128, configs); + assert(precheck_all_pass(results) == true); } test "precheck_count_passed" { - given configs = [_]LaneConfig{ + const configs = [_]LaneConfig{ .{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}, .{.enabled = false, .lut_base = 0, .lut_mask = 255, .priority = 0}, .{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}, - } - try std.testing.expect(results = precheck_all_lanes(0b00000111, 128, configs)); - try std.testing.expect(precheck_count_passed(results) == 2); + }; + const results = precheck_all_lanes(0b00000111, 128, configs); + assert(precheck_count_passed(results) == 2); } test "precheck_get_ready_lanes" { - given configs = [_]LaneConfig{ + const configs = [_]LaneConfig{ .{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}, .{.enabled = false, .lut_base = 0, .lut_mask = 255, .priority = 0}, .{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}, - } - try std.testing.expect(results = precheck_all_lanes(0b00000111, 128, configs)); - try std.testing.expect(precheck_get_ready_lanes(results) == 0b00000101); + }; + const results = precheck_all_lanes(0b00000111, 128, configs); + assert(precheck_get_ready_lanes(results) == 0b00000101); } test "lut_address_valid_true" { - given config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0} - try std.testing.expect(lut_address_valid(128, config) == true); + const config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}; + assert(lut_address_valid(128, config) == true); } test "lut_address_valid_disabled" { - given config = LaneConfig{.enabled = false, .lut_base = 0, .lut_mask = 255, .priority = 0} - try std.testing.expect(lut_address_valid(128, config) == false); + const config = LaneConfig{.enabled = false, .lut_base = 0, .lut_mask = 255, .priority = 0}; + assert(lut_address_valid(128, config) == false); } test "lut_address_valid_masked" { - given config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 0x0F, .priority = 0} - try std.testing.expect(lut_address_valid(0x08, config) == true); - try std.testing.expect(lut_address_valid(0x80, config) == false); + const config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 0x0F, .priority = 0}; + assert(lut_address_valid(0x08, config) == true); + assert(lut_address_valid(0x80, config) == false); } test "lut_address_masked_value" { - given config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 0x0F, .priority = 0} - try std.testing.expect(lut_address_masked(0xAB, config) == 0x0B); + const config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 0x0F, .priority = 0}; + assert(lut_address_masked(0xAB, config) == 0x0B); } test "lut_address_offset" { - try std.testing.expect(lut_address_offset(20, 10) == 10); - try std.testing.expect(lut_address_offset(5, 10) == 0); + assert(lut_address_offset(20, 10) == 10); + assert(lut_address_offset(5, 10) == 0); } test "encode_lut_lookup" { - given encoded = encode_lut_lookup(0b00000101, 0x10) - try std.testing.expect((encoded >> 8) == OP_LUT_LOOKUP); + const encoded = encode_lut_lookup(0b00000101, 0x10); + assert((encoded >> 8) == OP_LUT_LOOKUP); } test "decode_lut_lookup" { - given decoded = decode_lut_lookup(0xDF50) - try std.testing.expect(decoded.lane_bits == 0b00000010); - try std.testing.expect(decoded.lut_addr == 0x10); + const decoded = decode_lut_lookup(0xDF50); + assert(decoded.lane_bits == 0b00000010); + assert(decoded.lut_addr == 0x10); } test "opcode_constant" { - try std.testing.expect(OP_LUT_LOOKUP == 0xDF); + assert(OP_LUT_LOOKUP == 0xDF); } // ============================================================================ // Invariants // ============================================================================ -} invariant lane_count_eight assert LANE_COUNT == 8 @@ -445,32 +447,35 @@ invariant check_fail_zero invariant lane_valid_range assert lane_is_valid(0) == true and lane_is_valid(7) == true and lane_is_valid(8) == false -invariant precheck_pass_and_fail_opposite - given config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0} - try std.testing.expect(result = precheck_lane(0, 128, config)); - assert precheck_pass(result) != precheck_fail(result) +invariant precheck_pass_and_fail_opposite { + const config = LaneConfig{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}; + const result = precheck_lane(0, 128, config); + assert(precheck_pass(result) != precheck_fail(result)); +} invariant ready_lane_not_busy - try std.testing.expect(lane_is_ready(LaneStatus.ready) != lane_is_busy(LaneStatus.ready)); + assert lane_is_ready(LaneStatus.ready) != lane_is_busy(LaneStatus.ready) invariant error_lane_not_ready - try std.testing.expect(lane_is_error(LaneStatus.error) != lane_is_ready(LaneStatus.error)); + assert lane_is_error(LaneStatus.error) != lane_is_ready(LaneStatus.error) -invariant precheck_count_bound - given configs = [_]LaneConfig{ +invariant precheck_count_bound { + const configs = [_]LaneConfig{ .{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}, .{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}, - } - try std.testing.expect(results = precheck_all_lanes(0xFF, 128, configs)); - assert precheck_count_passed(results) <= LANE_COUNT + }; + const results = precheck_all_lanes(0xFF, 128, configs); + assert(precheck_count_passed(results) <= LANE_COUNT); +} -invariant ready_mask_bound - given configs = [_]LaneConfig{ +invariant ready_mask_bound { + const configs = [_]LaneConfig{ .{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}, .{.enabled = true, .lut_base = 0, .lut_mask = 255, .priority = 0}, - } - try std.testing.expect(results = precheck_all_lanes(0xFF, 128, configs)); - try std.testing.expect(precheck_get_ready_lanes(results) < (@as(u8, 1) << LANE_COUNT)); + }; + const results = precheck_all_lanes(0xFF, 128, configs); + assert(precheck_get_ready_lanes(results) < (@as(u8, 1) << LANE_COUNT)); +} // ============================================================================ // Benchmarks diff --git a/specs/fpga/lut_npu_81_entry.t27 b/specs/fpga/lut_npu_81_entry.t27 index 9aa2002..8807822 100644 --- a/specs/fpga/lut_npu_81_entry.t27 +++ b/specs/fpga/lut_npu_81_entry.t27 @@ -93,8 +93,11 @@ pub fn npu_transform_9x9(grid: [9][9]i8) Transform9x9 { var phi_score : u16 = 0; // Count zeros and compute phi score - for (grid, 0..) |row, i| { - for (row, 0..) |val, j| { + // Zig `for (grid, 0..) |row, i|` written as index ranges over the 9x9 grid + for i in 0..9 { + const row = grid[i]; + for j in 0..9 { + const val = row[j]; if (val == 0) { zero_count += 1; } @@ -133,7 +136,7 @@ pub fn transform_phi_optimized(transform: Transform9x9) bool { // lut_lookup_base(lut: [LUT_SIZE]LutEntry, addr: u8) -> LutEntry // Base LUT lookup pub fn lut_lookup_base(lut: [LUT_SIZE]LutEntry, addr: u8) LutEntry { - if (not lut_entry_address_valid(addr)) { + if (!lut_entry_address_valid(addr)) { return LutEntry{.address = 255, .value = 0, .valid = false, .phi_related = false}; } return lut[@as(u8, @intCast(addr))]; @@ -142,7 +145,7 @@ pub fn lut_lookup_base(lut: [LUT_SIZE]LutEntry, addr: u8) LutEntry { // lut_lookup_phi(lut: [LUT_SIZE]LutEntry, addr: u8) -> LutEntry // Phi-optimized LUT lookup pub fn lut_lookup_phi(lut: [LUT_SIZE]LutEntry, addr: u8) LutEntry { - if (not lut_entry_address_valid(addr)) { + if (!lut_entry_address_valid(addr)) { return LutEntry{.address = 255, .value = 0, .valid = false, .phi_related = false}; } @@ -152,7 +155,7 @@ pub fn lut_lookup_phi(lut: [LUT_SIZE]LutEntry, addr: u8) LutEntry { } // Fallback: search for nearest phi-related entry - for (0..LUT_SIZE) |i| { + for i in 0..LUT_SIZE { const e = lut[i]; if (e.valid and e.phi_related) { return e; @@ -167,7 +170,7 @@ pub fn lut_lookup_phi(lut: [LUT_SIZE]LutEntry, addr: u8) LutEntry { pub fn lut_lookup_range(lut: [LUT_SIZE]LutEntry, start_addr: u8, count: u8) [LUT_SIZE]LutEntry { var result : [LUT_SIZE]LutEntry = undefined; - for (0..LUT_SIZE) |i| { + for i in 0..LUT_SIZE { if (i < count and lut_entry_address_valid(start_addr + i)) { result[i] = lut[@as(u8, @intCast(start_addr + i))]; } else { @@ -199,16 +202,17 @@ pub fn decode_lut_npu(encoded: u16) struct { op: NpuOperation, addr: u8 } { const addr : u8 = @as(u8, @truncate(encoded & 0x1F)); var op : NpuOperation = undefined; - switch (opcode_val) { - 0 => op = NpuOperation.lookup, - 1 => op = NpuOperation.transform, - 2 => op = NpuOperation.phi_project, - 3 => op = NpuOperation.sparse_reduce, - 4 => op = NpuOperation.quantize, - 5 => op = NpuOperation.dequantize, - 6 => op = NpuOperation.composite, - else => op = NpuOperation.custom, - } + // switch arms are expressions in t27: the arm value is assigned to op + op = switch (opcode_val) { + 0 => NpuOperation.lookup, + 1 => NpuOperation.transform, + 2 => NpuOperation.phi_project, + 3 => NpuOperation.sparse_reduce, + 4 => NpuOperation.quantize, + 5 => NpuOperation.dequantize, + 6 => NpuOperation.composite, + else => NpuOperation.custom, + }; return .{ .op = op, .addr = addr }; } @@ -218,48 +222,48 @@ pub fn decode_lut_npu(encoded: u16) struct { op: NpuOperation, addr: u8 } { // ============================================================================ test "lut_size_eighty_one" { - try std.testing.expect(LUT_SIZE == 81); + assert(LUT_SIZE == 81); } test "lut_entry_address_valid_true" { - try std.testing.expect(lut_entry_address_valid(0) == true); - try std.testing.expect(lut_entry_address_valid(80) == true); + assert(lut_entry_address_valid(0) == true); + assert(lut_entry_address_valid(80) == true); } test "lut_entry_address_valid_false" { - try std.testing.expect(lut_entry_address_valid(81) == false); - try std.testing.expect(lut_entry_address_valid(255) == false); + assert(lut_entry_address_valid(81) == false); + assert(lut_entry_address_valid(255) == false); } test "lut_entry_valid_true" { - given entry = LutEntry{.address = 40, .value = 0x1234, .valid = true, .phi_related = false} - try std.testing.expect(lut_entry_valid(entry) == true); + const entry = LutEntry{.address = 40, .value = 0x1234, .valid = true, .phi_related = false}; + assert(lut_entry_valid(entry) == true); } test "lut_entry_valid_false_invalid_addr" { - given entry = LutEntry{.address = 255, .value = 0x1234, .valid = true, .phi_related = false} - try std.testing.expect(lut_entry_valid(entry) == false); + const entry = LutEntry{.address = 255, .value = 0x1234, .valid = true, .phi_related = false}; + assert(lut_entry_valid(entry) == false); } test "lut_entry_valid_false_invalid_flag" { - given entry = LutEntry{.address = 40, .value = 0x1234, .valid = false, .phi_related = false} - try std.testing.expect(lut_entry_valid(entry) == false); + const entry = LutEntry{.address = 40, .value = 0x1234, .valid = false, .phi_related = false}; + assert(lut_entry_valid(entry) == false); } test "create_lut_entry_valid" { - given entry = create_lut_entry(40, 0x1234, true) - try std.testing.expect(entry.valid == true); - try std.testing.expect(entry.phi_related == true); - try std.testing.expect(entry.value == 0x1234); + const entry = create_lut_entry(40, 0x1234, true); + assert(entry.valid == true); + assert(entry.phi_related == true); + assert(entry.value == 0x1234); } test "create_lut_entry_invalid" { - given entry = create_lut_entry(81, 0x1234, true) - try std.testing.expect(entry.valid == false); + const entry = create_lut_entry(81, 0x1234, true); + assert(entry.valid == false); } test "npu_transform_9x9_count" { - given grid = [_][9]i8{ + const grid = [_][9]i8{ [_]i8{0} ** 9, [_]i8{0} ** 9, [_]i8{0} ** 9, @@ -269,13 +273,13 @@ test "npu_transform_9x9_count" { [_]i8{0} ** 9, [_]i8{0} ** 9, [_]i8{0} ** 9, - } - try std.testing.expect(transform = npu_transform_9x9(grid)); - try std.testing.expect(transform.sparsity == 88); + }; + const transform = npu_transform_9x9(grid); + assert(transform.sparsity == 88); } test "transform_is_sparse_true" { - given grid = [_][9]i8{ + const grid = [_][9]i8{ [_]i8{0} ** 9, [_]i8{0} ** 9, [_]i8{0} ** 9, @@ -285,19 +289,19 @@ test "transform_is_sparse_true" { [_]i8{0} ** 9, [_]i8{0} ** 9, [_]i8{0} ** 9, - } - try std.testing.expect(transform = npu_transform_9x9(grid)); - try std.testing.expect(transform_is_sparse(transform) == true); + }; + const transform = npu_transform_9x9(grid); + assert(transform_is_sparse(transform) == true); } test "transform_is_sparse_false" { - given grid = [_][9]i8{[_]i8{1} ** 9} ** 9} - try std.testing.expect(transform = npu_transform_9x9(grid)); - try std.testing.expect(transform_is_sparse(transform) == false); + const grid = [_][9]i8{[_]i8{1} ** 9} ** 9; + const transform = npu_transform_9x9(grid); + assert(transform_is_sparse(transform) == false); } test "transform_phi_optimized_true" { - given grid = [_][9]i8{ + const grid = [_][9]i8{ [_]i8{1} ** 9, [_]i8{1} ** 9, [_]i8{1} ** 9, @@ -307,50 +311,49 @@ test "transform_phi_optimized_true" { [_]i8{1} ** 9, [_]i8{1} ** 9, [_]i8{1} ** 9, - } - try std.testing.expect(transform = npu_transform_9x9(grid)); - try std.testing.expect(transform_phi_optimized(transform) == true); + }; + const transform = npu_transform_9x9(grid); + assert(transform_phi_optimized(transform) == true); } test "transform_phi_optimized_false" { - given grid = [_][9]i8{[_]i8{1} ** 9} ** 9} - try std.testing.expect(transform = npu_transform_9x9(grid)); - try std.testing.expect(transform_phi_optimized(transform) == false); + const grid = [_][9]i8{[_]i8{1} ** 9} ** 9; + const transform = npu_transform_9x9(grid); + assert(transform_phi_optimized(transform) == false); } test "lut_lookup_base_valid" { - given lut = [_]LutEntry{.{.address = 40, .value = 0x1234, .valid = true, .phi_related = false}} ** 81 - try std.testing.expect(entry = lut_lookup_base(lut, 40)); - try std.testing.expect(entry.value == 0x1234); - try std.testing.expect(entry.valid == true); + const lut = [_]LutEntry{.{.address = 40, .value = 0x1234, .valid = true, .phi_related = false}} ** 81; + const entry = lut_lookup_base(lut, 40); + assert(entry.value == 0x1234); + assert(entry.valid == true); } test "lut_lookup_base_invalid_addr" { - given lut = [_]LutEntry{.{.address = 40, .value = 0x1234, .valid = true, .phi_related = false}} ** 81 - try std.testing.expect(entry = lut_lookup_base(lut, 81)); - try std.testing.expect(entry.valid == false); + const lut = [_]LutEntry{.{.address = 40, .value = 0x1234, .valid = true, .phi_related = false}} ** 81; + const entry = lut_lookup_base(lut, 81); + assert(entry.valid == false); } test "encode_lut_npu" { - given encoded = encode_lut_npu(NpuOperation.phi_project, 0x10) - try std.testing.expect((encoded >> 8) == OP_LUT_NPU); + const encoded = encode_lut_npu(NpuOperation.phi_project, 0x10); + assert((encoded >> 8) == OP_LUT_NPU); } test "decode_lut_npu" { - given decoded = decode_lut_npu(0xE350) - try std.testing.expect(decoded.op == NpuOperation.phi_project); - try std.testing.expect(decoded.addr == 0x10); + const decoded = decode_lut_npu(0xE350); + assert(decoded.op == NpuOperation.phi_project); + assert(decoded.addr == 0x10); } test "opcode_constant" { - try std.testing.expect(OP_LUT_NPU == 0xE3); + assert(OP_LUT_NPU == 0xE3); } // ============================================================================ // Invariants // ============================================================================ -} invariant lut_size_eighty_one assert LUT_SIZE == 81 @@ -376,23 +379,23 @@ invariant lut_address_bound assert lut_entry_address_valid(80) == true and lut_entry_address_valid(81) == false invariant transform_sparsity_bound - given grid = [_][9]i8{[_]i8{1} ** 9} ** 9} - try std.testing.expect(transform = npu_transform_9x9(grid)); - try std.testing.expect(transform.sparsity <= 100); + given grid = [_][9]i8{[_]i8{1} ** 9} ** 9 + when transform = npu_transform_9x9(grid) + assert transform.sparsity <= 100; invariant transform_sparsity_dense - given grid = [_][9]i8{[_]i8{1} ** 9} ** 9} - try std.testing.expect(transform = npu_transform_9x9(grid)); - try std.testing.expect(transform.sparsity == 0); + given grid = [_][9]i8{[_]i8{1} ** 9} ** 9 + when transform = npu_transform_9x9(grid) + assert transform.sparsity == 0; invariant phi_score_non_negative - given grid = [_][9]i8{[_]i8{1} ** 9} ** 9} - try std.testing.expect(transform = npu_transform_9x9(grid)); - try std.testing.expect(transform.phi_score >= 0); + given grid = [_][9]i8{[_]i8{1} ** 9} ** 9 + when transform = npu_transform_9x9(grid) + assert transform.phi_score >= 0; invariant npu_operation_enum_values - try std.testing.expect(@intFromEnum(NpuOperation.lookup) == 0); - try std.testing.expect(@intFromEnum(NpuOperation.custom) == 7); + assert @intFromEnum(NpuOperation.lookup) == 0; + assert @intFromEnum(NpuOperation.custom) == 7; // ============================================================================ // Benchmarks diff --git a/specs/fpga/nf4.t27 b/specs/fpga/nf4.t27 index 7d67c80..2e783e5 100644 --- a/specs/fpga/nf4.t27 +++ b/specs/fpga/nf4.t27 @@ -96,7 +96,7 @@ module NF4 { // 7. Helper Functions fn abs(x: f32) -> f32 { - if (x < 0.0) { -x } else { x }; + if (x < 0.0) { return -x; } else { return x; } } fn quantization_error_pct(value: f32) -> f32 { @@ -207,9 +207,11 @@ module NF4 { given valid = validate_format() then valid == true - test nf4_all_levels_encode_decode - for (i in 0..15) - then abs(decode(NF4{ raw = i }) - (i as f64) / 15.0) < 0.01 + test nf4_all_levels_encode_decode { + for (i in 0..15) { + assert abs(decode(NF4{ raw = i }) - (i as f64) / 15.0) < 0.01; + } + } test nf4_quantization_error_small_mid_range given value = 0.5 @@ -270,9 +272,11 @@ module NF4 { invariant nf4_decode_max_is_one assert decode(NF4{ raw = 15 }) == 1.0 - invariant nf4_all_values_in_range - for (i in 0..15) - then decode(NF4{ raw = i }) >= 0.0 and decode(NF4{ raw = i }) <= 1.0 + invariant nf4_all_values_in_range { + for (i in 0..15) { + assert decode(NF4{ raw = i }) >= 0.0 and decode(NF4{ raw = i }) <= 1.0; + } + } invariant nf4_epsilon_is_step_size given val = decode(NF4{ raw = 1 }) @@ -283,13 +287,17 @@ module NF4 { given x1 = 0.3 and x2 = 0.6 then encode(x1).raw <= encode(x2).raw - invariant nf4_decode_monotonic - for (i in 0..14) - then decode(NF4{ raw = i }) <= decode(NF4{ raw = i + 1 }) + invariant nf4_decode_monotonic { + for (i in 0..14) { + assert decode(NF4{ raw = i }) <= decode(NF4{ raw = i + 1 }); + } + } - invariant nf4_quantization_error_bounds - for (i in 0..15) - then quantization_error(0.0, NF4{ raw = 0 }) == 0.0 + invariant nf4_quantization_error_bounds { + for (i in 0..15) { + assert quantization_error(0.0, NF4{ raw = 0 }) == 0.0; + } + } invariant nf4_symmetric_quantization given x = 0.5 diff --git a/specs/fpga/null_pe.t27 b/specs/fpga/null_pe.t27 index f5fcb0f..b1eb9d6 100644 --- a/specs/fpga/null_pe.t27 +++ b/specs/fpga/null_pe.t27 @@ -104,7 +104,7 @@ pub fn pe_set_state(status: PeStatus, state: PeState) PeStatus { // pe_config_enabled(config: PeConfig) -> bool // Check if PE config enables operation pub fn pe_config_enabled(config: PeConfig) -> bool { - return config.enabled and not config.bypass_enabled; + return config.enabled and !config.bypass_enabled; } // pe_is_null(config: PeConfig) -> bool @@ -129,7 +129,8 @@ pub fn null_pe_skip(input: u16, pe_mask: u8, configs: [PE_COUNT]PeConfig) -> Nul var skip_count : u8 = 0; var output_data : u16 = input; - for (configs, 0..) |config, i| { + for (0..PE_COUNT) |i| { // was `for (configs, 0..) |config, i|`; configs has PE_COUNT entries + const config = configs[i]; if (((pe_mask >> i) & 1) != 0 and pe_is_null(config)) { skip_count += 1; } @@ -148,7 +149,8 @@ pub fn null_pe_skip(input: u16, pe_mask: u8, configs: [PE_COUNT]PeConfig) -> Nul pub fn null_pe_zero(input: u16, pe_mask: u8, configs: [PE_COUNT]PeConfig) -> NullPeResult { var skip_count : u8 = 0; - for (configs, 0..) |config, i| { + for (0..PE_COUNT) |i| { // was `for (configs, 0..) |config, i|`; configs has PE_COUNT entries + const config = configs[i]; if (((pe_mask >> i) & 1) != 0 and pe_is_null(config)) { skip_count += 1; } @@ -167,7 +169,8 @@ pub fn null_pe_zero(input: u16, pe_mask: u8, configs: [PE_COUNT]PeConfig) -> Nul pub fn null_pe_identity(input: u16, pe_mask: u8, configs: [PE_COUNT]PeConfig) -> NullPeResult { var active_count : u8 = 0; - for (configs, 0..) |config, i| { + for (0..PE_COUNT) |i| { // was `for (configs, 0..) |config, i|`; configs has PE_COUNT entries + const config = configs[i]; if (((pe_mask >> i) & 1) != 0 and pe_is_identity(config)) { active_count += 1; } @@ -187,31 +190,23 @@ pub fn null_pe_execute(input: u16, pe_mask: u8, configs: [PE_COUNT]PeConfig) -> var mode : u8 = NULL_MODE_SKIP; // Determine primary mode from active PEs - for (configs, 0..) |config, i| { + for (0..PE_COUNT) |i| { // was `for (configs, 0..) |config, i|`; configs has PE_COUNT entries + const config = configs[i]; if (((pe_mask >> i) & 1) != 0 and config.enabled) { mode = config.mode; break; } } - switch (mode) { - NULL_MODE_SKIP => { - return null_pe_skip(input, pe_mask, configs); - }, - NULL_MODE_ZERO => { - return null_pe_zero(input, pe_mask, configs); - }, - NULL_MODE_IDENTITY => { - return null_pe_identity(input, pe_mask, configs); - }, - NULL_MODE_CUSTOM => { - // Custom: return zero for null PEs - return null_pe_zero(input, pe_mask, configs); - }, - else => { - return null_pe_skip(input, pe_mask, configs); - }, - } + // t27 switch arms are expressions, so the per-arm `{ return X; }` blocks become `return switch` + return switch (mode) { + NULL_MODE_SKIP => null_pe_skip(input, pe_mask, configs), + NULL_MODE_ZERO => null_pe_zero(input, pe_mask, configs), + NULL_MODE_IDENTITY => null_pe_identity(input, pe_mask, configs), + // Custom: return zero for null PEs + NULL_MODE_CUSTOM => null_pe_zero(input, pe_mask, configs), + else => null_pe_skip(input, pe_mask, configs), + }; } // ============================================================================ @@ -253,7 +248,7 @@ pub fn pe_array_enable(pe_array: PeArray, pe_mask: u8) -> PeArray { pub fn pe_array_count_active(pe_array: PeArray) -> u8 { var count : u8 = 0; for (pe_array.configs) |config| { - if (config.enabled and not config.bypass_enabled) { + if (config.enabled and !config.bypass_enabled) { count += 1; } } @@ -276,7 +271,8 @@ pub fn pe_array_count_null(pe_array: PeArray) -> u8 { // Get bitmask of null PEs pub fn pe_array_get_null_mask(pe_array: PeArray) -> u8 { var mask : u8 = 0; - for (pe_array.configs, 0..) |config, i| { + for (0..PE_COUNT) |i| { // was `for (pe_array.configs, 0..) |config, i|`; pe_array.configs has PE_COUNT entries + const config = pe_array.configs[i]; if (pe_is_null(config)) { mask |= (@as(u8, 1) << i); } @@ -311,172 +307,171 @@ pub fn decode_null_pe(encoded: u16) -> struct { pe_mask: u8, mode: u8 } { // ============================================================================ test "pe_count_four" { - try std.testing.expect(PE_COUNT == 4); + assert(PE_COUNT == 4); } test "data_width_sixteen" { - try std.testing.expect(DATA_WIDTH == 16); + assert(DATA_WIDTH == 16); } test "null_mode_constants" { - try std.testing.expect(NULL_MODE_SKIP == 0); - try std.testing.expect(NULL_MODE_ZERO == 1); - try std.testing.expect(NULL_MODE_IDENTITY == 2); - try std.testing.expect(NULL_MODE_CUSTOM == 3); + assert(NULL_MODE_SKIP == 0); + assert(NULL_MODE_ZERO == 1); + assert(NULL_MODE_IDENTITY == 2); + assert(NULL_MODE_CUSTOM == 3); } test "pe_state_constants" { - try std.testing.expect(PE_STATE_IDLE == 0); - try std.testing.expect(PE_STATE_ACTIVE == 1); - try std.testing.expect(PE_STATE_WAITING == 2); - try std.testing.expect(PE_STATE_ERROR == 3); + assert(PE_STATE_IDLE == 0); + assert(PE_STATE_ACTIVE == 1); + assert(PE_STATE_WAITING == 2); + assert(PE_STATE_ERROR == 3); } test "pe_is_active_true" { - given status = PeStatus{.state = PeState.active, .cycle_count = 10, .op_count = 5} - try std.testing.expect(pe_is_active(status) == true); + const status = PeStatus{.state = PeState.active, .cycle_count = 10, .op_count = 5}; + assert(pe_is_active(status) == true); } test "pe_is_active_false" { - given status = PeStatus{.state = PeState.idle, .cycle_count = 0, .op_count = 0} - try std.testing.expect(pe_is_active(status) == false); + const status = PeStatus{.state = PeState.idle, .cycle_count = 0, .op_count = 0}; + assert(pe_is_active(status) == false); } test "pe_is_idle_true" { - given status = PeStatus{.state = PeState.idle, .cycle_count = 0, .op_count = 0} - try std.testing.expect(pe_is_idle(status) == true); + const status = PeStatus{.state = PeState.idle, .cycle_count = 0, .op_count = 0}; + assert(pe_is_idle(status) == true); } test "pe_set_state_increments" { - given status = PeStatus{.state = PeState.idle, .cycle_count = 10, .op_count = 5} - try std.testing.expect(result = pe_set_state(status, PeState.active)); - try std.testing.expect(result.cycle_count == 11); - try std.testing.expect(result.op_count == 6); + const status = PeStatus{.state = PeState.idle, .cycle_count = 10, .op_count = 5}; + const result = pe_set_state(status, PeState.active); + assert(result.cycle_count == 11); + assert(result.op_count == 6); } test "pe_config_enabled_true" { - given config = PeConfig{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false} - try std.testing.expect(pe_config_enabled(config) == true); + const config = PeConfig{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false}; + assert(pe_config_enabled(config) == true); } test "pe_config_enabled_disabled" { - given config = PeConfig{.mode = NULL_MODE_SKIP, .enabled = false, .bypass_enabled = false} - try std.testing.expect(pe_config_enabled(config) == false); + const config = PeConfig{.mode = NULL_MODE_SKIP, .enabled = false, .bypass_enabled = false}; + assert(pe_config_enabled(config) == false); } test "pe_config_enabled_bypass" { - given config = PeConfig{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = true} - try std.testing.expect(pe_config_enabled(config) == false); + const config = PeConfig{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = true}; + assert(pe_config_enabled(config) == false); } test "pe_is_null_skip" { - try std.testing.expect(pe_is_null(.{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false}) == true); - try std.testing.expect(pe_is_null(.{.mode = NULL_MODE_ZERO, .enabled = true, .bypass_enabled = false}) == true); + assert(pe_is_null(.{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false}) == true); + assert(pe_is_null(.{.mode = NULL_MODE_ZERO, .enabled = true, .bypass_enabled = false}) == true); } test "pe_is_null_not" { - try std.testing.expect(pe_is_null(.{.mode = NULL_MODE_IDENTITY, .enabled = true, .bypass_enabled = false}) == false); + assert(pe_is_null(.{.mode = NULL_MODE_IDENTITY, .enabled = true, .bypass_enabled = false}) == false); } test "null_pe_skip_some" { - given configs = [_]PeConfig{ + const configs = [_]PeConfig{ .{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false}, .{.mode = NULL_MODE_IDENTITY, .enabled = true, .bypass_enabled = false}, .{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false}, .{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false}, - } - try std.testing.expect(result = null_pe_skip(0x1234, 0b1010, configs)); - try std.testing.expect(result.skip_count == 3); + }; + const result = null_pe_skip(0x1234, 0b1010, configs); + assert(result.skip_count == 3); } test "null_pe_zero_always_zero" { - given configs = [_]PeConfig{.{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false}} ** 4 - try std.testing.expect(result = null_pe_zero(0x1234, 0b1111, configs)); - try std.testing.expect(result.output_data == 0); - try std.testing.expect(result.valid == true); + const configs = [_]PeConfig{.{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false}} ** 4; + const result = null_pe_zero(0x1234, 0b1111, configs); + assert(result.output_data == 0); + assert(result.valid == true); } test "null_pe_identity_pass" { - given configs = [_]PeConfig{.{.mode = NULL_MODE_IDENTITY, .enabled = true, .bypass_enabled = false}} ** 4 - try std.testing.expect(result = null_pe_identity(0x1234, 0b1111, configs)); - try std.testing.expect(result.output_data == 0x1234); + const configs = [_]PeConfig{.{.mode = NULL_MODE_IDENTITY, .enabled = true, .bypass_enabled = false}} ** 4; + const result = null_pe_identity(0x1234, 0b1111, configs); + assert(result.output_data == 0x1234); } test "null_pe_execute_skip" { - given configs = [_]PeConfig{.{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false}} ** 4 - try std.testing.expect(result = null_pe_execute(0x1234, 0b1111, configs)); - try std.testing.expect(result.output_data == 0x1234); + const configs = [_]PeConfig{.{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false}} ** 4; + const result = null_pe_execute(0x1234, 0b1111, configs); + assert(result.output_data == 0x1234); } test "null_pe_execute_zero" { - given configs = [_]PeConfig{.{.mode = NULL_MODE_ZERO, .enabled = true, .bypass_enabled = false}} ** 4 - try std.testing.expect(result = null_pe_execute(0x1234, 0b1111, configs)); - try std.testing.expect(result.output_data == 0); + const configs = [_]PeConfig{.{.mode = NULL_MODE_ZERO, .enabled = true, .bypass_enabled = false}} ** 4; + const result = null_pe_execute(0x1234, 0b1111, configs); + assert(result.output_data == 0); } test "pe_array_init" { - given array = pe_array_init() - try std.testing.expect(pe_array_count_active(array) == 0); - try std.testing.expect(pe_array_count_null(array) == 0); + const array = pe_array_init(); + assert(pe_array_count_active(array) == 0); + assert(pe_array_count_null(array) == 0); } test "pe_array_enable" { - given array = pe_array_init() - try std.testing.expect(result = pe_array_enable(array, 0b1010)); - try std.testing.expect(result.configs[0].enabled == false); - try std.testing.expect(result.configs[1].enabled == true); - try std.testing.expect(result.configs[2].enabled == false); - try std.testing.expect(result.configs[3].enabled == true); + const array = pe_array_init(); + const result = pe_array_enable(array, 0b1010); + assert(result.configs[0].enabled == false); + assert(result.configs[1].enabled == true); + assert(result.configs[2].enabled == false); + assert(result.configs[3].enabled == true); } test "pe_array_count_active" { - given array = pe_array_enable(pe_array_init(), 0b1111) - try std.testing.expect(pe_array_count_active(array) == 4); + const array = pe_array_enable(pe_array_init(), 0b1111); + assert(pe_array_count_active(array) == 4); } test "pe_array_count_null" { - given configs = [_]PeConfig{ + const configs = [_]PeConfig{ .{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false}, .{.mode = NULL_MODE_ZERO, .enabled = true, .bypass_enabled = false}, .{.mode = NULL_MODE_SKIP, .enabled = false, .bypass_enabled = false}, .{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false}, - } - try std.testing.expect(array = PeArray{.configs = configs, .statuses = [_]PeStatus{.state = PeState.idle, .cycle_count = 0, .op_count = 0} ** 4}); - try std.testing.expect(pe_array_count_null(array) == 2); + }; + const array = PeArray{.configs = configs, .statuses = [_]PeStatus{.{.state = PeState.idle, .cycle_count = 0, .op_count = 0}} ** 4}; + assert(pe_array_count_null(array) == 2); } test "pe_array_get_null_mask" { - given configs = [_]PeConfig{ + const configs = [_]PeConfig{ .{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false}, .{.mode = NULL_MODE_ZERO, .enabled = true, .bypass_enabled = false}, .{.mode = NULL_MODE_SKIP, .enabled = false, .bypass_enabled = false}, .{.mode = NULL_MODE_IDENTITY, .enabled = true, .bypass_enabled = false}, - } - try std.testing.expect(array = PeArray{.configs = configs, .statuses = [_]PeStatus{.state = PeState.idle, .cycle_count = 0, .op_count = 0} ** 4}); - try std.testing.expect(mask = pe_array_get_null_mask(array)); - try std.testing.expect(mask == 0b1011); + }; + const array = PeArray{.configs = configs, .statuses = [_]PeStatus{.{.state = PeState.idle, .cycle_count = 0, .op_count = 0}} ** 4}; + const mask = pe_array_get_null_mask(array); + assert(mask == 0b1011); } test "encode_null_pe" { - given encoded = encode_null_pe(0b1010, 1) - try std.testing.expect((encoded >> 8) == OP_NULL_PE); + const encoded = encode_null_pe(0b1010, 1); + assert((encoded >> 8) == OP_NULL_PE); } test "decode_null_pe" { - given decoded = decode_null_pe(0xEA5A) - try std.testing.expect(decoded.pe_mask == 0b1010); - try std.testing.expect(decoded.mode == 1); + const decoded = decode_null_pe(0xEA5A); + assert(decoded.pe_mask == 0b1010); + assert(decoded.mode == 1); } test "opcode_constant" { - try std.testing.expect(OP_NULL_PE == 0xEA); + assert(OP_NULL_PE == 0xEA); } // ============================================================================ // Invariants // ============================================================================ -} invariant pe_count_four assert PE_COUNT == 4 @@ -484,52 +479,52 @@ invariant data_width_sixteen assert DATA_WIDTH == 16 invariant null_mode_values - try std.testing.expect(NULL_MODE_SKIP >= 0 and NULL_MODE_CUSTOM <= 3); + assert NULL_MODE_SKIP >= 0 and NULL_MODE_CUSTOM <= 3 invariant pe_state_values - try std.testing.expect(PE_STATE_IDLE >= 0 and PE_STATE_ERROR <= 3); + assert PE_STATE_IDLE >= 0 and PE_STATE_ERROR <= 3 invariant pe_set_state_increments given status = PeStatus{.state = PeState.idle, .cycle_count = 0, .op_count = 0} - try std.testing.expect(result = pe_set_state(status, PeState.active)); - try std.testing.expect(result.cycle_count == status.cycle_count + 1); - try std.testing.expect(result.op_count == status.op_count + 1); + and result = pe_set_state(status, PeState.active) + assert result.cycle_count == status.cycle_count + 1 + assert result.op_count == status.op_count + 1 invariant pe_set_state_preserves_when_idle given status = PeStatus{.state = PeState.active, .cycle_count = 10, .op_count = 5} - try std.testing.expect(result = pe_set_state(status, PeState.idle)); - try std.testing.expect(result.cycle_count == status.cycle_count); - try std.testing.expect(result.op_count == status.op_count); + and result = pe_set_state(status, PeState.idle) + assert result.cycle_count == status.cycle_count + assert result.op_count == status.op_count invariant null_pe_skip_valid given configs = [_]PeConfig{.{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false}} ** 4 - try std.testing.expect(null_pe_skip(0x1234, 0, configs).valid == false); - try std.testing.expect(null_pe_skip(0x1234, 0b1111, configs).skip_count == 4); + assert null_pe_skip(0x1234, 0, configs).valid == false + assert null_pe_skip(0x1234, 0b1111, configs).skip_count == 4 invariant null_pe_zero_always_valid given configs = [_]PeConfig{.{.mode = NULL_MODE_ZERO, .enabled = true, .bypass_enabled = false}} ** 4 - try std.testing.expect(null_pe_zero(0x1234, 0, configs).valid == true); + assert null_pe_zero(0x1234, 0, configs).valid == true invariant null_pe_zero_output given configs = [_]PeConfig{.{.mode = NULL_MODE_ZERO, .enabled = true, .bypass_enabled = false}} ** 4 - try std.testing.expect(null_pe_zero(0x1234, 0b1111, configs).output_data == 0); + assert null_pe_zero(0x1234, 0b1111, configs).output_data == 0 invariant null_pe_identity_preserves given configs = [_]PeConfig{.{.mode = NULL_MODE_IDENTITY, .enabled = true, .bypass_enabled = false}} ** 4 - try std.testing.expect(null_pe_identity(0x1234, 0, configs).output_data == 0x1234); + assert null_pe_identity(0x1234, 0, configs).output_data == 0x1234 invariant pe_array_count_bounds given array = pe_array_enable(pe_array_init(), 0xFF) - try std.testing.expect(pe_array_count_active(array) <= PE_COUNT); - try std.testing.expect(pe_array_count_null(array) <= PE_COUNT); + assert pe_array_count_active(array) <= PE_COUNT + assert pe_array_count_null(array) <= PE_COUNT invariant pe_array_get_null_mask_bound - try std.testing.expect(pe_array_get_null_mask(pe_array_init()) < (@as(u8, 1) << PE_COUNT)); + assert pe_array_get_null_mask(pe_array_init()) < (@as(u8, 1) << PE_COUNT) invariant pe_array_count_all given configs = [_]PeConfig{.{.mode = NULL_MODE_SKIP, .enabled = true, .bypass_enabled = false}} ** 4 - try std.testing.expect(array = PeArray{.configs = configs, .statuses = [_]PeStatus{.state = PeState.idle, .cycle_count = 0, .op_count = 0} ** 4}); - try std.testing.expect(pe_array_count_active(array) + pe_array_count_null(array) == PE_COUNT); + and array = PeArray{.configs = configs, .statuses = [_]PeStatus{.{.state = PeState.idle, .cycle_count = 0, .op_count = 0}} ** 4} + assert pe_array_count_active(array) + pe_array_count_null(array) == PE_COUNT // ============================================================================ // Benchmarks diff --git a/specs/fpga/posit16.t27 b/specs/fpga/posit16.t27 index d868ba6..ddf137d 100644 --- a/specs/fpga/posit16.t27 +++ b/specs/fpga/posit16.t27 @@ -59,7 +59,7 @@ pub fn posit16_extract_regime(pos: Posit16) i8 { var regime_run : i8 = 0; var first_bit : u16 = (remaining_bits >> (NBITS - 1)) & 1; - for (0..NBITS-1) |i| { + for i in 0..NBITS - 1 { const bit = (remaining_bits >> (NBITS - 1 - i)) & 1; if (bit == first_bit) { regime_run += 1; @@ -81,7 +81,7 @@ pub fn posit16_extract_exponent(pos: Posit16) i8 { var regime_run : u8 = 0; var first_bit : u16 = (remaining_bits >> (NBITS - 1)) & 1; - for (0..NBITS-1) |i| { + for i in 0..NBITS - 1 { const bit = (remaining_bits >> (NBITS - 1 - i)) & 1; if (bit == first_bit) { regime_run += 1; @@ -108,7 +108,7 @@ pub fn posit16_extract_fraction(pos: Posit16) u16 { var regime_run : u8 = 0; var first_bit : u16 = (remaining_bits >> (NBITS - 1)) & 1; - for (0..NBITS-1) |i| { + for i in 0..NBITS - 1 { const bit = (remaining_bits >> (NBITS - 1 - i)) & 1; if (bit == first_bit) { regime_run += 1; @@ -184,7 +184,7 @@ pub fn posit16_is_special(pos: Posit16) bool { // posit16_is_finite(pos: Posit16) -> bool // Check if posit is finite (not NaR) pub fn posit16_is_finite(pos: Posit16) bool { - return not posit16_is_nar(pos); + return !posit16_is_nar(pos); } // ============================================================================ @@ -248,7 +248,7 @@ pub fn posit16_encode_f32(value: f32) Posit16 { var frac_val = remaining - 1.0; // Remove implicit 1 if (fraction_bits > 0) { - for (0..fraction_bits) |i| { + for i in 0..fraction_bits { frac_val *= 2.0; if (frac_val >= 1.0) { fraction |= (@as(u16, 1) << (fraction_bits - 1 - i)); @@ -276,7 +276,7 @@ pub fn posit16_encode_f32(value: f32) Posit16 { const regime_start = SIGN_SHIFT - 1 - regime_bits_remaining; if (k >= 0) { // k+1 ones followed by zero (if space permits) - for (0..@as(u8, @intCast(k + 1))) |i| { + for i in 0..@as(u8, @intCast(k + 1)) { if (regime_start - i >= 0) { result |= (@as(u16, 1) << (regime_start - i)); } @@ -452,7 +452,7 @@ pub fn posit16_is_greater(a: Posit16, b: Posit16) bool { const sign_a = posit16_extract_sign(a); const sign_b = posit16_extract_sign(b); if (sign_a != sign_b) { - return not sign_a; // Positive > negative + return !sign_a; // Positive > negative } if (sign_a) { // Both negative, compare magnitudes (inverse) @@ -550,8 +550,11 @@ pub fn posit16_to_f32_scaled(value: Posit16, scale: f32) f32 { // Dot product of two posit arrays pub fn posit16_dot_product(a: []const Posit16, b: []const Posit16) Posit16 { var sum: f32 = 0.0; - for (a, 0..) |val_a, i| { - if (i >= b.len) break; + for i in 0..a.len { + const val_a = a[i]; + if (i >= b.len) { + break; + } const fa = posit16_decode_f32(val_a); const fb = posit16_decode_f32(b[i]); sum += fa * fb; @@ -563,7 +566,7 @@ pub fn posit16_dot_product(a: []const Posit16, b: []const Posit16) Posit16 { // Sum all elements of a vector pub fn posit16_vector_sum(vec: []const Posit16) Posit16 { var sum: f32 = 0.0; - for (vec) |val| { + for val in vec { sum += posit16_decode_f32(val); } return posit16_encode_f32(sum); @@ -584,285 +587,284 @@ pub fn posit16_vector_mean(vec: []const Posit16) Posit16 { // ============================================================================ test "posit16_is_zero_true" { - try std.testing.expect(posit16_is_zero(POS16_ZERO) == true); + assert(posit16_is_zero(POS16_ZERO) == true); } test "posit16_is_zero_false" { - try std.testing.expect(posit16_is_zero(0x0001) == false); + assert(posit16_is_zero(0x0001) == false); } test "posit16_is_nar_true" { - try std.testing.expect(posit16_is_nar(POS16_NAR) == true); + assert(posit16_is_nar(POS16_NAR) == true); } test "posit16_is_nar_false" { - try std.testing.expect(posit16_is_nar(POS16_ZERO) == false); + assert(posit16_is_nar(POS16_ZERO) == false); } test "posit16_is_special_zero" { - try std.testing.expect(posit16_is_special(POS16_ZERO) == true); + assert(posit16_is_special(POS16_ZERO) == true); } test "posit16_is_special_nar" { - try std.testing.expect(posit16_is_special(POS16_NAR) == true); + assert(posit16_is_special(POS16_NAR) == true); } test "posit16_is_special_normal" { - try std.testing.expect(posit16_is_special(0x4000) == false); + assert(posit16_is_special(0x4000) == false); } test "posit16_extract_sign_positive" { - given value = 0x4000 - try std.testing.expect(sign = posit16_extract_sign(value)); - try std.testing.expect(sign == false); + const value = 0x4000; + const sign = posit16_extract_sign(value); + assert(sign == false); } test "posit16_extract_sign_negative" { - given value = 0xC000 - try std.testing.expect(sign = posit16_extract_sign(value)); - try std.testing.expect(sign == true); + const value = 0xC000; + const sign = posit16_extract_sign(value); + assert(sign == true); } test "posit16_encode_f32_zero" { - given pos = posit16_encode_f32(0.0) - try std.testing.expect(pos == POS16_ZERO); + const pos = posit16_encode_f32(0.0); + assert(pos == POS16_ZERO); } test "posit16_encode_f32_one" { - given pos = posit16_encode_f32(1.0) - try std.testing.expect(decoded = posit16_decode_f32(pos)); - try std.testing.expect(abs(decoded - 1.0) < 0.1); + const pos = posit16_encode_f32(1.0); + const decoded = posit16_decode_f32(pos); + assert(abs(decoded - 1.0) < 0.1); } test "posit16_encode_f32_negative_one" { - given pos = posit16_encode_f32(-1.0) - try std.testing.expect(decoded = posit16_decode_f32(pos)); - try std.testing.expect(abs(decoded + 1.0) < 0.1); + const pos = posit16_encode_f32(-1.0); + const decoded = posit16_decode_f32(pos); + assert(abs(decoded + 1.0) < 0.1); } test "posit16_encode_f32_ten" { - given pos = posit16_encode_f32(10.0) - try std.testing.expect(decoded = posit16_decode_f32(pos)); - try std.testing.expect(abs(decoded - 10.0) < 2.0); + const pos = posit16_encode_f32(10.0); + const decoded = posit16_decode_f32(pos); + assert(abs(decoded - 10.0) < 2.0); } test "posit16_encode_f32_roundtrip_positive" { - given original = 1.5 - try std.testing.expect(pos = posit16_encode_f32(original)); - try std.testing.expect(decoded = posit16_decode_f32(pos)); - try std.testing.expect(abs(decoded - original) < 0.3); + const original = 1.5; + const pos = posit16_encode_f32(original); + const decoded = posit16_decode_f32(pos); + assert(abs(decoded - original) < 0.3); } test "posit16_encode_f32_roundtrip_negative" { - given original = -1.5 - try std.testing.expect(pos = posit16_encode_f32(original)); - try std.testing.expect(decoded = posit16_decode_f32(pos)); - try std.testing.expect(abs(decoded - original) < 0.3); + const original = -1.5; + const pos = posit16_encode_f32(original); + const decoded = posit16_decode_f32(pos); + assert(abs(decoded - original) < 0.3); } test "posit16_decode_f32_zero" { - try std.testing.expect(posit16_decode_f32(POS16_ZERO) == 0.0); + assert(posit16_decode_f32(POS16_ZERO) == 0.0); } test "posit16_decode_f32_nar" { - try std.testing.expect(std.math.isNan(posit16_decode_f32(POS16_NAR)) == true); + assert(std.math.isNan(posit16_decode_f32(POS16_NAR)) == true); } test "posit16_add_simple" { - given a = posit16_encode_f32(10.0) - try std.testing.expect(b = posit16_encode_f32(20.0)); - try std.testing.expect(result = posit16_add(a, b)); - try std.testing.expect(decoded = posit16_decode_f32(result)); - try std.testing.expect(abs(decoded - 30.0) < 5.0); + const a = posit16_encode_f32(10.0); + const b = posit16_encode_f32(20.0); + const result = posit16_add(a, b); + const decoded = posit16_decode_f32(result); + assert(abs(decoded - 30.0) < 5.0); } test "posit16_sub_simple" { - given a = posit16_encode_f32(50.0) - try std.testing.expect(b = posit16_encode_f32(30.0)); - try std.testing.expect(result = posit16_sub(a, b)); - try std.testing.expect(decoded = posit16_decode_f32(result)); - try std.testing.expect(abs(decoded - 20.0) < 5.0); + const a = posit16_encode_f32(50.0); + const b = posit16_encode_f32(30.0); + const result = posit16_sub(a, b); + const decoded = posit16_decode_f32(result); + assert(abs(decoded - 20.0) < 5.0); } test "posit16_mul_simple" { - given a = posit16_encode_f32(10.0) - try std.testing.expect(b = posit16_encode_f32(10.0)); - try std.testing.expect(result = posit16_mul(a, b)); - try std.testing.expect(decoded = posit16_decode_f32(result)); - try std.testing.expect(abs(decoded - 100.0) < 20.0); + const a = posit16_encode_f32(10.0); + const b = posit16_encode_f32(10.0); + const result = posit16_mul(a, b); + const decoded = posit16_decode_f32(result); + assert(abs(decoded - 100.0) < 20.0); } test "posit16_div_simple" { - given a = posit16_encode_f32(100.0) - try std.testing.expect(b = posit16_encode_f32(10.0)); - try std.testing.expect(result = posit16_div(a, b)); - try std.testing.expect(decoded = posit16_decode_f32(result)); - try std.testing.expect(abs(decoded - 10.0) < 3.0); + const a = posit16_encode_f32(100.0); + const b = posit16_encode_f32(10.0); + const result = posit16_div(a, b); + const decoded = posit16_decode_f32(result); + assert(abs(decoded - 10.0) < 3.0); } test "posit16_sqrt_four" { - given value = posit16_encode_f32(4.0) - try std.testing.expect(result = posit16_sqrt(value)); - try std.testing.expect(decoded = posit16_decode_f32(result)); - try std.testing.expect(abs(decoded - 2.0) < 0.3); + const value = posit16_encode_f32(4.0); + const result = posit16_sqrt(value); + const decoded = posit16_decode_f32(result); + assert(abs(decoded - 2.0) < 0.3); } test "posit16_sqrt_negative" { - given value = posit16_encode_f32(-4.0) - try std.testing.expect(result = posit16_sqrt(value)); - try std.testing.expect(posit16_is_nar(result) == true); + const value = posit16_encode_f32(-4.0); + const result = posit16_sqrt(value); + assert(posit16_is_nar(result) == true); } test "posit16_abs_positive" { - given value = posit16_encode_f32(50.0) - try std.testing.expect(result = posit16_abs(value)); - try std.testing.expect(posit16_is_equal(result, value) == true); + const value = posit16_encode_f32(50.0); + const result = posit16_abs(value); + assert(posit16_is_equal(result, value) == true); } test "posit16_abs_negative" { - given value = posit16_encode_f32(-50.0) - try std.testing.expect(abs_val = posit16_abs(value)); - try std.testing.expect(posit16_extract_sign(abs_val) == false); + const value = posit16_encode_f32(-50.0); + const abs_val = posit16_abs(value); + assert(posit16_extract_sign(abs_val) == false); } test "posit16_neg_positive" { - given value = posit16_encode_f32(50.0) - try std.testing.expect(neg_val = posit16_neg(value)); - try std.testing.expect(posit16_extract_sign(neg_val) == true); + const value = posit16_encode_f32(50.0); + const neg_val = posit16_neg(value); + assert(posit16_extract_sign(neg_val) == true); } test "posit16_neg_negative" { - given value = posit16_encode_f32(-50.0) - try std.testing.expect(neg_val = posit16_neg(value)); - try std.testing.expect(posit16_extract_sign(neg_val) == false); + const value = posit16_encode_f32(-50.0); + const neg_val = posit16_neg(value); + assert(posit16_extract_sign(neg_val) == false); } test "posit16_is_equal_true" { - given value = posit16_encode_f32(10.0) - try std.testing.expect(posit16_is_equal(value, value) == true); + const value = posit16_encode_f32(10.0); + assert(posit16_is_equal(value, value) == true); } test "posit16_is_equal_false" { - given a = posit16_encode_f32(10.0) - try std.testing.expect(b = posit16_encode_f32(20.0)); - try std.testing.expect(posit16_is_equal(a, b) == false); + const a = posit16_encode_f32(10.0); + const b = posit16_encode_f32(20.0); + assert(posit16_is_equal(a, b) == false); } test "posit16_is_equal_nar" { - try std.testing.expect(posit16_is_equal(POS16_NAR, POS16_NAR) == false); + assert(posit16_is_equal(POS16_NAR, POS16_NAR) == false); } test "posit16_is_greater_positive" { - given a = posit16_encode_f32(50.0) - try std.testing.expect(b = posit16_encode_f32(30.0)); - try std.testing.expect(posit16_is_greater(a, b) == true); + const a = posit16_encode_f32(50.0); + const b = posit16_encode_f32(30.0); + assert(posit16_is_greater(a, b) == true); } test "posit16_max_returns_larger" { - given a = posit16_encode_f32(30.0) - try std.testing.expect(b = posit16_encode_f32(50.0)); - try std.testing.expect(result = posit16_max(a, b)); - try std.testing.expect(decoded = posit16_decode_f32(result)); - try std.testing.expect(decoded >= 35.0); + const a = posit16_encode_f32(30.0); + const b = posit16_encode_f32(50.0); + const result = posit16_max(a, b); + const decoded = posit16_decode_f32(result); + assert(decoded >= 35.0); } test "posit16_min_returns_smaller" { - given a = posit16_encode_f32(30.0) - try std.testing.expect(b = posit16_encode_f32(50.0)); - try std.testing.expect(result = posit16_min(a, b)); - try std.testing.expect(decoded = posit16_decode_f32(result)); - try std.testing.expect(decoded <= 45.0); + const a = posit16_encode_f32(30.0); + const b = posit16_encode_f32(50.0); + const result = posit16_min(a, b); + const decoded = posit16_decode_f32(result); + assert(decoded <= 45.0); } test "posit16_relu_positive" { - given value = posit16_encode_f32(50.0) - try std.testing.expect(result = posit16_relu(value)); - try std.testing.expect(posit16_is_equal(result, value) == true); + const value = posit16_encode_f32(50.0); + const result = posit16_relu(value); + assert(posit16_is_equal(result, value) == true); } test "posit16_relu_negative" { - given value = posit16_encode_f32(-50.0) - try std.testing.expect(result = posit16_relu(value)); - try std.testing.expect(result == POS16_ZERO); + const value = posit16_encode_f32(-50.0); + const result = posit16_relu(value); + assert(result == POS16_ZERO); } test "posit16_sigmoid_zero" { - given value = POS16_ZERO - try std.testing.expect(result = posit16_sigmoid(value)); - try std.testing.expect(decoded = posit16_decode_f32(result)); - try std.testing.expect(abs(decoded - 0.5) < 0.1); + const value = POS16_ZERO; + const result = posit16_sigmoid(value); + const decoded = posit16_decode_f32(result); + assert(abs(decoded - 0.5) < 0.1); } test "posit16_sigmoid_positive_large" { - given value = posit16_encode_f32(10.0) - try std.testing.expect(result = posit16_sigmoid(value)); - try std.testing.expect(decoded = posit16_decode_f32(result)); - try std.testing.expect(decoded >= 0.9); + const value = posit16_encode_f32(10.0); + const result = posit16_sigmoid(value); + const decoded = posit16_decode_f32(result); + assert(decoded >= 0.9); } test "posit16_quantize_to_int4_max" { - given value = posit16_encode_f32(100.0) - try std.testing.expect(result = posit16_quantize_to_int4(value)); - try std.testing.expect(result == 7); + const value = posit16_encode_f32(100.0); + const result = posit16_quantize_to_int4(value); + assert(result == 7); } test "posit16_quantize_to_int4_min" { - given value = posit16_encode_f32(-100.0) - try std.testing.expect(result = posit16_quantize_to_int4(value)); - try std.testing.expect(result == -8); + const value = posit16_encode_f32(-100.0); + const result = posit16_quantize_to_int4(value); + assert(result == -8); } test "posit16_from_f32_scaled_up" { - given value = 1.0 - try std.testing.expect(scale = 100.0); - try std.testing.expect(result = posit16_from_f32_scaled(value, scale)); - try std.testing.expect(decoded = posit16_decode_f32(result)); - try std.testing.expect(abs(decoded - 100.0) < 20.0); + const value = 1.0; + const scale = 100.0; + const result = posit16_from_f32_scaled(value, scale); + const decoded = posit16_decode_f32(result); + assert(abs(decoded - 100.0) < 20.0); } test "posit16_dot_product_simple" { - given a = [_]Posit16{posit16_encode_f32(1.0), posit16_encode_f32(2.0), posit16_encode_f32(3.0), posit16_encode_f32(4.0)} - try std.testing.expect(b = [_]Posit16{posit16_encode_f32(2.0), posit16_encode_f32(2.0), posit16_encode_f32(2.0), posit16_encode_f32(2.0)}); - try std.testing.expect(result = posit16_dot_product(a, b)); - try std.testing.expect(decoded = posit16_decode_f32(result)); - try std.testing.expect(abs(decoded - 20.0) < 5.0); + const a = [_]Posit16{posit16_encode_f32(1.0), posit16_encode_f32(2.0), posit16_encode_f32(3.0), posit16_encode_f32(4.0)}; + const b = [_]Posit16{posit16_encode_f32(2.0), posit16_encode_f32(2.0), posit16_encode_f32(2.0), posit16_encode_f32(2.0)}; + const result = posit16_dot_product(a, b); + const decoded = posit16_decode_f32(result); + assert(abs(decoded - 20.0) < 5.0); } test "posit16_vector_sum_simple" { - given vec = [_]Posit16{posit16_encode_f32(1.0), posit16_encode_f32(2.0), posit16_encode_f32(3.0), posit16_encode_f32(4.0)} - try std.testing.expect(result = posit16_vector_sum(vec)); - try std.testing.expect(decoded = posit16_decode_f32(result)); - try std.testing.expect(abs(decoded - 10.0) < 3.0); + const vec = [_]Posit16{posit16_encode_f32(1.0), posit16_encode_f32(2.0), posit16_encode_f32(3.0), posit16_encode_f32(4.0)}; + const result = posit16_vector_sum(vec); + const decoded = posit16_decode_f32(result); + assert(abs(decoded - 10.0) < 3.0); } test "posit16_vector_mean_simple" { - given vec = [_]Posit16{posit16_encode_f32(2.0), posit16_encode_f32(4.0), posit16_encode_f32(6.0), posit16_encode_f32(8.0)} - try std.testing.expect(result = posit16_vector_mean(vec)); - try std.testing.expect(decoded = posit16_decode_f32(result)); - try std.testing.expect(abs(decoded - 5.0) < 1.0); + const vec = [_]Posit16{posit16_encode_f32(2.0), posit16_encode_f32(4.0), posit16_encode_f32(6.0), posit16_encode_f32(8.0)}; + const result = posit16_vector_mean(vec); + const decoded = posit16_decode_f32(result); + assert(abs(decoded - 5.0) < 1.0); } test "posit16_lerp_zero" { - given a = posit16_encode_f32(10.0) - try std.testing.expect(b = posit16_encode_f32(50.0)); - try std.testing.expect(t = 0.0); - try std.testing.expect(result = posit16_lerp(a, b, t)); - try std.testing.expect(posit16_is_equal(result, a) == true); + const a = posit16_encode_f32(10.0); + const b = posit16_encode_f32(50.0); + const t = 0.0; + const result = posit16_lerp(a, b, t); + assert(posit16_is_equal(result, a) == true); } test "posit16_lerp_one" { - given a = posit16_encode_f32(10.0) - try std.testing.expect(b = posit16_encode_f32(50.0)); - try std.testing.expect(t = 1.0); - try std.testing.expect(result = posit16_lerp(a, b, t)); - try std.testing.expect(posit16_is_equal(result, b) == true); + const a = posit16_encode_f32(10.0); + const b = posit16_encode_f32(50.0); + const t = 1.0; + const result = posit16_lerp(a, b, t); + assert(posit16_is_equal(result, b) == true); } // ============================================================================ // Invariants // ============================================================================ -} invariant posit16_bits_constant assert BITS == 16 @@ -906,45 +908,51 @@ invariant posit16_div_nar_propagates given value = posit16_encode_f32(50.0) assert posit16_is_nar(posit16_div(POS16_NAR, value)) == true -invariant posit16_relu_non_negative - given result = posit16_relu(posit16_encode_f32(50.0)) - try std.testing.expect(posit16_extract_sign(result) == false); +invariant posit16_relu_non_negative { + const result = posit16_relu(posit16_encode_f32(50.0)); + assert(posit16_extract_sign(result) == false); +} -invariant posit16_sqrt_non_negative - given result = posit16_sqrt(posit16_encode_f32(4.0)) - try std.testing.expect(posit16_extract_sign(result) == false); +invariant posit16_sqrt_non_negative { + const result = posit16_sqrt(posit16_encode_f32(4.0)); + assert(posit16_extract_sign(result) == false); +} invariant posit16_quantize_to_int4_in_range given result = posit16_quantize_to_int4(posit16_encode_f32(50.0)) assert result >= -8 and result <= 7 -invariant posit16_scale_roundtrip - given value = posit16_encode_f32(50.0) - try std.testing.expect(scale = 2.0); - try std.testing.expect(scaled = posit16_scale(value, scale)); - try std.testing.expect(decoded = posit16_to_f32_scaled(scaled, scale)); - try std.testing.expect(abs(decoded - posit16_decode_f32(value)) < 5.0); - -invariant posit16_max_ge_both - given a = posit16_encode_f32(30.0) - try std.testing.expect(b = posit16_encode_f32(50.0)); - try std.testing.expect(result = posit16_max(a, b)); - try std.testing.expect(posit16_is_greater(result, a) == true or posit16_is_equal(result, a) == true); - -invariant posit16_min_le_both - given a = posit16_encode_f32(30.0) - try std.testing.expect(b = posit16_encode_f32(50.0)); - try std.testing.expect(result = posit16_min(a, b)); - try std.testing.expect(posit16_is_greater(b, result) == true or posit16_is_equal(b, result) == true); - -invariant posit16_lerp_bounded - given a = posit16_encode_f32(10.0) - try std.testing.expect(b = posit16_encode_f32(50.0)); - try std.testing.expect(result_half = posit16_lerp(a, b, 0.5)); - try std.testing.expect(decoded_a = posit16_decode_f32(a)); - try std.testing.expect(decoded_b = posit16_decode_f32(b)); - try std.testing.expect(decoded_half = posit16_decode_f32(result_half)); - try std.testing.expect(decoded_half > decoded_a and decoded_half < decoded_b); +invariant posit16_scale_roundtrip { + const value = posit16_encode_f32(50.0); + const scale = 2.0; + const scaled = posit16_scale(value, scale); + const decoded = posit16_to_f32_scaled(scaled, scale); + assert(abs(decoded - posit16_decode_f32(value)) < 5.0); +} + +invariant posit16_max_ge_both { + const a = posit16_encode_f32(30.0); + const b = posit16_encode_f32(50.0); + const result = posit16_max(a, b); + assert(posit16_is_greater(result, a) == true or posit16_is_equal(result, a) == true); +} + +invariant posit16_min_le_both { + const a = posit16_encode_f32(30.0); + const b = posit16_encode_f32(50.0); + const result = posit16_min(a, b); + assert(posit16_is_greater(b, result) == true or posit16_is_equal(b, result) == true); +} + +invariant posit16_lerp_bounded { + const a = posit16_encode_f32(10.0); + const b = posit16_encode_f32(50.0); + const result_half = posit16_lerp(a, b, 0.5); + const decoded_a = posit16_decode_f32(a); + const decoded_b = posit16_decode_f32(b); + const decoded_half = posit16_decode_f32(result_half); + assert(decoded_half > decoded_a and decoded_half < decoded_b); +} // ============================================================================ // Benchmarks diff --git a/specs/fpga/purkinje_thermal_gate.t27 b/specs/fpga/purkinje_thermal_gate.t27 index 1c81432..f1a0274 100644 --- a/specs/fpga/purkinje_thermal_gate.t27 +++ b/specs/fpga/purkinje_thermal_gate.t27 @@ -182,7 +182,7 @@ pub fn ptg_thermal_state_init() -> ThermalState { // ptg_gate_state_from_temp(temp_c: i8, config: GateConfig) -> GateState // Determine gate state from temperature pub fn ptg_gate_state_from_temp(temp_c: i8, config: GateConfig) -> GateState { - if (not ptg_temp_valid(temp_c)) { + if (!ptg_temp_valid(temp_c)) { return GateState.error; } else if (ptg_temp_critical(temp_c, config)) { return GateState.error; @@ -348,243 +348,242 @@ pub fn decode_ptg_cmd(encoded: u16) -> struct { opcode: u8, temp_c: i8, threshol // ============================================================================ test "ptg_opcode_constant" { - try std.testing.expect(PTG_OPCODE == 0xF4); + assert(PTG_OPCODE == 0xF4); } test "temp_constants" { - try std.testing.expect(TEMP_MIN_C == -40); - try std.testing.expect(TEMP_MAX_C == 125); - try std.testing.expect(TEMP_NOMINAL_C == 25); + assert(TEMP_MIN_C == -40); + assert(TEMP_MAX_C == 125); + assert(TEMP_NOMINAL_C == 25); } test "temp_threshold_constants" { - try std.testing.expect(TEMP_THRESHOLD_LOW_C == 0); - try std.testing.expect(TEMP_THRESHOLD_HIGH_C == 85); - try std.testing.expect(TEMP_CRITICAL_C == 100); + assert(TEMP_THRESHOLD_LOW_C == 0); + assert(TEMP_THRESHOLD_HIGH_C == 85); + assert(TEMP_CRITICAL_C == 100); } test "temp_hysteresis_constant" { - try std.testing.expect(TEMP_HYSTERESIS_C == 5); + assert(TEMP_HYSTERESIS_C == 5); } test "gate_state_constants" { - try std.testing.expect(GATE_STATE_CLOSED == 0); - try std.testing.expect(GATE_STATE_OPEN == 1); - try std.testing.expect(GATE_STATE_THROTTLING == 2); - try std.testing.expect(GATE_STATE_ERROR == 3); + assert(GATE_STATE_CLOSED == 0); + assert(GATE_STATE_OPEN == 1); + assert(GATE_STATE_THROTTLING == 2); + assert(GATE_STATE_ERROR == 3); } test "throttle_level_constants" { - try std.testing.expect(THROTTLE_LEVEL_NONE == 0); - try std.testing.expect(THROTTLE_LEVEL_LOW == 1); - try std.testing.expect(THROTTLE_LEVEL_MED == 2); - try std.testing.expect(THROTTLE_LEVEL_HIGH == 3); + assert(THROTTLE_LEVEL_NONE == 0); + assert(THROTTLE_LEVEL_LOW == 1); + assert(THROTTLE_LEVEL_MED == 2); + assert(THROTTLE_LEVEL_HIGH == 3); } test "ptg_config_init_structure" { - given config = ptg_config_init() - try std.testing.expect(config.low_threshold_c == TEMP_THRESHOLD_LOW_C); - try std.testing.expect(config.high_threshold_c == TEMP_THRESHOLD_HIGH_C); - try std.testing.expect(config.auto_throttle == true); + const config = ptg_config_init(); + assert(config.low_threshold_c == TEMP_THRESHOLD_LOW_C); + assert(config.high_threshold_c == TEMP_THRESHOLD_HIGH_C); + assert(config.auto_throttle == true); } test "ptg_config_strict_structure" { - given config = ptg_config_strict() - try std.testing.expect(config.high_threshold_c == 70); - try std.testing.expect(config.critical_temp_c == 90); + const config = ptg_config_strict(); + assert(config.high_threshold_c == 70); + assert(config.critical_temp_c == 90); } test "ptg_config_permissive_structure" { - given config = ptg_config_permissive() - try std.testing.expect(config.high_threshold_c == 100); - try std.testing.expect(config.critical_temp_c == 115); + const config = ptg_config_permissive(); + assert(config.high_threshold_c == 100); + assert(config.critical_temp_c == 115); } test "ptg_config_manual_structure" { - given config = ptg_config_manual() - try std.testing.expect(config.auto_throttle == false); + const config = ptg_config_manual(); + assert(config.auto_throttle == false); } test "ptg_temp_valid_true" { - try std.testing.expect(ptg_temp_valid(0) == true); - try std.testing.expect(ptg_temp_valid(25) == true); - try std.testing.expect(ptg_temp_valid(100) == true); + assert(ptg_temp_valid(0) == true); + assert(ptg_temp_valid(25) == true); + assert(ptg_temp_valid(100) == true); } test "ptg_temp_valid_false" { - try std.testing.expect(ptg_temp_valid(-50) == false); - try std.testing.expect(ptg_temp_valid(150) == false); + assert(ptg_temp_valid(-50) == false); + assert(ptg_temp_valid(150) == false); } test "ptg_temp_critical_true" { - given config = ptg_config_init() - try std.testing.expect(ptg_temp_critical(105, config) == true); - try std.testing.expect(ptg_temp_critical(100, config) == true); + const config = ptg_config_init(); + assert(ptg_temp_critical(105, config) == true); + assert(ptg_temp_critical(100, config) == true); } test "ptg_temp_critical_false" { - given config = ptg_config_init() - try std.testing.expect(ptg_temp_critical(90, config) == false); + const config = ptg_config_init(); + assert(ptg_temp_critical(90, config) == false); } test "ptg_temp_high_true" { - given config = ptg_config_init() - try std.testing.expect(ptg_temp_high(90, config) == true); - try std.testing.expect(ptg_temp_high(85, config) == true); + const config = ptg_config_init(); + assert(ptg_temp_high(90, config) == true); + assert(ptg_temp_high(85, config) == true); } test "ptg_temp_high_false" { - given config = ptg_config_init() - try std.testing.expect(ptg_temp_high(80, config) == false); + const config = ptg_config_init(); + assert(ptg_temp_high(80, config) == false); } test "ptg_temp_low_true" { - given config = ptg_config_init() - try std.testing.expect(ptg_temp_low(-10, config) == true); - try std.testing.expect(ptg_temp_low(-1, config) == true); + const config = ptg_config_init(); + assert(ptg_temp_low(-10, config) == true); + assert(ptg_temp_low(-1, config) == true); } test "ptg_temp_low_false" { - given config = ptg_config_init() - try std.testing.expect(ptg_temp_low(0, config) == false); - try std.testing.expect(ptg_temp_low(10, config) == false); + const config = ptg_config_init(); + assert(ptg_temp_low(0, config) == false); + assert(ptg_temp_low(10, config) == false); } test "ptg_temp_in_hysteresis_true" { - try std.testing.expect(ptg_temp_in_hysteresis(85, 85, 5) == true); - try std.testing.expect(ptg_temp_in_hysteresis(87, 85, 5) == true); - try std.testing.expect(ptg_temp_in_hysteresis(83, 85, 5) == true); + assert(ptg_temp_in_hysteresis(85, 85, 5) == true); + assert(ptg_temp_in_hysteresis(87, 85, 5) == true); + assert(ptg_temp_in_hysteresis(83, 85, 5) == true); } test "ptg_temp_in_hysteresis_false" { - try std.testing.expect(ptg_temp_in_hysteresis(95, 85, 5) == false); - try std.testing.expect(ptg_temp_in_hysteresis(75, 85, 5) == false); + assert(ptg_temp_in_hysteresis(95, 85, 5) == false); + assert(ptg_temp_in_hysteresis(75, 85, 5) == false); } test "ptg_thermal_state_init_structure" { - given thermal = ptg_thermal_state_init() - try std.testing.expect(thermal.temp_c == TEMP_NOMINAL_C); - try std.testing.expect(thermal.gate_state == GateState.open); + const thermal = ptg_thermal_state_init(); + assert(thermal.temp_c == TEMP_NOMINAL_C); + assert(thermal.gate_state == GateState.open); } test "ptg_gate_state_from_temp_open" { - given config = ptg_config_init() - try std.testing.expect(ptg_gate_state_from_temp(50, config) == GateState.open); + const config = ptg_config_init(); + assert(ptg_gate_state_from_temp(50, config) == GateState.open); } test "ptg_gate_state_from_temp_throttling" { - given config = ptg_config_init() - try std.testing.expect(ptg_gate_state_from_temp(90, config) == GateState.throttling); + const config = ptg_config_init(); + assert(ptg_gate_state_from_temp(90, config) == GateState.throttling); } test "ptg_gate_state_from_temp_closed" { - given config = ptg_config_init() - try std.testing.expect(ptg_gate_state_from_temp(-10, config) == GateState.closed); + const config = ptg_config_init(); + assert(ptg_gate_state_from_temp(-10, config) == GateState.closed); } test "ptg_gate_state_from_temp_error" { - given config = ptg_config_init() - try std.testing.expect(ptg_gate_state_from_temp(105, config) == GateState.error); + const config = ptg_config_init(); + assert(ptg_gate_state_from_temp(105, config) == GateState.error); } test "ptg_throttle_from_temp_none" { - given config = ptg_config_init() - try std.testing.expect(ptg_throttle_from_temp(50, config) == ThrottleLevel.none); + const config = ptg_config_init(); + assert(ptg_throttle_from_temp(50, config) == ThrottleLevel.none); } test "ptg_throttle_from_temp_low" { - given config = ptg_config_init() - try std.testing.expect(ptg_throttle_from_temp(90, config) == ThrottleLevel.low); + const config = ptg_config_init(); + assert(ptg_throttle_from_temp(90, config) == ThrottleLevel.low); } test "ptg_throttle_from_temp_medium" { - given config = ptg_config_init() - try std.testing.expect(ptg_throttle_from_temp(100, config) == ThrottleLevel.medium); + const config = ptg_config_init(); + assert(ptg_throttle_from_temp(100, config) == ThrottleLevel.medium); } test "ptg_throttle_from_temp_high" { - given config = ptg_config_init() - try std.testing.expect(ptg_throttle_from_temp(110, config) == ThrottleLevel.high); + const config = ptg_config_init(); + assert(ptg_throttle_from_temp(110, config) == ThrottleLevel.high); } test "ptg_thermal_state_update" { - given thermal = ptg_thermal_state_init() - try std.testing.expect(config = ptg_config_init()); - try std.testing.expect(result = ptg_thermal_state_update(thermal, 90, config)); - try std.testing.expect(result.temp_c == 90); - try std.testing.expect(result.gate_state == GateState.throttling); + const thermal = ptg_thermal_state_init(); + const config = ptg_config_init(); + const result = ptg_thermal_state_update(thermal, 90, config); + assert(result.temp_c == 90); + assert(result.gate_state == GateState.throttling); } test "ptg_gate_status_init_structure" { - given status = ptg_gate_status_init() - try std.testing.expect(status.current_state == GateState.open); - try std.testing.expect(status.fault_count == 0); + const status = ptg_gate_status_init(); + assert(status.current_state == GateState.open); + assert(status.fault_count == 0); } test "ptg_gate_status_open" { - given status = ptg_gate_status_init() - try std.testing.expect(result = ptg_gate_status_open(status)); - try std.testing.expect(result.current_state == GateState.open); - try std.testing.expect(result.throttle_level == ThrottleLevel.none); + const status = ptg_gate_status_init(); + const result = ptg_gate_status_open(status); + assert(result.current_state == GateState.open); + assert(result.throttle_level == ThrottleLevel.none); } test "ptg_gate_status_close" { - given status = ptg_gate_status_init() - try std.testing.expect(result = ptg_gate_status_close(status)); - try std.testing.expect(result.current_state == GateState.closed); - try std.testing.expect(result.throttle_level == ThrottleLevel.high); + const status = ptg_gate_status_init(); + const result = ptg_gate_status_close(status); + assert(result.current_state == GateState.closed); + assert(result.throttle_level == ThrottleLevel.high); } test "ptg_gate_status_throttle" { - given status = ptg_gate_status_init() - try std.testing.expect(result = ptg_gate_status_throttle(status, ThrottleLevel.medium)); - try std.testing.expect(result.current_state == GateState.throttling); - try std.testing.expect(result.throttle_level == ThrottleLevel.medium); + const status = ptg_gate_status_init(); + const result = ptg_gate_status_throttle(status, ThrottleLevel.medium); + assert(result.current_state == GateState.throttling); + assert(result.throttle_level == ThrottleLevel.medium); } test "ptg_gate_status_error" { - given status = ptg_gate_status_init() - try std.testing.expect(result = ptg_gate_status_error(status)); - try std.testing.expect(result.current_state == GateState.error); - try std.testing.expect(result.fault_count == 1); + const status = ptg_gate_status_init(); + const result = ptg_gate_status_error(status); + assert(result.current_state == GateState.error); + assert(result.fault_count == 1); } test "ptg_gate_status_update_temp" { - given status = ptg_gate_status_init() - try std.testing.expect(result = ptg_gate_status_update_temp(status, 75)); - try std.testing.expect(result.temp_measured_c == 75); + const status = ptg_gate_status_init(); + const result = ptg_gate_status_update_temp(status, 75); + assert(result.temp_measured_c == 75); } test "ptg_gate_status_increment_cycle" { - given status = ptg_gate_status_init() - try std.testing.expect(result = ptg_gate_status_increment_cycle(status)); - try std.testing.expect(result.cycle_count == 1); + const status = ptg_gate_status_init(); + const result = ptg_gate_status_increment_cycle(status); + assert(result.cycle_count == 1); } test "encode_ptg_cmd" { - given encoded = encode_ptg_cmd(0x10, 25, 1) - try std.testing.expect((encoded >> 8) == 0x10); + const encoded = encode_ptg_cmd(0x10, 25, 1); + assert((encoded >> 8) == 0x10); } test "decode_ptg_cmd" { - given decoded = decode_ptg_cmd(0x1033) - try std.testing.expect(decoded.opcode == 0x10); - try std.testing.expect(decoded.temp_c == 25); + const decoded = decode_ptg_cmd(0x1033); + assert(decoded.opcode == 0x10); + assert(decoded.temp_c == 25); } // ============================================================================ // Invariants // ============================================================================ -} invariant temp_range_valid assert TEMP_MIN_C < TEMP_MAX_C - try std.testing.expect(TEMP_NOMINAL_C > TEMP_MIN_C); - try std.testing.expect(TEMP_NOMINAL_C < TEMP_MAX_C); + assert TEMP_NOMINAL_C > TEMP_MIN_C + assert TEMP_NOMINAL_C < TEMP_MAX_C invariant temp_thresholds_ordered assert TEMP_THRESHOLD_LOW_C < TEMP_THRESHOLD_HIGH_C - try std.testing.expect(TEMP_THRESHOLD_HIGH_C < TEMP_CRITICAL_C); + assert TEMP_THRESHOLD_HIGH_C < TEMP_CRITICAL_C invariant temp_hysteresis_positive assert TEMP_HYSTERESIS_C > 0 @@ -592,19 +591,19 @@ invariant temp_hysteresis_positive invariant ptg_config_init_valid given config = ptg_config_init() assert config.low_threshold_c < config.high_threshold_c - try std.testing.expect(config.high_threshold_c < config.critical_temp_c); + assert config.high_threshold_c < config.critical_temp_c invariant ptg_config_strict_lower_thresholds given strict = ptg_config_strict() - try std.testing.expect(normal = ptg_config_init()); + and normal = ptg_config_init() assert strict.high_threshold_c < normal.high_threshold_c - try std.testing.expect(strict.critical_temp_c < normal.critical_temp_c); + assert strict.critical_temp_c < normal.critical_temp_c invariant ptg_config_permissive_higher_thresholds given perm = ptg_config_permissive() - try std.testing.expect(normal = ptg_config_init()); + and normal = ptg_config_init() assert perm.high_threshold_c > normal.high_threshold_c - try std.testing.expect(perm.critical_temp_c > normal.critical_temp_c); + assert perm.critical_temp_c > normal.critical_temp_c invariant ptg_config_manual_no_auto_throttle given config = ptg_config_manual() @@ -612,36 +611,36 @@ invariant ptg_config_manual_no_auto_throttle invariant ptg_thermal_state_init_open given thermal = ptg_thermal_state_init() - try std.testing.expect(thermal.gate_state == GateState.open); + assert thermal.gate_state == GateState.open invariant ptg_gate_state_from_temp_nominal_open given config = ptg_config_init() - try std.testing.expect(state = ptg_gate_state_from_temp(TEMP_NOMINAL_C, config)); - try std.testing.expect(state == GateState.open); + and state = ptg_gate_state_from_temp(TEMP_NOMINAL_C, config) + assert state == GateState.open invariant ptg_throttle_from_temp_nominal_none given config = ptg_config_init() - try std.testing.expect(level = ptg_throttle_from_temp(TEMP_NOMINAL_C, config)); - try std.testing.expect(level == ThrottleLevel.none); + and level = ptg_throttle_from_temp(TEMP_NOMINAL_C, config) + assert level == ThrottleLevel.none invariant ptg_gate_status_init_open given status = ptg_gate_status_init() - try std.testing.expect(status.current_state == GateState.open); + assert status.current_state == GateState.open invariant ptg_gate_status_error_increments_fault given status = ptg_gate_status_init() - try std.testing.expect(result = ptg_gate_status_error(status)); - try std.testing.expect(result.fault_count == 1); + and result = ptg_gate_status_error(status) + assert result.fault_count == 1 invariant ptg_gate_status_increment_cycle_increments given status = ptg_gate_status_init() - try std.testing.expect(result = ptg_gate_status_increment_cycle(status)); - try std.testing.expect(result.cycle_count == 1); + and result = ptg_gate_status_increment_cycle(status) + assert result.cycle_count == 1 invariant ptg_gate_status_close_high_throttle given status = ptg_gate_status_init() - try std.testing.expect(result = ptg_gate_status_close(status)); - try std.testing.expect(result.throttle_level == ThrottleLevel.high); + and result = ptg_gate_status_close(status) + assert result.throttle_level == ThrottleLevel.high // ============================================================================ // Benchmarks diff --git a/specs/fpga/sparse_mask.t27 b/specs/fpga/sparse_mask.t27 index 49c8fb1..0907d75 100644 --- a/specs/fpga/sparse_mask.t27 +++ b/specs/fpga/sparse_mask.t27 @@ -103,7 +103,7 @@ pub fn mask_generate_density(density: u8) -> u16 { // Set first target_bits bits while (i < target_bits) { - mask |= (@as(u16, 1) << i); + mask |= ((1 as u16) << i); i += 1; } @@ -116,13 +116,13 @@ pub fn mask_generate_phi() -> u16 { // φ ≈ 1.618, use pattern based on Fibonacci sequence // Set bits at positions: 0, 1, 2, 3, 5, 8, 13 (first few Fib numbers) var mask : u16 = 0; - mask |= (@as(u16, 1) << 0); - mask |= (@as(u16, 1) << 1); - mask |= (@as(u16, 1) << 2); - mask |= (@as(u16, 1) << 3); - mask |= (@as(u16, 1) << 5); - mask |= (@as(u16, 1) << 8); - mask |= (@as(u16, 1) << 13); + mask |= ((1 as u16) << 0); + mask |= ((1 as u16) << 1); + mask |= ((1 as u16) << 2); + mask |= ((1 as u16) << 3); + mask |= ((1 as u16) << 5); + mask |= ((1 as u16) << 8); + mask |= ((1 as u16) << 13); return mask; } @@ -132,9 +132,9 @@ pub fn mask_generate_pattern(pattern: u8) -> u16 { var mask : u16 = 0; const pattern_bits : u8 = 4; - for (0..MASK_SIZE) |i| { + for i in 0..MASK_SIZE { if ((pattern >> (i % pattern_bits)) & 1 != 0) { - mask |= (@as(u16, 1) << i); + mask |= ((1 as u16) << i); } } @@ -147,10 +147,10 @@ pub fn mask_generate_random(seed: u16) -> u16 { var lfsr = seed; var mask : u16 = 0; - for (0..MASK_SIZE) |i| { + for i in 0..MASK_SIZE { const bit = (lfsr >> 0) & 1; if (bit != 0) { - mask |= (@as(u16, 1) << i); + mask |= ((1 as u16) << i); } // LFSR feedback (X^16 + X^14 + X^13 + X^11) const feedback = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5)) & 1; @@ -170,26 +170,23 @@ pub fn mask_generate(config: MaskConfig, seed: u16) -> SparseMask { var mask : u16 = 0; var pattern_type : u8 = config.mask_type; - switch (config.mask_type) { - MASK_TYPE_DENSITY => { - mask = mask_generate_density(config.threshold); - }, - MASK_TYPE_PATTERN => { - mask = mask_generate_pattern(config.threshold); - }, - MASK_TYPE_RANDOM => { - mask = mask_generate_random(seed); - }, - MASK_TYPE_PHI => { - if (config.phi_optimized) { - mask = mask_generate_phi(); - } else { - mask = mask_generate_pattern(0x05); // Default pattern - } - }, - else => { - mask = mask_generate_pattern(0x0F); - }, + // Dispatch on config.mask_type. The arms are statement blocks, which a + // t27 switch (expression arms only) cannot hold, so the same dispatch is + // written as an if / else-if chain with the switch's `else` arm last. + if (config.mask_type == MASK_TYPE_DENSITY) { + mask = mask_generate_density(config.threshold); + } else if (config.mask_type == MASK_TYPE_PATTERN) { + mask = mask_generate_pattern(config.threshold); + } else if (config.mask_type == MASK_TYPE_RANDOM) { + mask = mask_generate_random(seed); + } else if (config.mask_type == MASK_TYPE_PHI) { + if (config.phi_optimized) { + mask = mask_generate_phi(); + } else { + mask = mask_generate_pattern(0x05); // Default pattern + } + } else { + mask = mask_generate_pattern(0x0F); } return SparseMask { @@ -205,7 +202,8 @@ pub fn mask_apply(vector: Vector16, mask: SparseMask) -> Vector16 { var result : Vector16 = undefined; result.mask = mask.bits; - for (vector.values, 0..) |val, i| { + for i in 0..MASK_SIZE { + const val = vector.values[i]; if ((mask.bits >> i) & 1 != 0) { result.values[i] = val; } else { @@ -219,18 +217,18 @@ pub fn mask_apply(vector: Vector16, mask: SparseMask) -> Vector16 { // mask_combine(mask1: u16, mask2: u16, operation: u8) -> u16 // Combine two masks pub fn mask_combine(mask1: u16, mask2: u16, operation: u8) -> u16 { - switch (operation) { - 0 => return mask1 & mask2, // AND - 1 => return mask1 | mask2, // OR - 2 => return mask1 ^ mask2, // XOR - else => return mask1 & ~mask2, // NAND - } + return switch (operation) { + 0 => mask1 & mask2, // AND + 1 => mask1 | mask2, // OR + 2 => mask1 ^ mask2, // XOR + else => mask1 & ~mask2, // NAND + }; } // mask_invert(mask: u16) -> u16 // Invert mask pub fn mask_invert(mask: u16) -> u16 { - return ~mask & ((@as(u16, 1) << MASK_SIZE) - 1); + return ~mask & (((1 as u16) << MASK_SIZE) - 1); } // mask_complement(mask: SparseMask) -> SparseMask @@ -252,19 +250,19 @@ pub fn mask_complement(mask: SparseMask) -> SparseMask { // Encode sparse mask instruction pub fn encode_sparse_mask(mode: u8, mask_type: u8, seed: u8) u16 { // Format: [OP:8][MODE:2][TYPE:2][SEED:4] - const op : u16 = @as(u16, OP_SPARSE_MASK) << 8; - const mode_field : u16 = @as(u16, mode & 0x03) << 6; - const type_field : u16 = @as(u16, mask_type & 0x03) << 4; - const seed_field : u16 = @as(u16, seed & 0x0F); + const op : u16 = (OP_SPARSE_MASK as u16) << 8; + const mode_field : u16 = ((mode & 0x03) as u16) << 6; + const type_field : u16 = ((mask_type & 0x03) as u16) << 4; + const seed_field : u16 = (seed & 0x0F) as u16; return op | mode_field | type_field | seed_field; } // decode_sparse_mask(encoded: u16) -> struct { mode: u8, mask_type: u8, seed: u8 } // Decode sparse mask instruction pub fn decode_sparse_mask(encoded: u16) struct { mode: u8, mask_type: u8, seed: u8 } { - const mode : u8 = @as(u8, @truncate((encoded >> 6) & 0x03)); - const mask_type : u8 = @as(u8, @truncate((encoded >> 4) & 0x03)); - const seed : u8 = @as(u8, @truncate(encoded & 0x0F)); + const mode : u8 = ((encoded >> 6) & 0x03) as u8; + const mask_type : u8 = ((encoded >> 4) & 0x03) as u8; + const seed : u8 = (encoded & 0x0F) as u8; return .{ .mode = mode, .mask_type = mask_type, .seed = seed }; } @@ -273,11 +271,11 @@ pub fn decode_sparse_mask(encoded: u16) struct { mode: u8, mask_type: u8, seed: // ============================================================================ test "mask_size_sixteen" { - try std.testing.expect(MASK_SIZE == 16); + assert(MASK_SIZE == 16); } test "sparse_threshold_fifty" { - try std.testing.expect(SPARSE_THRESHOLD_RATIO == 50); + assert(SPARSE_THRESHOLD_RATIO == 50); } test "mask_mode_gen" { @@ -293,178 +291,177 @@ test "mask_type_phi" { } test "mask_count_set_bits_all" { - try std.testing.expect(mask_count_set_bits(0xFFFF) == 16); + assert(mask_count_set_bits(0xFFFF) == 16); } test "mask_count_set_bits_none" { - try std.testing.expect(mask_count_set_bits(0x0000) == 0); + assert(mask_count_set_bits(0x0000) == 0); } test "mask_count_set_bits_half" { - try std.testing.expect(mask_count_set_bits(0x00FF) == 8); + assert(mask_count_set_bits(0x00FF) == 8); } test "mask_count_clear_bits_all" { - try std.testing.expect(mask_count_clear_bits(0xFFFF) == 0); + assert(mask_count_clear_bits(0xFFFF) == 0); } test "mask_count_clear_bits_none" { - try std.testing.expect(mask_count_clear_bits(0x0000) == 16); + assert(mask_count_clear_bits(0x0000) == 16); } test "mask_density_zero" { - try std.testing.expect(mask_density(0x0000) == 0); + assert(mask_density(0x0000) == 0); } test "mask_density_fifty" { - try std.testing.expect(mask_density(0x00FF) == 50); + assert(mask_density(0x00FF) == 50); } test "mask_density_full" { - try std.testing.expect(mask_density(0xFFFF) == 100); + assert(mask_density(0xFFFF) == 100); } test "mask_is_sparse_true" { - try std.testing.expect(mask_is_sparse(0x000F) == true); - try std.testing.expect(mask_is_sparse(0x003F) == true); + assert(mask_is_sparse(0x000F) == true); + assert(mask_is_sparse(0x003F) == true); } test "mask_is_sparse_false" { - try std.testing.expect(mask_is_sparse(0x00FF) == false); - try std.testing.expect(mask_is_sparse(0xFFFF) == false); + assert(mask_is_sparse(0x00FF) == false); + assert(mask_is_sparse(0xFFFF) == false); } test "mask_is_dense_true" { - try std.testing.expect(mask_is_dense(0x00FF) == true); - try std.testing.expect(mask_is_dense(0xFFFF) == true); + assert(mask_is_dense(0x00FF) == true); + assert(mask_is_dense(0xFFFF) == true); } test "mask_is_dense_false" { - try std.testing.expect(mask_is_dense(0x000F) == false); - try std.testing.expect(mask_is_dense(0x003F) == false); + assert(mask_is_dense(0x000F) == false); + assert(mask_is_dense(0x003F) == false); } test "mask_generate_density_zero" { - try std.testing.expect(mask_generate_density(0) == 0); + assert(mask_generate_density(0) == 0); } test "mask_generate_density_full" { - try std.testing.expect(mask_generate_density(100) == 0xFFFF); + assert(mask_generate_density(100) == 0xFFFF); } test "mask_generate_density_fifty" { - try std.testing.expect(mask_count_set_bits(mask_generate_density(50)) == 8); + assert(mask_count_set_bits(mask_generate_density(50)) == 8); } test "mask_generate_phi" { - given mask = mask_generate_phi() - try std.testing.expect(mask_count_set_bits(mask) == 7); - try std.testing.expect(mask_density(mask) == 43 // 7/16 ≈ 43%); + const mask = mask_generate_phi(); + assert(mask_count_set_bits(mask) == 7); + assert(mask_density(mask) == 43); // 7/16 ≈ 43% } test "mask_generate_pattern_alternating" { - try std.testing.expect(mask_generate_pattern(0x05) == 0xAAAA); + assert(mask_generate_pattern(0x05) == 0xAAAA); } test "mask_generate_pattern_ones" { - try std.testing.expect(mask_generate_pattern(0x0F) == 0xFFFF); + assert(mask_generate_pattern(0x0F) == 0xFFFF); } test "mask_generate_pattern_zeros" { - try std.testing.expect(mask_generate_pattern(0x00) == 0x0000); + assert(mask_generate_pattern(0x00) == 0x0000); } test "mask_generate_random_seeded" { - given mask1 = mask_generate_random(0x1234) - try std.testing.expect(mask2 = mask_generate_random(0x1234)); - try std.testing.expect(mask1 == mask2); + const mask1 = mask_generate_random(0x1234); + const mask2 = mask_generate_random(0x1234); + assert(mask1 == mask2); } test "mask_generate_random_different" { - given mask1 = mask_generate_random(0x1234) - try std.testing.expect(mask2 = mask_generate_random(0x4321)); - try std.testing.expect(mask1 != mask2); + const mask1 = mask_generate_random(0x1234); + const mask2 = mask_generate_random(0x4321); + assert(mask1 != mask2); } test "mask_generate_dense" { - given config = MaskConfig{.mode = MASK_MODE_GEN, .mask_type = MASK_TYPE_DENSITY, .threshold = 80, .phi_optimized = false} - try std.testing.expect(mask = mask_generate(config, 0)); - try std.testing.expect(mask.density >= 75); + const config = MaskConfig{.mode = MASK_MODE_GEN, .mask_type = MASK_TYPE_DENSITY, .threshold = 80, .phi_optimized = false}; + const mask = mask_generate(config, 0); + assert(mask.density >= 75); } test "mask_generate_sparse" { - given config = MaskConfig{.mode = MASK_MODE_GEN, .mask_type = MASK_TYPE_DENSITY, .threshold = 20, .phi_optimized = false} - try std.testing.expect(mask = mask_generate(config, 0)); - try std.testing.expect(mask.density <= 30); + const config = MaskConfig{.mode = MASK_MODE_GEN, .mask_type = MASK_TYPE_DENSITY, .threshold = 20, .phi_optimized = false}; + const mask = mask_generate(config, 0); + assert(mask.density <= 30); } test "mask_apply_zero_mask" { - given vector = Vector16{.values = [_]i8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, .mask = 0xFFFF} - try std.testing.expect(mask_obj = SparseMask{.bits = 0x0000, .density = 0, .pattern_type = 0}); - try std.testing.expect(result = mask_apply(vector, mask_obj)); - try std.testing.expect(result.values[0] == 0); - try std.testing.expect(result.values[15] == 0); + const vector = Vector16{.values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], .mask = 0xFFFF}; + const mask_obj = SparseMask{.bits = 0x0000, .density = 0, .pattern_type = 0}; + const result = mask_apply(vector, mask_obj); + assert(result.values[0] == 0); + assert(result.values[15] == 0); } test "mask_apply_full_mask" { - given vector = Vector16{.values = [_]i8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, .mask = 0x0000} - try std.testing.expect(mask_obj = SparseMask{.bits = 0xFFFF, .density = 100, .pattern_type = 0}); - try std.testing.expect(result = mask_apply(vector, mask_obj)); - try std.testing.expect(result.values[0] == 1); - try std.testing.expect(result.values[15] == 16); + const vector = Vector16{.values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], .mask = 0x0000}; + const mask_obj = SparseMask{.bits = 0xFFFF, .density = 100, .pattern_type = 0}; + const result = mask_apply(vector, mask_obj); + assert(result.values[0] == 1); + assert(result.values[15] == 16); } test "mask_combine_and" { - try std.testing.expect(mask_combine(0xFF00, 0xF0F0, 0) == 0xF000); + assert(mask_combine(0xFF00, 0xF0F0, 0) == 0xF000); } test "mask_combine_or" { - try std.testing.expect(mask_combine(0xFF00, 0xF0F0, 1) == 0xFFF0); + assert(mask_combine(0xFF00, 0xF0F0, 1) == 0xFFF0); } test "mask_combine_xor" { - try std.testing.expect(mask_combine(0xFF00, 0xF0F0, 2) == 0x0FF0); + assert(mask_combine(0xFF00, 0xF0F0, 2) == 0x0FF0); } test "mask_combine_nand" { - try std.testing.expect(mask_combine(0xFF00, 0xF0F0, 3) == 0x0FFF); + assert(mask_combine(0xFF00, 0xF0F0, 3) == 0x0FFF); } test "mask_invert_full" { - try std.testing.expect(mask_invert(0xFFFF) == 0); + assert(mask_invert(0xFFFF) == 0); } test "mask_invert_zero" { - try std.testing.expect(mask_invert(0) == 0xFFFF); + assert(mask_invert(0) == 0xFFFF); } test "mask_complement_sparse_to_dense" { - given mask = SparseMask{.bits = 0x000F, .density = 25, .pattern_type = 0} - try std.testing.expect(result = mask_complement(mask)); - try std.testing.expect(result.density == 75); + const mask = SparseMask{.bits = 0x000F, .density = 25, .pattern_type = 0}; + const result = mask_complement(mask); + assert(result.density == 75); } test "encode_sparse_mask" { - given encoded = encode_sparse_mask(1, 2, 0x0A) - try std.testing.expect((encoded >> 8) == OP_SPARSE_MASK); + const encoded = encode_sparse_mask(1, 2, 0x0A); + assert((encoded >> 8) == OP_SPARSE_MASK); } test "decode_sparse_mask" { - given decoded = decode_sparse_mask(0xE86A) - try std.testing.expect(decoded.mode == 1); - try std.testing.expect(decoded.mask_type == 2); - try std.testing.expect(decoded.seed == 0x0A); + const decoded = decode_sparse_mask(0xE86A); + assert(decoded.mode == 1); + assert(decoded.mask_type == 2); + assert(decoded.seed == 0x0A); } test "opcode_constant" { - try std.testing.expect(OP_SPARSE_MASK == 0xE8); + assert(OP_SPARSE_MASK == 0xE8); } // ============================================================================ // Invariants // ============================================================================ -} invariant mask_size_sixteen assert MASK_SIZE == 16 @@ -476,7 +473,7 @@ invariant mask_count_bits_sum assert mask_count_set_bits(mask) + mask_count_clear_bits(mask) == MASK_SIZE invariant mask_density_range - try std.testing.expect(mask_density(0) == 0 and mask_density(0xFFFF) == 100); + assert mask_density(0) == 0 and mask_density(0xFFFF) == 100 invariant mask_is_sparse_inverse_dense given mask = 0x0F0F @@ -484,44 +481,46 @@ invariant mask_is_sparse_inverse_dense invariant mask_is_complement_inverse given mask = 0x1234 - try std.testing.expect(inverted = mask_invert(mask)); - try std.testing.expect(mask_invert(inverted) == mask); + when inverted = mask_invert(mask) + assert mask_invert(inverted) == mask invariant mask_complement_density given mask = SparseMask{.bits = 0x0F0F, .density = 50, .pattern_type = 0} - try std.testing.expect(result = mask_complement(mask)); - try std.testing.expect(result.density + mask.density == 100); + when result = mask_complement(mask) + assert result.density + mask.density == 100 invariant mask_combine_and_less_than_or given m1 = 0xAAAA - try std.testing.expect(m2 = 0x5555); - try std.testing.expect(combined_and = mask_combine(m1, m2, 0)); - try std.testing.expect(combined_or = mask_combine(m1, m2, 1)); - try std.testing.expect(combined_and <= m1 and combined_and <= m2); - try std.testing.expect(combined_or >= m1 and combined_or >= m2); + and m2 = 0x5555 + when combined_and = mask_combine(m1, m2, 0) + and combined_or = mask_combine(m1, m2, 1) + assert combined_and <= m1 and combined_and <= m2 + assert combined_or >= m1 and combined_or >= m2 invariant mask_generate_phi_consistent given mask1 = mask_generate_phi() - try std.testing.expect(mask2 = mask_generate_phi()); - try std.testing.expect(mask1 == mask2); + when mask2 = mask_generate_phi() + assert mask1 == mask2 invariant mask_generate_density_range - try std.testing.expect(mask_density(mask_generate_density(0)) == 0); - try std.testing.expect(mask_density(mask_generate_density(100)) == 100); + assert mask_density(mask_generate_density(0)) == 0 + assert mask_density(mask_generate_density(100)) == 100 invariant mask_apply_preserves_unmasked - given vector = Vector16{.values = [_]i8{1, 2, 3, 4} ** 4, .mask = 0x0000} - try std.testing.expect(mask_obj = SparseMask{.bits = 0x00FF, .density = 50, .pattern_type = 0}); - try std.testing.expect(result = mask_apply(vector, mask_obj)); - try std.testing.expect(result.values[0] == 1); - try std.testing.expect(result.values[7] == 8); + // values: {1, 2, 3, 4} repeated 4 times, written out (t27 has no `**`). + given vector = Vector16{.values = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4], .mask = 0x0000} + and mask_obj = SparseMask{.bits = 0x00FF, .density = 50, .pattern_type = 0} + when result = mask_apply(vector, mask_obj) + assert result.values[0] == 1 + assert result.values[7] == 8 invariant mask_apply_masks_zero - given vector = Vector16{.values = [_]i8{1, 2, 3, 4} ** 4, .mask = 0x0000} - try std.testing.expect(mask_obj = SparseMask{.bits = 0xFF00, .density = 50, .pattern_type = 0}); - try std.testing.expect(result = mask_apply(vector, mask_obj)); - try std.testing.expect(result.values[0] == 0); - try std.testing.expect(result.values[8] == 0); + // values: {1, 2, 3, 4} repeated 4 times, written out (t27 has no `**`). + given vector = Vector16{.values = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4], .mask = 0x0000} + and mask_obj = SparseMask{.bits = 0xFF00, .density = 50, .pattern_type = 0} + when result = mask_apply(vector, mask_obj) + assert result.values[0] == 0 + assert result.values[8] == 0 // ============================================================================ // Benchmarks @@ -544,7 +543,7 @@ bench mask_generate_random_latency target: < 100ns bench mask_apply_latency - measure: nanoseconds to mask_apply(Vector16{.values = [_]i8{1} ** 16, .mask = 0}, SparseMask{.bits = 0x00FF, .density = 50, .pattern_type = 0}) + measure: nanoseconds to mask_apply(Vector16{.values = [1; 16], .mask = 0}, SparseMask{.bits = 0x00FF, .density = 50, .pattern_type = 0}) target: < 100ns bench encode_sparse_mask_latency diff --git a/specs/fpga/sparse_skip.t27 b/specs/fpga/sparse_skip.t27 index cd5620c..cf290fb 100644 --- a/specs/fpga/sparse_skip.t27 +++ b/specs/fpga/sparse_skip.t27 @@ -71,7 +71,8 @@ pub fn is_below_threshold(value: i8, threshold: i8) bool { // Count zeros in a vector pub fn count_zeros(vector: [VECTOR_SIZE]i8) u8 { var count : u8 = 0; - for (vector) |val| { + for i in 0..VECTOR_SIZE { + const val = vector[i]; if (is_zero(val)) { count += 1; } @@ -83,8 +84,9 @@ pub fn count_zeros(vector: [VECTOR_SIZE]i8) u8 { // Count non-zeros in a vector pub fn count_non_zeros(vector: [VECTOR_SIZE]i8) u8 { var count : u8 = 0; - for (vector) |val| { - if (not is_zero(val)) { + for i in 0..VECTOR_SIZE { + const val = vector[i]; + if (!is_zero(val)) { count += 1; } } @@ -111,7 +113,7 @@ pub fn analyze_sparsity(vector: [VECTOR_SIZE]i8) SparsePattern { .is_sparse = is_sparse, .zero_count = zeros, .non_zero_count = non_zeros, - .sparsity_ratio = @as(u8, @truncate(sparsity_ratio)), + .sparsity_ratio = sparsity_ratio as u8, }; } @@ -131,9 +133,10 @@ pub fn skip_zeros(vector: [VECTOR_SIZE]i8) SkipResult { var mask : u16 = 0; var skipped : u8 = 0; - for (vector, 0..) |val, i| { - if (not is_zero(val)) { - mask |= (@as(u16, 1) << i); + for i in 0..VECTOR_SIZE { + const val = vector[i]; + if (!is_zero(val)) { + mask |= ((1 as u16) << i); } else { skipped += 1; } @@ -142,7 +145,7 @@ pub fn skip_zeros(vector: [VECTOR_SIZE]i8) SkipResult { return SkipResult { .mode = SkipMode.zero, .skipped_count = skipped, - .processed_count = @as(u8, @truncate(VECTOR_SIZE - skipped)), + .processed_count = (VECTOR_SIZE - skipped) as u8, .mask = mask, }; } @@ -153,9 +156,10 @@ pub fn skip_threshold(vector: [VECTOR_SIZE]i8, threshold: i8) SkipResult { var mask : u16 = 0; var skipped : u8 = 0; - for (vector, 0..) |val, i| { - if (not is_below_threshold(val, threshold)) { - mask |= (@as(u16, 1) << i); + for i in 0..VECTOR_SIZE { + const val = vector[i]; + if (!is_below_threshold(val, threshold)) { + mask |= ((1 as u16) << i); } else { skipped += 1; } @@ -164,7 +168,7 @@ pub fn skip_threshold(vector: [VECTOR_SIZE]i8, threshold: i8) SkipResult { return SkipResult { .mode = SkipMode.threshold, .skipped_count = skipped, - .processed_count = @as(u8, @truncate(VECTOR_SIZE - skipped)), + .processed_count = (VECTOR_SIZE - skipped) as u8, .mask = mask, }; } @@ -184,8 +188,8 @@ pub fn skip_all(vector: [VECTOR_SIZE]i8) SkipResult { // Process all elements without skipping pub fn skip_none(vector: [VECTOR_SIZE]i8) SkipResult { var mask : u16 = 0; - for (0..VECTOR_SIZE) |i| { - mask |= (@as(u16, 1) << i); + for i in 0..VECTOR_SIZE { + mask |= ((1 as u16) << i); } return SkipResult { @@ -206,9 +210,10 @@ pub fn create_sparse_vector(vector: [VECTOR_SIZE]i8) SparseVector { var mask : u16 = 0; var zero_count : u8 = 0; - for (vector, 0..) |val, i| { - if (not is_zero(val)) { - mask |= (@as(u16, 1) << i); + for i in 0..VECTOR_SIZE { + const val = vector[i]; + if (!is_zero(val)) { + mask |= ((1 as u16) << i); } else { zero_count += 1; } @@ -227,7 +232,8 @@ pub fn get_non_zero_elements(sparse: SparseVector) [VECTOR_SIZE]i8 { var result : [VECTOR_SIZE]i8 = undefined; var idx : u8 = 0; - for (sparse.values, 0..) |val, i| { + for i in 0..VECTOR_SIZE { + const val = sparse.values[i]; if ((sparse.mask >> i) & 1 != 0) { result[idx] = val; idx += 1; @@ -251,17 +257,17 @@ pub fn get_non_zero_elements(sparse: SparseVector) [VECTOR_SIZE]i8 { // Encode sparse skip instruction pub fn encode_sparse_skip(mode: u8, vector_addr: u8) u16 { // Format: [OP:8][MODE:2][ADDR:6] - const op : u16 = @as(u16, OP_SPARSE_SKIP) << 8; - const mode_field : u16 = @as(u16, mode & 0x03) << 6; - const addr_field : u16 = @as(u16, vector_addr & 0x3F); + const op : u16 = (OP_SPARSE_SKIP as u16) << 8; + const mode_field : u16 = ((mode & 0x03) as u16) << 6; + const addr_field : u16 = (vector_addr & 0x3F) as u16; return op | mode_field | addr_field; } // decode_sparse_skip(encoded: u16) -> struct { mode: u8, vector_addr: u8 } // Decode sparse skip instruction pub fn decode_sparse_skip(encoded: u16) struct { mode: u8, vector_addr: u8 } { - const mode : u8 = @as(u8, @truncate((encoded >> 6) & 0x03)); - const vector_addr : u8 = @as(u8, @truncate(encoded & 0x3F)); + const mode : u8 = ((encoded >> 6) & 0x03) as u8; + const vector_addr : u8 = (encoded & 0x3F) as u8; return .{ .mode = mode, .vector_addr = vector_addr }; } @@ -270,137 +276,136 @@ pub fn decode_sparse_skip(encoded: u16) struct { mode: u8, vector_addr: u8 } { // ============================================================================ test "is_zero_true" { - try std.testing.expect(is_zero(0) == true); + assert(is_zero(0) == true); } test "is_zero_false" { - try std.testing.expect(is_zero(1) == false); - try std.testing.expect(is_zero(-1) == false); + assert(is_zero(1) == false); + assert(is_zero(-1) == false); } test "is_below_threshold_positive" { - try std.testing.expect(is_below_threshold(3, 5) == true); - try std.testing.expect(is_below_threshold(7, 5) == false); + assert(is_below_threshold(3, 5) == true); + assert(is_below_threshold(7, 5) == false); } test "is_below_threshold_negative" { - try std.testing.expect(is_below_threshold(-3, 5) == true); - try std.testing.expect(is_below_threshold(-7, 5) == false); + assert(is_below_threshold(-3, 5) == true); + assert(is_below_threshold(-7, 5) == false); } test "count_zeros_empty" { - given vector = [_]i8{0} ** 16 - try std.testing.expect(count_zeros(vector) == 16); + const vector : [16]i8 = [0; 16]; + assert(count_zeros(vector) == 16); } test "count_zeros_none" { - given vector = [_]i8{1} ** 16 - try std.testing.expect(count_zeros(vector) == 0); + const vector : [16]i8 = [1; 16]; + assert(count_zeros(vector) == 0); } test "count_zeros_mixed" { - given vector = [_]i8{1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0} - try std.testing.expect(count_zeros(vector) == 8); + const vector : [16]i8 = [1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0]; + assert(count_zeros(vector) == 8); } test "count_non_zeros_mixed" { - given vector = [_]i8{1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0} - try std.testing.expect(count_non_zeros(vector) == 8); + const vector : [16]i8 = [1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0]; + assert(count_non_zeros(vector) == 8); } test "analyze_sparsity_dense" { - given vector = [_]i8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} - try std.testing.expect(pattern = analyze_sparsity(vector)); - try std.testing.expect(pattern.is_sparse == false); - try std.testing.expect(pattern.zero_count == 0); + const vector : [16]i8 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + const pattern = analyze_sparsity(vector); + assert(pattern.is_sparse == false); + assert(pattern.zero_count == 0); } test "analyze_sparsity_sparse" { - given vector = [_]i8{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - try std.testing.expect(pattern = analyze_sparsity(vector)); - try std.testing.expect(pattern.is_sparse == true); - try std.testing.expect(pattern.zero_count == 15); + const vector : [16]i8 = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + const pattern = analyze_sparsity(vector); + assert(pattern.is_sparse == true); + assert(pattern.zero_count == 15); } test "should_skip_sparsity_true" { - given vector = [_]i8{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - try std.testing.expect(pattern = analyze_sparsity(vector)); - try std.testing.expect(should_skip_sparsity(pattern) == true); + const vector : [16]i8 = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + const pattern = analyze_sparsity(vector); + assert(should_skip_sparsity(pattern) == true); } test "should_skip_sparsity_false" { - given vector = [_]i8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} - try std.testing.expect(pattern = analyze_sparsity(vector)); - try std.testing.expect(should_skip_sparsity(pattern) == false); + const vector : [16]i8 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + const pattern = analyze_sparsity(vector); + assert(should_skip_sparsity(pattern) == false); } test "skip_zeros_mixed" { - given vector = [_]i8{1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0} - try std.testing.expect(result = skip_zeros(vector)); - try std.testing.expect(result.skipped_count == 8); - try std.testing.expect(result.processed_count == 8); - try std.testing.expect(result.mask == 0xAAAA); + const vector : [16]i8 = [1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0]; + const result = skip_zeros(vector); + assert(result.skipped_count == 8); + assert(result.processed_count == 8); + assert(result.mask == 0xAAAA); } test "skip_threshold_mixed" { - given vector = [_]i8{1, 0, 2, 0, 10, 0, 4, 0, 5, 0, 20, 0, 7, 0, 8, 0} - try std.testing.expect(result = skip_threshold(vector, 5)); - try std.testing.expect(result.skipped_count == 5); + const vector : [16]i8 = [1, 0, 2, 0, 10, 0, 4, 0, 5, 0, 20, 0, 7, 0, 8, 0]; + const result = skip_threshold(vector, 5); + assert(result.skipped_count == 5); } test "skip_all" { - given vector = [_]i8{1} ** 16 - try std.testing.expect(result = skip_all(vector)); - try std.testing.expect(result.skipped_count == 16); - try std.testing.expect(result.processed_count == 0); - try std.testing.expect(result.mask == 0); + const vector : [16]i8 = [1; 16]; + const result = skip_all(vector); + assert(result.skipped_count == 16); + assert(result.processed_count == 0); + assert(result.mask == 0); } test "skip_none" { - given vector = [_]i8{1} ** 16 - try std.testing.expect(result = skip_none(vector)); - try std.testing.expect(result.skipped_count == 0); - try std.testing.expect(result.processed_count == 16); - try std.testing.expect(result.mask == 0xFFFF); + const vector : [16]i8 = [1; 16]; + const result = skip_none(vector); + assert(result.skipped_count == 0); + assert(result.processed_count == 16); + assert(result.mask == 0xFFFF); } test "create_sparse_vector" { - given vector = [_]i8{1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0} - try std.testing.expect(sparse = create_sparse_vector(vector)); - try std.testing.expect(sparse.mask == 0xAAAA); - try std.testing.expect(sparse.zero_count == 8); + const vector : [16]i8 = [1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0]; + const sparse = create_sparse_vector(vector); + assert(sparse.mask == 0xAAAA); + assert(sparse.zero_count == 8); } test "get_non_zero_elements" { - given vector = [_]i8{1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0} - try std.testing.expect(sparse = create_sparse_vector(vector)); - try std.testing.expect(non_zeros = get_non_zero_elements(sparse)); - try std.testing.expect(non_zeros[0] == 1); - try std.testing.expect(non_zeros[1] == 2); - try std.testing.expect(non_zeros[2] == 3); - try std.testing.expect(non_zeros[7] == 0); + const vector : [16]i8 = [1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0]; + const sparse = create_sparse_vector(vector); + const non_zeros = get_non_zero_elements(sparse); + assert(non_zeros[0] == 1); + assert(non_zeros[1] == 2); + assert(non_zeros[2] == 3); + assert(non_zeros[7] == 0); } test "encode_sparse_skip" { - given encoded = encode_sparse_skip(1, 0x20) - try std.testing.expect((encoded >> 8) == OP_SPARSE_SKIP); + const encoded = encode_sparse_skip(1, 0x20); + assert((encoded >> 8) == OP_SPARSE_SKIP); } test "decode_sparse_skip" { - given decoded = decode_sparse_skip(0xE150) - try std.testing.expect(decoded.mode == 1); - try std.testing.expect(decoded.vector_addr == 0x10); + const decoded = decode_sparse_skip(0xE150); + assert(decoded.mode == 1); + assert(decoded.vector_addr == 0x10); } test "opcode_constant" { - try std.testing.expect(OP_SPARSE_SKIP == 0xE1); + assert(OP_SPARSE_SKIP == 0xE1); } // ============================================================================ // Invariants // ============================================================================ -} invariant vector_size_sixteen assert VECTOR_SIZE == 16 @@ -417,58 +422,59 @@ invariant skip_mode_all_three assert SKIP_ALL == 3 invariant zero_count_plus_non_zero_equals_size - given vector = [_]i8{1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0} + given vector = [1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0] assert count_zeros(vector) + count_non_zeros(vector) == VECTOR_SIZE invariant skip_all_skips_all - try std.testing.expect(skip_all([_]i8{1} ** 16).skipped_count == VECTOR_SIZE); + assert skip_all([1; 16]).skipped_count == VECTOR_SIZE invariant skip_none_skips_none - try std.testing.expect(skip_none([_]i8{1} ** 16).skipped_count == 0); + assert skip_none([1; 16]).skipped_count == 0 invariant processed_plus_skipped_equals_size - given vector = [_]i8{1, 0, 2, 0, 3, 0, 4, 0} - try std.testing.expect(result = skip_zeros(vector)); + given vector = [1, 0, 2, 0, 3, 0, 4, 0] + when result = skip_zeros(vector) assert result.skipped_count + result.processed_count == VECTOR_SIZE invariant sparsity_ratio_bound - given vector = [_]i8{1} ** 16 - try std.testing.expect(pattern = analyze_sparsity(vector)); - try std.testing.expect(pattern.sparsity_ratio <= 100); - -invariant mask_bits_processed_equals_processed_count - given vector = [_]i8{1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0} - try std.testing.expect(result = skip_zeros(vector)); - var mask_bits : u8 = 0 - for (0..VECTOR_SIZE) |i| { + given vector = [1; 16] + when pattern = analyze_sparsity(vector) + assert pattern.sparsity_ratio <= 100 + +invariant mask_bits_processed_equals_processed_count { + const vector : [16]i8 = [1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0]; + const result = skip_zeros(vector); + var mask_bits : u8 = 0; + for i in 0..VECTOR_SIZE { if ((result.mask >> i) & 1 != 0) { mask_bits += 1; } } - assert mask_bits == result.processed_count + assert(mask_bits == result.processed_count); +} // ============================================================================ // Benchmarks // ============================================================================ bench count_zeros_latency - measure: nanoseconds to count_zeros([_]i8{1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0}) + measure: nanoseconds to count_zeros([1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0]) target: < 100ns bench analyze_sparsity_latency - measure: nanoseconds to analyze_sparsity([_]i8{1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0}) + measure: nanoseconds to analyze_sparsity([1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0]) target: < 150ns bench skip_zeros_latency - measure: nanoseconds to skip_zeros([_]i8{1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0}) + measure: nanoseconds to skip_zeros([1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0]) target: < 150ns bench skip_threshold_latency - measure: nanoseconds to skip_threshold([_]i8{1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0}, 5) + measure: nanoseconds to skip_threshold([1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0], 5) target: < 150ns bench create_sparse_vector_latency - measure: nanoseconds to create_sparse_vector([_]i8{1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0}) + measure: nanoseconds to create_sparse_vector([1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0]) target: < 150ns bench encode_sparse_skip_latency diff --git a/specs/fpga/spec_exit.t27 b/specs/fpga/spec_exit.t27 index d716d9c..8edeed9 100644 --- a/specs/fpga/spec_exit.t27 +++ b/specs/fpga/spec_exit.t27 @@ -204,7 +204,7 @@ pub fn spec_context_init() -> SpecContext { // spec_context_enter_speculation(context: SpecContext, depth_limit: u8) -> SpecContext // Enter speculation pub fn spec_context_enter_speculation(context: SpecContext, depth_limit: u8) -> SpecContext { - if (not spec_state_can_speculate(context.state)) { + if (!spec_state_can_speculate(context.state)) { return context; } if (context.current_depth >= depth_limit) { @@ -289,220 +289,219 @@ pub fn decode_spec_exit(encoded: u32) -> struct { reason: u8, depth: u8, checkpo // ============================================================================ test "max_nesting_depth_eight" { - try std.testing.expect(MAX_NESTING_DEPTH == 8); + assert(MAX_NESTING_DEPTH == 8); } test "exit_reason_constants" { - try std.testing.expect(EXIT_SUCCESS == 0); - try std.testing.expect(EXIT_ABORT == 5); - try std.testing.expect(EXIT_RECOVER == 6); + assert(EXIT_SUCCESS == 0); + assert(EXIT_ABORT == 5); + assert(EXIT_RECOVER == 6); } test "state_constants" { - try std.testing.expect(STATE_RUNNING == 0); - try std.testing.expect(STATE_EXITED == 3); - try std.testing.expect(STATE_ERROR == 5); + assert(STATE_RUNNING == 0); + assert(STATE_EXITED == 3); + assert(STATE_ERROR == 5); } test "spec_state_is_running_true" { - try std.testing.expect(spec_state_is_running(SpecState.running) == true); + assert(spec_state_is_running(SpecState.running) == true); } test "spec_state_is_running_false" { - try std.testing.expect(spec_state_is_running(SpecState.speculating) == false); + assert(spec_state_is_running(SpecState.speculating) == false); } test "spec_state_is_terminal_true" { - try std.testing.expect(spec_state_is_terminal(SpecState.exited) == true); - try std.testing.expect(spec_is_terminal(SpecState.error) == true); + assert(spec_state_is_terminal(SpecState.exited) == true); + assert(spec_state_is_terminal(SpecState.error) == true); } test "spec_state_is_terminal_false" { - try std.testing.expect(spec_state_is_terminal(SpecState.running) == false); + assert(spec_state_is_terminal(SpecState.running) == false); } test "spec_state_can_speculate_true" { - try std.testing.expect(spec_state_can_speculate(SpecState.running) == true); - try std.testing.expect(spec_state_can_speculate(SpecState.recovering) == true); + assert(spec_state_can_speculate(SpecState.running) == true); + assert(spec_state_can_speculate(SpecState.recovering) == true); } test "spec_state_can_speculate_false" { - try std.testing.expect(spec_state_can_speculate(SpecState.exiting) == false); - try std.testing.expect(spec_state_can_speculate(SpecState.error) == false); + assert(spec_state_can_speculate(SpecState.exiting) == false); + assert(spec_state_can_speculate(SpecState.error) == false); } test "spec_exit_success_structure" { - given exit = spec_exit_success(5, 0x1000) - try std.testing.expect(exit.reason == ExitReason.success); - try std.testing.expect(exit.depth == 5); - try std.testing.expect(exit.recovery_possible == true); + const exit = spec_exit_success(5, 0x1000); + assert(exit.reason == ExitReason.success); + assert(exit.depth == 5); + assert(exit.recovery_possible == true); } test "spec_exit_fail_structure" { - given exit = spec_exit_fail(ExitReason.exception, 3, 0x2000, true) - try std.testing.expect(exit.reason == ExitReason.exception); - try std.testing.expect(exit.recovery_possible == true); + const exit = spec_exit_fail(ExitReason.exception, 3, 0x2000, true); + assert(exit.reason == ExitReason.exception); + assert(exit.recovery_possible == true); } test "spec_exit_abort_no_recovery" { - given exit = spec_exit_abort(5) - try std.testing.expect(exit.reason == ExitReason.abort); - try std.testing.expect(exit.recovery_possible == false); + const exit = spec_exit_abort(5); + assert(exit.reason == ExitReason.abort); + assert(exit.recovery_possible == false); } test "spec_exit_recover_structure" { - given exit = spec_exit_recover(3, 0x3000) - try std.testing.expect(exit.reason == ExitReason.recover); - try std.testing.expect(exit.recovery_possible == true); + const exit = spec_exit_recover(3, 0x3000); + assert(exit.reason == ExitReason.recover); + assert(exit.recovery_possible == true); } test "spec_context_init_structure" { - given context = spec_context_init() - try std.testing.expect(context.state == SpecState.running); - try std.testing.expect(context.current_depth == 0); - try std.testing.expect(context.spec_count == 0); + const context = spec_context_init(); + assert(context.state == SpecState.running); + assert(context.current_depth == 0); + assert(context.spec_count == 0); } test "spec_context_enter_speculation" { - given context = spec_context_init() - try std.testing.expect(result = spec_context_enter_speculation(context, 8)); - try std.testing.expect(result.state == SpecState.speculating); - try std.testing.expect(result.current_depth == 1); + const context = spec_context_init(); + const result = spec_context_enter_speculation(context, 8); + assert(result.state == SpecState.speculating); + assert(result.current_depth == 1); } test "spec_context_enter_depth_limit" { - given context = spec_context_init() - try std.testing.expect(deep = spec_context_enter_speculation(spec_context_enter_speculation(context, 8), 8)); - try std.testing.expect(deep.current_depth == 2); + const context = spec_context_init(); + const deep = spec_context_enter_speculation(spec_context_enter_speculation(context, 8), 8); + assert(deep.current_depth == 2); } test "spec_context_enter_depth_limit_exceeded" { - given context = SpecContext{.state = SpecState.running, .current_depth = 8, .spec_count = 0, .exit_count = 0} - try std.testing.expect(result = spec_context_enter_speculation(context, 8)); - try std.testing.expect(result.current_depth == 8); + const context = SpecContext{.state = SpecState.running, .current_depth = 8, .spec_count = 0, .exit_count = 0}; + const result = spec_context_enter_speculation(context, 8); + assert(result.current_depth == 8); } test "spec_context_exit_success" { - given context = spec_context_init() - try std.testing.expect(exit = spec_exit_success(5, 0x1000)); - try std.testing.expect(result = spec_context_exit(context, exit)); - try std.testing.expect(result.state == SpecState.exiting); + const context = spec_context_init(); + const exit = spec_exit_success(5, 0x1000); + const result = spec_context_exit(context, exit); + assert(result.state == SpecState.exiting); } test "spec_context_exit_fail_recover" { - given context = spec_context_init() - try std.testing.expect(exit = spec_exit_fail(ExitReason.exception, 3, 0x2000, true)); - try std.testing.expect(result = spec_context_exit(context, exit)); - try std.testing.expect(result.state == SpecState.recovering); + const context = spec_context_init(); + const exit = spec_exit_fail(ExitReason.exception, 3, 0x2000, true); + const result = spec_context_exit(context, exit); + assert(result.state == SpecState.recovering); } test "spec_context_exit_fail_no_recover" { - given context = spec_context_init() - try std.testing.expect(exit = spec_exit_fail(ExitReason.abort, 3, 0, false)); - try std.testing.expect(result = spec_context_exit(context, exit)); - try std.testing.expect(result.state == SpecState.error); + const context = spec_context_init(); + const exit = spec_exit_fail(ExitReason.abort, 3, 0, false); + const result = spec_context_exit(context, exit); + assert(result.state == SpecState.error); } test "spec_context_complete" { - given context = spec_context_init() - try std.testing.expect(result = spec_context_complete(context)); - try std.testing.expect(result.state == SpecState.exited); - try std.testing.expect(result.current_depth == 0); + const context = spec_context_init(); + const result = spec_context_complete(context); + assert(result.state == SpecState.exited); + assert(result.current_depth == 0); } test "spec_context_check_timeout_true" { - given context = SpecContext{.state = SpecState.speculating, .current_depth = 3, .spec_count = 10, .exit_count = 0} - try std.testing.expect(config = SpecConfig{.max_depth = 8, .timeout_cycles = 500, .enable_recovery = true, .checkpoint_interval = 1}); - try std.testing.expect(spec_context_check_timeout(context, config, 1000) == true); + const context = SpecContext{.state = SpecState.speculating, .current_depth = 3, .spec_count = 10, .exit_count = 0}; + const config = SpecConfig{.max_depth = 8, .timeout_cycles = 500, .enable_recovery = true, .checkpoint_interval = 1}; + assert(spec_context_check_timeout(context, config, 1000) == true); } test "spec_context_check_timeout_false" { - given context = SpecContext{.state = SpecState.speculating, .current_depth = 3, .spec_count = 1, .exit_count = 0} - try std.testing.expect(config = SpecConfig{.max_depth = 8, .timeout_cycles = 500, .enable_recovery = true, .checkpoint_interval = 1}); - try std.testing.expect(spec_context_check_timeout(context, config, 1000) == false); + const context = SpecContext{.state = SpecState.speculating, .current_depth = 3, .spec_count = 1, .exit_count = 0}; + const config = SpecConfig{.max_depth = 8, .timeout_cycles = 500, .enable_recovery = true, .checkpoint_interval = 1}; + assert(spec_context_check_timeout(context, config, 1000) == false); } test "encode_spec_exit" { - given encoded = encode_spec_exit(1, 5, 0x1234) - try std.testing.expect((encoded >> 24) == OP_SPEC_EXIT); + const encoded = encode_spec_exit(1, 5, 0x1234); + assert((encoded >> 24) == OP_SPEC_EXIT); } test "decode_spec_exit" { - given decoded = decode_spec_exit(0xEB081234) - try std.testing.expect(decoded.reason == 1); - try std.testing.expect(decoded.depth == 5); - try std.testing.expect(decoded.checkpoint == 0x1234); + const decoded = decode_spec_exit(0xEB081234); + assert(decoded.reason == 1); + assert(decoded.depth == 5); + assert(decoded.checkpoint == 0x1234); } test "opcode_constant" { - try std.testing.expect(OP_SPEC_EXIT == 0xEB); + assert(OP_SPEC_EXIT == 0xEB); } // ============================================================================ // Invariants // ============================================================================ -} invariant max_nesting_depth_eight assert MAX_NESTING_DEPTH == 8 invariant exit_reason_values - try std.testing.expect(EXIT_SUCCESS >= 0 and EXIT_MAX <= 7); + assert EXIT_SUCCESS >= 0 and EXIT_MAX <= 7 invariant state_values - try std.testing.expect(STATE_RUNNING >= 0 and STATE_ERROR <= 5); + assert STATE_RUNNING >= 0 and STATE_ERROR <= 5 invariant spec_exit_success_recoverable given exit = spec_exit_success(0, 0x1000) - try std.testing.expect(exit.recovery_possible == true); + assert exit.recovery_possible == true invariant spec_exit_abort_not_recoverable given exit = spec_exit_abort(5) - try std.testing.expect(exit.recovery_possible == false); + assert exit.recovery_possible == false invariant spec_exit_depth_bound - try std.testing.expect(spec_exit_abort(0).depth == 0); - try std.testing.expect(spec_exit_abort(MAX_NESTING_DEPTH).depth == MAX_NESTING_DEPTH); + assert spec_exit_abort(0).depth == 0 + assert spec_exit_abort(MAX_NESTING_DEPTH).depth == MAX_NESTING_DEPTH invariant spec_context_init_zero_depth given context = spec_context_init() - try std.testing.expect(context.current_depth == 0); + assert context.current_depth == 0 invariant spec_context_enter_increases_depth given context = spec_context_init() - try std.testing.expect(result = spec_context_enter_speculation(context, 8)); - try std.testing.expect(result.current_depth == context.current_depth + 1); + and result = spec_context_enter_speculation(context, 8) + assert result.current_depth == context.current_depth + 1 invariant spec_context_exit_preserves_reason given context = spec_context_init() - try std.testing.expect(exit = spec_exit_fail(ExitReason.exception, 3, 0x2000, true)); - try std.testing.expect(result = spec_context_exit(context, exit)); - try std.testing.expect(exit.reason == ExitReason.exception); + and exit = spec_exit_fail(ExitReason.exception, 3, 0x2000, true) + and result = spec_context_exit(context, exit) + assert exit.reason == ExitReason.exception invariant spec_context_complete_zero_depth given context = SpecContext{.state = SpecState.running, .current_depth = 5, .spec_count = 10, .exit_count = 0} - try std.testing.expect(result = spec_context_complete(context)); - try std.testing.expect(result.current_depth == 0); + and result = spec_context_complete(context) + assert result.current_depth == 0 invariant spec_context_complete_exited_state given context = spec_context_init() - try std.testing.expect(result = spec_context_complete(context)); - try std.testing.expect(result.state == SpecState.exited); + and result = spec_context_complete(context) + assert result.state == SpecState.exited invariant spec_context_check_timeout_no_timeout given config = SpecConfig{.max_depth = 8, .timeout_cycles = 0, .enable_recovery = true, .checkpoint_interval = 1} - try std.testing.expect(context = SpecContext{.state = SpecState.speculating, .current_depth = 3, .spec_count = 1000, .exit_count = 0}); - try std.testing.expect(spec_context_check_timeout(context, config, 1000) == false); + and context = SpecContext{.state = SpecState.speculating, .current_depth = 3, .spec_count = 1000, .exit_count = 0} + assert spec_context_check_timeout(context, config, 1000) == false invariant spec_context_enter_speculate_requires_running_or_recovering given context = SpecContext{.state = SpecState.exiting, .current_depth = 0, .spec_count = 0, .exit_count = 0} - try std.testing.expect(spec_context_enter_speculation(context, 8).current_depth == 0); + assert spec_context_enter_speculation(context, 8).current_depth == 0 invariant spec_context_exit_increases_exit_count given context = spec_context_init() - try std.testing.expect(exit = spec_exit_success(0, 0x1000)); - try std.testing.expect(result = spec_context_exit(context, exit)); - try std.testing.expect(result.exit_count == context.exit_count + 1); + and exit = spec_exit_success(0, 0x1000) + and result = spec_context_exit(context, exit) + assert result.exit_count == context.exit_count + 1 // ============================================================================ // Benchmarks diff --git a/specs/fpga/stoch_round.t27 b/specs/fpga/stoch_round.t27 index 7bb7a55..77aa752 100644 --- a/specs/fpga/stoch_round.t27 +++ b/specs/fpga/stoch_round.t27 @@ -46,32 +46,55 @@ pub const RngState = struct { state : u16, } +// Named forms of the anonymous `struct { ... }` return types used below (same +// fields, same types); `.{ ... }` return literals are spelled with these names. +pub const RngStep = struct { + state : RngState, + value : u8, +} + +pub const StochRoundStep = struct { + result : RoundResult, + new_state : RngState, +} + +pub const VectorStochStep = struct { + results : [8]RoundResult, + new_state : RngState, +} + +pub const StochRoundFields = struct { + mode : u8, + target_bits : u8, + seed : u8, +} + // ============================================================================ // RNG Functions (XorShift LFSR) // ============================================================================ // rng_init(seed: u16) -> RngState // Initialize RNG with seed -pub fn rng_init(seed: u16) RngState { +pub fn rng_init(seed: u16) -> RngState { return RngState{.state = if (seed == 0) 1 else seed}; } // rng_next(state: RngState) -> struct { state: RngState, value: u8 } // Get next random byte -pub fn rng_next(state: RngState) -> struct { state: RngState, value: u8 } { +pub fn rng_next(state: RngState) -> RngStep { var s = state.state; s ^= s >> 7; s ^= s << 9; s ^= s >> 8; - return .{ .state = RngState{.state = s}, .value = @as(u8, @truncate(s)) }; + return RngStep{ .state = RngState{.state = s}, .value = @as(u8, @truncate(s)) }; } // rng_next_range(state: RngState, max: u8) -> struct { state: RngState, value: u8 } // Get next random value in range [0, max) -pub fn rng_next_range(state: RngState, max: u8) -> struct { state: RngState, value: u8 } { +pub fn rng_next_range(state: RngState, max: u8) -> RngStep { const next_result = rng_next(state); const scaled = (@as(u16, next_result.value) * @as(u16, max)) >> 8; - return .{ .state = next_result.state, .value = @as(u8, @truncate(scaled)) }; + return RngStep{ .state = next_result.state, .value = @as(u8, @truncate(scaled)) }; } // ============================================================================ @@ -115,13 +138,13 @@ pub fn round_nearest(value: i16, bits: u8) -> RoundResult { // round_stochastic(value: i16, bits: u8, state: RngState) -> struct { result: RoundResult, new_state: RngState } // Stochastic rounding -pub fn round_stochastic(value: i16, bits: u8, state: RngState) -> struct { result: RoundResult, new_state: RngState } { +pub fn round_stochastic(value: i16, bits: u8, state: RngState) -> StochRoundStep { const shift = 16 - bits; var result : i16 = 0; if (shift <= 0) { result = value << (-shift); - return .{ .result = RoundResult{.value = result, .original = value, .rounded = false, .overflow = false}, .new_state = state }; + return StochRoundStep{ .result = RoundResult{.value = result, .original = value, .rounded = false, .overflow = false}, .new_state = state }; } const abs_val = if (value < 0) -value else value; @@ -156,7 +179,7 @@ pub fn round_stochastic(value: i16, bits: u8, state: RngState) -> struct { resul overflow = true; } - return .{ .result = RoundResult{.value = result, .original = value, .rounded = result != (abs_val >> shift), .overflow = overflow}, .new_state = rng_result.state }; + return StochRoundStep{ .result = RoundResult{.value = result, .original = value, .rounded = result != (abs_val >> shift), .overflow = overflow}, .new_state = rng_result.state }; } // round_truncate(value: i16, bits: u8) -> RoundResult @@ -237,23 +260,18 @@ pub fn round_ceil(value: i16, bits: u8) -> RoundResult { // round_with_config(value: i16, config: RoundConfig, state: RngState) -> struct { result: RoundResult, new_state: RngState } // Round using config -pub fn round_with_config(value: i16, config: RoundConfig, state: RngState) -> struct { result: RoundResult, new_state: RngState } { - switch (config.mode) { - ROUND_MODE_NEAREST => { - return .{ .result = round_nearest(value, config.target_bits), .new_state = state }; - }, - ROUND_MODE_STOCHASTIC => { - return round_stochastic(value, config.target_bits, state); - }, - ROUND_MODE_TRUNCATE => { - return .{ .result = round_truncate(value, config.target_bits), .new_state = state }; - }, - ROUND_MODE_CEIL => { - return .{ .result = round_ceil(value, config.target_bits), .new_state = state }; - }, - else => { - return .{ .result = RoundResult{.value = 0, .original = value, .rounded = false, .overflow = true}, .new_state = state }; - }, +pub fn round_with_config(value: i16, config: RoundConfig, state: RngState) -> StochRoundStep { + // switch (config.mode) with block arms, written as the equivalent if / else-if chain + if (config.mode == ROUND_MODE_NEAREST) { + return StochRoundStep{ .result = round_nearest(value, config.target_bits), .new_state = state }; + } else if (config.mode == ROUND_MODE_STOCHASTIC) { + return round_stochastic(value, config.target_bits, state); + } else if (config.mode == ROUND_MODE_TRUNCATE) { + return StochRoundStep{ .result = round_truncate(value, config.target_bits), .new_state = state }; + } else if (config.mode == ROUND_MODE_CEIL) { + return StochRoundStep{ .result = round_ceil(value, config.target_bits), .new_state = state }; + } else { + return StochRoundStep{ .result = RoundResult{.value = 0, .original = value, .rounded = false, .overflow = true}, .new_state = state }; } } @@ -263,9 +281,12 @@ pub fn round_with_config(value: i16, config: RoundConfig, state: RngState) -> st // round_vector_nearest(values: [8]i16, bits: u8) -> [8]RoundResult // Round vector to nearest -pub fn round_vector_nearest(values: [8]i16, bits: u8) [8]RoundResult { +pub fn round_vector_nearest(values: [8]i16, bits: u8) -> [8]RoundResult { var results : [8]RoundResult = undefined; - for (values, 0..) |val, i| { + // for (values, 0..) |val, i|: index loop over the same elements + // (values is [8]i16, so the index runs 0..8) + for (0..8) |i| { + const val = values[i]; results[i] = round_nearest(val, bits); } return results; @@ -273,17 +294,20 @@ pub fn round_vector_nearest(values: [8]i16, bits: u8) [8]RoundResult { // round_vector_stochastic(values: [8]i16, bits: u8, state: RngState) -> struct { results: [8]RoundResult, new_state: RngState } // Round vector stochastically -pub fn round_vector_stochastic(values: [8]i16, bits: u8, state: RngState) -> struct { results: [8]RoundResult, new_state: RngState } { +pub fn round_vector_stochastic(values: [8]i16, bits: u8, state: RngState) -> VectorStochStep { var results : [8]RoundResult = undefined; var current_state = state; - for (values, 0..) |val, i| { + // for (values, 0..) |val, i|: index loop over the same elements + // (values is [8]i16, so the index runs 0..8) + for (0..8) |i| { + const val = values[i]; const round_result = round_stochastic(val, bits, current_state); results[i] = round_result.result; current_state = round_result.new_state; } - return .{ .results = results, .new_state = current_state }; + return VectorStochStep{ .results = results, .new_state = current_state }; } // ============================================================================ @@ -292,7 +316,7 @@ pub fn round_vector_stochastic(values: [8]i16, bits: u8, state: RngState) -> str // encode_stoch_round(mode: u8, target_bits: u8, seed: u8) -> u16 // Encode stochastic rounding instruction -pub fn encode_stoch_round(mode: u8, target_bits: u8, seed: u8) u16 { +pub fn encode_stoch_round(mode: u8, target_bits: u8, seed: u8) -> u16 { // Format: [OP:8][MODE:2][BITS:4][SEED:2] const op : u16 = @as(u16, OP_STOCH_ROUND) << 8; const mode_field : u16 = @as(u16, mode & 0x03) << 6; @@ -303,11 +327,11 @@ pub fn encode_stoch_round(mode: u8, target_bits: u8, seed: u8) u16 { // decode_stoch_round(encoded: u16) -> struct { mode: u8, target_bits: u8, seed: u8 } // Decode stochastic rounding instruction -pub fn decode_stoch_round(encoded: u16) struct { mode: u8, target_bits: u8, seed: u8 } { +pub fn decode_stoch_round(encoded: u16) -> StochRoundFields { const mode : u8 = @as(u8, @truncate((encoded >> 6) & 0x03)); const target_bits : u8 = @as(u8, @truncate((encoded >> 2) & 0x0F)); const seed : u8 = @as(u8, @truncate(encoded & 0x03)); - return .{ .mode = mode, .target_bits = target_bits, .seed = seed }; + return StochRoundFields{ .mode = mode, .target_bits = target_bits, .seed = seed }; } // ============================================================================ @@ -315,157 +339,156 @@ pub fn decode_stoch_round(encoded: u16) struct { mode: u8, target_bits: u8, seed // ============================================================================ test "round_mode_constants" { - try std.testing.expect(ROUND_MODE_NEAREST == 0); - try std.testing.expect(ROUND_MODE_STOCHASTIC == 1); - try std.testing.expect(ROUND_MODE_TRUNCATE == 2); - try std.testing.expect(ROUND_MODE_CEIL == 3); + assert(ROUND_MODE_NEAREST == 0); + assert(ROUND_MODE_STOCHASTIC == 1); + assert(ROUND_MODE_TRUNCATE == 2); + assert(ROUND_MODE_CEIL == 3); } test "int4_bounds" { - try std.testing.expect(INT4_MAX == 7 and INT4_MIN == -8); + assert(INT4_MAX == 7 and INT4_MIN == -8); } test "int8_bounds" { - try std.testing.expect(INT8_MAX == 127 and INT8_MIN == -128); + assert(INT8_MAX == 127 and INT8_MIN == -128); } test "round_nearest_basic" { - given result = round_nearest(10, 4) - try std.testing.expect(result.value == 1); + const result = round_nearest(10, 4); + assert(result.value == 1); } test "round_nearest_negative" { - given result = round_nearest(-10, 4) - try std.testing.expect(result.value == -1); + const result = round_nearest(-10, 4); + assert(result.value == -1); } test "round_nearest_overflow" { - given result = round_nearest(0x7FFF, 8) - try std.testing.expect(result.value == INT8_MAX); - try std.testing.expect(result.overflow == true); + const result = round_nearest(0x7FFF, 8); + assert(result.value == INT8_MAX); + assert(result.overflow == true); } test "round_nearest_underflow" { - given result = round_nearest(-0x8000, 8) - try std.testing.expect(result.value == INT8_MIN); - try std.testing.expect(result.overflow == true); + const result = round_nearest(-0x8000, 8); + assert(result.value == INT8_MIN); + assert(result.overflow == true); } test "round_nearest_no_change" { - given result = round_nearest(0x1000, 8) - try std.testing.expect(result.value == 0x10); - try std.testing.expect(result.rounded == false); + const result = round_nearest(0x1000, 8); + assert(result.value == 0x10); + assert(result.rounded == false); } test "round_truncate_basic" { - given result = round_truncate(10, 4) - try std.testing.expect(result.value == 0); + const result = round_truncate(10, 4); + assert(result.value == 0); } test "round_truncate_negative" { - given result = round_truncate(-10, 4) - try std.testing.expect(result.value == 0); + const result = round_truncate(-10, 4); + assert(result.value == 0); } test "round_truncate_fractional" { - given result = round_truncate(15, 4) - try std.testing.expect(result.value == 0); + const result = round_truncate(15, 4); + assert(result.value == 0); } test "round_ceil_basic" { - given result = round_ceil(10, 4) - try std.testing.expect(result.value == 1); + const result = round_ceil(10, 4); + assert(result.value == 1); } test "round_ceil_negative" { - given result = round_ceil(-10, 4) - try std.testing.expect(result.value == 0); + const result = round_ceil(-10, 4); + assert(result.value == 0); } test "round_ceil_fractional" { - given result = round_ceil(1, 4) - try std.testing.expect(result.value == 1); + const result = round_ceil(1, 4); + assert(result.value == 1); } test "round_stochastic_seeded" { - given state = RngState{.state = 0x1234} - try std.testing.expect(round1 = round_stochastic(10, 4, state)); - try std.testing.expect(state2 = RngState{.state = 0x1234}); - try std.testing.expect(round2 = round_stochastic(10, 4, state2)); - try std.testing.expect(round1.result.value == round2.result.value); - try std.testing.expect(round1.new_state == round2.new_state); + const state = RngState{.state = 0x1234}; + const round1 = round_stochastic(10, 4, state); + const state2 = RngState{.state = 0x1234}; + const round2 = round_stochastic(10, 4, state2); + assert(round1.result.value == round2.result.value); + assert(round1.new_state == round2.new_state); } test "round_stochastic_reproducible" { - given state = RngState{.state = 0x1234} - try std.testing.expect(round1 = round_stochastic(10, 4, state)); - try std.testing.expect(round2 = round_stochastic(10, 4, round1.new_state)); - try std.testing.expect(round2.result.value != round1.result.value or round2.new_state != round1.new_state); + const state = RngState{.state = 0x1234}; + const round1 = round_stochastic(10, 4, state); + const round2 = round_stochastic(10, 4, round1.new_state); + assert(round2.result.value != round1.result.value or round2.new_state != round1.new_state); } test "round_vector_nearest" { - given results = round_vector_nearest([_]i16{10, 20, 30, 40, 50, 60, 70, 80}, 4) - try std.testing.expect(results[0].value == 1); - try std.testing.expect(results[7].value == 5); + const results = round_vector_nearest([_]i16{10, 20, 30, 40, 50, 60, 70, 80}, 4); + assert(results[0].value == 1); + assert(results[7].value == 5); } test "round_vector_stochastic" { - given state = RngState{.state = 0x1234} - try std.testing.expect(round_result = round_vector_stochastic([_]i16{10, 20, 30, 40}, 4, state)); - try std.testing.expect(round_result.new_state.state != 0x1234); + const state = RngState{.state = 0x1234}; + const round_result = round_vector_stochastic([_]i16{10, 20, 30, 40}, 4, state); + assert(round_result.new_state.state != 0x1234); } test "rng_init_default" { - given state = rng_init(0) - try std.testing.expect(state.state == 1); + const state = rng_init(0); + assert(state.state == 1); } test "rng_init_with_seed" { - given state = rng_init(0x1234) - try std.testing.expect(state.state == 0x1234); + const state = rng_init(0x1234); + assert(state.state == 0x1234); } test "rng_next_range" { - given state = rng_init(0x1234) - try std.testing.expect(result = rng_next_range(state, 100)); - try std.testing.expect(result.value <= 100); + const state = rng_init(0x1234); + const result = rng_next_range(state, 100); + assert(result.value <= 100); } test "round_with_config_nearest" { - given config = RoundConfig{.mode = ROUND_MODE_NEAREST, .target_bits = 8, .seed = 0} - try std.testing.expect(state = RngState{.state = 1}); - try std.testing.expect(result = round_with_config(10, config, state)); - try std.testing.expect(result.result.value == 10); + const config = RoundConfig{.mode = ROUND_MODE_NEAREST, .target_bits = 8, .seed = 0}; + const state = RngState{.state = 1}; + const result = round_with_config(10, config, state); + assert(result.result.value == 10); } test "round_with_config_stochastic" { - given config = RoundConfig{.mode = ROUND_MODE_STOCHASTIC, .target_bits = 4, .seed = 0} - try std.testing.expect(state = RngState{.state = 1}); - try std.testing.expect(result = round_with_config(10, config, state)); - try std.testing.expect(result.result.value <= INT4_MAX); + const config = RoundConfig{.mode = ROUND_MODE_STOCHASTIC, .target_bits = 4, .seed = 0}; + const state = RngState{.state = 1}; + const result = round_with_config(10, config, state); + assert(result.result.value <= INT4_MAX); } test "encode_stoch_round" { - given encoded = encode_stoch_round(1, 4, 2) - try std.testing.expect((encoded >> 8) == OP_STOCH_ROUND); + const encoded = encode_stoch_round(1, 4, 2); + assert((encoded >> 8) == OP_STOCH_ROUND); } test "decode_stoch_round" { - given decoded = decode_stoch_round(0xE932) - try std.testing.expect(decoded.mode == 1); - try std.testing.expect(decoded.target_bits == 4); - try std.testing.expect(decoded.seed == 2); + const decoded = decode_stoch_round(0xE932); + assert(decoded.mode == 1); + assert(decoded.target_bits == 4); + assert(decoded.seed == 2); } test "opcode_constant" { - try std.testing.expect(OP_STOCH_ROUND == 0xE9); + assert(OP_STOCH_ROUND == 0xE9); } // ============================================================================ // Invariants // ============================================================================ -} invariant random_bits_eight assert RANDOM_BITS == 8 @@ -476,63 +499,63 @@ invariant int8_bits_eight assert INT8_BITS == 8 invariant int4_max_min_relation - try std.testing.expect(INT4_MAX == -INT4_MIN - 1); + assert INT4_MAX == -INT4_MIN - 1 invariant int8_max_min_relation - try std.testing.expect(INT8_MAX == -INT8_MIN - 1); + assert INT8_MAX == -INT8_MIN - 1 invariant round_mode_values - try std.testing.expect(ROUND_MODE_NEAREST >= 0 and ROUND_MODE_CEIL <= 3); + assert ROUND_MODE_NEAREST >= 0 and ROUND_MODE_CEIL <= 3 invariant round_nearest_range given result = round_nearest(0, 4) - try std.testing.expect(result.value >= -8 and result.value <= 7); + then result.value >= -8 and result.value <= 7 invariant round_truncate_range given result = round_truncate(0, 4) - try std.testing.expect(result.value >= -8 and result.value <= 7); + then result.value >= -8 and result.value <= 7 invariant round_ceil_range given result = round_ceil(0, 4) - try std.testing.expect(result.value >= -8 and result.value <= 7); + then result.value >= -8 and result.value <= 7 invariant round_stochastic_range given state = RngState{.state = 1} - try std.testing.expect(result = round_stochastic(0, 4, state)); - try std.testing.expect(result.result.value >= INT4_MIN and result.result.value <= INT4_MAX); + and result = round_stochastic(0, 4, state) + then result.result.value >= INT4_MIN and result.result.value <= INT4_MAX invariant round_nearest_preserves_sign given result_pos = round_nearest(100, 4) - try std.testing.expect(result_neg = round_nearest(-100, 4)); - try std.testing.expect(result_pos.value >= 0 and result_neg.value <= 0); + and result_neg = round_nearest(-100, 4) + then result_pos.value >= 0 and result_neg.value <= 0 invariant round_truncate_preserves_sign given result_pos = round_truncate(100, 4) - try std.testing.expect(result_neg = round_truncate(-100, 4)); - try std.testing.expect(result_pos.value >= 0 and result_neg.value <= 0); + and result_neg = round_truncate(-100, 4) + then result_pos.value >= 0 and result_neg.value <= 0 invariant round_ceil_non_negative given result = round_ceil(0, 4) - try std.testing.expect(result.value >= 0); + then result.value >= 0 invariant rng_next_state_changes given state = RngState{.state = 0x1234} - try std.testing.expect(result = rng_next(state)); - try std.testing.expect(result.state.state != state.state); + and result = rng_next(state) + then result.state.state != state.state invariant rng_next_range_value_bound given state = RngState{.state = 1} - try std.testing.expect(result = rng_next_range(state, 100)); - try std.testing.expect(result.value <= 100); + and result = rng_next_range(state, 100) + then result.value <= 100 invariant round_vector_nearest_length given results = round_vector_nearest([_]i16{0} ** 8, 4) - try std.testing.expect(results.len == 8); + then results.len == 8 invariant round_vector_stochastic_length given state = RngState{.state = 1} - try std.testing.expect(result = round_vector_stochastic([_]i16{0} ** 8, 4, state)); - try std.testing.expect(result.results.len == 8); + and result = round_vector_stochastic([_]i16{0} ** 8, 4, state) + then result.results.len == 8 // ============================================================================ // Benchmarks diff --git a/specs/fpga/subth_clk.t27 b/specs/fpga/subth_clk.t27 index 4d3fdd5..848bc44 100644 --- a/specs/fpga/subth_clk.t27 +++ b/specs/fpga/subth_clk.t27 @@ -119,7 +119,7 @@ pub fn clk_domain_decay(domain: ClkDomain) ClkDomain { // is_subthreshold(voltage_mv: u16, config: SubthConfig) -> bool // Check if voltage is in sub-threshold region pub fn is_subthreshold(voltage_mv: u16, config: SubthConfig) bool { - if (not config.enable_subth) { + if (!config.enable_subth) { return false; } return voltage_mv < config.threshold_mv; @@ -182,8 +182,9 @@ pub fn power_state_deeper(a: PowerState, b: PowerState) PowerState { // power_state_sleep_ok(domains: [NUM_CLK_DOMAINS]ClkDomain, current_cycle: u32) -> bool // Check if all domains can go to sleep pub fn power_state_sleep_ok(domains: [NUM_CLK_DOMAINS]ClkDomain, current_cycle: u32) bool { - for (domains) |domain| { - if (not clk_domain_is_idle(domain, current_cycle, 100)) { + for i in 0..NUM_CLK_DOMAINS { + const domain = domains[i]; + if (!clk_domain_is_idle(domain, current_cycle, 100)) { return false; } } @@ -217,207 +218,206 @@ pub fn decode_subth_clk(encoded: u16) struct { domain_id: u8, mode: u8 } { // ============================================================================ test "num_clk_domains_eight" { - try std.testing.expect(NUM_CLK_DOMAINS == 8); + assert(NUM_CLK_DOMAINS == 8); } test "subth_threshold_four_hundred" { - try std.testing.expect(SUBTH_THRESHOLD_MV == 400); + assert(SUBTH_THRESHOLD_MV == 400); } test "normal_voltage_eleven_hundred" { - try std.testing.expect(NORMAL_VOLTAGE_MV == 1100); + assert(NORMAL_VOLTAGE_MV == 1100); } test "clk_gate_mode_off" { - try std.testing.expect(@intFromEnum(ClkGateMode.off) == 0); + assert(@intFromEnum(ClkGateMode.off) == 0); } test "clk_gate_mode_on" { - try std.testing.expect(@intFromEnum(ClkGateMode.on) == 1); + assert(@intFromEnum(ClkGateMode.on) == 1); } test "clk_gate_mode_auto" { - try std.testing.expect(@intFromEnum(ClkGateMode.auto) == 2); + assert(@intFromEnum(ClkGateMode.auto) == 2); } test "power_state_active" { - try std.testing.expect(@intFromEnum(PowerState.active) == 0); + assert(@intFromEnum(PowerState.active) == 0); } test "power_state_deep_sleep" { - try std.testing.expect(@intFromEnum(PowerState.deep_sleep) == 3); + assert(@intFromEnum(PowerState.deep_sleep) == 3); } test "clk_domain_enabled_true" { - given domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 0} - try std.testing.expect(clk_domain_enabled(domain) == true); + const domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 0}; + assert(clk_domain_enabled(domain) == true); } test "clk_domain_enabled_false_gate_off" { - given domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.off, .activity_count = 0, .last_active_cycle = 0} - try std.testing.expect(clk_domain_enabled(domain) == false); + const domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.off, .activity_count = 0, .last_active_cycle = 0}; + assert(clk_domain_enabled(domain) == false); } test "clk_domain_enabled_false_disabled" { - given domain = ClkDomain{.id = 0, .enabled = false, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 0} - try std.testing.expect(clk_domain_enabled(domain) == false); + const domain = ClkDomain{.id = 0, .enabled = false, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 0}; + assert(clk_domain_enabled(domain) == false); } test "clk_domain_gate_active_off" { - given domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.off, .activity_count = 10, .last_active_cycle = 0} - try std.testing.expect(clk_domain_gate_active(domain) == true); + const domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.off, .activity_count = 10, .last_active_cycle = 0}; + assert(clk_domain_gate_active(domain) == true); } test "clk_domain_gate_active_auto_idle" { - given domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.auto, .activity_count = 0, .last_active_cycle = 0} - try std.testing.expect(clk_domain_gate_active(domain) == true); + const domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.auto, .activity_count = 0, .last_active_cycle = 0}; + assert(clk_domain_gate_active(domain) == true); } test "clk_domain_gate_active_auto_active" { - given domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.auto, .activity_count = 10, .last_active_cycle = 0} - try std.testing.expect(clk_domain_gate_active(domain) == false); + const domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.auto, .activity_count = 10, .last_active_cycle = 0}; + assert(clk_domain_gate_active(domain) == false); } test "clk_domain_is_idle_true" { - given domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 0} - try std.testing.expect(clk_domain_is_idle(domain, 200, 100) == true); + const domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 0}; + assert(clk_domain_is_idle(domain, 200, 100) == true); } test "clk_domain_is_idle_false_active" { - given domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 10, .last_active_cycle = 0} - try std.testing.expect(clk_domain_is_idle(domain, 200, 100) == false); + const domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 10, .last_active_cycle = 0}; + assert(clk_domain_is_idle(domain, 200, 100) == false); } test "clk_domain_is_idle_false_recent" { - given domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 150} - try std.testing.expect(clk_domain_is_idle(domain, 200, 100) == false); + const domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 150}; + assert(clk_domain_is_idle(domain, 200, 100) == false); } test "clk_domain_pulse" { - given domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 0} - try std.testing.expect(result = clk_domain_pulse(domain, 100)); - try std.testing.expect(result.activity_count == 1); - try std.testing.expect(result.last_active_cycle == 100); + const domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 0}; + const result = clk_domain_pulse(domain, 100); + assert(result.activity_count == 1); + assert(result.last_active_cycle == 100); } test "clk_domain_decay" { - given domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 5, .last_active_cycle = 0} - try std.testing.expect(result = clk_domain_decay(domain)); - try std.testing.expect(result.activity_count == 4); + const domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 5, .last_active_cycle = 0}; + const result = clk_domain_decay(domain); + assert(result.activity_count == 4); } test "clk_domain_decay_zero" { - given domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 0} - try std.testing.expect(result = clk_domain_decay(domain)); - try std.testing.expect(result.activity_count == 0); + const domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 0}; + const result = clk_domain_decay(domain); + assert(result.activity_count == 0); } test "is_subthreshold_true" { - given config = SubthConfig{.threshold_mv = 400, .hysteresis_mv = 20, .enable_subth = true, .transition_cycles = 10} - try std.testing.expect(is_subthreshold(300, config) == true); + const config = SubthConfig{.threshold_mv = 400, .hysteresis_mv = 20, .enable_subth = true, .transition_cycles = 10}; + assert(is_subthreshold(300, config) == true); } test "is_subthreshold_false_disabled" { - given config = SubthConfig{.threshold_mv = 400, .hysteresis_mv = 20, .enable_subth = false, .transition_cycles = 10} - try std.testing.expect(is_subthreshold(300, config) == false); + const config = SubthConfig{.threshold_mv = 400, .hysteresis_mv = 20, .enable_subth = false, .transition_cycles = 10}; + assert(is_subthreshold(300, config) == false); } test "is_subthreshold_false_high_voltage" { - given config = SubthConfig{.threshold_mv = 400, .hysteresis_mv = 20, .enable_subth = true, .transition_cycles = 10} - try std.testing.expect(is_subthreshold(500, config) == false); + const config = SubthConfig{.threshold_mv = 400, .hysteresis_mv = 20, .enable_subth = true, .transition_cycles = 10}; + assert(is_subthreshold(500, config) == false); } test "voltage_within_range_true" { - try std.testing.expect(voltage_within_range(1100, 1100, 50) == true); + assert(voltage_within_range(1100, 1100, 50) == true); } test "voltage_within_range_low" { - try std.testing.expect(voltage_within_range(1060, 1100, 50) == true); + assert(voltage_within_range(1060, 1100, 50) == true); } test "voltage_within_range_high" { - try std.testing.expect(voltage_within_range(1140, 1100, 50) == true); + assert(voltage_within_range(1140, 1100, 50) == true); } test "voltage_within_range_false" { - try std.testing.expect(voltage_within_range(1000, 1100, 50) == false); + assert(voltage_within_range(1000, 1100, 50) == false); } test "subth_power_estimate_normal" { - try std.testing.expect(subth_power_estimate(1100) == 100); + assert(subth_power_estimate(1100) == 100); } test "subth_power_estimate_half" { - try std.testing.expect(subth_power_estimate(550) == 25); + assert(subth_power_estimate(550) == 25); } test "subth_power_estimate_quarter" { - try std.testing.expect(subth_power_estimate(275) == 6); + assert(subth_power_estimate(275) == 6); } test "power_savings_ratio_fifty_percent" { - given result = power_savings_ratio(1100, 777) - try std.testing.expect(result == 50); + const result = power_savings_ratio(1100, 777); + assert(result == 50); } test "power_savings_ratio_seventy_five_percent" { - given result = power_savings_ratio(1100, 550) - try std.testing.expect(result == 75); + const result = power_savings_ratio(1100, 550); + assert(result == 75); } test "power_state_can_gate_active" { - try std.testing.expect(power_state_can_gate(PowerState.active) == false); + assert(power_state_can_gate(PowerState.active) == false); } test "power_state_can_gate_idle" { - try std.testing.expect(power_state_can_gate(PowerState.idle) == true); + assert(power_state_can_gate(PowerState.idle) == true); } test "power_state_can_gate_sleep" { - try std.testing.expect(power_state_can_gate(PowerState.sleep) == true); + assert(power_state_can_gate(PowerState.sleep) == true); } test "power_state_deeper" { - try std.testing.expect(power_state_deeper(PowerState.idle, PowerState.deep_sleep) == PowerState.deep_sleep); - try std.testing.expect(power_state_deeper(PowerState.deep_sleep, PowerState.idle) == PowerState.deep_sleep); + assert(power_state_deeper(PowerState.idle, PowerState.deep_sleep) == PowerState.deep_sleep); + assert(power_state_deeper(PowerState.deep_sleep, PowerState.idle) == PowerState.deep_sleep); } test "power_state_sleep_ok_true" { - given domains = [_]ClkDomain{ + const domains = [_]ClkDomain{ .{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 0}, .{.id = 1, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 0}, - } ** 8 - try std.testing.expect(power_state_sleep_ok(domains, 200) == true); + } ** 8; + assert(power_state_sleep_ok(domains, 200) == true); } test "power_state_sleep_ok_false" { - given domains = [_]ClkDomain{ + const domains = [_]ClkDomain{ .{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 10, .last_active_cycle = 0}, .{.id = 1, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 0}, - } ** 8 - try std.testing.expect(power_state_sleep_ok(domains, 200) == false); + } ** 8; + assert(power_state_sleep_ok(domains, 200) == false); } test "encode_subth_clk" { - given encoded = encode_subth_clk(0x05, 0x02) - try std.testing.expect((encoded >> 8) == OP_SUBTH_CLK); + const encoded = encode_subth_clk(0x05, 0x02); + assert((encoded >> 8) == OP_SUBTH_CLK); } test "decode_subth_clk" { - given decoded = decode_subth_clk(0xE5A8) - try std.testing.expect(decoded.domain_id == 0x05); - try std.testing.expect(decoded.mode == 0x02); + const decoded = decode_subth_clk(0xE5A8); + assert(decoded.domain_id == 0x05); + assert(decoded.mode == 0x02); } test "opcode_constant" { - try std.testing.expect(OP_SUBTH_CLK == 0xE5); + assert(OP_SUBTH_CLK == 0xE5); } // ============================================================================ // Invariants // ============================================================================ -} invariant num_clk_domains_eight assert NUM_CLK_DOMAINS == 8 @@ -425,25 +425,25 @@ invariant subth_threshold_bound assert SUBTH_THRESHOLD_MV < NORMAL_VOLTAGE_MV invariant power_estimate_positive - try std.testing.expect(subth_power_estimate(100) >= 0); + assert subth_power_estimate(100) >= 0 invariant power_savings_bound - try std.testing.expect(power_savings_ratio(1100, 550) <= 100); + assert power_savings_ratio(1100, 550) <= 100 invariant power_state_enum_range - try std.testing.expect(@intFromEnum(PowerState.active) >= 0 and @intFromEnum(PowerState.deep_sleep) <= 3); + assert @intFromEnum(PowerState.active) >= 0 and @intFromEnum(PowerState.deep_sleep) <= 3 invariant clk_gate_mode_enum_range - try std.testing.expect(@intFromEnum(ClkGateMode.off) >= 0 and @intFromEnum(ClkGateMode.auto) <= 2); + assert @intFromEnum(ClkGateMode.off) >= 0 and @intFromEnum(ClkGateMode.auto) <= 2 invariant clk_domain_pulse_increases_activity given domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 0, .last_active_cycle = 0} - try std.testing.expect(result = clk_domain_pulse(domain, 100)); + and result = clk_domain_pulse(domain, 100) assert result.activity_count > domain.activity_count invariant clk_domain_decay_decreases_or_same given domain = ClkDomain{.id = 0, .enabled = true, .gate_mode = ClkGateMode.on, .activity_count = 5, .last_active_cycle = 0} - try std.testing.expect(result = clk_domain_decay(domain)); + and result = clk_domain_decay(domain) assert result.activity_count <= domain.activity_count invariant power_savings_symmetric diff --git a/specs/numeric/formats.t27 b/specs/numeric/formats.t27 index 90cda34..6faa742 100644 --- a/specs/numeric/formats.t27 +++ b/specs/numeric/formats.t27 @@ -10,6 +10,9 @@ module Formats { use base::types; use numeric::gf16; + // Signature-only fns: a Zig/Rust prototype `fn f(...) -> T;` is written + // as `fn f(...) -> T { }` (empty body), as in t27 specs/numeric/formats.t27. + // ======================================================================== // 1. GF16 Bit Layout Constants // ======================================================================== @@ -58,7 +61,7 @@ module Formats { // value = (-1)^s * (1 + m/2^9) * 2^(e - Bias) // // Complexity: O(1) - pub fn gf16_to_f32(x: u16) -> gf16; + pub fn gf16_to_f32(x: u16) -> gf16 { } // ======================================================================== // 3. f32 1 GF16 (encode, round-to-nearest) @@ -76,7 +79,7 @@ module Formats { // 6. Check underflow/overflow // // Complexity: O(1) - pub fn f32_to_gf16(a: f32) -> u16; + pub fn f32_to_gf16(a: f32) -> u16 { } // ======================================================================== // 4. Ternary Quantization @@ -98,14 +101,14 @@ module Formats { // - Otherwise: return 0 // // Complexity: O(1) - pub fn f32_to_ternary(x: f32) -> Trit; + pub fn f32_to_ternary(x: f32) -> Trit { } // ternary_to_f32(t: Trit) -> gf16 // Convert ternary to f32 // // Mapping: -1 -> -1.0, 0 -> 0.0, +1 -> 1.0 // Complexity: O(1) - pub fn ternary_to_f32(t: Trit) -> gf16; + pub fn ternary_to_f32(t: Trit) -> gf16 { } // ======================================================================== // 5. Format Enum @@ -172,7 +175,7 @@ module Formats { // - posit16: 2 bytes (16 bits) // // Complexity: O(1) - pub fn format_bytes(fmt: Format) -> usize; + pub fn format_bytes(fmt: Format) -> usize { } // ======================================================================== // 6. Quantization Utility @@ -182,7 +185,7 @@ module Formats { // Quantize f32 to target format // // Complexity: O(1) - pub fn quantize_value(x: f32, fmt: Format) -> gf16; + pub fn quantize_value(x: f32, fmt: Format) -> gf16 { } // ======================================================================== // TDD - Tests @@ -445,93 +448,104 @@ module Formats { // TDD - Invariants // ======================================================================== - invariant gf16_to_f32_preserves_zero + invariant gf16_to_f32_preserves_zero { // Zero should decode to zero - assert gf16.to_f64(gf16_to_f32(0)) == 0.0; - assert gf16.to_f64(gf16_to_f32(0x8000)) == -0.0; + assert(gf16.to_f64(gf16_to_f32(0)) == 0.0); + assert(gf16.to_f64(gf16_to_f32(0x8000)) == -0.0); + } - invariant gf16_to_f32_preserves_infinity + invariant gf16_to_f32_preserves_infinity { // Infinity should decode to infinity - assert gf16.to_f64(gf16_to_f32(0x7E00)) == std.math.inf(f32); - assert gf16.to_f64(gf16_to_f32(0xFE00)) == -std.math.inf(f32); + assert(gf16.to_f64(gf16_to_f32(0x7E00)) == std.math.inf(f32)); + assert(gf16.to_f64(gf16_to_f32(0xFE00)) == -std.math.inf(f32)); + } - invariant f32_to_gf16_roundtrip_loss + invariant f32_to_gf16_roundtrip_loss { // Roundtrip should be within tolerance for normal values const original = gf16.from_f64(1.5); const encoded = f32_to_gf16(gf16.to_f64(original)); const decoded = gf16_to_f32(encoded); const error = gf16.abs(gf16.sub(original, decoded)); - assert gf16.to_f64(error) < gf16.from_f64(0.01); + assert(gf16.to_f64(error) < gf16.from_f64(0.01)); + } - invariant ternary_quantization_symmetric + invariant ternary_quantization_symmetric { // Quantization threshold is symmetric const p = f32_to_ternary(0.5); const n = f32_to_ternary(-0.5); const p_decoded = ternary_to_f32(p); const n_decoded = ternary_to_f32(n); - assert gf16.to_f64(p_decoded) == -gf16.to_f64(n_decoded); + assert(gf16.to_f64(p_decoded) == -gf16.to_f64(n_decoded)); + } - invariant ternary_to_f32_is_inverse + invariant ternary_to_f32_is_inverse { // ternary_to_f32 is inverse of f32_to_ternary - const values = [_]f32{ -1.0, -0.5, 0.0, 0.5, 1.0 }; - for (values) |v| { + const values = [5]f32{ -1.0, -0.5, 0.0, 0.5, 1.0 }; + for i in 0..5 { + const v = values[i]; const t = f32_to_ternary(v); const recovered = ternary_to_f32(t); const diff = gf16.abs(gf16.sub(v, recovered)); - assert gf16.eq(v, recovered) or (gf16.to_f64(diff) < gf16.from_f64(0.01)); + assert(gf16.eq(v, recovered) or (gf16.to_f64(diff) < gf16.from_f64(0.01))); } + } - invariant format_bytes_positive + invariant format_bytes_positive { // All format byte sizes should be positive - assert format_bytes(.fp32) > 0; - assert format_bytes(.fp16) > 0; - assert format_bytes(.ternary) > 0; + assert(format_bytes(.fp32) > 0); + assert(format_bytes(.fp16) > 0); + assert(format_bytes(.ternary) > 0); + } // ======================================================================== // TDD - Benchmarks // ======================================================================== - bench gf16_to_f32_latency + bench gf16_to_f32_latency { // Measure: cycles for gf16_to_f32 conversion // Target: < 50 cycles (simple bit extraction + lookup) @setEvalBranchQuota(10000); var result : gf16; const test_value: u16 = 0x3C00; - for (0..1000) |_| { + for _ in 0..1000 { result = gf16_to_f32(test_value); } _ = result; + } - bench f32_to_gf16_latency + bench f32_to_gf16_latency { // Measure: cycles for f32_to_gf16 conversion // Target: < 100 cycles (frexp + bit packing) @setEvalBranchQuota(10000); var result : u16; const test_value: f32 = 1.5; - for (0..1000) |_| { + for _ in 0..1000 { result = f32_to_gf16(test_value); } _ = result; + } - bench f32_to_ternary_latency + bench f32_to_ternary_latency { // Measure: cycles for f32_to_ternary conversion // Target: < 10 cycles (single comparison) @setEvalBranchQuota(10000); var result : Trit; const test_value: f32 = 0.75; - for (0..1000) |_| { + for _ in 0..1000 { result = f32_to_ternary(test_value); } _ = result; + } - bench ternary_to_f32_latency + bench ternary_to_f32_latency { // Measure: cycles for ternary_to_f32 conversion // Target: < 10 cycles (simple switch) @setEvalBranchQuota(10000); var result : gf16; const test_trit: Trit = .pos; - for (0..1000) |_| { + for _ in 0..1000 { result = ternary_to_f32(test_trit); } _ = result; + } } diff --git a/specs/numeric/gf128.t27 b/specs/numeric/gf128.t27 index f32ee7a..6fcbf00 100644 --- a/specs/numeric/gf128.t27 +++ b/specs/numeric/gf128.t27 @@ -347,123 +347,122 @@ pub fn gf128_clamp(value: GF128, min: GF128, max: GF128) GF128 { // ============================================================================ test "gf128_extract_sign_positive" { - given value = 0x00000000000000000000000000001234 - try std.testing.expect(sign = gf128_extract_sign(value)); - try std.testing.expect(sign == 0); + const value = 0x00000000000000000000000000001234; + const sign = gf128_extract_sign(value); + assert(sign == 0); } test "gf128_extract_sign_negative" { - given value = 0x80000000000000000000000000001234 - try std.testing.expect(sign = gf128_extract_sign(value)); - try std.testing.expect(sign == -1); + const value = 0x80000000000000000000000000001234; + const sign = gf128_extract_sign(value); + assert(sign == -1); } test "gf128_extract_exponent_middle" { - given value = 0x00008000000000000000000000000000 // exp = 134217728 - try std.testing.expect(exp = gf128_extract_exponent(value)); - try std.testing.expect(exp == 134217728); + const value = 0x00008000000000000000000000000000; // exp = 134217728 + const exp = gf128_extract_exponent(value); + assert(exp == 134217728); } test "gf128_is_zero_positive" { - try std.testing.expect(gf128_is_zero(GF128_ZERO_POS) == true); + assert(gf128_is_zero(GF128_ZERO_POS) == true); } test "gf128_is_zero_negative" { - try std.testing.expect(gf128_is_zero(GF128_ZERO_NEG) == true); + assert(gf128_is_zero(GF128_ZERO_NEG) == true); } test "gf128_is_inf_positive" { - try std.testing.expect(gf128_is_inf(GF128_INF_POS) == true); + assert(gf128_is_inf(GF128_INF_POS) == true); } test "gf128_is_nan" { - try std.testing.expect(gf128_is_nan(GF128_NAN) == true); + assert(gf128_is_nan(GF128_NAN) == true); } test "gf128_encode_f64_zero" { - given gf = gf128_encode_f64(0.0) - try std.testing.expect(gf == GF128_ZERO_POS); + const gf = gf128_encode_f64(0.0); + assert(gf == GF128_ZERO_POS); } test "gf128_encode_f64_one" { - given gf = gf128_encode_f64(1.0) - try std.testing.expect(decoded = gf128_decode_f64(gf)); - try std.testing.expect(abs(decoded - 1.0) < 0.0001); + const gf = gf128_encode_f64(1.0); + const decoded = gf128_decode_f64(gf); + assert(abs(decoded - 1.0) < 0.0001); } test "gf128_encode_f64_negative_one" { - given gf = gf128_encode_f64(-1.0) - try std.testing.expect(decoded = gf128_decode_f64(gf)); - try std.testing.expect(abs(decoded + 1.0) < 0.0001); + const gf = gf128_encode_f64(-1.0); + const decoded = gf128_decode_f64(gf); + assert(abs(decoded + 1.0) < 0.0001); } test "gf128_encode_f64_roundtrip" { - given original = 42.5 - try std.testing.expect(gf = gf128_encode_f64(original)); - try std.testing.expect(decoded = gf128_decode_f64(gf)); - try std.testing.expect(abs(decoded - original) < 0.001); + const original = 42.5; + const gf = gf128_encode_f64(original); + const decoded = gf128_decode_f64(gf); + assert(abs(decoded - original) < 0.001); } test "gf128_add_simple" { - given a = gf128_encode_f64(1.0) - try std.testing.expect(b = gf128_encode_f64(2.0)); - try std.testing.expect(result = gf128_add(a, b)); - try std.testing.expect(decoded = gf128_decode_f64(result)); - try std.testing.expect(abs(decoded - 3.0) < 0.01); + const a = gf128_encode_f64(1.0); + const b = gf128_encode_f64(2.0); + const result = gf128_add(a, b); + const decoded = gf128_decode_f64(result); + assert(abs(decoded - 3.0) < 0.01); } test "gf128_mul_simple" { - given a = gf128_encode_f64(3.0) - try std.testing.expect(b = gf128_encode_f64(4.0)); - try std.testing.expect(result = gf128_mul(a, b)); - try std.testing.expect(decoded = gf128_decode_f64(result)); - try std.testing.expect(abs(decoded - 12.0) < 0.01); + const a = gf128_encode_f64(3.0); + const b = gf128_encode_f64(4.0); + const result = gf128_mul(a, b); + const decoded = gf128_decode_f64(result); + assert(abs(decoded - 12.0) < 0.01); } test "gf128_abs_positive" { - given value = gf128_encode_f64(5.0) - try std.testing.expect(abs_val = gf128_abs(value)); - try std.testing.expect(gf128_is_equal(abs_val, value) == true); + const value = gf128_encode_f64(5.0); + const abs_val = gf128_abs(value); + assert(gf128_is_equal(abs_val, value) == true); } test "gf128_abs_negative" { - given value = gf128_encode_f64(-5.0) - try std.testing.expect(abs_val = gf128_abs(value)); - try std.testing.expect(gf128_extract_sign(abs_val) == 0); + const value = gf128_encode_f64(-5.0); + const abs_val = gf128_abs(value); + assert(gf128_extract_sign(abs_val) == 0); } test "gf128_neg" { - given value = gf128_encode_f64(5.0) - try std.testing.expect(neg_val = gf128_neg(value)); - try std.testing.expect(decoded = gf128_decode_f64(neg_val)); - try std.testing.expect(abs(decoded + 5.0) < 0.01); + const value = gf128_encode_f64(5.0); + const neg_val = gf128_neg(value); + const decoded = gf128_decode_f64(neg_val); + assert(abs(decoded + 5.0) < 0.01); } test "gf128_is_equal_nan" { - try std.testing.expect(gf128_is_equal(GF128_NAN, GF128_NAN) == false); + assert(gf128_is_equal(GF128_NAN, GF128_NAN) == false); } test "gf128_is_greater_positive" { - given a = gf128_encode_f64(5.0) - try std.testing.expect(b = gf128_encode_f64(3.0)); - try std.testing.expect(gf128_is_greater(a, b) == true); + const a = gf128_encode_f64(5.0); + const b = gf128_encode_f64(3.0); + assert(gf128_is_greater(a, b) == true); } test "gf128_from_components_roundtrip" { - given sign = -1 - try std.testing.expect(exp = 134217728); - try std.testing.expect(mant = 0x8000000000000000000000000); - try std.testing.expect(gf = gf128_from_components(sign, exp, mant)); - try std.testing.expect(extracted_sign = gf128_extract_sign(gf)); - try std.testing.expect(extracted_exp = gf128_extract_exponent(gf)); - try std.testing.expect(extracted_sign == sign and extracted_exp == exp); + const sign = -1; + const exp = 134217728; + const mant = 0x8000000000000000000000000; + const gf = gf128_from_components(sign, exp, mant); + const extracted_sign = gf128_extract_sign(gf); + const extracted_exp = gf128_extract_exponent(gf); + assert(extracted_sign == sign and extracted_exp == exp); } // ============================================================================ // Invariants // ============================================================================ -} invariant gf128_bits_total assert SIGN_BITS + EXP_BITS + MANT_BITS == 128 diff --git a/specs/numeric/gf256.t27 b/specs/numeric/gf256.t27 index 2d2facf..a6e68d9 100644 --- a/specs/numeric/gf256.t27 +++ b/specs/numeric/gf256.t27 @@ -380,175 +380,174 @@ pub fn gf256_clamp(value: GF256, min: GF256, max: GF256) GF256 { // ============================================================================ test "gf256_zero_is_zero" { - try std.testing.expect(gf256_is_zero(gf256_zero()) == true); + assert(gf256_is_zero(gf256_zero()) == true); } test "gf256_negative_zero_is_zero" { - try std.testing.expect(gf256_is_zero(gf256_negative_zero()) == true); + assert(gf256_is_zero(gf256_negative_zero()) == true); } test "gf256_nonzero_is_not_zero" { - given value = gf256_encode_f64(1.0) - try std.testing.expect(gf256_is_zero(value) == false); + const value = gf256_encode_f64(1.0); + assert(gf256_is_zero(value) == false); } test "gf256_inf_is_special" { - try std.testing.expect(gf256_is_special(gf256_inf_positive()) == true); + assert(gf256_is_special(gf256_inf_positive()) == true); } test "gf256_nan_is_special" { - try std.testing.expect(gf256_is_special(gf256_nan()) == true); + assert(gf256_is_special(gf256_nan()) == true); } test "gf256_inf_positive" { - try std.testing.expect(gf256_is_inf(gf256_inf_positive()) == true); + assert(gf256_is_inf(gf256_inf_positive()) == true); } test "gf256_inf_negative" { - try std.testing.expect(gf256_is_inf(gf256_inf_negative()) == true); + assert(gf256_is_inf(gf256_inf_negative()) == true); } test "gf256_nan" { - try std.testing.expect(gf256_is_nan(gf256_nan()) == true); + assert(gf256_is_nan(gf256_nan()) == true); } test "gf256_inf_not_nan" { - try std.testing.expect(gf256_is_nan(gf256_inf_positive()) == false); + assert(gf256_is_nan(gf256_inf_positive()) == false); } test "gf256_extract_sign_positive" { - given value = gf256_encode_f64(1.0) - try std.testing.expect(sign = gf256_extract_sign(value)); - try std.testing.expect(sign == 0); + const value = gf256_encode_f64(1.0); + const sign = gf256_extract_sign(value); + assert(sign == 0); } test "gf256_extract_sign_negative" { - given value = gf256_encode_f64(-1.0) - try std.testing.expect(sign = gf256_extract_sign(value)); - try std.testing.expect(sign == -1); + const value = gf256_encode_f64(-1.0); + const sign = gf256_extract_sign(value); + assert(sign == -1); } test "gf256_encode_f64_zero" { - given gf = gf256_encode_f64(0.0) - try std.testing.expect(gf256_is_equal(gf, gf256_zero()) == true); + const gf = gf256_encode_f64(0.0); + assert(gf256_is_equal(gf, gf256_zero()) == true); } test "gf256_encode_f64_one" { - given gf = gf256_encode_f64(1.0) - try std.testing.expect(decoded = gf256_decode_f64(gf)); - try std.testing.expect(abs(decoded - 1.0) < 0.0001); + const gf = gf256_encode_f64(1.0); + const decoded = gf256_decode_f64(gf); + assert(abs(decoded - 1.0) < 0.0001); } test "gf256_encode_f64_negative_one" { - given gf = gf256_encode_f64(-1.0) - try std.testing.expect(decoded = gf256_decode_f64(gf)); - try std.testing.expect(abs(decoded + 1.0) < 0.0001); + const gf = gf256_encode_f64(-1.0); + const decoded = gf256_decode_f64(gf); + assert(abs(decoded + 1.0) < 0.0001); } test "gf256_encode_f64_roundtrip" { - given original = 42.5 - try std.testing.expect(gf = gf256_encode_f64(original)); - try std.testing.expect(decoded = gf256_decode_f64(gf)); - try std.testing.expect(abs(decoded - original) < 0.001); + const original = 42.5; + const gf = gf256_encode_f64(original); + const decoded = gf256_decode_f64(gf); + assert(abs(decoded - original) < 0.001); } test "gf256_add_simple" { - given a = gf256_encode_f64(1.0) - try std.testing.expect(b = gf256_encode_f64(2.0)); - try std.testing.expect(result = gf256_add(a, b)); - try std.testing.expect(decoded = gf256_decode_f64(result)); - try std.testing.expect(abs(decoded - 3.0) < 0.01); + const a = gf256_encode_f64(1.0); + const b = gf256_encode_f64(2.0); + const result = gf256_add(a, b); + const decoded = gf256_decode_f64(result); + assert(abs(decoded - 3.0) < 0.01); } test "gf256_mul_simple" { - given a = gf256_encode_f64(3.0) - try std.testing.expect(b = gf256_encode_f64(4.0)); - try std.testing.expect(result = gf256_mul(a, b)); - try std.testing.expect(decoded = gf256_decode_f64(result)); - try std.testing.expect(abs(decoded - 12.0) < 0.01); + const a = gf256_encode_f64(3.0); + const b = gf256_encode_f64(4.0); + const result = gf256_mul(a, b); + const decoded = gf256_decode_f64(result); + assert(abs(decoded - 12.0) < 0.01); } test "gf256_abs_positive" { - given value = gf256_encode_f64(5.0) - try std.testing.expect(abs_val = gf256_abs(value)); - try std.testing.expect(gf256_is_equal(abs_val, value) == true); + const value = gf256_encode_f64(5.0); + const abs_val = gf256_abs(value); + assert(gf256_is_equal(abs_val, value) == true); } test "gf256_abs_negative" { - given value = gf256_encode_f64(-5.0) - try std.testing.expect(abs_val = gf256_abs(value)); - try std.testing.expect(gf256_extract_sign(abs_val) == 0); + const value = gf256_encode_f64(-5.0); + const abs_val = gf256_abs(value); + assert(gf256_extract_sign(abs_val) == 0); } test "gf256_neg_positive" { - given value = gf256_encode_f64(5.0) - try std.testing.expect(neg_val = gf256_neg(value)); - try std.testing.expect(gf256_extract_sign(neg_val) < 0); + const value = gf256_encode_f64(5.0); + const neg_val = gf256_neg(value); + assert(gf256_extract_sign(neg_val) < 0); } test "gf256_neg_negative" { - given value = gf256_encode_f64(-5.0) - try std.testing.expect(neg_val = gf256_neg(value)); - try std.testing.expect(gf256_extract_sign(neg_val) == 0); + const value = gf256_encode_f64(-5.0); + const neg_val = gf256_neg(value); + assert(gf256_extract_sign(neg_val) == 0); } test "gf256_is_equal_same" { - given value = gf256_encode_f64(1.0) - try std.testing.expect(gf256_is_equal(value, value) == true); + const value = gf256_encode_f64(1.0); + assert(gf256_is_equal(value, value) == true); } test "gf256_is_equal_nan" { - try std.testing.expect(gf256_is_equal(gf256_nan(), gf256_nan()) == false); + assert(gf256_is_equal(gf256_nan(), gf256_nan()) == false); } test "gf256_is_equal_zero" { - try std.testing.expect(gf256_is_equal(gf256_zero(), gf256_negative_zero()) == true); + assert(gf256_is_equal(gf256_zero(), gf256_negative_zero()) == true); } test "gf256_is_greater_positive" { - given a = gf256_encode_f64(5.0) - try std.testing.expect(b = gf256_encode_f64(3.0)); - try std.testing.expect(gf256_is_greater(a, b) == true); + const a = gf256_encode_f64(5.0); + const b = gf256_encode_f64(3.0); + assert(gf256_is_greater(a, b) == true); } test "gf256_is_greater_negative" { - given a = gf256_encode_f64(-3.0) - try std.testing.expect(b = gf256_encode_f64(-5.0)); - try std.testing.expect(gf256_is_greater(a, b) == true); + const a = gf256_encode_f64(-3.0); + const b = gf256_encode_f64(-5.0); + assert(gf256_is_greater(a, b) == true); } test "gf256_max_returns_larger" { - given a = gf256_encode_f64(3.0) - try std.testing.expect(b = gf256_encode_f64(5.0)); - try std.testing.expect(result = gf256_max(a, b)); - try std.testing.expect(decoded = gf256_decode_f64(result)); - try std.testing.expect(decoded >= 4.0); + const a = gf256_encode_f64(3.0); + const b = gf256_encode_f64(5.0); + const result = gf256_max(a, b); + const decoded = gf256_decode_f64(result); + assert(decoded >= 4.0); } test "gf256_min_returns_smaller" { - given a = gf256_encode_f64(3.0) - try std.testing.expect(b = gf256_encode_f64(5.0)); - try std.testing.expect(result = gf256_min(a, b)); - try std.testing.expect(decoded = gf256_decode_f64(result)); - try std.testing.expect(decoded <= 4.0); + const a = gf256_encode_f64(3.0); + const b = gf256_encode_f64(5.0); + const result = gf256_min(a, b); + const decoded = gf256_decode_f64(result); + assert(decoded <= 4.0); } test "gf256_from_components_roundtrip" { - given sign = -1 - try std.testing.expect(exp = 2147483648); - try std.testing.expect(mant = gf256_zero()); - try std.testing.expect(mant.parts[0] = 0x8000000000000000); - try std.testing.expect(gf = gf256_from_components(sign, exp, mant)); - try std.testing.expect(extracted_sign = gf256_extract_sign(gf)); - try std.testing.expect(extracted_exp = gf256_extract_exponent(gf)); - try std.testing.expect(extracted_sign == sign and extracted_exp == exp); + const sign = -1; + const exp = 2147483648; + var mant = gf256_zero(); + mant.parts[0] = 0x8000000000000000; + const gf = gf256_from_components(sign, exp, mant); + const extracted_sign = gf256_extract_sign(gf); + const extracted_exp = gf256_extract_exponent(gf); + assert(extracted_sign == sign and extracted_exp == exp); } // ============================================================================ // Invariants // ============================================================================ -} invariant gf256_bits_total assert SIGN_BITS + EXP_BITS + MANT_BITS == 256 @@ -569,10 +568,11 @@ invariant gf256_neg_zero_has_sign invariant gf256_abs_removes_sign assert (gf256_abs(gf256_negative_zero()).parts[3] & 0x8000000000000000) == 0 -invariant gf256_neg_toggles_sign - given pos = gf256_encode_f64(5.0) - try std.testing.expect(neg = gf256_neg(pos)); - assert (pos.parts[3] & 0x8000000000000000) != (neg.parts[3] & 0x8000000000000000) +invariant gf256_neg_toggles_sign { + const pos = gf256_encode_f64(5.0); + const neg = gf256_neg(pos); + assert((pos.parts[3] & 0x8000000000000000) != (neg.parts[3] & 0x8000000000000000)); +} // ============================================================================ // Benchmarks diff --git a/specs/numeric/gf64.t27 b/specs/numeric/gf64.t27 index cb86276..7d2fa73 100644 --- a/specs/numeric/gf64.t27 +++ b/specs/numeric/gf64.t27 @@ -58,7 +58,7 @@ pub fn gf64_extract_sign(gf64: GF64) i8 { // Extract exponent bits (bits 62-45) // Returns: 0-262143 pub fn gf64_extract_exponent(gf64: GF64) i16 { - return @as(i16, @intCast((gf64 >> EXP_SHIFT) & (EXP_MAX))); + return ((gf64 >> EXP_SHIFT) & (EXP_MAX)) as i16; } // gf64_extract_mantissa(gf64: GF64) -> u64 @@ -72,8 +72,9 @@ pub fn gf64_extract_mantissa(gf64: GF64) u64 { // Assemble GF64 from sign, exponent, mantissa pub fn gf64_from_components(sign: i8, exp: i16, mant: u64) GF64 { const sign_bit = if (sign < 0) 1 else 0; - return (@as(GF64, @intCast(sign_bit)) << SIGN_SHIFT) | - (@as(GF64, @intCast(exp & EXP_MAX)) << EXP_SHIFT) | + // `as` takes a builtin type name; GF64 is u64 (see Types). + return ((sign_bit as u64) << SIGN_SHIFT) | + (((exp & EXP_MAX) as u64) << EXP_SHIFT) | (mant & MANT_MASK); } @@ -86,7 +87,7 @@ pub fn gf64_is_zero(gf64: GF64) bool { // gf64_is_special(gf64: GF64) -> bool // Check if GF64 is Inf or NaN (exp == 262143) pub fn gf64_is_special(gf64: GF64) bool { - return gf64_extract_exponent(gf64) == @as(i16, @intCast(EXP_MAX)); + return gf64_extract_exponent(gf64) == (EXP_MAX as i16); } // gf64_is_inf(gf64: GF64) -> bool @@ -94,7 +95,7 @@ pub fn gf64_is_special(gf64: GF64) bool { pub fn gf64_is_inf(gf64: GF64) bool { const exp = gf64_extract_exponent(gf64); const mant = gf64_extract_mantissa(gf64); - return exp == @as(i16, @intCast(EXP_MAX)) and mant == 0; + return exp == (EXP_MAX as i16) and mant == 0; } // gf64_is_nan(gf64: GF64) -> bool @@ -102,7 +103,7 @@ pub fn gf64_is_inf(gf64: GF64) bool { pub fn gf64_is_nan(gf64: GF64) bool { const exp = gf64_extract_exponent(gf64); const mant = gf64_extract_mantissa(gf64); - return exp == @as(i16, @intCast(EXP_MAX)) and mant != 0; + return exp == (EXP_MAX as i16) and mant != 0; } // gf64_encode_f64(f64: f64) -> GF64 @@ -129,8 +130,10 @@ pub fn gf64_encode_f64(value: f64) GF64 { const abs_value = if (value < 0.0) -value else value; // Get f64 components + // @bitCast: reinterpret the f64 bits as u64 (no `as` form for this; the + // canonical numeric/gf16.t27 uses the same intrinsic). const f64_bits: u64 = @bitCast(abs_value); - var f64_exp: i16 = @intCast((f64_bits >> 52) & 0x7FF) - 1023; + var f64_exp: i16 = (((f64_bits >> 52) & 0x7FF) as i16) - 1023; var f64_mant: u64 = f64_bits & 0x000FFFFFFFFFFFFF; // Convert exp from f64 bias (1023) to GF64 bias (131071) @@ -140,7 +143,7 @@ pub fn gf64_encode_f64(value: f64) GF64 { if (gf64_exp < 0) { // Underflow - could return subnormal, but flushing to zero for simplicity return if (sign < 0) GF64_ZERO_NEG else GF64_ZERO_POS; - } else if (gf64_exp > @as(i16, @intCast(EXP_MAX - 1))) { + } else if (gf64_exp > ((EXP_MAX - 1) as i16)) { return if (sign < 0) GF64_INF_NEG else GF64_INF_POS; } @@ -157,7 +160,7 @@ pub fn gf64_encode_f64(value: f64) GF64 { mant += 1; if (mant > MANT_MASK) { mant = 0; - if (gf64_exp < @as(i16, @intCast(EXP_MAX - 1))) { + if (gf64_exp < ((EXP_MAX - 1) as i16)) { gf64_exp += 1; } } @@ -191,9 +194,9 @@ pub fn gf64_decode_f64(gf64: GF64) f64 { const mant = gf64_extract_mantissa(gf64); // Decode value: mantissa * 2^(exp - bias) - const bias_adjusted = @as(i64, exp) - @as(i64, BIAS); - const mant_f64 = @as(f64, @floatFromInt(mant)) / @as(f64, @floatFromInt(MANT_DIVISOR)); - const value = mant_f64 * std.math.pow(f64, 2.0, @as(f64, @floatFromInt(bias_adjusted))); + const bias_adjusted = (exp as i64) - (BIAS as i64); + const mant_f64 = (mant as f64) / (MANT_DIVISOR as f64); + const value = mant_f64 * std.math.pow(f64, 2.0, bias_adjusted as f64); return if (sign < 0) -value else value; } @@ -308,7 +311,7 @@ pub fn gf64_lerp(a: GF64, b: GF64, t: GF64) GF64 { // gf64_from_u32(value: u32) -> GF64 // Convert unsigned 32-bit integer to GF64 pub fn gf64_from_u32(value: u32) GF64 { - return gf64_encode_f64(@as(f64, @floatFromInt(value))); + return gf64_encode_f64(value as f64); } // gf64_to_u32(gf64: GF64) -> ?u32 @@ -318,17 +321,18 @@ pub fn gf64_to_u32(gf64: GF64) ?u32 { if (gf64_is_nan(gf64) or gf64_is_inf(gf64)) { return null; } - const value = gf64_decode_f64(gf64); - if (value < 0.0 or value > @as(f64, @floatFromInt(std.math.maxInt(u32)))) { + // Typed f64 local so the Zig backend lowers `value as u32` to @intFromFloat. + const value: f64 = gf64_decode_f64(gf64); + if (value < 0.0 or value > (std.math.maxInt(u32) as f64)) { return null; } - return @as(u32, @intFromFloat(value)); + return value as u32; } // gf64_from_i32(value: i32) -> GF64 // Convert signed 32-bit integer to GF64 pub fn gf64_from_i32(value: i32) GF64 { - return gf64_encode_f64(@as(f64, @floatFromInt(value))); + return gf64_encode_f64(value as f64); } // gf64_to_i32(gf64: GF64) -> ?i32 @@ -338,12 +342,13 @@ pub fn gf64_to_i32(gf64: GF64) ?i32 { if (gf64_is_nan(gf64) or gf64_is_inf(gf64)) { return null; } - const value = gf64_decode_f64(gf64); - if (value < @as(f64, @floatFromInt(std.math.minInt(i32))) or - value > @as(f64, @floatFromInt(std.math.maxInt(i32)))) { + // Typed f64 local so the Zig backend lowers `value as i32` to @intFromFloat. + const value: f64 = gf64_decode_f64(gf64); + if (value < (std.math.minInt(i32) as f64) or + value > (std.math.maxInt(i32) as f64)) { return null; } - return @as(i32, @intFromFloat(value)); + return value as i32; } // ============================================================================ @@ -351,348 +356,347 @@ pub fn gf64_to_i32(gf64: GF64) ?i32 { // ============================================================================ test "gf64_extract_sign_positive" { - given value = 0x0000000000001234 - try std.testing.expect(sign = gf64_extract_sign(value)); - try std.testing.expect(sign == 0); + const value = 0x0000000000001234; + const sign = gf64_extract_sign(value); + assert(sign == 0); } test "gf64_extract_sign_negative" { - given value = 0x8000000000001234 - try std.testing.expect(sign = gf64_extract_sign(value)); - try std.testing.expect(sign == -1); + const value = 0x8000000000001234; + const sign = gf64_extract_sign(value); + assert(sign == -1); } test "gf64_extract_exponent_middle" { - given value = 0x0000800000000000 // exp = 131072 - try std.testing.expect(exp = gf64_extract_exponent(value)); - try std.testing.expect(exp == 131072); + const value = 0x0000800000000000; // exp = 131072 + const exp = gf64_extract_exponent(value); + assert(exp == 131072); } test "gf64_extract_mantissa_max" { - given value = 0x00007FFFFFFFFFFF - try std.testing.expect(mant = gf64_extract_mantissa(value)); - try std.testing.expect(mant == 0x00007FFFFFFFFFFF); + const value = 0x00007FFFFFFFFFFF; + const mant = gf64_extract_mantissa(value); + assert(mant == 0x00007FFFFFFFFFFF); } test "gf64_is_zero_positive" { - try std.testing.expect(gf64_is_zero(GF64_ZERO_POS) == true); + assert(gf64_is_zero(GF64_ZERO_POS) == true); } test "gf64_is_zero_negative" { - try std.testing.expect(gf64_is_zero(GF64_ZERO_NEG) == true); + assert(gf64_is_zero(GF64_ZERO_NEG) == true); } test "gf64_is_zero_nonzero" { - try std.testing.expect(gf64_is_zero(0x0000000000000001) == false); + assert(gf64_is_zero(0x0000000000000001) == false); } test "gf64_is_special_inf" { - try std.testing.expect(gf64_is_special(GF64_INF_POS) == true); + assert(gf64_is_special(GF64_INF_POS) == true); } test "gf64_is_special_nan" { - try std.testing.expect(gf64_is_special(GF64_NAN) == true); + assert(gf64_is_special(GF64_NAN) == true); } test "gf64_is_special_normal" { - try std.testing.expect(gf64_is_special(0x0000000000001234) == false); + assert(gf64_is_special(0x0000000000001234) == false); } test "gf64_is_inf_positive" { - try std.testing.expect(gf64_is_inf(GF64_INF_POS) == true); + assert(gf64_is_inf(GF64_INF_POS) == true); } test "gf64_is_inf_negative" { - try std.testing.expect(gf64_is_inf(GF64_INF_NEG) == true); + assert(gf64_is_inf(GF64_INF_NEG) == true); } test "gf64_is_inf_not_nan" { - try std.testing.expect(gf64_is_inf(GF64_NAN) == false); + assert(gf64_is_inf(GF64_NAN) == false); } test "gf64_is_nan" { - try std.testing.expect(gf64_is_nan(GF64_NAN) == true); + assert(gf64_is_nan(GF64_NAN) == true); } test "gf64_is_nan_not_inf" { - try std.testing.expect(gf64_is_nan(GF64_INF_POS) == false); + assert(gf64_is_nan(GF64_INF_POS) == false); } test "gf64_encode_f64_zero" { - given gf = gf64_encode_f64(0.0) - try std.testing.expect(gf == GF64_ZERO_POS); + const gf = gf64_encode_f64(0.0); + assert(gf == GF64_ZERO_POS); } test "gf64_encode_f64_negative_zero" { - given gf = gf64_encode_f64(-0.0) - try std.testing.expect(gf == GF64_ZERO_NEG); + const gf = gf64_encode_f64(-0.0); + assert(gf == GF64_ZERO_NEG); } test "gf64_encode_f64_one" { - given gf = gf64_encode_f64(1.0) - try std.testing.expect(decoded = gf64_decode_f64(gf)); - try std.testing.expect(abs(decoded - 1.0) < 0.0001); + const gf = gf64_encode_f64(1.0); + const decoded = gf64_decode_f64(gf); + assert(abs(decoded - 1.0) < 0.0001); } test "gf64_encode_f64_negative_one" { - given gf = gf64_encode_f64(-1.0) - try std.testing.expect(decoded = gf64_decode_f64(gf)); - try std.testing.expect(abs(decoded + 1.0) < 0.0001); + const gf = gf64_encode_f64(-1.0); + const decoded = gf64_decode_f64(gf); + assert(abs(decoded + 1.0) < 0.0001); } test "gf64_encode_f64_two_pow_ten" { - given gf = gf64_encode_f64(1024.0) - try std.testing.expect(decoded = gf64_decode_f64(gf)); - try std.testing.expect(abs(decoded - 1024.0) < 1.0); + const gf = gf64_encode_f64(1024.0); + const decoded = gf64_decode_f64(gf); + assert(abs(decoded - 1024.0) < 1.0); } test "gf64_encode_f64_pi" { - given gf = gf64_encode_f64(std.math.pi) - try std.testing.expect(decoded = gf64_decode_f64(gf)); - try std.testing.expect(abs(decoded - std.math.pi) < 0.001); + const gf = gf64_encode_f64(std.math.pi); + const decoded = gf64_decode_f64(gf); + assert(abs(decoded - std.math.pi) < 0.001); } test "gf64_decode_f64_roundtrip_positive" { - given original = 42.5 - try std.testing.expect(gf = gf64_encode_f64(original)); - try std.testing.expect(decoded = gf64_decode_f64(gf)); - try std.testing.expect(abs(decoded - original) < 0.001); + const original = 42.5; + const gf = gf64_encode_f64(original); + const decoded = gf64_decode_f64(gf); + assert(abs(decoded - original) < 0.001); } test "gf64_decode_f64_roundtrip_negative" { - given original = -17.75 - try std.testing.expect(gf = gf64_encode_f64(original)); - try std.testing.expect(decoded = gf64_decode_f64(gf)); - try std.testing.expect(abs(decoded - original) < 0.001); + const original = -17.75; + const gf = gf64_encode_f64(original); + const decoded = gf64_decode_f64(gf); + assert(abs(decoded - original) < 0.001); } test "gf64_add_simple" { - given a = gf64_encode_f64(1.0) - try std.testing.expect(b = gf64_encode_f64(2.0)); - try std.testing.expect(result = gf64_add(a, b)); - try std.testing.expect(decoded = gf64_decode_f64(result)); - try std.testing.expect(abs(decoded - 3.0) < 0.01); + const a = gf64_encode_f64(1.0); + const b = gf64_encode_f64(2.0); + const result = gf64_add(a, b); + const decoded = gf64_decode_f64(result); + assert(abs(decoded - 3.0) < 0.01); } test "gf64_sub_simple" { - given a = gf64_encode_f64(5.0) - try std.testing.expect(b = gf64_encode_f64(3.0)); - try std.testing.expect(result = gf64_sub(a, b)); - try std.testing.expect(decoded = gf64_decode_f64(result)); - try std.testing.expect(abs(decoded - 2.0) < 0.01); + const a = gf64_encode_f64(5.0); + const b = gf64_encode_f64(3.0); + const result = gf64_sub(a, b); + const decoded = gf64_decode_f64(result); + assert(abs(decoded - 2.0) < 0.01); } test "gf64_mul_simple" { - given a = gf64_encode_f64(3.0) - try std.testing.expect(b = gf64_encode_f64(4.0)); - try std.testing.expect(result = gf64_mul(a, b)); - try std.testing.expect(decoded = gf64_decode_f64(result)); - try std.testing.expect(abs(decoded - 12.0) < 0.01); + const a = gf64_encode_f64(3.0); + const b = gf64_encode_f64(4.0); + const result = gf64_mul(a, b); + const decoded = gf64_decode_f64(result); + assert(abs(decoded - 12.0) < 0.01); } test "gf64_div_simple" { - given a = gf64_encode_f64(12.0) - try std.testing.expect(b = gf64_encode_f64(4.0)); - try std.testing.expect(result = gf64_div(a, b)); - try std.testing.expect(decoded = gf64_decode_f64(result)); - try std.testing.expect(abs(decoded - 3.0) < 0.01); + const a = gf64_encode_f64(12.0); + const b = gf64_encode_f64(4.0); + const result = gf64_div(a, b); + const decoded = gf64_decode_f64(result); + assert(abs(decoded - 3.0) < 0.01); } test "gf64_abs_positive" { - given value = gf64_encode_f64(5.0) - try std.testing.expect(abs_val = gf64_abs(value)); - try std.testing.expect(abs_val == value); + const value = gf64_encode_f64(5.0); + const abs_val = gf64_abs(value); + assert(abs_val == value); } test "gf64_abs_negative" { - given value = gf64_encode_f64(-5.0) - try std.testing.expect(abs_val = gf64_abs(value)); - try std.testing.expect(decoded = gf64_decode_f64(abs_val)); - try std.testing.expect(decoded > 0.0); + const value = gf64_encode_f64(-5.0); + const abs_val = gf64_abs(value); + const decoded = gf64_decode_f64(abs_val); + assert(decoded > 0.0); } test "gf64_neg" { - given value = gf64_encode_f64(5.0) - try std.testing.expect(neg_val = gf64_neg(value)); - try std.testing.expect(decoded = gf64_decode_f64(neg_val)); - try std.testing.expect(abs(decoded + 5.0) < 0.01); + const value = gf64_encode_f64(5.0); + const neg_val = gf64_neg(value); + const decoded = gf64_decode_f64(neg_val); + assert(abs(decoded + 5.0) < 0.01); } test "gf64_is_equal_same" { - given value = gf64_encode_f64(1.0) - try std.testing.expect(gf64_is_equal(value, value) == true); + const value = gf64_encode_f64(1.0); + assert(gf64_is_equal(value, value) == true); } test "gf64_is_equal_different" { - given a = gf64_encode_f64(1.0) - try std.testing.expect(b = gf64_encode_f64(2.0)); - try std.testing.expect(gf64_is_equal(a, b) == false); + const a = gf64_encode_f64(1.0); + const b = gf64_encode_f64(2.0); + assert(gf64_is_equal(a, b) == false); } test "gf64_is_equal_nan" { - try std.testing.expect(gf64_is_equal(GF64_NAN, GF64_NAN) == false); + assert(gf64_is_equal(GF64_NAN, GF64_NAN) == false); } test "gf64_is_equal_zero" { - try std.testing.expect(gf64_is_equal(GF64_ZERO_POS, GF64_ZERO_NEG) == true); + assert(gf64_is_equal(GF64_ZERO_POS, GF64_ZERO_NEG) == true); } test "gf64_is_greater_positive" { - given a = gf64_encode_f64(5.0) - try std.testing.expect(b = gf64_encode_f64(3.0)); - try std.testing.expect(gf64_is_greater(a, b) == true); + const a = gf64_encode_f64(5.0); + const b = gf64_encode_f64(3.0); + assert(gf64_is_greater(a, b) == true); } test "gf64_is_greater_negative" { - given a = gf64_encode_f64(-3.0) - try std.testing.expect(b = gf64_encode_f64(-5.0)); - try std.testing.expect(gf64_is_greater(a, b) == true); + const a = gf64_encode_f64(-3.0); + const b = gf64_encode_f64(-5.0); + assert(gf64_is_greater(a, b) == true); } test "gf64_is_greater_positive_vs_negative" { - given a = gf64_encode_f64(1.0) - try std.testing.expect(b = gf64_encode_f64(-1.0)); - try std.testing.expect(gf64_is_greater(a, b) == true); + const a = gf64_encode_f64(1.0); + const b = gf64_encode_f64(-1.0); + assert(gf64_is_greater(a, b) == true); } test "gf64_max_returns_larger" { - given a = gf64_encode_f64(3.0) - try std.testing.expect(b = gf64_encode_f64(5.0)); - try std.testing.expect(result = gf64_max(a, b)); - try std.testing.expect(decoded = gf64_decode_f64(result)); - try std.testing.expect(decoded >= 4.0); + const a = gf64_encode_f64(3.0); + const b = gf64_encode_f64(5.0); + const result = gf64_max(a, b); + const decoded = gf64_decode_f64(result); + assert(decoded >= 4.0); } test "gf64_min_returns_smaller" { - given a = gf64_encode_f64(3.0) - try std.testing.expect(b = gf64_encode_f64(5.0)); - try std.testing.expect(result = gf64_min(a, b)); - try std.testing.expect(decoded = gf64_decode_f64(result)); - try std.testing.expect(decoded <= 4.0); + const a = gf64_encode_f64(3.0); + const b = gf64_encode_f64(5.0); + const result = gf64_min(a, b); + const decoded = gf64_decode_f64(result); + assert(decoded <= 4.0); } test "gf64_clamp_within_range" { - given value = gf64_encode_f64(3.0) - try std.testing.expect(min = gf64_encode_f64(0.0)); - try std.testing.expect(max = gf64_encode_f64(10.0)); - try std.testing.expect(result = gf64_clamp(value, min, max)); - try std.testing.expect(result == value); + const value = gf64_encode_f64(3.0); + const min = gf64_encode_f64(0.0); + const max = gf64_encode_f64(10.0); + const result = gf64_clamp(value, min, max); + assert(result == value); } test "gf64_clamp_below_min" { - given value = gf64_encode_f64(-5.0) - try std.testing.expect(min = gf64_encode_f64(0.0)); - try std.testing.expect(max = gf64_encode_f64(10.0)); - try std.testing.expect(result = gf64_clamp(value, min, max)); - try std.testing.expect(decoded = gf64_decode_f64(result)); - try std.testing.expect(decoded >= 0.0); + const value = gf64_encode_f64(-5.0); + const min = gf64_encode_f64(0.0); + const max = gf64_encode_f64(10.0); + const result = gf64_clamp(value, min, max); + const decoded = gf64_decode_f64(result); + assert(decoded >= 0.0); } test "gf64_clamp_above_max" { - given value = gf64_encode_f64(15.0) - try std.testing.expect(min = gf64_encode_f64(0.0)); - try std.testing.expect(max = gf64_encode_f64(10.0)); - try std.testing.expect(result = gf64_clamp(value, min, max)); - try std.testing.expect(decoded = gf64_decode_f64(result)); - try std.testing.expect(decoded <= 10.0); + const value = gf64_encode_f64(15.0); + const min = gf64_encode_f64(0.0); + const max = gf64_encode_f64(10.0); + const result = gf64_clamp(value, min, max); + const decoded = gf64_decode_f64(result); + assert(decoded <= 10.0); } test "gf64_lerp_zero" { - given a = gf64_encode_f64(1.0) - try std.testing.expect(b = gf64_encode_f64(5.0)); - try std.testing.expect(t = gf64_encode_f64(0.0)); - try std.testing.expect(result = gf64_lerp(a, b, t)); - try std.testing.expect(gf64_is_equal(result, a) == true); + const a = gf64_encode_f64(1.0); + const b = gf64_encode_f64(5.0); + const t = gf64_encode_f64(0.0); + const result = gf64_lerp(a, b, t); + assert(gf64_is_equal(result, a) == true); } test "gf64_lerp_one" { - given a = gf64_encode_f64(1.0) - try std.testing.expect(b = gf64_encode_f64(5.0)); - try std.testing.expect(t = gf64_encode_f64(1.0)); - try std.testing.expect(result = gf64_lerp(a, b, t)); - try std.testing.expect(gf64_is_equal(result, b) == true); + const a = gf64_encode_f64(1.0); + const b = gf64_encode_f64(5.0); + const t = gf64_encode_f64(1.0); + const result = gf64_lerp(a, b, t); + assert(gf64_is_equal(result, b) == true); } test "gf64_lerp_half" { - given a = gf64_encode_f64(1.0) - try std.testing.expect(b = gf64_encode_f64(5.0)); - try std.testing.expect(t = gf64_encode_f64(0.5)); - try std.testing.expect(result = gf64_lerp(a, b, t)); - try std.testing.expect(decoded = gf64_decode_f64(result)); - try std.testing.expect(abs(decoded - 3.0) < 0.1); + const a = gf64_encode_f64(1.0); + const b = gf64_encode_f64(5.0); + const t = gf64_encode_f64(0.5); + const result = gf64_lerp(a, b, t); + const decoded = gf64_decode_f64(result); + assert(abs(decoded - 3.0) < 0.1); } test "gf64_from_u32_zero" { - given value = 0 - try std.testing.expect(gf = gf64_from_u32(value)); - try std.testing.expect(gf == GF64_ZERO_POS); + const value = 0; + const gf = gf64_from_u32(value); + assert(gf == GF64_ZERO_POS); } test "gf64_from_u32_max" { - given value = std.math.maxInt(u32) - try std.testing.expect(gf = gf64_from_u32(value)); - try std.testing.expect(decoded = gf64_to_u32(gf)); - try std.testing.expect(decoded.? == value); + const value = std.math.maxInt(u32); + const gf = gf64_from_u32(value); + const decoded = gf64_to_u32(gf); + assert(decoded.? == value); } test "gf64_to_u32_success" { - given gf = gf64_encode_f64(123.0) - try std.testing.expect(result = gf64_to_u32(gf)); - try std.testing.expect(result.? == 123); + const gf = gf64_encode_f64(123.0); + const result = gf64_to_u32(gf); + assert(result.? == 123); } test "gf64_to_u32_negative" { - given gf = gf64_encode_f64(-1.0) - try std.testing.expect(result = gf64_to_u32(gf)); - try std.testing.expect(result == null); + const gf = gf64_encode_f64(-1.0); + const result = gf64_to_u32(gf); + assert(result == null); } test "gf64_to_u32_nan" { - given result = gf64_to_u32(GF64_NAN) - try std.testing.expect(result == null); + const result = gf64_to_u32(GF64_NAN); + assert(result == null); } test "gf64_from_i32_zero" { - given value = 0 - try std.testing.expect(gf = gf64_from_i32(value)); - try std.testing.expect(gf == GF64_ZERO_POS); + const value = 0; + const gf = gf64_from_i32(value); + assert(gf == GF64_ZERO_POS); } test "gf64_from_i32_negative" { - given value = -42 - try std.testing.expect(gf = gf64_from_i32(value)); - try std.testing.expect(decoded = gf64_to_i32(gf)); - try std.testing.expect(decoded.? == value); + const value = -42; + const gf = gf64_from_i32(value); + const decoded = gf64_to_i32(gf); + assert(decoded.? == value); } test "gf64_to_i32_positive" { - given gf = gf64_encode_f64(123.0) - try std.testing.expect(result = gf64_to_i32(gf)); - try std.testing.expect(result.? == 123); + const gf = gf64_encode_f64(123.0); + const result = gf64_to_i32(gf); + assert(result.? == 123); } test "gf64_to_i32_negative" { - given gf = gf64_encode_f64(-123.0) - try std.testing.expect(result = gf64_to_i32(gf)); - try std.testing.expect(result.? == -123); + const gf = gf64_encode_f64(-123.0); + const result = gf64_to_i32(gf); + assert(result.? == -123); } test "gf64_from_components_roundtrip" { - given sign = -1 - try std.testing.expect(exp = 131072); - try std.testing.expect(mant = 0x0000000000000800); - try std.testing.expect(gf = gf64_from_components(sign, exp, mant)); - try std.testing.expect(extracted_sign = gf64_extract_sign(gf)); - try std.testing.expect(extracted_exp = gf64_extract_exponent(gf)); - try std.testing.expect(extracted_mant = gf64_extract_mantissa(gf)); - try std.testing.expect(extracted_sign == sign and extracted_exp == exp and extracted_mant == mant); + const sign = -1; + const exp = 131072; + const mant = 0x0000000000000800; + const gf = gf64_from_components(sign, exp, mant); + const extracted_sign = gf64_extract_sign(gf); + const extracted_exp = gf64_extract_exponent(gf); + const extracted_mant = gf64_extract_mantissa(gf); + assert(extracted_sign == sign and extracted_exp == exp and extracted_mant == mant); } // ============================================================================ // Invariants // ============================================================================ -} invariant gf64_sign_mask_single_bit assert (SIGN_MASK & (SIGN_MASK - 1)) == 0 diff --git a/specs/numeric/goldenfloat_family.t27 b/specs/numeric/goldenfloat_family.t27 index 78e552c..43f029d 100644 --- a/specs/numeric/goldenfloat_family.t27 +++ b/specs/numeric/goldenfloat_family.t27 @@ -141,7 +141,7 @@ module GoldenFloatFamily { // 352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 fn get_format_by_name(name: string) -> Option { - for (const GOLDEN_FLOAT_FAMILY) |fmt| { + for fmt in GOLDEN_FLOAT_FAMILY { if (fmt.name == name) { return fmt; } @@ -150,7 +150,7 @@ module GoldenFloatFamily { } fn get_format_by_bits(bits: u8) -> Option { - for (const GOLDEN_FLOAT_FAMILY) |fmt| { + for fmt in GOLDEN_FLOAT_FAMILY { if (fmt.bits == bits) { return fmt; } @@ -188,7 +188,7 @@ module GoldenFloatFamily { // Check for duplicate names var names_seen : [10]string = ["", "", "", "", "", "", "", "", "", ""]; - for (const GOLDEN_FLOAT_FAMILY) |fmt| { + for fmt in GOLDEN_FLOAT_FAMILY { format_count = format_count + 1; // Count primary formats (should be exactly 1) @@ -205,7 +205,7 @@ module GoldenFloatFamily { total_dist = total_dist + fmt.phi_distance; // Check for duplicate names - for (const names_seen) |name| { + for name in names_seen { if (name != "" && name == fmt.name) { all_names_unique = false; } @@ -301,7 +301,7 @@ module GoldenFloatFamily { test gffamily_only_gf16_is_primary var count = 0 - for (const GOLDEN_FLOAT_FAMILY) |fmt| { + for fmt in GOLDEN_FLOAT_FAMILY { if (fmt.is_primary) { count = count + 1; } } then count == 1 @@ -403,23 +403,26 @@ module GoldenFloatFamily { invariant gffamily_gf32_at_index_6 assert GOLDEN_FLOAT_FAMILY[6].name == "GF32" - invariant gffamily_all_formats_have_sign_bits_1 - for (const GOLDEN_FLOAT_FAMILY) |fmt| { + invariant gffamily_all_formats_have_sign_bits_1 { + for fmt in GOLDEN_FLOAT_FAMILY { assert fmt.sign_bits == 1; } + } - invariant gffamily_all_formats_bits_sum_correct - for (const GOLDEN_FLOAT_FAMILY) |fmt| { + invariant gffamily_all_formats_bits_sum_correct { + for fmt in GOLDEN_FLOAT_FAMILY { assert fmt.sign_bits + fmt.exp_bits + fmt.mant_bits == fmt.bits; } + } invariant gffamily_primary_is_gf16 assert GOLDEN_FLOAT_FAMILY[3].is_primary == true - invariant gffamily_phi_distances_non_negative - for (const GOLDEN_FLOAT_FAMILY) |fmt| { + invariant gffamily_phi_distances_non_negative { + for fmt in GOLDEN_FLOAT_FAMILY { assert fmt.phi_distance >= 0.0; } + } invariant gffamily_memory_efficiency_gf4 assert abs(memory_efficiency(GOLDEN_FLOAT_FAMILY[0]) - 0.125) < 0.01 diff --git a/specs/numeric/int4.t27 b/specs/numeric/int4.t27 index 7a49385..508b56f 100644 --- a/specs/numeric/int4.t27 +++ b/specs/numeric/int4.t27 @@ -266,407 +266,406 @@ pub fn int4_abs_diff(a: Int4, b: Int4) Int4 { // ============================================================================ test "int4_from_i8_in_range" { - given value = 5 - try std.testing.expect(result = int4_from_i8(value)); - try std.testing.expect(result == 5); + const value = 5; + const result = int4_from_i8(value); + assert(result == 5); } test "int4_from_i8_above_max" { - given value = 10 - try std.testing.expect(result = int4_from_i8(value)); - try std.testing.expect(result == MAX); + const value = 10; + const result = int4_from_i8(value); + assert(result == MAX); } test "int4_from_i8_below_min" { - given value = -10 - try std.testing.expect(result = int4_from_i8(value)); - try std.testing.expect(result == MIN); + const value = -10; + const result = int4_from_i8(value); + assert(result == MIN); } test "int4_from_i8_at_max" { - given value = 7 - try std.testing.expect(result = int4_from_i8(value)); - try std.testing.expect(result == MAX); + const value = 7; + const result = int4_from_i8(value); + assert(result == MAX); } test "int4_from_i8_at_min" { - given value = -8 - try std.testing.expect(result = int4_from_i8(value)); - try std.testing.expect(result == MIN); + const value = -8; + const result = int4_from_i8(value); + assert(result == MIN); } test "int4_from_i16_positive" { - given value = 100 - try std.testing.expect(result = int4_from_i16(value)); - try std.testing.expect(result == MAX); + const value = 100; + const result = int4_from_i16(value); + assert(result == MAX); } test "int4_from_i16_negative" { - given value = -100 - try std.testing.expect(result = int4_from_i16(value)); - try std.testing.expect(result == MIN); + const value = -100; + const result = int4_from_i16(value); + assert(result == MIN); } test "int4_from_i16_in_range" { - given value = 3 - try std.testing.expect(result = int4_from_i16(value)); - try std.testing.expect(result == 3); + const value = 3; + const result = int4_from_i16(value); + assert(result == 3); } test "int4_from_i32_positive" { - given value = 1000 - try std.testing.expect(result = int4_from_i32(value)); - try std.testing.expect(result == MAX); + const value = 1000; + const result = int4_from_i32(value); + assert(result == MAX); } test "int4_from_i32_negative" { - given value = -1000 - try std.testing.expect(result = int4_from_i32(value)); - try std.testing.expect(result == MIN); + const value = -1000; + const result = int4_from_i32(value); + assert(result == MIN); } test "int4_from_f32_zero" { - given value = 0.0 - try std.testing.expect(result = int4_from_f32(value)); - try std.testing.expect(result == 0); + const value = 0.0; + const result = int4_from_f32(value); + assert(result == 0); } test "int4_from_f32_one" { - given value = 1.0 - try std.testing.expect(result = int4_from_f32(value)); - try std.testing.expect(result == 1); + const value = 1.0; + const result = int4_from_f32(value); + assert(result == 1); } test "int4_from_f32_negative" { - given value = -1.5 - try std.testing.expect(result = int4_from_f32(value)); - try std.testing.expect(result == -2); + const value = -1.5; + const result = int4_from_f32(value); + assert(result == -2); } test "int4_from_f32_nan" { - given result = int4_from_f32(std.math.nan(f32)) - try std.testing.expect(result == 0); + const result = int4_from_f32(std.math.nan(f32)); + assert(result == 0); } test "int4_from_f32_round_up" { - given value = 1.6 - try std.testing.expect(result = int4_from_f32(value)); - try std.testing.expect(result == 2); + const value = 1.6; + const result = int4_from_f32(value); + assert(result == 2); } test "int4_from_f32_round_down" { - given value = 1.4 - try std.testing.expect(result = int4_from_f32(value)); - try std.testing.expect(result == 1); + const value = 1.4; + const result = int4_from_f32(value); + assert(result == 1); } test "int4_to_i8_identity" { - given value: Int4 = 5 - try std.testing.expect(result = int4_to_i8(value)); - try std.testing.expect(result == value); + const value: Int4 = 5; + const result = int4_to_i8(value); + assert(result == value); } test "int4_to_i16_sign_extend" { - given value: Int4 = -1 - try std.testing.expect(result = int4_to_i16(value)); - try std.testing.expect(result == -1); + const value: Int4 = -1; + const result = int4_to_i16(value); + assert(result == -1); } test "int4_to_i32_sign_extend" { - given value: Int4 = -1 - try std.testing.expect(result = int4_to_i32(value)); - try std.testing.expect(result == -1); + const value: Int4 = -1; + const result = int4_to_i32(value); + assert(result == -1); } test "int4_to_f32_positive" { - given value: Int4 = 5 - try std.testing.expect(result = int4_to_f32(value)); - try std.testing.expect(abs(result - 5.0) < 0.001); + const value: Int4 = 5; + const result = int4_to_f32(value); + assert(abs(result - 5.0) < 0.001); } test "int4_to_f32_negative" { - given value: Int4 = -3 - try std.testing.expect(result = int4_to_f32(value)); - try std.testing.expect(abs(result + 3.0) < 0.001); + const value: Int4 = -3; + const result = int4_to_f32(value); + assert(abs(result + 3.0) < 0.001); } test "int4_add_simple" { - given a: Int4 = 3 - try std.testing.expect(b: Int4 = 4); - try std.testing.expect(result = int4_add(a, b)); - try std.testing.expect(result == MAX // 3 + 4 = 7 = MAX); + const a: Int4 = 3; + const b: Int4 = 4; + const result = int4_add(a, b); + assert(result == MAX); // 3 + 4 = 7 = MAX } test "int4_add_overflow" { - given a: Int4 = 5 - try std.testing.expect(b: Int4 = 5); - try std.testing.expect(result = int4_add(a, b)); - try std.testing.expect(result == MAX // 5 + 5 = 10 -> 7); + const a: Int4 = 5; + const b: Int4 = 5; + const result = int4_add(a, b); + assert(result == MAX); // 5 + 5 = 10 -> 7 } test "int4_add_underflow" { - given a: Int4 = -5 - try std.testing.expect(b: Int4 = -5); - try std.testing.expect(result = int4_add(a, b)); - try std.testing.expect(result == MIN // -5 + -5 = -10 -> -8); + const a: Int4 = -5; + const b: Int4 = -5; + const result = int4_add(a, b); + assert(result == MIN); // -5 + -5 = -10 -> -8 } test "int4_sub_simple" { - given a: Int4 = 7 - try std.testing.expect(b: Int4 = 3); - try std.testing.expect(result = int4_sub(a, b)); - try std.testing.expect(result == 4); + const a: Int4 = 7; + const b: Int4 = 3; + const result = int4_sub(a, b); + assert(result == 4); } test "int4_sub_negative" { - given a: Int4 = 3 - try std.testing.expect(b: Int4 = 7); - try std.testing.expect(result = int4_sub(a, b)); - try std.testing.expect(result == -4); + const a: Int4 = 3; + const b: Int4 = 7; + const result = int4_sub(a, b); + assert(result == -4); } test "int4_mul_positive" { - given a: Int4 = 2 - try std.testing.expect(b: Int4 = 3); - try std.testing.expect(result = int4_mul(a, b)); - try std.testing.expect(result == 6); + const a: Int4 = 2; + const b: Int4 = 3; + const result = int4_mul(a, b); + assert(result == 6); } test "int4_mul_negative" { - given a: Int4 = -2 - try std.testing.expect(b: Int4 = 3); - try std.testing.expect(result = int4_mul(a, b)); - try std.testing.expect(result == -6); + const a: Int4 = -2; + const b: Int4 = 3; + const result = int4_mul(a, b); + assert(result == -6); } test "int4_mul_overflow" { - given a: Int4 = 4 - try std.testing.expect(b: Int4 = 4); - try std.testing.expect(result = int4_mul(a, b)); - try std.testing.expect(result == MAX // 4 * 4 = 16 -> 7); + const a: Int4 = 4; + const b: Int4 = 4; + const result = int4_mul(a, b); + assert(result == MAX); // 4 * 4 = 16 -> 7 } test "int4_div_simple" { - given a: Int4 = 6 - try std.testing.expect(b: Int4 = 2); - try std.testing.expect(result = int4_div(a, b)); - try std.testing.expect(result == 3); + const a: Int4 = 6; + const b: Int4 = 2; + const result = int4_div(a, b); + assert(result == 3); } test "int4_div_by_zero_positive" { - given a: Int4 = 5 - try std.testing.expect(b: Int4 = 0); - try std.testing.expect(result = int4_div(a, b)); - try std.testing.expect(result == MAX); + const a: Int4 = 5; + const b: Int4 = 0; + const result = int4_div(a, b); + assert(result == MAX); } test "int4_div_by_zero_negative" { - given a: Int4 = -5 - try std.testing.expect(b: Int4 = 0); - try std.testing.expect(result = int4_div(a, b)); - try std.testing.expect(result == MIN); + const a: Int4 = -5; + const b: Int4 = 0; + const result = int4_div(a, b); + assert(result == MIN); } test "int4_abs_positive" { - given value: Int4 = 5 - try std.testing.expect(result = int4_abs(value)); - try std.testing.expect(result == 5); + const value: Int4 = 5; + const result = int4_abs(value); + assert(result == 5); } test "int4_abs_negative" { - given value: Int4 = -5 - try std.testing.expect(result = int4_abs(value)); - try std.testing.expect(result == 5); + const value: Int4 = -5; + const result = int4_abs(value); + assert(result == 5); } test "int4_abs_min" { - given value: Int4 = MIN - try std.testing.expect(result = int4_abs(value)); - try std.testing.expect(result == MAX // |-8| = 7 (saturated)); + const value: Int4 = MIN; + const result = int4_abs(value); + assert(result == MAX); // |-8| = 7 (saturated) } test "int4_neg_positive" { - given value: Int4 = 5 - try std.testing.expect(result = int4_neg(value)); - try std.testing.expect(result == -5); + const value: Int4 = 5; + const result = int4_neg(value); + assert(result == -5); } test "int4_neg_negative" { - given value: Int4 = -5 - try std.testing.expect(result = int4_neg(value)); - try std.testing.expect(result == 5); + const value: Int4 = -5; + const result = int4_neg(value); + assert(result == 5); } test "int4_neg_min" { - given value: Int4 = MIN - try std.testing.expect(result = int4_neg(value)); - try std.testing.expect(result == MAX // -(-8) = 7 (saturated)); + const value: Int4 = MIN; + const result = int4_neg(value); + assert(result == MAX); // -(-8) = 7 (saturated) } test "int4_is_equal_true" { - given a: Int4 = 3 - try std.testing.expect(b: Int4 = 3); - try std.testing.expect(int4_is_equal(a, b) == true); + const a: Int4 = 3; + const b: Int4 = 3; + assert(int4_is_equal(a, b) == true); } test "int4_is_equal_false" { - given a: Int4 = 3 - try std.testing.expect(b: Int4 = 5); - try std.testing.expect(int4_is_equal(a, b) == false); + const a: Int4 = 3; + const b: Int4 = 5; + assert(int4_is_equal(a, b) == false); } test "int4_is_greater_true" { - given a: Int4 = 5 - try std.testing.expect(b: Int4 = 3); - try std.testing.expect(int4_is_greater(a, b) == true); + const a: Int4 = 5; + const b: Int4 = 3; + assert(int4_is_greater(a, b) == true); } test "int4_is_greater_false" { - given a: Int4 = 3 - try std.testing.expect(b: Int4 = 5); - try std.testing.expect(int4_is_greater(a, b) == false); + const a: Int4 = 3; + const b: Int4 = 5; + assert(int4_is_greater(a, b) == false); } test "int4_min_smaller" { - given a: Int4 = 3 - try std.testing.expect(b: Int4 = 5); - try std.testing.expect(result = int4_min(a, b)); - try std.testing.expect(result == 3); + const a: Int4 = 3; + const b: Int4 = 5; + const result = int4_min(a, b); + assert(result == 3); } test "int4_min_larger" { - given a: Int4 = 5 - try std.testing.expect(b: Int4 = 3); - try std.testing.expect(result = int4_min(a, b)); - try std.testing.expect(result == 3); + const a: Int4 = 5; + const b: Int4 = 3; + const result = int4_min(a, b); + assert(result == 3); } test "int4_max_smaller" { - given a: Int4 = 3 - try std.testing.expect(b: Int4 = 5); - try std.testing.expect(result = int4_max(a, b)); - try std.testing.expect(result == 5); + const a: Int4 = 3; + const b: Int4 = 5; + const result = int4_max(a, b); + assert(result == 5); } test "int4_max_larger" { - given a: Int4 = 5 - try std.testing.expect(b: Int4 = 3); - try std.testing.expect(result = int4_max(a, b)); - try std.testing.expect(result == 5); + const a: Int4 = 5; + const b: Int4 = 3; + const result = int4_max(a, b); + assert(result == 5); } test "int4_clamp_in_range" { - given value: Int4 = 5 - try std.testing.expect(min: Int4 = 0); - try std.testing.expect(max: Int4 = MAX); - try std.testing.expect(result = int4_clamp(value, min, max)); - try std.testing.expect(result == 5); + const value: Int4 = 5; + const min: Int4 = 0; + const max: Int4 = MAX; + const result = int4_clamp(value, min, max); + assert(result == 5); } test "int4_clamp_below_min" { - given value: Int4 = -10 - try std.testing.expect(min: Int4 = -5); - try std.testing.expect(max: Int4 = MAX); - try std.testing.expect(result = int4_clamp(value, min, max)); - try std.testing.expect(result == -5); + const value: Int4 = -10; + const min: Int4 = -5; + const max: Int4 = MAX; + const result = int4_clamp(value, min, max); + assert(result == -5); } test "int4_clamp_above_max" { - given value: Int4 = 10 - try std.testing.expect(min: Int4 = MIN); - try std.testing.expect(max: Int4 = 5); - try std.testing.expect(result = int4_clamp(value, min, max)); - try std.testing.expect(result == 5); + const value: Int4 = 10; + const min: Int4 = MIN; + const max: Int4 = 5; + const result = int4_clamp(value, min, max); + assert(result == 5); } test "int4_is_in_range_true" { - try std.testing.expect(int4_is_in_range(5) == true); + assert(int4_is_in_range(5) == true); } test "int4_is_in_range_false_high" { - try std.testing.expect(int4_is_in_range(10) == false); + assert(int4_is_in_range(10) == false); } test "int4_is_in_range_false_low" { - try std.testing.expect(int4_is_in_range(-10) == false); + assert(int4_is_in_range(-10) == false); } test "int4_is_in_range_at_max" { - try std.testing.expect(int4_is_in_range(MAX) == true); + assert(int4_is_in_range(MAX) == true); } test "int4_is_in_range_at_min" { - try std.testing.expect(int4_is_in_range(MIN) == true); + assert(int4_is_in_range(MIN) == true); } test "int4_lerp_zero" { - given a: Int4 = 1 - try std.testing.expect(b: Int4 = 5); - try std.testing.expect(t = 0.0); - try std.testing.expect(result = int4_lerp(a, b, t)); - try std.testing.expect(result == 1); + const a: Int4 = 1; + const b: Int4 = 5; + const t = 0.0; + const result = int4_lerp(a, b, t); + assert(result == 1); } test "int4_lerp_one" { - given a: Int4 = 1 - try std.testing.expect(b: Int4 = 5); - try std.testing.expect(t = 1.0); - try std.testing.expect(result = int4_lerp(a, b, t)); - try std.testing.expect(result == 5); + const a: Int4 = 1; + const b: Int4 = 5; + const t = 1.0; + const result = int4_lerp(a, b, t); + assert(result == 5); } test "int4_lerp_half" { - given a: Int4 = 0 - try std.testing.expect(b: Int4 = 4); - try std.testing.expect(t = 0.5); - try std.testing.expect(result = int4_lerp(a, b, t)); - try std.testing.expect(result == 2); + const a: Int4 = 0; + const b: Int4 = 4; + const t = 0.5; + const result = int4_lerp(a, b, t); + assert(result == 2); } test "int4_sq_positive" { - given value: Int4 = 3 - try std.testing.expect(result = int4_sq(value)); - try std.testing.expect(result == 9 // saturates to 7); + const value: Int4 = 3; + const result = int4_sq(value); + assert(result == 9); // saturates to 7 } test "int4_sq_negative" { - given value: Int4 = -3 - try std.testing.expect(result = int4_sq(value)); - try std.testing.expect(result == 9 // saturates to 7); + const value: Int4 = -3; + const result = int4_sq(value); + assert(result == 9); // saturates to 7 } test "int4_sq_zero" { - given value: Int4 = 0 - try std.testing.expect(result = int4_sq(value)); - try std.testing.expect(result == 0); + const value: Int4 = 0; + const result = int4_sq(value); + assert(result == 0); } test "int4_abs_diff_same" { - given a: Int4 = 5 - try std.testing.expect(b: Int4 = 5); - try std.testing.expect(result = int4_abs_diff(a, b)); - try std.testing.expect(result == 0); + const a: Int4 = 5; + const b: Int4 = 5; + const result = int4_abs_diff(a, b); + assert(result == 0); } test "int4_abs_diff_positive" { - given a: Int4 = 5 - try std.testing.expect(b: Int4 = 2); - try std.testing.expect(result = int4_abs_diff(a, b)); - try std.testing.expect(result == 3); + const a: Int4 = 5; + const b: Int4 = 2; + const result = int4_abs_diff(a, b); + assert(result == 3); } test "int4_abs_diff_negative" { - given a: Int4 = 2 - try std.testing.expect(b: Int4 = 5); - try std.testing.expect(result = int4_abs_diff(a, b)); - try std.testing.expect(result == 3); + const a: Int4 = 2; + const b: Int4 = 5; + const result = int4_abs_diff(a, b); + assert(result == 3); } // ============================================================================ // Invariants // ============================================================================ -} invariant int4_bits_constant assert BITS == 4 @@ -721,20 +720,20 @@ invariant int4_abs_non_negative invariant int4_neg_twice_original given value: Int4 = 5 - try std.testing.expect(neg = int4_neg(value)); - try std.testing.expect(neg_again = int4_neg(neg)); + when neg = int4_neg(value) + and neg_again = int4_neg(neg) assert neg_again == value or value == MIN // MIN saturates invariant int4_min_le_both given a: Int4 = 3 - try std.testing.expect(b: Int4 = 5); - try std.testing.expect(result = int4_min(a, b)); + and b: Int4 = 5 + and result = int4_min(a, b) assert result <= a and result <= b invariant int4_max_ge_both given a: Int4 = 3 - try std.testing.expect(b: Int4 = 5); - try std.testing.expect(result = int4_max(a, b)); + and b: Int4 = 5 + and result = int4_max(a, b) assert result >= a and result >= b invariant int4_clamp_result_in_range diff --git a/specs/numeric/int8.t27 b/specs/numeric/int8.t27 index 82e33b8..a20e18a 100644 --- a/specs/numeric/int8.t27 +++ b/specs/numeric/int8.t27 @@ -452,545 +452,544 @@ pub fn int8_reverse_bits(value: Int8) Int8 { // ============================================================================ test "int8_from_i8_identity" { - given value = 42 - try std.testing.expect(result = int8_from_i8(value)); - try std.testing.expect(result == 42); + const value = 42; + const result = int8_from_i8(value); + assert(result == 42); } test "int8_from_i16_positive" { - given value = 100 - try std.testing.expect(result = int8_from_i16(value)); - try std.testing.expect(result == 100); + const value = 100; + const result = int8_from_i16(value); + assert(result == 100); } test "int8_from_i16_overflow" { - given value = 200 - try std.testing.expect(result = int8_from_i16(value)); - try std.testing.expect(result == MAX); + const value = 200; + const result = int8_from_i16(value); + assert(result == MAX); } test "int8_from_i16_negative" { - given value = -50 - try std.testing.expect(result = int8_from_i16(value)); - try std.testing.expect(result == -50); + const value = -50; + const result = int8_from_i16(value); + assert(result == -50); } test "int8_from_i16_underflow" { - given value = -200 - try std.testing.expect(result = int8_from_i16(value)); - try std.testing.expect(result == MIN); + const value = -200; + const result = int8_from_i16(value); + assert(result == MIN); } test "int8_from_i32_in_range" { - given value = 42 - try std.testing.expect(result = int8_from_i32(value)); - try std.testing.expect(result == 42); + const value = 42; + const result = int8_from_i32(value); + assert(result == 42); } test "int8_from_i32_overflow" { - given value = 1000 - try std.testing.expect(result = int8_from_i32(value)); - try std.testing.expect(result == MAX); + const value = 1000; + const result = int8_from_i32(value); + assert(result == MAX); } test "int8_from_u8_in_range" { - given value = 100 - try std.testing.expect(result = int8_from_u8(value)); - try std.testing.expect(result == 100); + const value = 100; + const result = int8_from_u8(value); + assert(result == 100); } test "int8_from_u8_overflow" { - given value = 200 - try std.testing.expect(result = int8_from_u8(value)); - try std.testing.expect(result == MAX); + const value = 200; + const result = int8_from_u8(value); + assert(result == MAX); } test "int8_from_f32_zero" { - given value = 0.0 - try std.testing.expect(result = int8_from_f32(value)); - try std.testing.expect(result == 0); + const value = 0.0; + const result = int8_from_f32(value); + assert(result == 0); } test "int8_from_f32_one" { - given value = 1.0 - try std.testing.expect(result = int8_from_f32(value)); - try std.testing.expect(result == 1); + const value = 1.0; + const result = int8_from_f32(value); + assert(result == 1); } test "int8_from_f32_round_up" { - given value = 1.6 - try std.testing.expect(result = int8_from_f32(value)); - try std.testing.expect(result == 2); + const value = 1.6; + const result = int8_from_f32(value); + assert(result == 2); } test "int8_from_f32_round_down" { - given value = 1.4 - try std.testing.expect(result = int8_from_f32(value)); - try std.testing.expect(result == 1); + const value = 1.4; + const result = int8_from_f32(value); + assert(result == 1); } test "int8_from_f32_nan" { - given result = int8_from_f32(std.math.nan(f32)) - try std.testing.expect(result == 0); + const result = int8_from_f32(std.math.nan(f32)); + assert(result == 0); } test "int8_to_i8_identity" { - given value: Int8 = 42 - try std.testing.expect(result = int8_to_i8(value)); - try std.testing.expect(result == 42); + const value: Int8 = 42; + const result = int8_to_i8(value); + assert(result == 42); } test "int8_to_i16_sign_extend" { - given value: Int8 = -1 - try std.testing.expect(result = int8_to_i16(value)); - try std.testing.expect(result == -1); + const value: Int8 = -1; + const result = int8_to_i16(value); + assert(result == -1); } test "int8_to_i32_sign_extend" { - given value: Int8 = -1 - try std.testing.expect(result = int8_to_i32(value)); - try std.testing.expect(result == -1); + const value: Int8 = -1; + const result = int8_to_i32(value); + assert(result == -1); } test "int8_to_u8_positive" { - given value: Int8 = 42 - try std.testing.expect(result = int8_to_u8(value)); - try std.testing.expect(result.? == 42); + const value: Int8 = 42; + const result = int8_to_u8(value); + assert(result.? == 42); } test "int8_to_u8_negative" { - given value: Int8 = -1 - try std.testing.expect(result = int8_to_u8(value)); - try std.testing.expect(result == null); + const value: Int8 = -1; + const result = int8_to_u8(value); + assert(result == null); } test "int8_add_simple" { - given a: Int8 = 50 - try std.testing.expect(b: Int8 = 30); - try std.testing.expect(result = int8_add(a, b)); - try std.testing.expect(result == 80); + const a: Int8 = 50; + const b: Int8 = 30; + const result = int8_add(a, b); + assert(result == 80); } test "int8_add_overflow" { - given a: Int8 = 100 - try std.testing.expect(b: Int8 = 50); - try std.testing.expect(result = int8_add(a, b)); - try std.testing.expect(result == MAX); + const a: Int8 = 100; + const b: Int8 = 50; + const result = int8_add(a, b); + assert(result == MAX); } test "int8_add_underflow" { - given a: Int8 = -100 - try std.testing.expect(b: Int8 = -50); - try std.testing.expect(result = int8_add(a, b)); - try std.testing.expect(result == MIN); + const a: Int8 = -100; + const b: Int8 = -50; + const result = int8_add(a, b); + assert(result == MIN); } test "int8_sub_simple" { - given a: Int8 = 50 - try std.testing.expect(b: Int8 = 30); - try std.testing.expect(result = int8_sub(a, b)); - try std.testing.expect(result == 20); + const a: Int8 = 50; + const b: Int8 = 30; + const result = int8_sub(a, b); + assert(result == 20); } test "int8_sub_negative" { - given a: Int8 = 30 - try std.testing.expect(b: Int8 = 50); - try std.testing.expect(result = int8_sub(a, b)); - try std.testing.expect(result == -20); + const a: Int8 = 30; + const b: Int8 = 50; + const result = int8_sub(a, b); + assert(result == -20); } test "int8_mul_positive" { - given a: Int8 = 10 - try std.testing.expect(b: Int8 = 5); - try std.testing.expect(result = int8_mul(a, b)); - try std.testing.expect(result == 50); + const a: Int8 = 10; + const b: Int8 = 5; + const result = int8_mul(a, b); + assert(result == 50); } test "int8_mul_negative" { - given a: Int8 = -10 - try std.testing.expect(b: Int8 = 5); - try std.testing.expect(result = int8_mul(a, b)); - try std.testing.expect(result == -50); + const a: Int8 = -10; + const b: Int8 = 5; + const result = int8_mul(a, b); + assert(result == -50); } test "int8_mul_overflow" { - given a: Int8 = 20 - try std.testing.expect(b: Int8 = 20); - try std.testing.expect(result = int8_mul(a, b)); - try std.testing.expect(result == MAX); + const a: Int8 = 20; + const b: Int8 = 20; + const result = int8_mul(a, b); + assert(result == MAX); } test "int8_div_simple" { - given a: Int8 = 50 - try std.testing.expect(b: Int8 = 5); - try std.testing.expect(result = int8_div(a, b)); - try std.testing.expect(result == 10); + const a: Int8 = 50; + const b: Int8 = 5; + const result = int8_div(a, b); + assert(result == 10); } test "int8_div_by_zero_positive" { - given a: Int8 = 50 - try std.testing.expect(b: Int8 = 0); - try std.testing.expect(result = int8_div(a, b)); - try std.testing.expect(result == MAX); + const a: Int8 = 50; + const b: Int8 = 0; + const result = int8_div(a, b); + assert(result == MAX); } test "int8_div_by_zero_negative" { - given a: Int8 = -50 - try std.testing.expect(b: Int8 = 0); - try std.testing.expect(result = int8_div(a, b)); - try std.testing.expect(result == MIN); + const a: Int8 = -50; + const b: Int8 = 0; + const result = int8_div(a, b); + assert(result == MIN); } test "int8_mod_simple" { - given a: Int8 = 10 - try std.testing.expect(b: Int8 = 3); - try std.testing.expect(result = int8_mod(a, b)); - try std.testing.expect(result == 1); + const a: Int8 = 10; + const b: Int8 = 3; + const result = int8_mod(a, b); + assert(result == 1); } test "int8_mod_by_zero" { - given a: Int8 = 10 - try std.testing.expect(b: Int8 = 0); - try std.testing.expect(result = int8_mod(a, b)); - try std.testing.expect(result == 0); + const a: Int8 = 10; + const b: Int8 = 0; + const result = int8_mod(a, b); + assert(result == 0); } test "int8_pow_zero" { - given base: Int8 = 5 - try std.testing.expect(exp: u8 = 0); - try std.testing.expect(result = int8_pow(base, exp)); - try std.testing.expect(result == 1); + const base: Int8 = 5; + const exp: u8 = 0; + const result = int8_pow(base, exp); + assert(result == 1); } test "int8_pow_one" { - given base: Int8 = 5 - try std.testing.expect(exp: u8 = 1); - try std.testing.expect(result = int8_pow(base, exp)); - try std.testing.expect(result == 5); + const base: Int8 = 5; + const exp: u8 = 1; + const result = int8_pow(base, exp); + assert(result == 5); } test "int8_pow_two" { - given base: Int8 = 5 - try std.testing.expect(exp: u8 = 2); - try std.testing.expect(result = int8_pow(base, exp)); - try std.testing.expect(result == 25); + const base: Int8 = 5; + const exp: u8 = 2; + const result = int8_pow(base, exp); + assert(result == 25); } test "int8_pow_overflow" { - given base: Int8 = 20 - try std.testing.expect(exp: u8 = 2); - try std.testing.expect(result = int8_pow(base, exp)); - try std.testing.expect(result == MAX); + const base: Int8 = 20; + const exp: u8 = 2; + const result = int8_pow(base, exp); + assert(result == MAX); } test "int8_and_simple" { - given a: Int8 = 0b10101010 - try std.testing.expect(b: Int8 = 0b11001100); - try std.testing.expect(result = int8_and(a, b)); - try std.testing.expect(result == 0b10001000); + const a: Int8 = 0b10101010; + const b: Int8 = 0b11001100; + const result = int8_and(a, b); + assert(result == 0b10001000); } test "int8_or_simple" { - given a: Int8 = 0b10101010 - try std.testing.expect(b: Int8 = 0b11001100); - try std.testing.expect(result = int8_or(a, b)); - try std.testing.expect(result == 0b11101110); + const a: Int8 = 0b10101010; + const b: Int8 = 0b11001100; + const result = int8_or(a, b); + assert(result == 0b11101110); } test "int8_xor_simple" { - given a: Int8 = 0b10101010 - try std.testing.expect(b: Int8 = 0b11001100); - try std.testing.expect(result = int8_xor(a, b)); - try std.testing.expect(result == 0b01100110); + const a: Int8 = 0b10101010; + const b: Int8 = 0b11001100; + const result = int8_xor(a, b); + assert(result == 0b01100110); } test "int8_not_simple" { - given value: Int8 = 0b10101010 - try std.testing.expect(result = int8_not(value)); - try std.testing.expect(result == 0b01010101); + const value: Int8 = 0b10101010; + const result = int8_not(value); + assert(result == 0b01010101); } test "int8_shl_simple" { - given value: Int8 = 0b00000011 - try std.testing.expect(amount: u8 = 2); - try std.testing.expect(result = int8_shl(value, amount)); - try std.testing.expect(result == 0b00001100); + const value: Int8 = 0b00000011; + const amount: u8 = 2; + const result = int8_shl(value, amount); + assert(result == 0b00001100); } test "int8_shl_overflow" { - given value: Int8 = 64 - try std.testing.expect(amount: u8 = 2); - try std.testing.expect(result = int8_shl(value, amount)); - try std.testing.expect(result == MAX); + const value: Int8 = 64; + const amount: u8 = 2; + const result = int8_shl(value, amount); + assert(result == MAX); } test "int8_shr_simple" { - given value: Int8 = 0b00001100 - try std.testing.expect(amount: u8 = 2); - try std.testing.expect(result = int8_shr(value, amount)); - try std.testing.expect(result == 0b00000011); + const value: Int8 = 0b00001100; + const amount: u8 = 2; + const result = int8_shr(value, amount); + assert(result == 0b00000011); } test "int8_rol_simple" { - given value: Int8 = 0b00000011 - try std.testing.expect(amount: u8 = 2); - try std.testing.expect(result = int8_rol(value, amount)); - try std.testing.expect(result == 0b00001100); + const value: Int8 = 0b00000011; + const amount: u8 = 2; + const result = int8_rol(value, amount); + assert(result == 0b00001100); } test "int8_ror_simple" { - given value: Int8 = 0b00001100 - try std.testing.expect(amount: u8 = 2); - try std.testing.expect(result = int8_ror(value, amount)); - try std.testing.expect(result == 0b00000011); + const value: Int8 = 0b00001100; + const amount: u8 = 2; + const result = int8_ror(value, amount); + assert(result == 0b00000011); } test "int8_abs_positive" { - given value: Int8 = 42 - try std.testing.expect(result = int8_abs(value)); - try std.testing.expect(result == 42); + const value: Int8 = 42; + const result = int8_abs(value); + assert(result == 42); } test "int8_abs_negative" { - given value: Int8 = -42 - try std.testing.expect(result = int8_abs(value)); - try std.testing.expect(result == 42); + const value: Int8 = -42; + const result = int8_abs(value); + assert(result == 42); } test "int8_abs_min" { - given value: Int8 = MIN - try std.testing.expect(result = int8_abs(value)); - try std.testing.expect(result == MAX); + const value: Int8 = MIN; + const result = int8_abs(value); + assert(result == MAX); } test "int8_neg_positive" { - given value: Int8 = 42 - try std.testing.expect(result = int8_neg(value)); - try std.testing.expect(result == -42); + const value: Int8 = 42; + const result = int8_neg(value); + assert(result == -42); } test "int8_neg_negative" { - given value: Int8 = -42 - try std.testing.expect(result = int8_neg(value)); - try std.testing.expect(result == 42); + const value: Int8 = -42; + const result = int8_neg(value); + assert(result == 42); } test "int8_neg_min" { - given value: Int8 = MIN - try std.testing.expect(result = int8_neg(value)); - try std.testing.expect(result == MAX); + const value: Int8 = MIN; + const result = int8_neg(value); + assert(result == MAX); } test "int8_sign_positive" { - given value: Int8 = 42 - try std.testing.expect(result = int8_sign(value)); - try std.testing.expect(result == 1); + const value: Int8 = 42; + const result = int8_sign(value); + assert(result == 1); } test "int8_sign_negative" { - given value: Int8 = -42 - try std.testing.expect(result = int8_sign(value)); - try std.testing.expect(result == -1); + const value: Int8 = -42; + const result = int8_sign(value); + assert(result == -1); } test "int8_sign_zero" { - given value: Int8 = 0 - try std.testing.expect(result = int8_sign(value)); - try std.testing.expect(result == 0); + const value: Int8 = 0; + const result = int8_sign(value); + assert(result == 0); } test "int8_min_smaller" { - given a: Int8 = 42 - try std.testing.expect(b: Int8 = 50); - try std.testing.expect(result = int8_min(a, b)); - try std.testing.expect(result == 42); + const a: Int8 = 42; + const b: Int8 = 50; + const result = int8_min(a, b); + assert(result == 42); } test "int8_max_larger" { - given a: Int8 = 42 - try std.testing.expect(b: Int8 = 50); - try std.testing.expect(result = int8_max(a, b)); - try std.testing.expect(result == 50); + const a: Int8 = 42; + const b: Int8 = 50; + const result = int8_max(a, b); + assert(result == 50); } test "int8_clamp_in_range" { - given value: Int8 = 42 - try std.testing.expect(min: Int8 = 0); - try std.testing.expect(max: Int8 = 100); - try std.testing.expect(result = int8_clamp(value, min, max)); - try std.testing.expect(result == 42); + const value: Int8 = 42; + const min: Int8 = 0; + const max: Int8 = 100; + const result = int8_clamp(value, min, max); + assert(result == 42); } test "int8_clamp_below" { - given value: Int8 = -50 - try std.testing.expect(min: Int8 = 0); - try std.testing.expect(max: Int8 = 100); - try std.testing.expect(result = int8_clamp(value, min, max)); - try std.testing.expect(result == 0); + const value: Int8 = -50; + const min: Int8 = 0; + const max: Int8 = 100; + const result = int8_clamp(value, min, max); + assert(result == 0); } test "int8_clamp_above" { - given value: Int8 = 150 - try std.testing.expect(min: Int8 = 0); - try std.testing.expect(max: Int8 = 100); - try std.testing.expect(result = int8_clamp(value, min, max)); - try std.testing.expect(result == 100); + const value: Int8 = 150; + const min: Int8 = 0; + const max: Int8 = 100; + const result = int8_clamp(value, min, max); + assert(result == 100); } test "int8_lerp_zero" { - given a: Int8 = 10 - try std.testing.expect(b: Int8 = 50); - try std.testing.expect(t = 0.0); - try std.testing.expect(result = int8_lerp(a, b, t)); - try std.testing.expect(result == 10); + const a: Int8 = 10; + const b: Int8 = 50; + const t = 0.0; + const result = int8_lerp(a, b, t); + assert(result == 10); } test "int8_lerp_one" { - given a: Int8 = 10 - try std.testing.expect(b: Int8 = 50); - try std.testing.expect(t = 1.0); - try std.testing.expect(result = int8_lerp(a, b, t)); - try std.testing.expect(result == 50); + const a: Int8 = 10; + const b: Int8 = 50; + const t = 1.0; + const result = int8_lerp(a, b, t); + assert(result == 50); } test "int8_lerp_half" { - given a: Int8 = 0 - try std.testing.expect(b: Int8 = 20); - try std.testing.expect(t = 0.5); - try std.testing.expect(result = int8_lerp(a, b, t)); - try std.testing.expect(result == 10); + const a: Int8 = 0; + const b: Int8 = 20; + const t = 0.5; + const result = int8_lerp(a, b, t); + assert(result == 10); } test "int8_sq_positive" { - given value: Int8 = 10 - try std.testing.expect(result = int8_sq(value)); - try std.testing.expect(result == 100); + const value: Int8 = 10; + const result = int8_sq(value); + assert(result == 100); } test "int8_sq_negative" { - given value: Int8 = -10 - try std.testing.expect(result = int8_sq(value)); - try std.testing.expect(result == 100); + const value: Int8 = -10; + const result = int8_sq(value); + assert(result == 100); } test "int8_sq_overflow" { - given value: Int8 = 20 - try std.testing.expect(result = int8_sq(value)); - try std.testing.expect(result == MAX); + const value: Int8 = 20; + const result = int8_sq(value); + assert(result == MAX); } test "int8_abs_diff_same" { - given a: Int8 = 42 - try std.testing.expect(b: Int8 = 42); - try std.testing.expect(result = int8_abs_diff(a, b)); - try std.testing.expect(result == 0); + const a: Int8 = 42; + const b: Int8 = 42; + const result = int8_abs_diff(a, b); + assert(result == 0); } test "int8_abs_diff_positive" { - given a: Int8 = 50 - try std.testing.expect(b: Int8 = 30); - try std.testing.expect(result = int8_abs_diff(a, b)); - try std.testing.expect(result == 20); + const a: Int8 = 50; + const b: Int8 = 30; + const result = int8_abs_diff(a, b); + assert(result == 20); } test "int8_sqrt_zero" { - given value: Int8 = 0 - try std.testing.expect(result = int8_sqrt(value)); - try std.testing.expect(result == 0); + const value: Int8 = 0; + const result = int8_sqrt(value); + assert(result == 0); } test "int8_sqrt_one" { - given value: Int8 = 1 - try std.testing.expect(result = int8_sqrt(value)); - try std.testing.expect(result == 1); + const value: Int8 = 1; + const result = int8_sqrt(value); + assert(result == 1); } test "int8_sqrt_four" { - given value: Int8 = 4 - try std.testing.expect(result = int8_sqrt(value)); - try std.testing.expect(result == 2); + const value: Int8 = 4; + const result = int8_sqrt(value); + assert(result == 2); } test "int8_sqrt_sixteen" { - given value: Int8 = 16 - try std.testing.expect(result = int8_sqrt(value)); - try std.testing.expect(result == 4); + const value: Int8 = 16; + const result = int8_sqrt(value); + assert(result == 4); } test "int8_sqrt_negative" { - given value: Int8 = -4 - try std.testing.expect(result = int8_sqrt(value)); - try std.testing.expect(result == 0); + const value: Int8 = -4; + const result = int8_sqrt(value); + assert(result == 0); } test "int8_is_power_of_two_true" { - given value: Int8 = 8 - try std.testing.expect(int8_is_power_of_two(value) == true); + const value: Int8 = 8; + assert(int8_is_power_of_two(value) == true); } test "int8_is_power_of_two_false" { - given value: Int8 = 6 - try std.testing.expect(int8_is_power_of_two(value) == false); + const value: Int8 = 6; + assert(int8_is_power_of_two(value) == false); } test "int8_is_power_of_two_zero" { - given value: Int8 = 0 - try std.testing.expect(int8_is_power_of_two(value) == false); + const value: Int8 = 0; + assert(int8_is_power_of_two(value) == false); } test "int8_count_ones_zero" { - given value: Int8 = 0 - try std.testing.expect(result = int8_count_ones(value)); - try std.testing.expect(result == 0); + const value: Int8 = 0; + const result = int8_count_ones(value); + assert(result == 0); } test "int8_count_ones_all" { - given value: Int8 = 0xFF - try std.testing.expect(result = int8_count_ones(value)); - try std.testing.expect(result == 8); + const value: Int8 = 0xFF; + const result = int8_count_ones(value); + assert(result == 8); } test "int8_count_ones_mixed" { - given value: Int8 = 0b10101010 - try std.testing.expect(result = int8_count_ones(value)); - try std.testing.expect(result == 4); + const value: Int8 = 0b10101010; + const result = int8_count_ones(value); + assert(result == 4); } test "int8_count_zeros_zero" { - given value: Int8 = 0 - try std.testing.expect(result = int8_count_zeros(value)); - try std.testing.expect(result == 8); + const value: Int8 = 0; + const result = int8_count_zeros(value); + assert(result == 8); } test "int8_count_zeros_all" { - given value: Int8 = 0xFF - try std.testing.expect(result = int8_count_zeros(value)); - try std.testing.expect(result == 0); + const value: Int8 = 0xFF; + const result = int8_count_zeros(value); + assert(result == 0); } test "int8_reverse_bits_zero" { - given value: Int8 = 0 - try std.testing.expect(result = int8_reverse_bits(value)); - try std.testing.expect(result == 0); + const value: Int8 = 0; + const result = int8_reverse_bits(value); + assert(result == 0); } test "int8_reverse_bits_one" { - given value: Int8 = 0b10000000 - try std.testing.expect(result = int8_reverse_bits(value)); - try std.testing.expect(result == 0b00000001); + const value: Int8 = 0b10000000; + const result = int8_reverse_bits(value); + assert(result == 0b00000001); } test "int8_reverse_bits_all" { - given value: Int8 = 0xFF - try std.testing.expect(result = int8_reverse_bits(value)); - try std.testing.expect(result == 0xFF); + const value: Int8 = 0xFF; + const result = int8_reverse_bits(value); + assert(result == 0xFF); } // ============================================================================ // Invariants // ============================================================================ -} invariant int8_bits_constant assert BITS == 8 @@ -1072,8 +1071,8 @@ invariant int8_abs_non_negative invariant int8_neg_twice_original given value: Int8 = 42 - try std.testing.expect(neg = int8_neg(value)); - try std.testing.expect(neg_again = int8_neg(neg)); + and neg = int8_neg(value) + and neg_again = int8_neg(neg) assert neg_again == value or value == MIN invariant int8_sign_positive_one @@ -1087,35 +1086,35 @@ invariant int8_sign_zero_zero invariant int8_min_le_both given a: Int8 = 42 - try std.testing.expect(b: Int8 = 50); - try std.testing.expect(result = int8_min(a, b)); + and b: Int8 = 50 + and result = int8_min(a, b) assert result <= a and result <= b invariant int8_max_ge_both given a: Int8 = 42 - try std.testing.expect(b: Int8 = 50); - try std.testing.expect(result = int8_max(a, b)); + and b: Int8 = 50 + and result = int8_max(a, b) assert result >= a and result >= b invariant int8_lerp_zero_start given a: Int8 = 10 - try std.testing.expect(b: Int8 = 50); + and b: Int8 = 50 assert int8_lerp(a, b, 0.0) == a invariant int8_lerp_one_end given a: Int8 = 10 - try std.testing.expect(b: Int8 = 50); + and b: Int8 = 50 assert int8_lerp(a, b, 1.0) == b invariant int8_sq_non_negative given value: Int8 = 42 - try std.testing.expect(result = int8_sq(value)); + and result = int8_sq(value) assert result >= 0 invariant int8_sqrt_square_original_or_less given value: Int8 = 42 - try std.testing.expect(sqrt_result = int8_sqrt(value)); - try std.testing.expect(sqrt_sq = int8_sq(sqrt_result)); + and sqrt_result = int8_sqrt(value) + and sqrt_sq = int8_sq(sqrt_result) assert sqrt_sq <= value invariant int8_count_ones_plus_count_zeros_equals_bits diff --git a/specs/numeric/nf4.t27 b/specs/numeric/nf4.t27 index 005f676..f96c624 100644 --- a/specs/numeric/nf4.t27 +++ b/specs/numeric/nf4.t27 @@ -303,432 +303,431 @@ pub fn nf4_scale(value: NF4, scale: f32) NF4 { // ============================================================================ test "nf4_from_f32_zero" { - given value = 0.0 - try std.testing.expect(result = nf4_from_f32(value)); - try std.testing.expect(result == 0); + const value = 0.0; + const result = nf4_from_f32(value); + assert(result == 0); } test "nf4_from_f32_small_positive" { - given value = 0.1 - try std.testing.expect(result = nf4_from_f32(value)); - try std.testing.expect(nf4_is_zero(result) == true); + const value = 0.1; + const result = nf4_from_f32(value); + assert(nf4_is_zero(result) == true); } test "nf4_from_f32_medium_positive" { - given value = 0.5 - try std.testing.expect(result = nf4_from_f32(value)); - try std.testing.expect(result == 0b010 // level 2); + const value = 0.5; + const result = nf4_from_f32(value); + assert(result == 0b010); // level 2 } test "nf4_from_f32_large_positive" { - given value = 0.9 - try std.testing.expect(result = nf4_from_f32(value)); - try std.testing.expect(result == 0b011 // level 3 (max)); + const value = 0.9; + const result = nf4_from_f32(value); + assert(result == 0b011); // level 3 (max) } test "nf4_from_f32_max_positive" { - given value = 1.0 - try std.testing.expect(result = nf4_from_f32(value)); - try std.testing.expect(result == 0b011); + const value = 1.0; + const result = nf4_from_f32(value); + assert(result == 0b011); } test "nf4_from_f32_above_max" { - given value = 1.5 - try std.testing.expect(result = nf4_from_f32(value)); - try std.testing.expect(result == 0b011 // saturated to max); + const value = 1.5; + const result = nf4_from_f32(value); + assert(result == 0b011); // saturated to max } test "nf4_from_f32_small_negative" { - given value = -0.1 - try std.testing.expect(result = nf4_from_f32(value)); - try std.testing.expect(nf4_is_zero(result) == true); + const value = -0.1; + const result = nf4_from_f32(value); + assert(nf4_is_zero(result) == true); } test "nf4_from_f32_medium_negative" { - given value = -0.5 - try std.testing.expect(result = nf4_from_f32(value)); - try std.testing.expect(result == 0b110 // level 2, negative); + const value = -0.5; + const result = nf4_from_f32(value); + assert(result == 0b110); // level 2, negative } test "nf4_from_f32_large_negative" { - given value = -0.9 - try std.testing.expect(result = nf4_from_f32(value)); - try std.testing.expect(result == 0b111 // level 3, negative (min)); + const value = -0.9; + const result = nf4_from_f32(value); + assert(result == 0b111); // level 3, negative (min) } test "nf4_from_f32_max_negative" { - given value = -1.0 - try std.testing.expect(result = nf4_from_f32(value)); - try std.testing.expect(result == 0b111); + const value = -1.0; + const result = nf4_from_f32(value); + assert(result == 0b111); } test "nf4_from_f32_below_min" { - given value = -1.5 - try std.testing.expect(result = nf4_from_f32(value)); - try std.testing.expect(result == 0b111 // saturated to min); + const value = -1.5; + const result = nf4_from_f32(value); + assert(result == 0b111); // saturated to min } test "nf4_from_f32_nan" { - given result = nf4_from_f32(std.math.nan(f32)) - try std.testing.expect(result == 0); + const result = nf4_from_f32(std.math.nan(f32)); + assert(result == 0); } test "nf4_from_f32_inf" { - given result = nf4_from_f32(std.math.inf(f32)) - try std.testing.expect(result == 0b011); + const result = nf4_from_f32(std.math.inf(f32)); + assert(result == 0b011); } test "nf4_from_f32_neg_inf" { - given result = nf4_from_f32(-std.math.inf(f32)) - try std.testing.expect(result == 0b111); + const result = nf4_from_f32(-std.math.inf(f32)); + assert(result == 0b111); } test "nf4_to_f32_zero" { - given value: NF4 = 0 - try std.testing.expect(result = nf4_to_f32(value)); - try std.testing.expect(result == 0.0); + const value: NF4 = 0; + const result = nf4_to_f32(value); + assert(result == 0.0); } test "nf4_to_f32_positive_max" { - given value: NF4 = 0b011 - try std.testing.expect(result = nf4_to_f32(value)); - try std.testing.expect(result == 1.0); + const value: NF4 = 0b011; + const result = nf4_to_f32(value); + assert(result == 1.0); } test "nf4_to_f32_negative_min" { - given value: NF4 = 0b111 - try std.testing.expect(result = nf4_to_f32(value)); - try std.testing.expect(result == -1.0); + const value: NF4 = 0b111; + const result = nf4_to_f32(value); + assert(result == -1.0); } test "nf4_to_f32_roundtrip_positive" { - given original = 0.7 - try std.testing.expect(encoded = nf4_from_f32(original)); - try std.testing.expect(decoded = nf4_to_f32(encoded)); - try std.testing.expect(abs(decoded - original) < 0.2); + const original = 0.7; + const encoded = nf4_from_f32(original); + const decoded = nf4_to_f32(encoded); + assert(abs(decoded - original) < 0.2); } test "nf4_to_f32_roundtrip_negative" { - given original = -0.7 - try std.testing.expect(encoded = nf4_from_f32(original)); - try std.testing.expect(decoded = nf4_to_f32(encoded)); - try std.testing.expect(abs(decoded - original) < 0.2); + const original = -0.7; + const encoded = nf4_from_f32(original); + const decoded = nf4_to_f32(encoded); + assert(abs(decoded - original) < 0.2); } test "nf4_from_i8_zero" { - given value: i8 = 0 - try std.testing.expect(result = nf4_from_i8(value)); - try std.testing.expect(result == 0); + const value: i8 = 0; + const result = nf4_from_i8(value); + assert(result == 0); } test "nf4_from_i8_max" { - given value: i8 = 127 - try std.testing.expect(result = nf4_from_i8(value)); - try std.testing.expect(result == 0b011); + const value: i8 = 127; + const result = nf4_from_i8(value); + assert(result == 0b011); } test "nf4_from_i8_min" { - given value: i8 = -128 - try std.testing.expect(result = nf4_from_i8(value)); - try std.testing.expect(result == 0b111); + const value: i8 = -128; + const result = nf4_from_i8(value); + assert(result == 0b111); } test "nf4_from_i8_medium" { - given value: i8 = 64 - try std.testing.expect(result = nf4_from_i8(value)); - try std.testing.expect(result == 0b011 // 64/127 ≈ 0.5 -> level 3); + const value: i8 = 64; + const result = nf4_from_i8(value); + assert(result == 0b011); // 64/127 ≈ 0.5 -> level 3 } test "nf4_to_i8_max" { - given value: NF4 = 0b011 - try std.testing.expect(result = nf4_to_i8(value)); - try std.testing.expect(result >= 120 // Should be ~127); + const value: NF4 = 0b011; + const result = nf4_to_i8(value); + assert(result >= 120); // Should be ~127 } test "nf4_to_i8_min" { - given value: NF4 = 0b111 - try std.testing.expect(result = nf4_to_i8(value)); - try std.testing.expect(result <= -120 // Should be ~-127); + const value: NF4 = 0b111; + const result = nf4_to_i8(value); + assert(result <= -120); // Should be ~-127 } test "nf4_add_zero" { - given a: NF4 = 0b010 - try std.testing.expect(b: NF4 = 0); - try std.testing.expect(result = nf4_add(a, b)); - try std.testing.expect(result == a); + const a: NF4 = 0b010; + const b: NF4 = 0; + const result = nf4_add(a, b); + assert(result == a); } test "nf4_add_positives" { - given a: NF4 = 0b010 - try std.testing.expect(b: NF4 = 0b001); - try std.testing.expect(result = nf4_add(a, b)); - try std.testing.expect(nf4_is_positive(result) == true); + const a: NF4 = 0b010; + const b: NF4 = 0b001; + const result = nf4_add(a, b); + assert(nf4_is_positive(result) == true); } test "nf4_add_opposite" { - given a: NF4 = 0b010 - try std.testing.expect(b: NF4 = 0b110); - try std.testing.expect(result = nf4_add(a, b)); - try std.testing.expect(nf4_is_zero(result) == true or nf4_magnitude(result) < 0.5); + const a: NF4 = 0b010; + const b: NF4 = 0b110; + const result = nf4_add(a, b); + assert(nf4_is_zero(result) == true or nf4_magnitude(result) < 0.5); } test "nf4_sub_same" { - given a: NF4 = 0b010 - try std.testing.expect(result = nf4_sub(a, a)); - try std.testing.expect(result == 0); + const a: NF4 = 0b010; + const result = nf4_sub(a, a); + assert(result == 0); } test "nf4_mul_zero" { - given a: NF4 = 0b011 - try std.testing.expect(b: NF4 = 0); - try std.testing.expect(result = nf4_mul(a, b)); - try std.testing.expect(result == 0); + const a: NF4 = 0b011; + const b: NF4 = 0; + const result = nf4_mul(a, b); + assert(result == 0); } test "nf4_mul_max_max" { - given a: NF4 = 0b011 - try std.testing.expect(b: NF4 = 0b011); - try std.testing.expect(result = nf4_mul(a, b)); - try std.testing.expect(result == 0b011 // 1.0 * 1.0 = 1.0); + const a: NF4 = 0b011; + const b: NF4 = 0b011; + const result = nf4_mul(a, b); + assert(result == 0b011); // 1.0 * 1.0 = 1.0 } test "nf4_mul_pos_neg" { - given a: NF4 = 0b011 - try std.testing.expect(b: NF4 = 0b111); - try std.testing.expect(result = nf4_mul(a, b)); - try std.testing.expect(nf4_is_negative(result) == true); + const a: NF4 = 0b011; + const b: NF4 = 0b111; + const result = nf4_mul(a, b); + assert(nf4_is_negative(result) == true); } test "nf4_div_same" { - given a: NF4 = 0b010 - try std.testing.expect(result = nf4_div(a, a)); - try std.testing.expect(result == 0b001 // x/x = 1); + const a: NF4 = 0b010; + const result = nf4_div(a, a); + assert(result == 0b001); // x/x = 1 } test "nf4_div_zero" { - given a: NF4 = 0b011 - try std.testing.expect(b: NF4 = 0); - try std.testing.expect(result = nf4_div(a, b)); - try std.testing.expect(result == 0); + const a: NF4 = 0b011; + const b: NF4 = 0; + const result = nf4_div(a, b); + assert(result == 0); } test "nf4_is_zero_true" { - try std.testing.expect(nf4_is_zero(0) == true); + assert(nf4_is_zero(0) == true); } test "nf4_is_zero_false" { - given value: NF4 = 0b001 - try std.testing.expect(nf4_is_zero(value) == false); + const value: NF4 = 0b001; + assert(nf4_is_zero(value) == false); } test "nf4_is_negative_true" { - try std.testing.expect(nf4_is_negative(0b111) == true); + assert(nf4_is_negative(0b111) == true); } test "nf4_is_negative_false_positive" { - try std.testing.expect(nf4_is_negative(0b011) == false); + assert(nf4_is_negative(0b011) == false); } test "nf4_is_negative_false_zero" { - try std.testing.expect(nf4_is_negative(0) == false); + assert(nf4_is_negative(0) == false); } test "nf4_is_positive_true" { - try std.testing.expect(nf4_is_positive(0b011) == true); + assert(nf4_is_positive(0b011) == true); } test "nf4_is_positive_false_negative" { - try std.testing.expect(nf4_is_positive(0b111) == false); + assert(nf4_is_positive(0b111) == false); } test "nf4_is_positive_false_zero" { - try std.testing.expect(nf4_is_positive(0) == false); + assert(nf4_is_positive(0) == false); } test "nf4_abs_positive" { - given value: NF4 = 0b010 - try std.testing.expect(result = nf4_abs(value)); - try std.testing.expect(result == value); + const value: NF4 = 0b010; + const result = nf4_abs(value); + assert(result == value); } test "nf4_abs_negative" { - given value: NF4 = 0b110 - try std.testing.expect(result = nf4_abs(value)); - try std.testing.expect(result == 0b010); + const value: NF4 = 0b110; + const result = nf4_abs(value); + assert(result == 0b010); } test "nf4_abs_zero" { - given result = nf4_abs(0) - try std.testing.expect(result == 0); + const result = nf4_abs(0); + assert(result == 0); } test "nf4_neg_positive" { - given value: NF4 = 0b010 - try std.testing.expect(result = nf4_neg(value)); - try std.testing.expect(result == 0b110); + const value: NF4 = 0b010; + const result = nf4_neg(value); + assert(result == 0b110); } test "nf4_neg_negative" { - given value: NF4 = 0b110 - try std.testing.expect(result = nf4_neg(value)); - try std.testing.expect(result == 0b010); + const value: NF4 = 0b110; + const result = nf4_neg(value); + assert(result == 0b010); } test "nf4_neg_zero" { - given result = nf4_neg(0) - try std.testing.expect(result == 0); + const result = nf4_neg(0); + assert(result == 0); } test "nf4_is_equal_true" { - given a: NF4 = 0b010 - try std.testing.expect(b: NF4 = 0b010); - try std.testing.expect(nf4_is_equal(a, b) == true); + const a: NF4 = 0b010; + const b: NF4 = 0b010; + assert(nf4_is_equal(a, b) == true); } test "nf4_is_equal_false" { - given a: NF4 = 0b010 - try std.testing.expect(b: NF4 = 0b110); - try std.testing.expect(nf4_is_equal(a, b) == false); + const a: NF4 = 0b010; + const b: NF4 = 0b110; + assert(nf4_is_equal(a, b) == false); } test "nf4_is_greater_true" { - given a: NF4 = 0b011 - try std.testing.expect(b: NF4 = 0b010); - try std.testing.expect(nf4_is_greater(a, b) == true); + const a: NF4 = 0b011; + const b: NF4 = 0b010; + assert(nf4_is_greater(a, b) == true); } test "nf4_is_greater_false" { - given a: NF4 = 0b010 - try std.testing.expect(b: NF4 = 0b011); - try std.testing.expect(nf4_is_greater(a, b) == false); + const a: NF4 = 0b010; + const b: NF4 = 0b011; + assert(nf4_is_greater(a, b) == false); } test "nf4_is_less_true" { - given a: NF4 = 0b010 - try std.testing.expect(b: NF4 = 0b011); - try std.testing.expect(nf4_is_less(a, b) == true); + const a: NF4 = 0b010; + const b: NF4 = 0b011; + assert(nf4_is_less(a, b) == true); } test "nf4_is_less_false" { - given a: NF4 = 0b011 - try std.testing.expect(b: NF4 = 0b010); - try std.testing.expect(nf4_is_less(a, b) == false); + const a: NF4 = 0b011; + const b: NF4 = 0b010; + assert(nf4_is_less(a, b) == false); } test "nf4_max_returns_larger" { - given a: NF4 = 0b010 - try std.testing.expect(b: NF4 = 0b011); - try std.testing.expect(result = nf4_max(a, b)); - try std.testing.expect(result == 0b011); + const a: NF4 = 0b010; + const b: NF4 = 0b011; + const result = nf4_max(a, b); + assert(result == 0b011); } test "nf4_min_returns_smaller" { - given a: NF4 = 0b010 - try std.testing.expect(b: NF4 = 0b011); - try std.testing.expect(result = nf4_min(a, b)); - try std.testing.expect(result == 0b010); + const a: NF4 = 0b010; + const b: NF4 = 0b011; + const result = nf4_min(a, b); + assert(result == 0b010); } test "nf4_clamp_in_range" { - given value: NF4 = 0b010 - try std.testing.expect(min: NF4 = 0b001); - try std.testing.expect(max: NF4 = 0b011); - try std.testing.expect(result = nf4_clamp(value, min, max)); - try std.testing.expect(result == value); + const value: NF4 = 0b010; + const min: NF4 = 0b001; + const max: NF4 = 0b011; + const result = nf4_clamp(value, min, max); + assert(result == value); } test "nf4_clamp_below_min" { - given value: NF4 = 0 - try std.testing.expect(min: NF4 = 0b001); - try std.testing.expect(max: NF4 = 0b011); - try std.testing.expect(result = nf4_clamp(value, min, max)); - try std.testing.expect(result == min); + const value: NF4 = 0; + const min: NF4 = 0b001; + const max: NF4 = 0b011; + const result = nf4_clamp(value, min, max); + assert(result == min); } test "nf4_clamp_above_max" { - given value: NF4 = 0b111 - try std.testing.expect(min: NF4 = 0b001); - try std.testing.expect(max: NF4 = 0b011); - try std.testing.expect(result = nf4_clamp(value, min, max)); - try std.testing.expect(result == max); + const value: NF4 = 0b111; + const min: NF4 = 0b001; + const max: NF4 = 0b011; + const result = nf4_clamp(value, min, max); + assert(result == max); } test "nf4_lerp_zero" { - given a: NF4 = 0b001 - try std.testing.expect(b: NF4 = 0b011); - try std.testing.expect(t = 0.0); - try std.testing.expect(result = nf4_lerp(a, b, t)); - try std.testing.expect(result == a); + const a: NF4 = 0b001; + const b: NF4 = 0b011; + const t = 0.0; + const result = nf4_lerp(a, b, t); + assert(result == a); } test "nf4_lerp_one" { - given a: NF4 = 0b001 - try std.testing.expect(b: NF4 = 0b011); - try std.testing.expect(t = 1.0); - try std.testing.expect(result = nf4_lerp(a, b, t)); - try std.testing.expect(result == b); + const a: NF4 = 0b001; + const b: NF4 = 0b011; + const t = 1.0; + const result = nf4_lerp(a, b, t); + assert(result == b); } test "nf4_lerp_half" { - given a: NF4 = 0 - try std.testing.expect(b: NF4 = 0b011); - try std.testing.expect(t = 0.5); - try std.testing.expect(result = nf4_lerp(a, b, t)); - try std.testing.expect(nf4_magnitude(result) > 0.3); + const a: NF4 = 0; + const b: NF4 = 0b011; + const t = 0.5; + const result = nf4_lerp(a, b, t); + assert(nf4_magnitude(result) > 0.3); } test "nf4_magnitude_positive" { - given value: NF4 = 0b011 - try std.testing.expect(result = nf4_magnitude(value)); - try std.testing.expect(result == 1.0); + const value: NF4 = 0b011; + const result = nf4_magnitude(value); + assert(result == 1.0); } test "nf4_magnitude_negative" { - given value: NF4 = 0b111 - try std.testing.expect(result = nf4_magnitude(value)); - try std.testing.expect(result == 1.0); + const value: NF4 = 0b111; + const result = nf4_magnitude(value); + assert(result == 1.0); } test "nf4_l1_distance_same" { - given a: NF4 = 0b010 - try std.testing.expect(b: NF4 = 0b010); - try std.testing.expect(result = nf4_l1_distance(a, b)); - try std.testing.expect(result == 0.0); + const a: NF4 = 0b010; + const b: NF4 = 0b010; + const result = nf4_l1_distance(a, b); + assert(result == 0.0); } test "nf4_l1_distance_max_min" { - given a: NF4 = 0b011 - try std.testing.expect(b: NF4 = 0b111); - try std.testing.expect(result = nf4_l1_distance(a, b)); - try std.testing.expect(result == 2.0); + const a: NF4 = 0b011; + const b: NF4 = 0b111; + const result = nf4_l1_distance(a, b); + assert(result == 2.0); } test "nf4_l2_distance_max_min" { - given a: NF4 = 0b011 - try std.testing.expect(b: NF4 = 0b111); - try std.testing.expect(result = nf4_l2_distance(a, b)); - try std.testing.expect(result == 4.0); + const a: NF4 = 0b011; + const b: NF4 = 0b111; + const result = nf4_l2_distance(a, b); + assert(result == 4.0); } test "nf4_scale_up" { - given value: NF4 = 0b001 - try std.testing.expect(scale = 2.0); - try std.testing.expect(result = nf4_scale(value, scale)); - try std.testing.expect(nf4_magnitude(result) > 0.4); + const value: NF4 = 0b001; + const scale = 2.0; + const result = nf4_scale(value, scale); + assert(nf4_magnitude(result) > 0.4); } test "nf4_scale_down" { - given value: NF4 = 0b011 - try std.testing.expect(scale = 0.5); - try std.testing.expect(result = nf4_scale(value, scale)); - try std.testing.expect(nf4_magnitude(result) < 1.0); + const value: NF4 = 0b011; + const scale = 0.5; + const result = nf4_scale(value, scale); + assert(nf4_magnitude(result) < 1.0); } // ============================================================================ // Invariants // ============================================================================ -} invariant nf4_bits_constant assert BITS == 4 @@ -758,60 +757,60 @@ invariant nf4_neg_zero_is_zero invariant nf4_max_positive_is_max given max_val: NF4 = 0b011 - try std.testing.expect(fmax = nf4_to_f32(max_val)); + and fmax = nf4_to_f32(max_val) assert fmax == 1.0 invariant nf4_min_negative_is_min given min_val: NF4 = 0b111 - try std.testing.expect(fmin = nf4_to_f32(min_val)); + and fmin = nf4_to_f32(min_val) assert fmin == -1.0 invariant nf4_abs_neg_is_pos given value: NF4 = 0b110 - try std.testing.expect(abs_val = nf4_abs(value)); + and abs_val = nf4_abs(value) assert nf4_is_positive(abs_val) == true invariant nf4_neg_neg_is_pos given value: NF4 = 0b110 - try std.testing.expect(neg_val = nf4_neg(value)); + and neg_val = nf4_neg(value) assert nf4_is_positive(neg_val) == true invariant nf4_double_neg_original_or_zero given value: NF4 = 0b010 - try std.testing.expect(neg_val = nf4_neg(value)); - try std.testing.expect(neg_neg_val = nf4_neg(neg_val)); + and neg_val = nf4_neg(value) + and neg_neg_val = nf4_neg(neg_val) assert neg_neg_val == value or value == 0 invariant nf4_abs_non_negative given value: NF4 = 0b111 - try std.testing.expect(abs_val = nf4_abs(value)); + and abs_val = nf4_abs(value) assert nf4_to_f32(abs_val) >= 0.0 invariant nf4_l1_distance_symmetric given a: NF4 = 0b010 - try std.testing.expect(b: NF4 = 0b111); + and b: NF4 = 0b111 assert nf4_l1_distance(a, b) == nf4_l1_distance(b, a) invariant nf4_l2_distance_symmetric given a: NF4 = 0b010 - try std.testing.expect(b: NF4 = 0b111); + and b: NF4 = 0b111 assert nf4_l2_distance(a, b) == nf4_l2_distance(b, a) invariant nf4_l1_distance_non_negative given a: NF4 = 0b010 - try std.testing.expect(b: NF4 = 0b111); + and b: NF4 = 0b111 assert nf4_l1_distance(a, b) >= 0.0 invariant nf4_max_ge_both given a: NF4 = 0b010 - try std.testing.expect(b: NF4 = 0b011); - try std.testing.expect(result = nf4_max(a, b)); + and b: NF4 = 0b011 + and result = nf4_max(a, b) assert nf4_is_greater(result, a) == true and nf4_is_greater(result, b) == true or nf4_is_equal(result, a) == true invariant nf4_min_le_both given a: NF4 = 0b010 - try std.testing.expect(b: NF4 = 0b011); - try std.testing.expect(result = nf4_min(a, b)); + and b: NF4 = 0b011 + and result = nf4_min(a, b) assert nf4_is_less(result, a) == true or nf4_is_equal(result, a) == true // ============================================================================ diff --git a/specs/numeric/tri_net_formats.t27 b/specs/numeric/tri_net_formats.t27 index bef8b1b..e47b351 100644 --- a/specs/numeric/tri_net_formats.t27 +++ b/specs/numeric/tri_net_formats.t27 @@ -486,7 +486,7 @@ module TriNetFormats { // ======================================================================== pub fn get_format_by_name(name: string) -> ?FormatDescriptor { - for (const TRI_NET_FORMATS) |fmt| { + for (TRI_NET_FORMATS) |fmt| { if (fmt.name == name) { return fmt; } @@ -497,7 +497,7 @@ module TriNetFormats { pub fn get_format_by_bits(bits: u8) -> []FormatDescriptor { var result : [16]FormatDescriptor = undefined; var count : u8 = 0; - for (const TRI_NET_FORMATS) |fmt| { + for (TRI_NET_FORMATS) |fmt| { if (fmt.bits == bits) { result[count] = fmt; count = count + 1; @@ -508,7 +508,7 @@ module TriNetFormats { pub fn get_phi_optimal_format() -> FormatDescriptor { var best : FormatDescriptor = TRI_NET_FORMATS[0]; - for (const TRI_NET_FORMATS) |fmt| { + for (TRI_NET_FORMATS) |fmt| { if (fmt.phi_dist < best.phi_dist) { best = fmt; } @@ -752,7 +752,7 @@ module TriNetFormats { return 0.0 / 0.0; } - const is_integer = exp == @floor(exp); + const is_integer = exp == floor(exp); // the helper below (was spelled @floor) if (is_integer) { let exp_int = exp as i32; @@ -812,7 +812,8 @@ module TriNetFormats { return result; } - fn @floor(x: f32) -> f32 { + // was `fn @floor`: @-names are Zig builtins, not declarable fn names + fn floor(x: f32) -> f32 { let xi = x as i32; if (x >= 0.0 || x == xi as f32) { return xi as f32; @@ -843,16 +844,18 @@ module TriNetFormats { given best = get_phi_optimal_format() then best.name == "GF12" and best.phi_dist < 0.05 - test tri_net_all_formats_have_positive_bits - for (const TRI_NET_FORMATS) |fmt| { + test tri_net_all_formats_have_positive_bits { + for (TRI_NET_FORMATS) |fmt| { assert fmt.bits > 0; } + } - test tri_net_all_formats_sum_bits_correct - for (const TRI_NET_FORMATS) |fmt| { + test tri_net_all_formats_sum_bits_correct { + for (TRI_NET_FORMATS) |fmt| { assert fmt.sign_bits + fmt.exp_bits + fmt.mant_bits == fmt.bits or fmt.category == .posit; // Posit has different structure } + } test tri_nft_n4_levels_count_is_16 given count = NF4_LEVELS.len() @@ -941,39 +944,44 @@ module TriNetFormats { given result = f32_to_nf4(0.0) then result == 6 or result == 7 // Either center value - invariant tri_net_all_formats_have_valid_category - for (const TRI_NET_FORMATS) |fmt| { + invariant tri_net_all_formats_have_valid_category { + for (TRI_NET_FORMATS) |fmt| { assert fmt.category >= .goldenfloat and fmt.category <= .binary; } + } - invariant tri_net_all_phi_distances_non_negative - for (const TRI_NET_FORMATS) |fmt| { + invariant tri_net_all_phi_distances_non_negative { + for (TRI_NET_FORMATS) |fmt| { assert fmt.phi_dist >= 0.0; } + } - invariant tri_nft_all_memory_ratios_positive - for (const TRI_NET_FORMATS) |fmt| { + invariant tri_nft_all_memory_ratios_positive { + for (TRI_NET_FORMATS) |fmt| { assert fmt.memory_ratio > 0.0; } + } invariant tri_net_gf_formats_have_best_phi_distance const golden_fmts = get_format_by_bits(16); // GF16 vs others // GF family should have better phi distance than IEEE formats // (This is a rough check - detailed comparison would need more logic) - invariant tri_net_nf4_levels_are_monotonic + invariant tri_net_nf4_levels_are_monotonic { for (i in 0..15) { if (i < 15) { assert NF4_LEVELS[i] < NF4_LEVELS[i + 1]; } } + } - invariant tri_net_format_registry_consistent - for (const TRI_NET_FORMATS) |fmt| { + invariant tri_net_format_registry_consistent { + for (TRI_NET_FORMATS) |fmt| { assert fmt.name.len() > 0; assert fmt.bits >= 4; assert fmt.sign_bits == 1; } + } bench tri_net_get_format_by_name_latency measure: nanoseconds to get_format_by_name("GF16")