From 5e0b8e774239832aa4655811f747fe24617b77ce Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Tue, 9 Jun 2020 21:55:39 +0200 Subject: [PATCH] sim: initial top-level framework --- erlang/Makefile | 2 +- erlang/apps/sim/src/sim.app.src | 25 +++++ erlang/apps/sim/src/sim.erl | 159 ++++++++++++++++++++++++++++++++ erlang/rebar.config | 3 + 4 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 erlang/apps/sim/src/sim.app.src create mode 100644 erlang/apps/sim/src/sim.erl diff --git a/erlang/Makefile b/erlang/Makefile index d827816..92b24ad 100644 --- a/erlang/Makefile +++ b/erlang/Makefile @@ -21,7 +21,7 @@ REBAR3=$(shell type -p rebar3 || echo ./rebar3) REBAR3_GIT=https://github.com/erlang/rebar3.git REBAR3_VSN=3.7.5 -PROGRAMS=8to9 ar as ld nm od readelf +PROGRAMS=8to9 ar as ld nm od readelf sim default: compile link diff --git a/erlang/apps/sim/src/sim.app.src b/erlang/apps/sim/src/sim.app.src new file mode 100644 index 0000000..dcbbf16 --- /dev/null +++ b/erlang/apps/sim/src/sim.app.src @@ -0,0 +1,25 @@ +%%% 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 . + +{application, sim, + [{description, "simulator for pdp10-elf"}, + {vsn, "0.1.0"}, + {registered, []}, + {applications, [kernel, stdlib, lib]}, + {env, []}, + {modules, []} + ]}. diff --git a/erlang/apps/sim/src/sim.erl b/erlang/apps/sim/src/sim.erl new file mode 100644 index 0000000..73a39ee --- /dev/null +++ b/erlang/apps/sim/src/sim.erl @@ -0,0 +1,159 @@ +%%% -*- 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 . + +-module(sim). + +-export([ main/1 + , format_error/1 + ]). + +-record(options, + { exe = "" :: string() % exe + , argv = [] :: [string()] % argv for exe + , stack_size = 510*512 :: pos_integer() % stack size + , trace = false :: boolean() % trace mode + }). + +%% Command-line interface ====================================================== + +main(Argv) -> + escript_runtime:start(fun main_/1, Argv). + +-spec main_([string()]) -> no_return(). +main_(Argv) -> + case sim(Argv) of + ok -> halt(0); + {error, Reason} -> + escript_runtime:fatal("~s\n", [error:format(Reason)]) + end. + +%% Usage: pdp10-elf-sim [] [] +%% +%% Simulates the execution of the given pdp10-elf . +%% +%% Options for the simulator: +%% +%% -s +%% --stack-size= +%% Sets the stack size for main thread. +%% Default: 261120 words (510 pages, one section with first and last +%% page unmapped). +%% +%% -t [] +%% --trace[=] +%% Enables ( true, non-zero, or absent) or disables ( +%% zero or false) tracing. Default: false. +%% +%% -v +%% --version +%% Outputs the version of the simulator and exits. + +sim(Argv) -> + case getopt:parse(Argv, "+s:t::v", + [ { "stack-size", required, $s } + , { "trace", optional, $t } + , { "version", no, $v } + ]) of + {ok, {Opts0, NonOpts0}} -> + case parse_options(Opts0, NonOpts0) of + {ok, Options} -> do_sim(Options); + Else -> Else % ok or {error, _Reason} + end; + {error, _Reason} = Error -> Error + end. + +parse_options(Opts, NonOpts) -> + parse_options(Opts, NonOpts, #options{}). + +parse_options([Opt | Opts], NonOpts, Options) -> + case parse_option(Opt, Options) of + {ok, NewOptions} -> parse_options(Opts, NonOpts, NewOptions); + Else -> Else % ok or {error, _Reason} + end; +parse_options([], [Exe | Argv], Options) -> + {ok, Options#options{exe = Exe, argv = Argv}}; +parse_options([], [], _Options) -> + {error, {?MODULE, no_exe}}. + +parse_option(Opt, Options) -> + case Opt of + {$s, _} -> handle_stack_size(Opt, Options); + {$t, _} -> handle_trace(Opt, Options); + $t -> handle_trace(Opt, Options); + $v -> handle_version(Opt, Options) + end. + +%% Option Handlers ============================================================= + +handle_stack_size({$s, Arg}, Options) -> + case strtol:parse(Arg, _Base = 0) of + {ok, {Number, Rest}} -> + case Rest of + [] -> do_handle_stack_size(Arg, Number, Options); + [$p] -> do_handle_stack_size(Arg, Number*512, Options); + _ -> invalid_stack_size(Arg) + end; + {error, _Reason} = Error -> Error + end. + +do_handle_stack_size(_Arg, Number, Options) when Number > 0 -> + {ok, Options#options{stack_size = Number}}; +do_handle_stack_size(Arg, _Number, _Options) -> + invalid_stack_size(Arg). + +invalid_stack_size(Arg) -> {error, {?MODULE, {invalid_stack_size, Arg}}}. + +handle_trace({$t, Arg}, Options) -> + case Arg of + "false" -> do_handle_trace(false, Options); + "true" -> do_handle_trace(true, Options); + _ -> + case strtol:parse(Arg, _Base = 0) of + {ok, {Number, _Rest = []}} -> do_handle_trace(Number =/= 0, Options); + {ok, {_Number, [_|_]}} -> {error, {?MODULE, {invalid_trace, Arg}}}; + {error, _Reason} = Error -> Error + end + end; +handle_trace($t, Options) -> do_handle_trace(true, Options). + +do_handle_trace(Mode, Options) -> {ok, Options#options{trace = Mode}}. + +handle_version($v, _Options) -> + version(), + ok. % causes main_/1 to halt(0) + +version() -> + io:format("pdp10-tools-sim version 0.1\n"). + +%% Simulation ================================================================== + +do_sim(_Options) -> ok. % FIXME + +%% Error Formatting ============================================================ + +-spec format_error(term()) -> io_lib:chars(). +format_error(Reason) -> + case Reason of + {invalid_stack_size, Arg} -> + io_lib:format("invalid value for -s/--stack-size: ~s", [Arg]); + {invalid_trace, Arg} -> + io_lib:format("invalid value for -t/--trace: ~s", [Arg]); + no_exe -> "no given" + end. diff --git a/erlang/rebar.config b/erlang/rebar.config index 8bb6b0d..95fa370 100644 --- a/erlang/rebar.config +++ b/erlang/rebar.config @@ -48,6 +48,7 @@ , {nm, main, 1} , {od, main, 1} , {readelf, main, 1} + , {sim, main, 1} %% indirect calls to Module:format_error/1 , {assemble, format_error, 1} , {getopt, format_error, 1} @@ -61,6 +62,7 @@ , {pdp10_stdio, format_error, 1} , {scan, format_error, 1} , {scan_state, format_error, 1} + , {sim, format_error, 1} , {strtol, format_error, 1} %% actual unused exports , {pdp10_opcodes, cpu_device_from_name, 2} @@ -77,4 +79,5 @@ , {nm, [{escript_main_app, nm}]} , {od, [{escript_main_app, od}]} , {readelf, [{escript_main_app, readelf}]} + , {sim, [{escript_main_app, sim}]} ]}.