mirror of
https://github.com/mikpe/pdp10-tools.git
synced 2026-01-24 11:22:52 +00:00
as: support symbols in instruction displacement operands
This commit is contained in:
parent
af93b5caab
commit
c41caee3ba
28
erlang/apps/as/priv/test2.s
Normal file
28
erlang/apps/as/priv/test2.s
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* test2.s
|
||||
* Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.file "test2.s"
|
||||
.text
|
||||
.globl foo
|
||||
.type foo,@function
|
||||
foo: jumpa .Lfie
|
||||
.Lfum: popj 017,
|
||||
.Lfie: jumpa .Lfum
|
||||
.size foo,.-foo
|
||||
@ -73,38 +73,61 @@ image_size(Image) -> image_size(Image, 0).
|
||||
|
||||
image_size([H | T], Acc) -> image_size(T, image_size(H, Acc));
|
||||
image_size([], Acc) -> Acc;
|
||||
image_size(TByte, Acc) when is_integer(TByte), 0 =< TByte, TByte =< 511 -> Acc + 1.
|
||||
image_size(TByte, Acc) when is_integer(TByte), 0 =< TByte, TByte =< 511 ->
|
||||
Acc + 1.
|
||||
|
||||
%% Assemble .text --------------------------------------------------------------
|
||||
|
||||
text(Section = #section{data = {stmts, Stmts}}, Tunit) ->
|
||||
Image = text_image(Stmts),
|
||||
{ok, tunit:put_section(Tunit, Section#section{data = {image, Image}})}.
|
||||
case text_image(Stmts, Tunit) of
|
||||
{ok, Image} ->
|
||||
{ok, tunit:put_section(Tunit, Section#section{data = {image, Image}})};
|
||||
{error, _Reason} = Error -> Error
|
||||
end.
|
||||
|
||||
text_image(Stmts) -> text_image(Stmts, []).
|
||||
text_image(Stmts, Tunit) -> text_image(Stmts, Tunit, []).
|
||||
|
||||
text_image([], Acc) -> Acc; % the input Stmts were in reverse order
|
||||
text_image([Stmt | Stmts], Acc) ->
|
||||
text_image(Stmts, [insn_image(Stmt) | Acc]).
|
||||
text_image([], _Tunit, Acc) -> {ok, Acc}; % the input Stmts were in reverse order
|
||||
text_image([Stmt | Stmts], Tunit, Acc) ->
|
||||
case insn_image(Stmt, Tunit) of
|
||||
{ok, Image} -> text_image(Stmts, Tunit, [Image | Acc]);
|
||||
{error, _Reason} = Error -> Error
|
||||
end.
|
||||
|
||||
insn_image(Insn) ->
|
||||
insn_image(Insn, Tunit) ->
|
||||
#s_insn{ high13 = High13
|
||||
, at = At
|
||||
, address = Address
|
||||
, address = AddressExpr
|
||||
, index = Index
|
||||
} = Insn,
|
||||
Word = (((High13 band ((1 bsl 13) - 1)) bsl (36 - 13)) bor
|
||||
((case At of true -> 1; false -> 0 end) bsl (36 - 14)) bor
|
||||
((Index band ((1 bsl 4) - 1)) bsl (36 - 18)) bor
|
||||
(Address band ((1 bsl 18) - 1))),
|
||||
%% big-endian conversion
|
||||
[(Word bsr 27) band 511,
|
||||
(Word bsr 18) band 511,
|
||||
(Word bsr 9) band 511,
|
||||
Word band 511].
|
||||
case insn_address(AddressExpr, Tunit) of
|
||||
{ok, Address} ->
|
||||
Word = (((High13 band ((1 bsl 13) - 1)) bsl (36 - 13)) bor
|
||||
((case At of true -> 1; false -> 0 end) bsl (36 - 14)) bor
|
||||
((Index band ((1 bsl 4) - 1)) bsl (36 - 18)) bor
|
||||
(Address band ((1 bsl 18) - 1))),
|
||||
%% big-endian conversion
|
||||
{ok, [(Word bsr 27) band 511,
|
||||
(Word bsr 18) band 511,
|
||||
(Word bsr 9) band 511,
|
||||
Word band 511]};
|
||||
{error, _Reason} = Error -> Error
|
||||
end.
|
||||
|
||||
insn_address(AddressExpr, Tunit) ->
|
||||
case AddressExpr of
|
||||
#e_integer{value = Value} -> {ok, Value};
|
||||
#e_symbol{name = Name} ->
|
||||
case tunit:get_symbol(Tunit, Name) of
|
||||
#symbol{st_value = Value} when Value =/= false -> {ok, Value};
|
||||
_ -> {error, {?MODULE, {undefined_symbol, Name}}}
|
||||
end
|
||||
end.
|
||||
|
||||
%% Error reporting -------------------------------------------------------------
|
||||
|
||||
-spec format_error(term()) -> io_lib:chars().
|
||||
format_error({cannot_assemble, Name}) ->
|
||||
io_lib:format("don't know how to assemble section ~s", [Name]).
|
||||
io_lib:format("don't know how to assemble section ~s", [Name]);
|
||||
format_error({undefined_symbol, Name}) ->
|
||||
io_lib:format("reference to undefined symbol ~s", [Name]).
|
||||
|
||||
@ -56,7 +56,7 @@ stmt(ScanState) ->
|
||||
%%
|
||||
%% <address> ::= "@"? <displacement>? <index>?
|
||||
%%
|
||||
%% <displacement> ::= <uinteger>
|
||||
%% <displacement> ::= <uinteger> | <symbol>
|
||||
%%
|
||||
%% <index> ::= "(" <accumulator> ")"
|
||||
%%
|
||||
@ -66,6 +66,7 @@ stmt(ScanState) ->
|
||||
%% popj 017,
|
||||
%% pushj 017,bar
|
||||
%% movei 1,@fum(2)
|
||||
%% jump bar
|
||||
%%
|
||||
%% TODO: <displacement> should be <expr> and permit parentheses and
|
||||
%% various operators.
|
||||
@ -92,6 +93,7 @@ stmt_after_symbol(ScanState, Name) ->
|
||||
{ok, ?T_COLON} -> {ok, #s_label{name = Name}};
|
||||
{ok, ?T_NEWLINE} -> make_insn(ScanState, Name, false, false, false, false);
|
||||
{ok, {?T_UINTEGER, UInt}} -> insn_uint(ScanState, Name, UInt);
|
||||
{ok, {?T_SYMBOL, Symbol}} -> insn_symbol(ScanState, Name, Symbol);
|
||||
ScanRes -> badtok(ScanState, "junk after symbol", ScanRes)
|
||||
end.
|
||||
|
||||
@ -102,27 +104,43 @@ insn_uint(ScanState, Name, UInt) ->
|
||||
{ok, ?T_COMMA} -> % the Uint is the Accumulator, parse EA next
|
||||
insn_ea(ScanState, Name, _AccOrDev = UInt);
|
||||
{ok, ?T_LPAREN} -> % the Uint is the Displacement, parse Index next
|
||||
insn_ea_index(ScanState, Name, _AccOrDev = false, _At = false, _Displacement = UInt);
|
||||
Displacement = #e_integer{value = UInt},
|
||||
insn_ea_index(ScanState, Name, _AccOrDev = false, _At = false, Displacement);
|
||||
{ok, ?T_NEWLINE} -> % the Uint is the Displacement
|
||||
make_insn(ScanState, Name, _AccOrDev = false, _At = false, _Displacement = UInt, _Index = false);
|
||||
Displacement = #e_integer{value = UInt},
|
||||
make_insn(ScanState, Name, _AccOrDev = false, _At = false, Displacement, _Index = false);
|
||||
ScanRes -> badtok(ScanState, "junk after <symbol> <uinteger>", ScanRes)
|
||||
end.
|
||||
|
||||
%% Seen "<symbol> <symbol2>". The <symbol2> is (the start of) the <displacement>.
|
||||
%% TODO: permit <symbol2> to be the <accumulator> (named register or device).
|
||||
insn_symbol(ScanState, Name, Symbol2) ->
|
||||
Displacement = #e_symbol{name = Symbol2},
|
||||
insn_ea_disp(ScanState, Name, _AccOrDev = false, _At = false, Displacement).
|
||||
|
||||
%% <symbol> <accordev> "," . [ ["@"] <displacement> ["(" <index> ")"] ] <newline>
|
||||
insn_ea(ScanState, Name, AccOrDev) ->
|
||||
case scan:token(ScanState) of
|
||||
{ok, ?T_NEWLINE} ->
|
||||
make_insn(ScanState, Name, AccOrDev, _At = false, _Displacement = false, _Index = false);
|
||||
{ok, ?T_AT} -> insn_ea_at(ScanState, Name, AccOrDev);
|
||||
{ok, {?T_UINTEGER, Displacement}} ->
|
||||
{ok, {?T_UINTEGER, UInt}} ->
|
||||
Displacement = #e_integer{value = UInt},
|
||||
insn_ea_disp(ScanState, Name, AccOrDev, _At = false, Displacement);
|
||||
{ok, {?T_SYMBOL, Symbol}} ->
|
||||
Displacement = #e_symbol{name = Symbol},
|
||||
insn_ea_disp(ScanState, Name, AccOrDev, _At = false, Displacement);
|
||||
ScanRes -> badtok(ScanState, "junk after comma", ScanRes)
|
||||
end.
|
||||
|
||||
%% <symbol> [<accordev> ","] "@" . <displacement> . ["(" <index> ")"] <newline>
|
||||
%% <symbol> [<accordev> ","] "@" . <displacement> ["(" <index> ")"] <newline>
|
||||
insn_ea_at(ScanState, Name, AccOrDev) ->
|
||||
case scan:token(ScanState) of
|
||||
{ok, {?T_UINTEGER, Displacement}} ->
|
||||
{ok, {?T_UINTEGER, UInt}} ->
|
||||
Displacement = #e_integer{value = UInt},
|
||||
insn_ea_disp(ScanState, Name, AccOrDev, _At = true, Displacement);
|
||||
{ok, {?T_SYMBOL, Symbol}} ->
|
||||
Displacement = #e_symbol{name = Symbol},
|
||||
insn_ea_disp(ScanState, Name, AccOrDev, _At = true, Displacement);
|
||||
ScanRes -> badtok(ScanState, "junk after @", ScanRes)
|
||||
end.
|
||||
@ -167,7 +185,10 @@ make_insn(ScanState, Name, AccOrDev, At, Displacement, Index) ->
|
||||
{error, _Reason} = Error -> Error;
|
||||
ok -> {ok, #s_insn{ high13 = FinalHigh13
|
||||
, at = At
|
||||
, address = if Displacement =:= false -> 0; true -> Displacement end
|
||||
, address = case Displacement of
|
||||
false -> #e_integer{value = 0};
|
||||
_ -> Displacement
|
||||
end
|
||||
, index = if Index =:= false -> 0; true -> Index end
|
||||
}}
|
||||
end
|
||||
|
||||
@ -21,6 +21,15 @@
|
||||
-ifndef(TUNIT_HRL).
|
||||
-define(TUNIT_HRL, 1).
|
||||
|
||||
%% An expression occurring in a statement. (TODO: extend)
|
||||
|
||||
-record(e_integer, {value :: integer()}).
|
||||
-record(e_symbol, {name :: string()}).
|
||||
|
||||
-type expr() :: #e_integer{}
|
||||
| #e_symbol{}
|
||||
.
|
||||
|
||||
%% A directive, label, or instruction is parsed to a statement, which is
|
||||
%% either interpreted immediately or appended to the representation of the
|
||||
%% current section.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user