sim: sim_shifts: handle ASH/ASHC, add unit tests

This commit is contained in:
Mikael Pettersson 2020-08-26 00:28:38 +02:00
parent edf7257d21
commit 17a9505036
3 changed files with 274 additions and 1 deletions

View File

@ -280,8 +280,10 @@ dispatch(Core, Mem, IR, EA) ->
8#215 -> sim_moves:handle_MOVEI(Core, Mem, IR, EA); % MOVMI = MOVEI
8#216 -> sim_moves:handle_MOVMM(Core, Mem, IR, EA);
8#217 -> sim_moves:handle_MOVMS(Core, Mem, IR, EA);
8#240 -> sim_shifts:handle_ASH(Core, Mem, IR, EA);
8#241 -> sim_shifts:handle_ROT(Core, Mem, IR, EA);
8#242 -> sim_shifts:handle_LSH(Core, Mem, IR, EA);
8#244 -> sim_shifts:handle_ASHC(Core, Mem, IR, EA);
8#245 -> sim_shifts:handle_ROTC(Core, Mem, IR, EA);
8#246 -> sim_shifts:handle_LSHC(Core, Mem, IR, EA);
8#250 -> sim_moves:handle_EXCH(Core, Mem, IR, EA);

View File

@ -24,7 +24,9 @@
-module(sim_shifts).
-export([ handle_LSH/4
-export([ handle_ASH/4
, handle_ASHC/4
, handle_LSH/4
, handle_LSHC/4
, handle_ROT/4
, handle_ROTC/4
@ -76,8 +78,161 @@ handle_ROTC(Core, Mem, IR, EA) ->
{Word0, Word1} = rotc(CA0, CA1, EA#ea.offset),
set_acs_next_pc(Core, Mem, AC, Word0, Word1).
%% ASH - Arithmetic Shift
-spec handle_ASH(#core{}, sim_mem:mem(), IR :: word(), #ea{})
-> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}.
handle_ASH(Core, Mem, IR, EA) ->
AC = IR band 8#17,
CA = sim_core:get_ac(Core, AC),
{Word, Flags} = ash(CA, EA#ea.offset),
set_ac_and_flags_next_pc(Core, Mem, AC, Word, Flags).
%% ASHC - Arithmetic Shift Combined
-spec handle_ASHC(#core{}, sim_mem:mem(), IR :: word(), #ea{})
-> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}.
handle_ASHC(Core, Mem, IR, EA) ->
AC = IR band 8#17,
CA0 = sim_core:get_ac(Core, AC),
CA1 = sim_core:get_ac(Core, (AC + 1) band 8#17),
{Word0, Word1, Flags} = ashc(CA0, CA1, EA#ea.offset),
set_acs_and_flags_next_pc(Core, Mem, AC, Word0, Word1, Flags).
%% Miscellaneous ===============================================================
ash(CA, Offset) ->
case Offset band (1 bsl 17) of
0 -> % left shift
Count = Offset band ((1 bsl 8) - 1),
case CA band (1 bsl 35) of
0 -> % non-negative
{Word, Lost} =
if Count >= 35 ->
{_Word = 0, _Lost = CA =/= 0};
true ->
LeftNrBits = Count,
RightNrBits = 35 - Count,
{_Word = (CA band ((1 bsl RightNrBits) - 1)) bsl LeftNrBits,
_Lost = (CA bsr RightNrBits) =/= 0}
end,
Flags =
case Lost of
false -> 0;
true -> (1 bsl ?PDP10_PF_TRAP_1) bor (1 bsl ?PDP10_PF_OVERFLOW)
end,
{Word, Flags};
_ -> % negative
{Word, Lost} =
if Count >= 35 ->
{_Word = 1 bsl 35,
_Lost = CA =/= ((1 bsl 36) - 1)};
true ->
LeftNrBits = Count,
RightNrBits = 35 - Count,
{_Word = ((CA band ((1 bsl RightNrBits) - 1)) bsl LeftNrBits) bor (1 bsl 35),
_Lost = ((CA bsr RightNrBits) band ((1 bsl LeftNrBits) - 1)) =/= ((1 bsl LeftNrBits) - 1)}
end,
Flags =
case Lost of
false -> 0;
true -> (1 bsl ?PDP10_PF_TRAP_1) bor (1 bsl ?PDP10_PF_OVERFLOW)
end,
{Word, Flags}
end;
_ -> % right shift
Count = (-Offset) band ((1 bsl 8) - 1),
case CA band (1 bsl 35) of
0 -> % non-negative
Word =
if Count >= 35 -> 0;
true -> CA bsr Count
end,
{Word, _Flags = 0};
_ -> % negative
Word =
if Count >= 35 -> (1 bsl 36) - 1;
true -> (((1 bsl Count) - 1) bsl (36 - Count)) bor (CA bsr Count)
end,
{Word, _Flags = 0}
end
end.
ashc(CA0, CA1, Offset) ->
case Offset band (1 bsl 17) of
0 -> % left shift
Count = Offset band ((1 bsl 8) - 1),
case CA0 band (1 bsl 35) of
0 -> % non-negative
{Word0, Word1, Lost} =
if Count >= 70 ->
{_Word0 = 0, _Word1 = 0, _Lost = CA0 bor (CA1 band ((1 bsl 35) - 1))};
Count >= 35 ->
Count1 = Count - 35,
W0 = (CA1 band ((1 bsl (35 - Count1)) - 1)) bsl Count1,
L1 = (CA1 bsr (35 - Count1)) band ((1 bsl Count1) - 1),
{_Word0 = W0, _Word1 = 0, _Lost = CA0 bor L1};
Count > 0 ->
W0 = ((CA0 band ((1 bsl (35 - Count)) - 1)) bsl Count) bor (CA1 bsr (35 - Count)),
W1 = (CA1 band ((1 bsl (35 - Count)) - 1)) bsl Count,
L0 = CA0 bsr (35 - Count),
{_Word0 = W0, _Word1 = W1, _Lost = L0};
true ->
{_Word0 = CA0, _Word1 = CA1, _Lost = 0}
end,
Flags =
case Lost of
0 -> 0;
_ -> (1 bsl ?PDP10_PF_TRAP_1) bor (1 bsl ?PDP10_PF_OVERFLOW)
end,
{Word0, Word1, Flags};
_ -> % negative
{Word0, Word1, Lost} =
if Count >= 70 ->
{_Word0 = 1 bsl 35, _Word1 = 1 bsl 35, _Lost = (CA0 bor CA1) band ((1 bsl 35) - 1)};
Count >= 35 ->
Count1 = Count - 35,
W0 = (CA1 band ((1 bsl (35 - Count1)) - 1)) bsl Count1,
L1 = (CA1 bsr Count1) band ((1 bsl Count1) - 1),
{_Word0 = W0, _Word1 = 1 bsl 35, _Lost = (CA0 band ((1 bsl 35) - 1)) bor L1};
true ->
W0 = ((CA1 band ((1 bsl (35 - Count)) - 1)) bsl Count) bor (1 bsl 35) bor ((CA1 bsr (35 - Count)) band ((1 bsl Count) - 1)),
W1 = ((CA1 band ((1 bsl (35 - Count)) - 1)) bsl Count) bor (1 bsl 35),
L0 = (CA0 bsr (35 - Count)) band ((1 bsl Count) - 1),
{_Word0 = W0, _Word1 = W1, _Lost = L0}
end,
Flags =
case Lost of
0 -> 0;
_ -> (1 bsl ?PDP10_PF_TRAP_1) bor (1 bsl ?PDP10_PF_OVERFLOW)
end,
{Word0, Word1, Flags}
end;
_ -> % right shift
Count = (-Offset) band ((1 bsl 8) - 1),
case CA0 band (1 bsl 35) of
0 -> % non-negative
if Count >= 70 ->
{_Word0 = 0, _Word1 = 0, _Flags = 0};
Count >= 35 ->
Word1 = CA0 bsr (Count - 35),
{_Word0 = 0, Word1, _Flags = 0};
true ->
Word0 = CA0 bsr Count,
Word1 = ((CA0 band ((1 bsl Count) - 1)) bsl (35 - Count)) bor (CA1 bsr Count),
{Word0, Word1, _Flags = 0}
end;
_ -> % negative
if Count >= 70 ->
{_Word0 = (1 bsl 36) - 1, _Word1 = (1 bsl 36) - 1, _Flags = 0};
Count >= 35 ->
Count1 = Count - 35,
W1 = (CA0 bsr Count1) bor (((1 bsl Count1) - 1) bsl (36 - Count1)),
{_Word0 = (1 bsl 36) - 1, _Word1 = W1, _Flags = 0}
end
end
end.
lsh(CA, Offset) ->
case Offset band (1 bsl 17) of
0 -> % left shift
@ -164,3 +319,11 @@ set_acs_next_pc(Core, Mem, AC, Word0, Word1) ->
set_ac_next_pc(Core, Mem, AC, Word) ->
sim_core:next_pc(sim_core:set_ac(Core, AC, Word), Mem).
set_acs_and_flags_next_pc(Core, Mem, AC, Word0, Word1, Flags) ->
set_ac_and_flags_next_pc(sim_core:set_ac(Core, AC, Word0), Mem, (AC + 1) band 8#17, Word1, Flags).
set_ac_and_flags_next_pc(Core, Mem, AC, Word, Flags) ->
Core1 = sim_core:set_ac(Core, AC, Word),
Core2 = sim_core:set_flags(Core1, Flags),
sim_core:next_pc(Core2, Mem).

View File

@ -46,8 +46,10 @@
-define(INSN_INVALID, ?INSN(0, 0, 0, 0, 0)).
-define(OP_ASH, 8#240).
-define(OP_ROT, 8#241).
-define(OP_LSH, 8#242).
-define(OP_ASHC, 8#244).
-define(OP_ROTC, 8#245).
-define(OP_LSHC, 8#246).
@ -175,6 +177,112 @@ rotc_test() ->
, {?AC(2), ?COMMA2(8#666777, 8#000111)} % AC2 = 666777000111
]).
%% ASH - Arithmetic Shift
ash_test() ->
ACS1 =
[ {1, ?COMMA2(8#000111, 8#222333)} % AC1 = 000111222333
],
Prog1 =
[ {1, 8#100, ?INSN(?OP_ASH, 1, 0, 0, 6)} % 1,,100/ ASH 1,6
, {1, 8#101, ?INSN_INVALID} % 1,,101/ <invalid>
],
expect(Prog1, ACS1, {1, 8#101}, ?DEFAULT_FLAGS,
[ {?AC(1), ?COMMA2(8#011122, 8#233300)} % AC1 = 011122233300
]),
Prog2 =
[ {1, 8#100, ?INSN(?OP_ASH, 1, 0, 0, -9)} % 1,,100/ ASH 1,-9
, {1, 8#101, ?INSN_INVALID} % 1,,101/ <invalid>
],
expect(Prog2, ACS1, {1, 8#101}, ?DEFAULT_FLAGS,
[ {?AC(1), ?COMMA2(8#000000, 8#111222)} % AC1 = 000000111222
]),
ACS2 =
[ {1, ?COMMA2(8#777555, 8#333111)} % AC1 = 777555333111
],
Prog3 =
[ {1, 8#100, ?INSN(?OP_ASH, 1, 0, 0, 6)} % 1,,100/ ASH 1,6
, {1, 8#101, ?INSN_INVALID} % 1,,101/ <invalid>
],
expect(Prog3, ACS2, {1, 8#101}, ?DEFAULT_FLAGS,
[ {?AC(1), ?COMMA2(8#755533, 8#311100)} % AC1 = 755533311100
]),
Prog4 =
[ {1, 8#100, ?INSN(?OP_ASH, 1, 0, 0, -9)} % 1,,100/ ASH 1,-9
, {1, 8#101, ?INSN_INVALID} % 1,,101/ <invalid>
],
expect(Prog4, ACS2, {1, 8#101}, ?DEFAULT_FLAGS,
[ {?AC(1), ?COMMA2(8#777777, 8#555333)} % AC1 = 777777555333
]).
%% ASHC - Arithmetic Shift Combined
ashc_test() ->
ACS1 =
[ {1, ?COMMA2(8#000111, 8#222333)} % AC1 = 000111222333
, {2, ?COMMA2(8#777666, 8#555444)} % AC2 = 777666555444
],
Prog1 =
[ {1, 8#100, ?INSN(?OP_ASHC, 1, 0, 0, 6)} % 1,,100/ ASHC 1,6
, {1, 8#101, ?INSN_INVALID} % 1,,101/ <invalid>
],
expect(Prog1, ACS1, {1, 8#101}, ?DEFAULT_FLAGS,
[ {?AC(1), ?COMMA2(8#011122, 8#233377)} % AC1 = 011122233377
, {?AC(2), ?COMMA2(8#366655, 8#544400)} % AC2 = 366655544400
]),
Prog2 =
[ {1, 8#100, ?INSN(?OP_ASHC, 1, 0, 0, -9)} % 1,,100/ ASHC 1,-9
, {1, 8#101, ?INSN_INVALID} % 1,,101/ <invalid>
],
expect(Prog2, ACS1, {1, 8#101}, ?DEFAULT_FLAGS,
[ {?AC(1), ?COMMA2(8#000000, 8#111222)} % AC1 = 000000111222
, {?AC(2), ?COMMA2(8#155777, 8#666555)} % AC2 = 155777666555
]),
ACS2 =
[ {1, ?COMMA2(8#000000, 8#000000)} % AC1 = 0
, {2, ?COMMA2(8#000666, 8#555444)} % AC2 = 000666555444
],
Prog3 =
[ {1, 8#100, ?INSN(?OP_ASHC, 1, 0, 0, 35+6)} % 1,,100/ ASHC 1,51
, {1, 8#101, ?INSN_INVALID} % 1,,101/ <invalid>
],
expect(Prog3, ACS2, {1, 8#101}, ?DEFAULT_FLAGS,
[ {?AC(1), ?COMMA2(8#066655, 8#544400)} % AC1 = 066655544400
, {?AC(2), ?COMMA2(8#000000, 8#000000)} % AC2 = 0
]),
Prog4 =
[ {1, 8#100, ?INSN(?OP_ASHC, 1, 0, 0, -(35+9))} % 1,,100/ ASHC 1,54
, {1, 8#101, ?INSN_INVALID} % 1,,101/ <invalid>
],
expect(Prog4, ACS1, {1, 8#101}, ?DEFAULT_FLAGS,
[ {?AC(1), ?COMMA2(8#000000, 8#000000)} % AC1 = 0
, {?AC(2), ?COMMA2(8#000000, 8#111222)} % AC2 = 000000111222
]),
ACS3 =
[ {1, 0} % AC1 = 0
, {2, 0} % AC2 = 0
],
Prog5 =
[ {1, 8#100, ?INSN(?OP_ASHC, 1, 0, 0, 70+6)} % 1,,100/ ASHC 1,114
, {1, 8#101, ?INSN_INVALID} % 1,,101/ <invalid>
],
expect(Prog5, ACS3, {1, 8#101}, ?DEFAULT_FLAGS,
[ {?AC(1), 0} % AC1 = 0
, {?AC(2), 0} % AC2 = 0
]),
ACS4 =
[ {1, ?COMMA2(-1, -1)} % AC1 = -1
, {2, ?COMMA2(-1, -1)} % AC2 = -1
],
Prog6 =
[ {1, 8#100, ?INSN(?OP_ASHC, 1, 0, 0, -(70+6))} % 1,,100/ ASHC 1,-114
, {1, 8#101, ?INSN_INVALID} % 1,,101/ <invalid>
],
expect(Prog6, ACS4, {1, 8#101}, ?DEFAULT_FLAGS,
[ {?AC(1), ?COMMA2(-1, -1)} % AC1 = -1
, {?AC(2), ?COMMA2(-1, -1)} % AC2 = -1
]).
%% Common code to run short sequences ==========================================
expect(Prog, ACs, ExpectedPC, ExpectedFlags, ExpectedEs) ->