From ddf5f818c43f5250701757987fd01660676b2f74 Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Tue, 21 Jul 2020 22:58:31 +0200 Subject: [PATCH] sim: sim_moves: handle BLT, add unit tests --- erlang/apps/sim/src/sim_core.erl | 1 + erlang/apps/sim/src/sim_moves.erl | 57 +++++++++++++++++- erlang/apps/sim/test/sim_moves_tests.erl | 77 ++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 1 deletion(-) diff --git a/erlang/apps/sim/src/sim_core.erl b/erlang/apps/sim/src/sim_core.erl index ff8dcae..48dc397 100644 --- a/erlang/apps/sim/src/sim_core.erl +++ b/erlang/apps/sim/src/sim_core.erl @@ -252,6 +252,7 @@ dispatch(Core, Mem, IR, EA) -> 8#216 -> sim_moves:handle_MOVMM(Core, Mem, IR, EA); 8#217 -> sim_moves:handle_MOVMS(Core, Mem, IR, EA); 8#250 -> sim_moves:handle_EXCH(Core, Mem, IR, EA); + 8#251 -> sim_moves:handle_BLT(Core, Mem, IR, EA); _ -> PC = (Core#core.pc_section bsl 18) bor Core#core.pc_offset, {Core, Mem, {error, {?MODULE, {dispatch, PC, IR, EA}}}} diff --git a/erlang/apps/sim/src/sim_moves.erl b/erlang/apps/sim/src/sim_moves.erl index d8d7651..07134b7 100644 --- a/erlang/apps/sim/src/sim_moves.erl +++ b/erlang/apps/sim/src/sim_moves.erl @@ -24,7 +24,8 @@ -module(sim_moves). --export([ handle_EXCH/4 +-export([ handle_BLT/4 + , handle_EXCH/4 , handle_DMOVE/4 , handle_DMOVEM/4 , handle_DMOVN/4 @@ -365,6 +366,57 @@ handle_DMOVNM(Core, Mem, Word0, Word1, Flags, EA) -> fun(Core1, Mem1) -> handle_DMOVNM(Core1, Mem1, Word0, Word1, Flags, EA) end) end. +%% 2.1.5 Block Transfers ======================================================= + +%% BLT - Block Transfer + +-spec handle_BLT(#core{}, sim_mem:mem(), IR :: word(), #ea{}) + -> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}. +handle_BLT(Core, Mem, IR, EA) -> + AC = IR band 8#17, + CA = sim_core:get_ac(Core, AC), + SrcOffset = CA bsr 18, + DstOffset = CA band ((1 bsl 18) - 1), + handle_BLT(Core, Mem, AC, EA, SrcOffset, DstOffset). + +handle_BLT(Core, Mem, AC, EA, SrcOffset, DstOffset) -> + SrcEA = EA#ea{offset = SrcOffset}, + case sim_core:c(Core, Mem, SrcEA) of + {ok, Word} -> + DstEA = EA#ea{offset = DstOffset}, + case sim_core:cset(Core, Mem, DstEA, Word) of + {ok, Core1} -> + SrcOffset1 = (SrcOffset + 1) band ((1 bsl 18) - 1), + DstOffset1 = (DstOffset + 1) band ((1 bsl 18) - 1), + case DstOffset >= EA#ea.offset of + true -> + Core2 = + case ea_is_ac(DstEA, AC) of + true -> Core1; + false -> handle_BLT_flush(Core, AC, SrcOffset1, DstOffset1) + end, + sim_core:next_pc(Core2, Mem); + false -> handle_BLT(Core1, Mem, AC, EA, SrcOffset1, DstOffset1) + end; + {error, Reason} -> + handle_BLT_fault(Core, Mem, DstEA, write, Reason, AC, SrcOffset, DstOffset) + end; + {error, Reason} -> + handle_BLT_fault(Core, Mem, SrcEA, read, Reason, AC, SrcOffset, DstOffset) + end. + +handle_BLT_fault(Core, Mem, EA, Op, Reason, AC, SrcOffset, DstOffset) -> + %% Following the "Caution" section in the documentation for BLT, this + %% flushes the internal source and destination offsets to AC, and then + %% arranges to resume the BLT at the instruction fetch stage instead of + %% from an internal stage. + Core1 = handle_BLT_flush(Core, AC, SrcOffset, DstOffset), + sim_core:page_fault(Core1, Mem, ea_address(EA), Op, Reason, + fun sim_core:run/2). + +handle_BLT_flush(Core, AC, SrcOffset, DstOffset) -> + sim_core:set_ac(Core, AC, (SrcOffset bsl 18) bor DstOffset). + %% Miscellaneous =============================================================== ac_plus_1(AC) -> @@ -373,6 +425,9 @@ ac_plus_1(AC) -> ea_address(#ea{section = Section, offset = Offset}) -> (Section bsl 18) bor Offset. +ea_is_ac(#ea{section = Section, offset = Offset, islocal = IsLocal}, AC) -> + (Offset =:= AC) andalso (IsLocal orelse Section =< 1). + ea_plus_1(#ea{offset = Offset, islocal = true} = EA) -> EA#ea{offset = (Offset + 1) band ((1 bsl 18) - 1)}; ea_plus_1(#ea{section = Section, offset = ((1 bsl 18) - 1)} = EA) -> diff --git a/erlang/apps/sim/test/sim_moves_tests.erl b/erlang/apps/sim/test/sim_moves_tests.erl index 2ed0d3e..5692e21 100644 --- a/erlang/apps/sim/test/sim_moves_tests.erl +++ b/erlang/apps/sim/test/sim_moves_tests.erl @@ -64,6 +64,7 @@ -define(OP_MOVMM, 8#216). -define(OP_MOVMS, 8#217). -define(OP_EXCH, 8#250). +-define(OP_BLT, 8#251). %% 2.1.1 Exchange Instruction ================================================== @@ -448,6 +449,82 @@ dmovnm_test() -> , {#ea{section = 1, offset = 8#151, islocal = false}, 1} % C(1,,151) = 1 ]). +%% 2.1.5 Block Transfers ======================================================= + +blt_bzero_test() -> + %% First example in 2.1.5: using BLT to clear a block of words. + Prog = + [ {1, 8#100, ?INSN(?OP_MOVEI, 1, 0, 0, 0)} % 1,,100/ MOVEI 1,0 + , {1, 8#101, ?INSN(?OP_MOVEM, 1, 0, 0, 8#200)} % 1,,101/ MOVEM 1,200 ; clear 200 + , {1, 8#102, ?INSN(?OP_MOVE, 1, 0, 0, 8#150)} % 1,,102/ MOVE 1,150 ; AC1 = 200,,201 + , {1, 8#103, ?INSN(?OP_BLT, 1, 0, 0, 8#203)} % 1,,103/ BLT 1,203 ; clear 201-203 + , {1, 8#104, ?INSN_INVALID} % 1,,104/ + , {1, 8#150, ?COMMA2(8#200, 8#201)} % 1,,150/ 200,,201 + , {1, 8#200, 1} % 1,,200/ 1 ; first to be cleared + , {1, 8#201, 1} % 1,,201/ 1 + , {1, 8#202, 1} % 1,,202/ 1 + , {1, 8#203, 1} % 1,,203/ 1 ; last to be cleared + , {1, 8#204, 1} % 1,,204/ 1 + ], + expect(Prog, [], {1, 8#104}, ?DEFAULT_FLAGS, + [ %% check that the four words at 200-203 were cleared + {#ea{section = 1, offset = 8#200, islocal = false}, 0} % C(1,,200) = 0 + , {#ea{section = 1, offset = 8#201, islocal = false}, 0} % C(1,,201) = 0 + , {#ea{section = 1, offset = 8#202, islocal = false}, 0} % C(1,,202) = 0 + , {#ea{section = 1, offset = 8#203, islocal = false}, 0} % C(1,,203) = 0 + %% check that the next word was not overwritten + , {#ea{section = 1, offset = 8#204, islocal = false}, 1} % C(1,,204) = 1 + %% check that AC1 contains the last transferred word's offsets + 1 + , {#ea{section = 1, offset = 1, islocal = false}, ?COMMA2(8#203, 8#204)} % AC1 = 203,,204 + ]). + +blt_load_acs_test() -> + %% Second example in 2.1.5: using BLT to load ACs from memory. + Prog = + [ {2, 8#100, ?INSN(?OP_MOVSI, 3, 0, 0, 8#200)} % 2,,100/ MOVSI 3,200 ; AC3 = 200,,0 + , {2, 8#101, ?INSN(?OP_BLT, 3, 0, 0, 3)} % 2,,101/ BLT 3,3 ; load ACs 0-3 from 200-203 + , {2, 8#102, ?INSN_INVALID} % 2,,102/ + , {2, 8#200, 1} % 2,,200/ 1 + , {2, 8#201, 2} % 2,,201/ 2 + , {2, 8#202, 3} % 2,,202/ 3 + , {2, 8#203, 4} % 2,,203/ 4 + ], + expect(Prog, [], {2, 8#102}, ?DEFAULT_FLAGS, + [ %% check that ACs 0-3 were loaded from 200-203 + {#ea{section = 1, offset = 1, islocal = false}, 2} % AC1 = 2 + , {#ea{section = 1, offset = 2, islocal = false}, 3} % AC2 = 3 + %% this also checks that if the AC parameter to BLT is the last + %% location to be copied, it still has that value and not the + %% last transferred word's offsets + 1 (204,,4 here) + , {#ea{section = 1, offset = 3, islocal = false}, 4} % AC3 = 4 + %% check that the next AC was not overwritten + , {#ea{section = 1, offset = 4, islocal = false}, 0} % AC4 = 0 + ]). + +blt_store_acs_test() -> + %% Third example in 2.1.5: using BLT to store ACs in memory. + Prog = + [ {2, 8#100, ?INSN(?OP_MOVEI, 4, 0, 0, 8#200)} % 2,,100/ MOVEI 4,200 ; AC4 = 0,,200 + , {2, 8#101, ?INSN(?OP_BLT, 4, 0, 0, 8#203)} % 2,,101/ BLT 4,203 ; store ACs 0-3 in 200-203 + , {2, 8#102, ?INSN_INVALID} % 2,,102/ + , {2, 8#200, 1} % 2,,200/ 1 + , {2, 8#201, 1} % 2,,201/ 1 + , {2, 8#202, 1} % 2,,202/ 1 + , {2, 8#203, 1} % 2,,203/ 1 + , {2, 8#204, 8#42} % 2,,204/ 42 + ], + expect(Prog, [], {2, 8#102}, ?DEFAULT_FLAGS, + [ %% check that ACs 0-3 were stored to 200-203 + {#ea{section = 2, offset = 8#200, islocal = false}, 0} % C(2,,200) = 0 + , {#ea{section = 2, offset = 8#201, islocal = false}, 0} % C(2,,201) = 0 + , {#ea{section = 2, offset = 8#202, islocal = false}, 0} % C(2,,202) = 0 + , {#ea{section = 2, offset = 8#203, islocal = false}, 0} % C(2,,203) = 0 + %% check that the next word was not overwritten + , {#ea{section = 2, offset = 8#204, islocal = false}, 8#42} % C(2,,204) = 42 + %% check that AC4 contains the last transferred word's offsets + 1 + , {#ea{section = 1, offset = 4, islocal = false}, ?COMMA2(4, 8#204)} % AC4 = 4,,204 + ]). + %% Common code to run short sequences ========================================== expect(Prog, ACs, ExpectedPC, ExpectedFlags, ExpectedEs) ->