From 82ee356c37aec995c6fafab93814d78bd26c1ace Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Fri, 14 Aug 2020 00:15:33 +0200 Subject: [PATCH] sim: sim_shifts: new, handle LSH/LSHC, add unit tests --- erlang/apps/sim/src/sim_core.erl | 2 + erlang/apps/sim/src/sim_shifts.erl | 105 ++++++++++++++ erlang/apps/sim/test/sim_shifts_tests.erl | 161 ++++++++++++++++++++++ 3 files changed, 268 insertions(+) create mode 100644 erlang/apps/sim/src/sim_shifts.erl create mode 100644 erlang/apps/sim/test/sim_shifts_tests.erl diff --git a/erlang/apps/sim/src/sim_core.erl b/erlang/apps/sim/src/sim_core.erl index bacafa4..2bb3a35 100644 --- a/erlang/apps/sim/src/sim_core.erl +++ b/erlang/apps/sim/src/sim_core.erl @@ -280,6 +280,8 @@ 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#242 -> sim_shifts:handle_LSH(Core, Mem, IR, EA); + 8#246 -> sim_shifts:handle_LSHC(Core, Mem, IR, EA); 8#250 -> sim_moves:handle_EXCH(Core, Mem, IR, EA); 8#251 -> sim_moves:handle_BLT(Core, Mem, IR, EA); 8#252 -> sim_arithmetic:handle_AOBJP(Core, Mem, IR, EA); diff --git a/erlang/apps/sim/src/sim_shifts.erl b/erlang/apps/sim/src/sim_shifts.erl new file mode 100644 index 0000000..7eb3c22 --- /dev/null +++ b/erlang/apps/sim/src/sim_shifts.erl @@ -0,0 +1,105 @@ +%%% -*- erlang-indent-level: 2 -*- +%%% +%%% simulator for pdp10-elf +%%% Copyright (C) 2020 Mikael Pettersson +%%% +%%% This file is part of pdp10-tools. +%%% +%%% pdp10-tools is free software: you can redistribute it and/or modify +%%% it under the terms of the GNU General Public License as published by +%%% the Free Software Foundation, either version 3 of the License, or +%%% (at your option) any later version. +%%% +%%% pdp10-tools is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +%%% GNU General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License +%%% along with pdp10-tools. If not, see . +%%% +%%%============================================================================= +%%% +%%% 2.5 Shift and Rotate + +-module(sim_shifts). + +-export([ handle_LSH/4 + , handle_LSHC/4 + ]). + +-include("sim_core.hrl"). + +%% 2.5 Shift and Rotate ======================================================== + +%% LSH - Logical Shift + +-spec handle_LSH(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_LSH(Core, Mem, IR, EA) -> + AC = IR band 8#17, + CA = sim_core:get_ac(Core, AC), + Word = lsh(CA, EA#ea.offset), + set_ac_next_pc(Core, Mem, AC, Word). + +%% LSHC - Logical Shift Combined + +-spec handle_LSHC(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_LSHC(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} = lshc(CA0, CA1, EA#ea.offset), + set_acs_next_pc(Core, Mem, AC, Word0, Word1). + +%% Miscellaneous =============================================================== + +lsh(CA, Offset) -> + case Offset band (1 bsl 17) of + 0 -> % left shift + Count = Offset band ((1 bsl 8) - 1), + if Count >= 36 -> 0; + true -> (CA band ((1 bsl (36 - Count)) - 1)) bsl Count + end; + _ -> % right shift + Count = (-Offset) band ((1 bsl 8) - 1), + if Count >= 36 -> 0; + true -> CA bsr Count + end + end. + +lshc(CA0, CA1, Offset) -> + case Offset band (1 bsl 17) of + 0 -> % left shift + Count = Offset band ((1 bsl 8) - 1), + if Count >= 72 -> + {_Word0 = 0, _Word1 = 0}; + Count >= 36 -> + Count1 = Count - 36, + Word0 = (CA1 band ((1 bsl (36 - Count1)) - 1)) bsl Count1, + {Word0, _Word1 = 0}; + true -> + Word0 = ((CA0 band ((1 bsl (36 - Count)) - 1)) bsl Count) bor (CA1 bsr (36 - Count)), + Word1 = ((CA1 band ((1 bsl (36 - Count)) - 1)) bsl Count), + {Word0, Word1} + end; + _ -> % right shift + Count = (-Offset) band ((1 bsl 8) - 1), + if Count >= 72 -> + {_Word0 = 0, _Word1 = 0}; + Count >= 36 -> + Word1 = CA0 bsr (Count - 36), + {_Word0 = 0, Word1}; + true -> + Word0 = CA0 bsr Count, + Word1 = ((CA0 band ((1 bsl Count) - 1)) bsl (36 - Count)) bor (CA1 bsr Count), + {Word0, Word1} + end + end. + +set_acs_next_pc(Core, Mem, AC, Word0, Word1) -> + set_ac_next_pc(sim_core:set_ac(Core, AC, Word0), Mem, (AC + 1) band 8#17, Word1). + +set_ac_next_pc(Core, Mem, AC, Word) -> + sim_core:next_pc(sim_core:set_ac(Core, AC, Word), Mem). diff --git a/erlang/apps/sim/test/sim_shifts_tests.erl b/erlang/apps/sim/test/sim_shifts_tests.erl new file mode 100644 index 0000000..b8da560 --- /dev/null +++ b/erlang/apps/sim/test/sim_shifts_tests.erl @@ -0,0 +1,161 @@ +%%% -*- erlang-indent-level: 2 -*- +%%% +%%% simulator for pdp10-elf +%%% Copyright (C) 2020 Mikael Pettersson +%%% +%%% This file is part of pdp10-tools. +%%% +%%% pdp10-tools is free software: you can redistribute it and/or modify +%%% it under the terms of the GNU General Public License as published by +%%% the Free Software Foundation, either version 3 of the License, or +%%% (at your option) any later version. +%%% +%%% pdp10-tools is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +%%% GNU General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License +%%% along with pdp10-tools. If not, see . +%%% +%%%============================================================================= +%%% +%%% Test cases for 2.5 Shift and Rotate + +-module(sim_shifts_tests). + +-include("../src/sim_core.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +-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 + ((AC) bsl (35 - 12)) bor + ((I) bsl (35 - 13)) bor + ((X) bsl (35 - 17)) bor + ?LOW18(Y))). + +-define(COMMA2(LEFT, RIGHT), ((?LOW18(LEFT) bsl 18) bor ?LOW18(RIGHT))). % LEFT,,RIGHT in MACRO-10 + +-define(EA(S, O), #ea{section = S, offset = O, islocal = false}). +-define(AC(A), ?EA(1, A)). + +-define(INSN_INVALID, ?INSN(0, 0, 0, 0, 0)). + +-define(OP_LSH, 8#242). +-define(OP_LSHC, 8#246). + +%% 2.5 Shift and Rotate ======================================================== + +%% LSH - Logical Shift + +lsh_test() -> + ACS = + [ {1, ?COMMA2(8#000111, 8#222333)} % AC1 = 000111222333 + ], + Prog1 = + [ {1, 8#100, ?INSN(?OP_LSH, 1, 0, 0, 9)} % 1,,100/ LSH 1,9 + , {1, 8#101, ?INSN_INVALID} % 1,,101/ + ], + expect(Prog1, ACS, {1, 8#101}, ?DEFAULT_FLAGS, + [ {?AC(1), ?COMMA2(8#111222, 8#333000)} % AC1 = 111222333000 + ]), + Prog2 = + [ {1, 8#100, ?INSN(?OP_LSH, 1, 0, 0, -9)} % 1,,100/ LSH 1,-9 + , {1, 8#101, ?INSN_INVALID} % 1,,101/ + ], + expect(Prog2, ACS, {1, 8#101}, ?DEFAULT_FLAGS, + [ {?AC(1), ?COMMA2(8#000000, 8#111222)} % AC1 = 000000111222 + ]). + +%% LSHC - Logical Shift Combined + +lshc_test() -> + ACS = + [ {1, ?COMMA2(8#000111, 8#222333)} % AC1 = 000111222333 + , {2, ?COMMA2(8#444555, 8#666777)} % AC2 = 444555666777 + ], + Prog1 = + [ {1, 8#100, ?INSN(?OP_LSHC, 1, 0, 0, 9)} % 1,,100/ LSHC 1,9 + , {1, 8#101, ?INSN_INVALID} % 1,,101/ + ], + expect(Prog1, ACS, {1, 8#101}, ?DEFAULT_FLAGS, + [ {?AC(1), ?COMMA2(8#111222, 8#333444)} % AC1 = 111222333444 + , {?AC(2), ?COMMA2(8#555666, 8#777000)} % AC2 = 555666777000 + ]), + Prog2 = + [ {1, 8#100, ?INSN(?OP_LSHC, 1, 0, 0, 45)} % 1,,100/ LSHC 1,55 + , {1, 8#101, ?INSN_INVALID} % 1,,101/ + ], + expect(Prog2, ACS, {1, 8#101}, ?DEFAULT_FLAGS, + [ {?AC(1), ?COMMA2(8#555666, 8#777000)} % AC1 = 555666777000 + , {?AC(2), ?COMMA2(8#000000, 8#000000)} % AC2 = 000000000000 + ]), + Prog3 = + [ {1, 8#100, ?INSN(?OP_LSHC, 1, 0, 0, -9)} % 1,,100/ LSHC 1,-9 + , {1, 8#101, ?INSN_INVALID} % 1,,101/ + ], + expect(Prog3, ACS, {1, 8#101}, ?DEFAULT_FLAGS, + [ {?AC(1), ?COMMA2(8#000000, 8#111222)} % AC1 = 000000111222 + , {?AC(2), ?COMMA2(8#333444, 8#555666)} % AC2 = 333444555666 + ]), + Prog4 = + [ {1, 8#100, ?INSN(?OP_LSHC, 1, 0, 0, -45)} % 1,,100/ LSHC 1,-55 + , {1, 8#101, ?INSN_INVALID} % 1,,101/ + ], + expect(Prog4, ACS, {1, 8#101}, ?DEFAULT_FLAGS, + [ {?AC(1), ?COMMA2(8#000000, 8#000000)} % AC1 = 000000000000 + , {?AC(2), ?COMMA2(8#000000, 8#111222)} % AC2 = 000000111222 + ]). + +%% Common code to run short sequences ========================================== + +expect(Prog, ACs, ExpectedPC, ExpectedFlags, ExpectedEs) -> + {Core, Mem} = init(Prog, ACs), + {Core1, Mem1, {error, {sim_core, {dispatch, PC, _IR, _EA}}}} = sim_core:run(Core, Mem), + ActualPC = {PC bsr 18, PC band ((1 bsl 18) - 1)}, + ?assertEqual(ExpectedPC, ActualPC), + ?assertEqual(ExpectedFlags, Core1#core.flags), + lists:foreach(fun({EA, ExpectedE}) -> + {ok, ActualE} = sim_core:c(Core1, Mem1, EA), + ?assertEqual(ExpectedE, ActualE) + end, ExpectedEs), + sim_mem:delete(Mem). + +init(Prog, ACs) -> + {PCSection, PCOffset} = prog_pc(Prog), + Mem = init_mem(Prog), + Core = init_core(PCSection, PCOffset, ACs), + {Core, Mem}. + +prog_pc([{Section, Offset, _Word} | _Rest]) -> {Section, Offset}. + +init_mem(Prog) -> init_mem(Prog, sim_mem:new()). + +init_mem([], Mem) -> Mem; +init_mem([{Section, Offset, Word} | Rest], Mem) -> + init_word(Section, Offset, Word, Mem), + init_mem(Rest, Mem). + +init_word(Section, Offset, Word, Mem) -> + Address = (Section bsl 18) bor Offset, + PFN = Address bsr 9, + case sim_mem:mquery(Mem, PFN) of + false -> sim_mem:mmap(Mem, PFN, 4+2, core); + {_Prot, _What} -> ok + end, + ok = sim_mem:write_word(Mem, Address, Word). + +init_core(PCSection, PCOffset, ACs) -> + #core{ pc_section = PCSection + , pc_offset = PCOffset + , acs = init_acs(ACs, list_to_tuple(lists:duplicate(16, 0))) + , flags = ?DEFAULT_FLAGS + }. + +init_acs([], ACS) -> ACS; +init_acs([{AC, Val} | Rest], ACS) -> init_acs(Rest, setelement(AC + 1, ACS, Val)).