mirror of
https://github.com/mikpe/pdp10-tools.git
synced 2026-01-22 02:26:24 +00:00
sim: sim_arithmetic: handle CAM{,L,E,LE,A,GE,N,G}, add unit tests
This commit is contained in:
parent
ca6a6325c7
commit
d1bddcde04
@ -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.
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) ->
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user