mirror of
https://github.com/mikpe/pdp10-tools.git
synced 2026-01-23 02:49:07 +00:00
sim: sim_moves: handle BLT, add unit tests
This commit is contained in:
parent
ccf68cbf70
commit
ddf5f818c4
@ -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}}}}
|
||||
|
||||
@ -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) ->
|
||||
|
||||
@ -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) ->
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user