From 63d030846bbed008b7cf8a5c8efb9bb337cd449a Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Wed, 8 Jul 2020 23:17:35 +0200 Subject: [PATCH] sim: sim_ea_tests: add unit tests for EA calculations --- erlang/Makefile | 3 + erlang/apps/sim/src/sim_core.erl | 1 + erlang/apps/sim/test/sim_ea_tests.erl | 201 ++++++++++++++++++++++++++ erlang/rebar.config | 2 + 4 files changed, 207 insertions(+) create mode 100644 erlang/apps/sim/test/sim_ea_tests.erl diff --git a/erlang/Makefile b/erlang/Makefile index 92b24ad..f2eb083 100644 --- a/erlang/Makefile +++ b/erlang/Makefile @@ -35,6 +35,9 @@ link: $(REBAR3) $(REBAR3) as $$PROG escriptize; \ done +test: + $(REBAR3) eunit + distclean realclean: clean rm -f ./rebar3 diff --git a/erlang/apps/sim/src/sim_core.erl b/erlang/apps/sim/src/sim_core.erl index c6af02e..7030423 100644 --- a/erlang/apps/sim/src/sim_core.erl +++ b/erlang/apps/sim/src/sim_core.erl @@ -25,6 +25,7 @@ -module(sim_core). -export([ run/6 + , run/2 , next_pc/2 , get_ac/2 , set_ac/3 diff --git a/erlang/apps/sim/test/sim_ea_tests.erl b/erlang/apps/sim/test/sim_ea_tests.erl new file mode 100644 index 0000000..86e39d7 --- /dev/null +++ b/erlang/apps/sim/test/sim_ea_tests.erl @@ -0,0 +1,201 @@ +%%% -*- 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 PDP10 Effective Address Calculation, taken from +%%% "Extended Addressing", Rev. 5, Jul. 1983, KC10 / Project Jupiter docs. + +-module(sim_ea_tests). + +-include("../src/sim_core.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +-define(LOW18(X), ((X) band ((1 bsl 18) - 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(OP_INVALID, 0). +-define(OP_MOVE, 8#200). +-define(OP_MOVEI, 8#201). + +no_indexing_5_1_1_test() -> + Prog1 = + [ {1, 8#100, ?INSN(?OP_INVALID, 1, 0, 0, 8#200)} % 1,,100/ MOVE 1,200 + ], + expect(Prog1, [], {1, 8#100}, #ea{section = 1, offset = 8#200, islocal = true}), + Prog2 = + [ {1, 8#100, ?INSN(?OP_INVALID, 1, 1, 0, 8#150)} % 1,,100/ MOVE 1,@150 + , {1, 8#150, ?COMMA2(8#400000, 8#200)} % 1,,150/ 400000,,200 ; IFIW + ], + expect(Prog2, [], {1, 8#100}, #ea{section = 1, offset = 8#200, islocal = true}), + Prog3 = + [ {1, 8#100, ?INSN(?OP_INVALID, 1, 1, 0, 8#150)} % 1,,100/ MOVE 1,@150 + , {1, 8#150, ?COMMA2(8#1, 8#200)} % 1,,150/ 1,,200 ; EFIW + ], + expect(Prog3, [], {1, 8#100}, #ea{section = 1, offset = 8#200, islocal = false}). + +ifiw_with_local_index_5_1_2_test() -> + Prog = + [ {1, 8#100, ?INSN(?OP_MOVE, 1, 0, 0, 8#150)} % 1,,100/ MOVE 1,150 + , {1, 8#101, ?INSN(?OP_INVALID, 2, 1, 0, 8#151)} % 1,,101/ MOVE 2,@151 + , {1, 8#150, ?COMMA2(-1, 8#10)} % 1,,150/ -1,,10 ; local index + , {1, 8#151, ?COMMA2(8#400001, 8#200)} % 1,,151/ 400001,,200 ; IFIW + ], + expect(Prog, [], {1, 8#101}, #ea{section = 1, offset = 8#210, islocal = true}). + +ifiw_with_global_index_5_1_3_test() -> + Prog = + [ {1, 8#100, ?INSN(?OP_MOVE, 1, 0, 0, 8#150)} % 1,,100/ MOVE 1,150 + , {1, 8#101, ?INSN(?OP_INVALID, 2, 0, 1, -2)} % 1,,101/ MOVE 2,-2(1) + , {1, 8#150, ?COMMA2(2, 8#10)} % 1,,150/ [2,,10] ; global index + ], + expect(Prog, [], {1, 8#101}, #ea{section = 2, offset = 6, islocal = false}). + +efiw_with_global_index_5_1_4_test() -> + Prog = + [ {1, 8#100, ?INSN(?OP_MOVE, 1, 0, 0, 8#150)} % 1,,100/ MOVE 1,150 + , {1, 8#101, ?INSN(?OP_INVALID, 2, 1, 0, 8#151)} % 1,,101/ MOVE 2,@151 + , {1, 8#150, ?COMMA2(2, 8#10)} % 1,,150/ 2,,10 + , {1, 8#151, ?COMMA2(8#010002, 8#200)} % 1,,151/ 010002,,200 ; EFIW + ], + expect(Prog, [], {1, 8#101}, #ea{section = 4, offset = 8#210, islocal = false}). + +simple_ea_calc_examples_5_3_test() -> + Prog1 = + [ {0, 8#200, ?INSN(?OP_INVALID, 1, 0, 0, 8#100)} % 0,,200/ MOVE 1,100 + ], + expect(Prog1, [], {0, 8#200}, #ea{section = 0, offset = 8#100, islocal = true}), + Prog2 = + [ {1, 8#200, ?INSN(?OP_INVALID, 1, 1, 0, 8#300)} % 1,,200/ MOVE1,@300 + , {1, 8#300, ?COMMA2(8#400000, 8#100)} % 1,,300/ 400000,,100 + ], + expect(Prog2, [], {1, 8#200}, #ea{section = 1, offset = 8#100, islocal = true}), + Prog3 = + [ {1, 8#100, ?INSN(?OP_INVALID, 1, 1, 0, 8#300)} % 1,,100/ MOVE 1,@300 + , {1, 8#300, ?COMMA2(2, 8#200)} % 1,,300/ 2,,200 + ], + expect(Prog3, [], {1, 8#100}, #ea{section = 2, offset = 8#200, islocal = false}). + +ac_references_6_1_test() -> + Prog1 = + [ {2, 8#100, ?INSN(?OP_INVALID, 1, 1, 0, 8#150)} % 2,,100/ MOVE 1,@150 + , {2, 8#150, ?COMMA2(8#400000, 5)} % 2,,150/ 400000,,5 + ], + expect(Prog1, [], {2, 8#100}, #ea{section = 2, offset = 5, islocal = true}), + Prog2 = + [ {2, 8#100, ?INSN(?OP_INVALID, 1, 1, 0, 8#150)} % 2,,100/ MOVE 1,@150 + , {2, 8#150, ?COMMA2(2, 5)} % 2,,150/ 2,,5 + ], + expect(Prog2, [], {2, 8#100}, #ea{section = 2, offset = 5, islocal = false}), + Prog3 = + [ {2, 8#100, ?INSN(?OP_INVALID, 1, 1, 0, 8#150)} % 2,,100/ MOVE 1,@150 + , {2, 8#150, ?COMMA2(1, 5)} % 2,,150/ 1,,5 + ], + expect(Prog3, [], {2, 8#100}, #ea{section = 1, offset = 5, islocal = false}). + +incrementing_ea_6_2_test() -> + Prog1 = + [ {2, 8#100, ?INSN(?OP_INVALID, 1, 1, 0, 8#150)} % 2,,100/ DMOVE 1,@150 + , {2, 8#150, ?COMMA2(8#400000, 8#777777)} % 2,,150/ 400000,,777777 + ], + expect(Prog1, [], {2, 8#100}, #ea{section = 2, offset = 8#777777, islocal = true}), + Prog2 = + [ {2, 8#100, ?INSN(?OP_INVALID, 1, 1, 0, 8#150)} % 2,,100/ DMOVE 1,@150 + , {2, 8#150, ?COMMA2(2, 8#777777)} % 2,,150/ 2,,777777 + ], + expect(Prog2, [], {2, 8#100}, #ea{section = 2, offset = 8#777777, islocal = false}). + +multi_section_ea_calcs_7_0_test() -> + Prog1 = + [ {3, 8#100, ?INSN(?OP_INVALID, 1, 1, 0, 8#150)} % 3,,100/ MOVE 1,@150 + , {3, 8#150, ?COMMA2(8#200002, 8#100)} % 3,,150/ 200002,,100 + , {2, 8#100, ?COMMA2(3, 8#200)} % 2,,100/ 3,,200 + ], + expect(Prog1, [], {3, 8#100}, #ea{section = 3, offset = 8#200, islocal = false}), + Prog2 = + [ {3, 8#100, ?INSN(?OP_INVALID, 1, 1, 0, 8#150)} % 3,,100/ MOVE 1,@150 + , {3, 8#150, ?COMMA2(8#200002, 8#100)} % 3,,150/ 200002,,100 + , {2, 8#100, ?COMMA2(8#400000, 8#200)} % 2,,100/ 400000,,200 + ], + expect(Prog2, [], {3, 8#100}, #ea{section = 2, offset = 8#200, islocal = true}), + Prog3 = + [ {3, 8#077, ?INSN(?OP_MOVEI, 3, 0, 0, 1)} % 3,,077/ MOVEI 3,1 + , {3, 8#100, ?INSN(?OP_INVALID, 1, 1, 0, 8#150)} % 3,,100/ MOVE 1,@150 + , {3, 8#150, ?COMMA2(8#200000, 8#100)} % 3,,150/ 200000,,100 + , {0, 8#100, ?COMMA2(3, 8#200)} % 0,,100/ 3,,200 + ], + expect(Prog3, [], {3, 8#100}, #ea{section = 0, offset = 8#201, islocal = true}). + +%% Remaining examples from the "Extended Addressing" document relate to +%% instructions using the EA not the initial EA calculation itself, and +%% they will be added as those instructions are implemented. + +%% Common code to run short sequences and check final EA ======================= + +expect(Prog, ACs, ExpectedPC, ExpectedEA) -> + {Core, Mem} = init(Prog, ACs), + {_Core, _Mem, {error, {sim_core, {dispatch, PC, _IR, ActualEA}}}} = sim_core:run(Core, Mem), + ActualPC = {PC bsr 18, PC band ((1 bsl 18) - 1)}, + ?assertEqual(ExpectedPC, ActualPC), + ?assertEqual(ExpectedEA, ActualEA), + 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) -> + Flags = (1 bsl ?PDP10_PF_USER), + #core{ pc_section = PCSection + , pc_offset = PCOffset + , acs = init_acs(ACs, list_to_tuple(lists:duplicate(16, 0))) + , flags = Flags + }. + +init_acs([], ACS) -> ACS; +init_acs([{AC, Val} | Rest], ACS) -> init_acs(Rest, setelement(AC + 1, Val, ACS)). diff --git a/erlang/rebar.config b/erlang/rebar.config index 6bc43af..46a72d3 100644 --- a/erlang/rebar.config +++ b/erlang/rebar.config @@ -66,6 +66,8 @@ , {sim_core, format_error, 1} , {sim_loader, format_error, 1} , {strtol, format_error, 1} + %% only called from tests + , {sim_core, run, 2} %% actual unused exports , {pdp10_opcodes, cpu_device_from_name, 2} , {pdp10_opcodes, models_from_name, 1}