diff --git a/erlang/apps/sim/src/sim_arithmetic.erl b/erlang/apps/sim/src/sim_arithmetic.erl index fe8f4ff..970af08 100644 --- a/erlang/apps/sim/src/sim_arithmetic.erl +++ b/erlang/apps/sim/src/sim_arithmetic.erl @@ -26,6 +26,12 @@ -export([ handle_AOBJN/4 , handle_AOBJP/4 + , handle_CAIE/4 + , handle_CAIG/4 + , handle_CAIGE/4 + , handle_CAIL/4 + , handle_CAILE/4 + , handle_CAIN/4 ]). -include("sim_core.hrl"). @@ -72,7 +78,84 @@ handle_AOBJN(Core, Mem, IR, EA) -> _ -> jump(Core1, Mem, EA) end. +%% 2.6.2 Comparisons, Skips, and Jumps ========================================= + +%% CAI - Compare AC Immediate and Skip if Condition Satisfied + +-spec handle_CAIL(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_CAIL(Core, Mem, IR, EA) -> + AC = IR band 8#17, + CA = sim_core:get_ac(Core, AC), + skip_if_L(Core, Mem, sext36(CA), EA#ea.offset). + +-spec handle_CAIE(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_CAIE(Core, Mem, IR, EA) -> + AC = IR band 8#17, + CA = sim_core:get_ac(Core, AC), + skip_if_E(Core, Mem, CA, EA#ea.offset). + +-spec handle_CAILE(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_CAILE(Core, Mem, IR, EA) -> + AC = IR band 8#17, + CA = sim_core:get_ac(Core, AC), + skip_if_LE(Core, Mem, sext36(CA), EA#ea.offset). + +-spec handle_CAIGE(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_CAIGE(Core, Mem, IR, EA) -> + AC = IR band 8#17, + CA = sim_core:get_ac(Core, AC), + skip_if_LE(Core, Mem, EA#ea.offset, sext36(CA)). % AC >= 0,E -> 0,E =< AC + +-spec handle_CAIN(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_CAIN(Core, Mem, IR, EA) -> + AC = IR band 8#17, + CA = sim_core:get_ac(Core, AC), + skip_if_N(Core, Mem, CA, EA#ea.offset). + +-spec handle_CAIG(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_CAIG(Core, Mem, IR, EA) -> + AC = IR band 8#17, + CA = sim_core:get_ac(Core, AC), + skip_if_L(Core, Mem, EA#ea.offset, sext36(CA)). % AC > 0,E -> 0,E < AC + %% Miscellaneous =============================================================== jump(Core, Mem, EA) -> sim_core:run(Core#core{pc_offset = EA#ea.offset}, Mem). + +skip_if_E(Core, Mem, X, Y) -> + case X =:= Y of + true -> sim_core:skip(Core, Mem); + false -> sim_core:next_pc(Core, Mem) + end. + +skip_if_L(Core, Mem, X, Y) -> + case X < Y of + true -> sim_core:skip(Core, Mem); + false -> sim_core:next_pc(Core, Mem) + end. + +skip_if_LE(Core, Mem, X, Y) -> + case X =< Y of + true -> sim_core:skip(Core, Mem); + false -> sim_core:next_pc(Core, Mem) + end. + +skip_if_N(Core, Mem, X, Y) -> + case X =/= Y of + true -> sim_core:skip(Core, Mem); + false -> sim_core:next_pc(Core, Mem) + end. + +%% Sign-extend a uint36_t() to the full width of its representation type. +-spec sext36(uint36_t()) -> integer(). +sext36(X) -> + UInt36Sbit = 1 bsl (36 - 1), + UInt36Max = (1 bsl 36) - 1, + ((X band UInt36Max) bxor UInt36Sbit) - UInt36Sbit. diff --git a/erlang/apps/sim/src/sim_core.erl b/erlang/apps/sim/src/sim_core.erl index 0a76203..1b6c133 100644 --- a/erlang/apps/sim/src/sim_core.erl +++ b/erlang/apps/sim/src/sim_core.erl @@ -288,6 +288,14 @@ dispatch(Core, Mem, IR, EA) -> 8#261 -> sim_stack:handle_PUSH(Core, Mem, IR, EA); 8#262 -> sim_stack:handle_POP(Core, Mem, IR, EA); 8#263 -> sim_stack:handle_POPJ(Core, Mem, IR, EA); + 8#300 -> next_pc(Core, Mem); % CAI = no-op + 8#301 -> sim_arithmetic:handle_CAIL(Core, Mem, IR, EA); + 8#302 -> sim_arithmetic:handle_CAIE(Core, Mem, IR, EA); + 8#303 -> sim_arithmetic:handle_CAILE(Core, Mem, IR, EA); + 8#304 -> skip(Core, Mem); % CAIA = SKIPA without the memory read + 8#305 -> sim_arithmetic:handle_CAIGE(Core, Mem, IR, EA); + 8#306 -> sim_arithmetic:handle_CAIN(Core, Mem, IR, EA); + 8#307 -> sim_arithmetic:handle_CAIG(Core, Mem, IR, EA); 8#400 -> sim_boolean:handle_SETZ(Core, Mem, IR, EA); 8#401 -> sim_boolean:handle_SETZ(Core, Mem, IR, EA); % SETZI = SETZ 8#402 -> sim_boolean:handle_SETZM(Core, Mem, IR, EA); diff --git a/erlang/apps/sim/test/sim_arithmetic_tests.erl b/erlang/apps/sim/test/sim_arithmetic_tests.erl index 7cdb27a..4e015c0 100644 --- a/erlang/apps/sim/test/sim_arithmetic_tests.erl +++ b/erlang/apps/sim/test/sim_arithmetic_tests.erl @@ -45,9 +45,19 @@ -define(INSN_INVALID, ?INSN(0, 0, 0, 0, 0)). +-define(OP_MOVEI, 8#201). -define(OP_MOVSI, 8#205). +-define(OP_MOVNI, 8#211). -define(OP_AOBJP, 8#252). -define(OP_AOBJN, 8#253). +-define(OP_CAI, 8#300). +-define(OP_CAIL, 8#301). +-define(OP_CAIE, 8#302). +-define(OP_CAILE, 8#303). +-define(OP_CAIA, 8#304). +-define(OP_CAIGE, 8#305). +-define(OP_CAIN, 8#306). +-define(OP_CAIG, 8#307). %% 2.6.1 Add One to Both Halves of AC and Jump ================================= @@ -95,6 +105,135 @@ aobjn_test() -> [{?AC(1), ?COMMA2(0, 1)} % AC1 = 0,,1 ]). +%% 2.6.2 Comparisons, Skips, and Jumps ========================================= + +%% CAI - Compare AC Immediate and Skip if Condition Satisfied + +cai_test() -> + Prog = + [ {1, 8#100, ?INSN(?OP_CAI, 0, 0, 0, 0)} % 1,,100/ CAI + , {1, 8#101, ?INSN_INVALID} % 1,,101/ + ], + expect(Prog, [], {1, 8#101}, ?DEFAULT_FLAGS, []). % no skip + +cail_test() -> + Prog1 = + [ {1, 8#100, ?INSN(?OP_MOVNI, 1, 0, 0, 3)} % 1,,100/ MOVNI 1,3 + , {1, 8#101, ?INSN(?OP_CAIL, 1, 0, 0, 2)} % 1,,101/ CAIL 1,2 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + ], + expect(Prog1, [], {1, 8#103}, ?DEFAULT_FLAGS, []), % skip + Prog2 = + [ {1, 8#100, ?INSN(?OP_MOVEI, 1, 0, 0, 3)} % 1,,100/ MOVEI 1,3 + , {1, 8#101, ?INSN(?OP_CAIL, 1, 0, 0, 2)} % 1,,101/ CAIL 1,2 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + ], + expect(Prog2, [], {1, 8#102}, ?DEFAULT_FLAGS, []). % no skip + +caie_test() -> + Prog1 = + [ {1, 8#100, ?INSN(?OP_MOVEI, 1, 0, 0, 2)} % 1,,100/ MOVEI 1,2 + , {1, 8#101, ?INSN(?OP_CAIE, 1, 0, 0, 2)} % 1,,101/ CAIE 1,2 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + ], + expect(Prog1, [], {1, 8#103}, ?DEFAULT_FLAGS, []), % skip + Prog2 = + [ {1, 8#100, ?INSN(?OP_MOVEI, 1, 0, 0, 3)} % 1,,100/ MOVEI 1,3 + , {1, 8#101, ?INSN(?OP_CAIE, 1, 0, 0, 2)} % 1,,101/ CAIE 1,2 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + ], + expect(Prog2, [], {1, 8#102}, ?DEFAULT_FLAGS, []). % no skip + +caile_test() -> + Prog1 = + [ {1, 8#100, ?INSN(?OP_MOVNI, 1, 0, 0, 3)} % 1,,100/ MOVNI 1,3 + , {1, 8#101, ?INSN(?OP_CAILE, 1, 0, 0, 2)} % 1,,101/ CAILE 1,2 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + ], + expect(Prog1, [], {1, 8#103}, ?DEFAULT_FLAGS, []), % skip + Prog2 = + [ {1, 8#100, ?INSN(?OP_MOVEI, 1, 0, 0, 2)} % 1,,100/ MOVEI 1,2 + , {1, 8#101, ?INSN(?OP_CAILE, 1, 0, 0, 2)} % 1,,101/ CAILE 1,2 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + ], + expect(Prog2, [], {1, 8#103}, ?DEFAULT_FLAGS, []), % skip + Prog3 = + [ {1, 8#100, ?INSN(?OP_MOVEI, 1, 0, 0, 3)} % 1,,100/ MOVEI 1,3 + , {1, 8#101, ?INSN(?OP_CAILE, 1, 0, 0, 2)} % 1,,101/ CAILE 1,2 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + ], + expect(Prog3, [], {1, 8#102}, ?DEFAULT_FLAGS, []). % no skip + +caia_test() -> + Prog = + [ {1, 8#100, ?INSN(?OP_CAIA, 0, 0, 0, 0)} % 1,,100/ CAIA + , {1, 8#101, ?INSN_INVALID} % 1,,101/ + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + ], + expect(Prog, [], {1, 8#102}, ?DEFAULT_FLAGS, []). % skip + +caige_test() -> + Prog1 = + [ {1, 8#100, ?INSN(?OP_MOVEI, 1, 0, 0, 3)} % 1,,100/ MOVEI 1,3 + , {1, 8#101, ?INSN(?OP_CAIGE, 1, 0, 0, 2)} % 1,,101/ CAIGE 1,2 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + ], + expect(Prog1, [], {1, 8#103}, ?DEFAULT_FLAGS, []), % skip + Prog2 = + [ {1, 8#100, ?INSN(?OP_MOVEI, 1, 0, 0, 2)} % 1,,100/ MOVEI 1,2 + , {1, 8#101, ?INSN(?OP_CAIGE, 1, 0, 0, 2)} % 1,,101/ CAIGE 1,2 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + ], + expect(Prog2, [], {1, 8#103}, ?DEFAULT_FLAGS, []), % skip + Prog3 = + [ {1, 8#100, ?INSN(?OP_MOVNI, 1, 0, 0, 3)} % 1,,100/ MOVNI 1,3 + , {1, 8#101, ?INSN(?OP_CAIGE, 1, 0, 0, 2)} % 1,,101/ CAIGE 1,2 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + ], + expect(Prog3, [], {1, 8#102}, ?DEFAULT_FLAGS, []). % no skip + +cain_test() -> + Prog1 = + [ {1, 8#100, ?INSN(?OP_MOVEI, 1, 0, 0, 3)} % 1,,100/ MOVEI 1,3 + , {1, 8#101, ?INSN(?OP_CAIN, 1, 0, 0, 2)} % 1,,101/ CAIN 1,2 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + ], + expect(Prog1, [], {1, 8#103}, ?DEFAULT_FLAGS, []), % skip + Prog2 = + [ {1, 8#100, ?INSN(?OP_MOVEI, 1, 0, 0, 2)} % 1,,100/ MOVEI 1,2 + , {1, 8#101, ?INSN(?OP_CAIN, 1, 0, 0, 2)} % 1,,101/ CAIN 1,2 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + ], + expect(Prog2, [], {1, 8#102}, ?DEFAULT_FLAGS, []). % no skip + +caig_test() -> + Prog1 = + [ {1, 8#100, ?INSN(?OP_MOVEI, 1, 0, 0, 3)} % 1,,100/ MOVEI 1,3 + , {1, 8#101, ?INSN(?OP_CAIG, 1, 0, 0, 2)} % 1,,101/ CAIG 1,2 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + ], + expect(Prog1, [], {1, 8#103}, ?DEFAULT_FLAGS, []), % skip + Prog2 = + [ {1, 8#100, ?INSN(?OP_MOVNI, 1, 0, 0, 3)} % 1,,100/ MOVNI 1,3 + , {1, 8#101, ?INSN(?OP_CAIG, 1, 0, 0, 2)} % 1,,101/ CAIG 1,2 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + ], + expect(Prog2, [], {1, 8#102}, ?DEFAULT_FLAGS, []). % no skip + %% Common code to run short sequences ========================================== expect(Prog, ACs, ExpectedPC, ExpectedFlags, ExpectedEs) ->