sim: sim_moves: handle BLT, add unit tests

This commit is contained in:
Mikael Pettersson 2020-07-21 22:58:31 +02:00
parent ccf68cbf70
commit ddf5f818c4
3 changed files with 134 additions and 1 deletions

View File

@ -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}}}}

View File

@ -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) ->

View File

@ -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/ <invalid>
, {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/ <invalid>
, {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/ <invalid>
, {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) ->