%%% -*- 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 .
%%%
%%%=============================================================================
%%%
%%% Simulate traps to the kernel.
-module(sim_kernel).
-export([ handle_JSYS/4
]).
-include("sim_core.hrl").
-define(ENOSYS, 38).
%% JSYS ========================================================================
%%
%% System calls are made using JSYS with the system call number in the low 18
%% bits of EA, and the parameters in AC1 to AC7.
%% A successful call clears the Overflow flag and returns a value in AC1.
%% A failed call sets the Overflow flag and returns an error code in AC1.
%% [FIXME: Change to return success as 0 in AC0 and a value in AC1, and failure
%% as a non-zero errno in AC0 and -1 in AC1. A more common approach on Linux
%% is to signal failure by returning -errno, detectable by being >= -4095U, but
%% implementing that comparison on the PDP10 is fairly expensive.]
%% System call numbers are from Linux' , and error codes
%% are from Linux' .
-spec handle_JSYS(#core{}, sim_mem:mem(), IR :: word(), #ea{})
-> {#core{}, sim_mem:mem(), {ok, integer()} | {error, {module(), term()}}}.
handle_JSYS(Core, Mem, _IR, #ea{offset = Nr}) ->
case Nr of
94 -> handle_exit_group(Core, Mem);
_ -> return_errno(Core, Mem, ?ENOSYS)
end.
handle_exit_group(Core, Mem) ->
{Core, Mem, {ok, sim_core:get_ac(Core, 1)}}.
return_errno(Core0, Mem, Errno) ->
Core1 = sim_core:set_ac(Core0, 1, Errno),
Core2 = sim_core:set_flag(Core1, ?PDP10_PF_OVERFLOW),
sim_core:next_pc(Core2, Mem).