sim: sim_arithmetic: handle CAM{,L,E,LE,A,GE,N,G}, add unit tests

This commit is contained in:
Mikael Pettersson 2020-08-02 20:00:09 +02:00
parent ca6a6325c7
commit d1bddcde04
3 changed files with 273 additions and 0 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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/ <invalid>
, {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/ <invalid>
, {1, 8#103, ?INSN_INVALID} % 1,,103/ <invalid>
, {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/ <invalid>
, {1, 8#103, ?INSN_INVALID} % 1,,103/ <invalid>
, {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/ <invalid>
, {1, 8#103, ?INSN_INVALID} % 1,,103/ <invalid>
, {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/ <invalid>
, {1, 8#103, ?INSN_INVALID} % 1,,103/ <invalid>
, {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/ <invalid>
, {1, 8#103, ?INSN_INVALID} % 1,,103/ <invalid>
, {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/ <invalid>
, {1, 8#103, ?INSN_INVALID} % 1,,103/ <invalid>
, {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/ <invalid>
, {1, 8#103, ?INSN_INVALID} % 1,,103/ <invalid>
, {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/ <invalid>
, {1, 8#102, ?INSN_INVALID} % 1,,102/ <invalid>
, {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/ <invalid>
, {1, 8#103, ?INSN_INVALID} % 1,,103/ <invalid>
, {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/ <invalid>
, {1, 8#103, ?INSN_INVALID} % 1,,103/ <invalid>
, {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/ <invalid>
, {1, 8#103, ?INSN_INVALID} % 1,,103/ <invalid>
, {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/ <invalid>
, {1, 8#103, ?INSN_INVALID} % 1,,103/ <invalid>
, {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/ <invalid>
, {1, 8#103, ?INSN_INVALID} % 1,,103/ <invalid>
, {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/ <invalid>
, {1, 8#103, ?INSN_INVALID} % 1,,103/ <invalid>
, {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/ <invalid>
, {1, 8#103, ?INSN_INVALID} % 1,,103/ <invalid>
, {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) ->