diff --git a/erlang/apps/sim/src/sim_arithmetic.erl b/erlang/apps/sim/src/sim_arithmetic.erl index 970af08..c36b542 100644 --- a/erlang/apps/sim/src/sim_arithmetic.erl +++ b/erlang/apps/sim/src/sim_arithmetic.erl @@ -32,6 +32,14 @@ , handle_CAIL/4 , handle_CAILE/4 , handle_CAIN/4 + , handle_CAM/4 + , handle_CAMA/4 + , handle_CAME/4 + , handle_CAMG/4 + , handle_CAMGE/4 + , handle_CAML/4 + , handle_CAMLE/4 + , handle_CAMN/4 ]). -include("sim_core.hrl"). @@ -124,6 +132,108 @@ handle_CAIG(Core, Mem, IR, EA) -> CA = sim_core:get_ac(Core, AC), skip_if_L(Core, Mem, EA#ea.offset, sext36(CA)). % AC > 0,E -> 0,E < AC +%% CAM - Compare AC with Memory and Skip if Condition Satisfied + +-spec handle_CAM(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_CAM(Core, Mem, IR, EA) -> + %% this reads memory, but is otherwise a no-op + case sim_core:c(Core, Mem, EA) of + {ok, _CE} -> sim_core:next_pc(Core, Mem); + {error, Reason} -> + sim_core:page_fault(Core, Mem, ea_address(EA), read, Reason, + fun(Core1, Mem1) -> ?FUNCTION_NAME(Core1, Mem1, IR, EA) end) + end. + +-spec handle_CAML(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_CAML(Core, Mem, IR, EA) -> + case sim_core:c(Core, Mem, EA) of + {ok, CE} -> + AC = IR band 8#17, + CA = sim_core:get_ac(Core, AC), + skip_if_L(Core, Mem, sext36(CA), sext36(CE)); + {error, Reason} -> + sim_core:page_fault(Core, Mem, ea_address(EA), read, Reason, + fun(Core1, Mem1) -> ?FUNCTION_NAME(Core1, Mem1, IR, EA) end) + end. + +-spec handle_CAME(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_CAME(Core, Mem, IR, EA) -> + case sim_core:c(Core, Mem, EA) of + {ok, CE} -> + AC = IR band 8#17, + CA = sim_core:get_ac(Core, AC), + skip_if_E(Core, Mem, CA, CE); + {error, Reason} -> + sim_core:page_fault(Core, Mem, ea_address(EA), read, Reason, + fun(Core1, Mem1) -> ?FUNCTION_NAME(Core1, Mem1, IR, EA) end) + end. + +-spec handle_CAMLE(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_CAMLE(Core, Mem, IR, EA) -> + case sim_core:c(Core, Mem, EA) of + {ok, CE} -> + AC = IR band 8#17, + CA = sim_core:get_ac(Core, AC), + skip_if_LE(Core, Mem, sext36(CA), sext36(CE)); + {error, Reason} -> + sim_core:page_fault(Core, Mem, ea_address(EA), read, Reason, + fun(Core1, Mem1) -> ?FUNCTION_NAME(Core1, Mem1, IR, EA) end) + end. + +-spec handle_CAMA(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_CAMA(Core, Mem, IR, EA) -> + %% this reads memory and skips, but has no other side-effect + case sim_core:c(Core, Mem, EA) of + {ok, _CE} -> sim_core:skip(Core, Mem); + {error, Reason} -> + sim_core:page_fault(Core, Mem, ea_address(EA), read, Reason, + fun(Core1, Mem1) -> ?FUNCTION_NAME(Core1, Mem1, IR, EA) end) + end. + +-spec handle_CAMGE(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_CAMGE(Core, Mem, IR, EA) -> + case sim_core:c(Core, Mem, EA) of + {ok, CE} -> + AC = IR band 8#17, + CA = sim_core:get_ac(Core, AC), + skip_if_LE(Core, Mem, sext36(CE), sext36(CA)); % AC >= E -> E =< AC + {error, Reason} -> + sim_core:page_fault(Core, Mem, ea_address(EA), read, Reason, + fun(Core1, Mem1) -> ?FUNCTION_NAME(Core1, Mem1, IR, EA) end) + end. + +-spec handle_CAMN(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_CAMN(Core, Mem, IR, EA) -> + case sim_core:c(Core, Mem, EA) of + {ok, CE} -> + AC = IR band 8#17, + CA = sim_core:get_ac(Core, AC), + skip_if_N(Core, Mem, CA, CE); + {error, Reason} -> + sim_core:page_fault(Core, Mem, ea_address(EA), read, Reason, + fun(Core1, Mem1) -> ?FUNCTION_NAME(Core1, Mem1, IR, EA) end) + end. + +-spec handle_CAMG(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_CAMG(Core, Mem, IR, EA) -> + case sim_core:c(Core, Mem, EA) of + {ok, CE} -> + AC = IR band 8#17, + CA = sim_core:get_ac(Core, AC), + skip_if_L(Core, Mem, sext36(CE), sext36(CA)); % AC > E -> E < AC + {error, Reason} -> + sim_core:page_fault(Core, Mem, ea_address(EA), read, Reason, + fun(Core1, Mem1) -> ?FUNCTION_NAME(Core1, Mem1, IR, EA) end) + end. + %% Miscellaneous =============================================================== jump(Core, Mem, EA) -> @@ -159,3 +269,6 @@ sext36(X) -> UInt36Sbit = 1 bsl (36 - 1), UInt36Max = (1 bsl 36) - 1, ((X band UInt36Max) bxor UInt36Sbit) - UInt36Sbit. + +ea_address(#ea{section = Section, offset = Offset}) -> + (Section bsl 18) bor Offset. diff --git a/erlang/apps/sim/src/sim_core.erl b/erlang/apps/sim/src/sim_core.erl index 1b6c133..2d57bbf 100644 --- a/erlang/apps/sim/src/sim_core.erl +++ b/erlang/apps/sim/src/sim_core.erl @@ -296,6 +296,14 @@ dispatch(Core, Mem, IR, EA) -> 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#310 -> sim_arithmetic:handle_CAM(Core, Mem, IR, EA); + 8#311 -> sim_arithmetic:handle_CAML(Core, Mem, IR, EA); + 8#312 -> sim_arithmetic:handle_CAME(Core, Mem, IR, EA); + 8#313 -> sim_arithmetic:handle_CAMLE(Core, Mem, IR, EA); + 8#314 -> sim_arithmetic:handle_CAMA(Core, Mem, IR, EA); + 8#315 -> sim_arithmetic:handle_CAMGE(Core, Mem, IR, EA); + 8#316 -> sim_arithmetic:handle_CAMN(Core, Mem, IR, EA); + 8#317 -> sim_arithmetic:handle_CAMG(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 4e015c0..4ca24c7 100644 --- a/erlang/apps/sim/test/sim_arithmetic_tests.erl +++ b/erlang/apps/sim/test/sim_arithmetic_tests.erl @@ -30,6 +30,7 @@ -define(DEFAULT_FLAGS, (1 bsl ?PDP10_PF_USER)). -define(LOW18(X), ((X) band ((1 bsl 18) - 1))). +-define(LOW36(X), ((X) band ((1 bsl 36) - 1))). -define(INSN(OP, AC, I, X, Y), (((OP) bsl (35 - 8)) bor @@ -58,6 +59,14 @@ -define(OP_CAIGE, 8#305). -define(OP_CAIN, 8#306). -define(OP_CAIG, 8#307). +-define(OP_CAM, 8#310). +-define(OP_CAML, 8#311). +-define(OP_CAME, 8#312). +-define(OP_CAMLE, 8#313). +-define(OP_CAMA, 8#314). +-define(OP_CAMGE, 8#315). +-define(OP_CAMN, 8#316). +-define(OP_CAMG, 8#317). %% 2.6.1 Add One to Both Halves of AC and Jump ================================= @@ -234,6 +243,149 @@ caig_test() -> ], expect(Prog2, [], {1, 8#102}, ?DEFAULT_FLAGS, []). % no skip +%% CAM - Compare AC with Memory and Skip if Condition Satisfied + +cam_test() -> + Prog = + [ {1, 8#100, ?INSN(?OP_CAM, 0, 0, 0, 8#150)} % 1,,100/ CAM 150 + , {1, 8#101, ?INSN_INVALID} % 1,,101/ + , {1, 8#150, 2} % 1,,150/ 0,,2 + ], + expect(Prog, [], {1, 8#101}, ?DEFAULT_FLAGS, []). % no skip + +caml_test() -> + Prog1 = + [ {1, 8#100, ?INSN(?OP_MOVNI, 1, 0, 0, 3)} % 1,,100/ MOVNI 1,3 + , {1, 8#101, ?INSN(?OP_CAML, 1, 0, 0, 8#150)} % 1,,101/ CAML 1,150 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + , {1, 8#150, 2} % 1,,150/ 0,,2 + ], + 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_CAML, 1, 0, 0, 8#150)} % 1,,101/ CAML 1,150 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + , {1, 8#150, 2} % 1,,150/ 0,,2 + ], + expect(Prog2, [], {1, 8#102}, ?DEFAULT_FLAGS, []). % no skip + +came_test() -> + Prog1 = + [ {1, 8#100, ?INSN(?OP_MOVEI, 1, 0, 0, 2)} % 1,,100/ MOVEI 1,2 + , {1, 8#101, ?INSN(?OP_CAME, 1, 0, 0, 8#150)} % 1,,101/ CAME 1,150 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + , {1, 8#150, 2} % 1,,150/ 0,,2 + ], + 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_CAME, 1, 0, 0, 8#150)} % 1,,101/ CAME 1,150 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + , {1, 8#150, 2} % 1,,150/ 0,,2 + ], + expect(Prog2, [], {1, 8#102}, ?DEFAULT_FLAGS, []). % no skip + +camle_test() -> + Prog1 = + [ {1, 8#100, ?INSN(?OP_MOVNI, 1, 0, 0, 3)} % 1,,100/ MOVNI 1,3 + , {1, 8#101, ?INSN(?OP_CAMLE, 1, 0, 0, 8#150)} % 1,,101/ CAMLE 1,150 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + , {1, 8#150, 2} % 1,,150/ 0,,2 + ], + 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_CAMLE, 1, 0, 0, 8#150)} % 1,,101/ CAMLE 1,150 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + , {1, 8#150, 2} % 1,,150/ 0,,2 + ], + 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_CAMLE, 1, 0, 0, 8#150)} % 1,,101/ CAMLE 1,150 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + , {1, 8#150, 2} % 1,,150/ 0,,2 + ], + expect(Prog3, [], {1, 8#102}, ?DEFAULT_FLAGS, []). % no skip + +cama_test() -> + Prog = + [ {1, 8#100, ?INSN(?OP_CAMA, 0, 0, 0, 8#150)} % 1,,100/ CAMA 150 + , {1, 8#101, ?INSN_INVALID} % 1,,101/ + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#150, 2} % 1,,150/ 0,,2 + ], + expect(Prog, [], {1, 8#102}, ?DEFAULT_FLAGS, []). % skip + +camge_test() -> + Prog1 = + [ {1, 8#100, ?INSN(?OP_MOVEI, 1, 0, 0, 3)} % 1,,100/ MOVEI 1,3 + , {1, 8#101, ?INSN(?OP_CAMGE, 1, 0, 0, 8#150)} % 1,,101/ CAMGE 1,150 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + , {1, 8#150, 2} % 1,,150/ 0,,2 + ], + 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_CAMGE, 1, 0, 0, 8#150)} % 1,,101/ CAMGE 1,150 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + , {1, 8#150, 2} % 1,,150/ 0,,2 + ], + 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_CAMGE, 1, 0, 0, 8#150)} % 1,,101/ CAMGE 1,150 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + , {1, 8#150, 2} % 1,,150/ 0,,2 + ], + expect(Prog3, [], {1, 8#102}, ?DEFAULT_FLAGS, []). % no skip + +camn_test() -> + Prog1 = + [ {1, 8#100, ?INSN(?OP_MOVEI, 1, 0, 0, 3)} % 1,,100/ MOVEI 1,3 + , {1, 8#101, ?INSN(?OP_CAMN, 1, 0, 0, 8#150)} % 1,,101/ CAMN 1,150 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + , {1, 8#150, 2} % 1,,150/ 0,,2 + ], + 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_CAMN, 1, 0, 0, 8#150)} % 1,,101/ CAMN 1,150 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + , {1, 8#150, 2} % 1,,150/ 0,,2 + ], + expect(Prog2, [], {1, 8#102}, ?DEFAULT_FLAGS, []). % no skip + +camg_test() -> + Prog1 = + [ {1, 8#100, ?INSN(?OP_MOVEI, 1, 0, 0, 3)} % 1,,100/ MOVEI 1,3 + , {1, 8#101, ?INSN(?OP_CAMG, 1, 0, 0, 8#150)} % 1,,101/ CAMG 1,150 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + , {1, 8#150, ?LOW36(-2)} % 1,,150/ -2 + ], + 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_CAMG, 1, 0, 0, 8#150)} % 1,,101/ CAMG 1,150 + , {1, 8#102, ?INSN_INVALID} % 1,,102/ + , {1, 8#103, ?INSN_INVALID} % 1,,103/ + , {1, 8#150, ?LOW36(-2)} % 1,,150/ -2 + ], + expect(Prog2, [], {1, 8#102}, ?DEFAULT_FLAGS, []). % no skip + %% Common code to run short sequences ========================================== expect(Prog, ACs, ExpectedPC, ExpectedFlags, ExpectedEs) ->