diff --git a/erlang/apps/sim/src/sim_core.erl b/erlang/apps/sim/src/sim_core.erl index e21a028..2c7daa2 100644 --- a/erlang/apps/sim/src/sim_core.erl +++ b/erlang/apps/sim/src/sim_core.erl @@ -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); diff --git a/erlang/apps/sim/src/sim_shifts.erl b/erlang/apps/sim/src/sim_shifts.erl index 2cf05f4..27ef90d 100644 --- a/erlang/apps/sim/src/sim_shifts.erl +++ b/erlang/apps/sim/src/sim_shifts.erl @@ -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). diff --git a/erlang/apps/sim/test/sim_shifts_tests.erl b/erlang/apps/sim/test/sim_shifts_tests.erl index e3a5727..dcf1ffe 100644 --- a/erlang/apps/sim/test/sim_shifts_tests.erl +++ b/erlang/apps/sim/test/sim_shifts_tests.erl @@ -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/ + ], + 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/ + ], + 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/ + ], + 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/ + ], + 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/ + ], + 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/ + ], + 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/ + ], + 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/ + ], + 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/ + ], + 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/ + ], + 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) ->