1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2% Copyright (c) 2017, ETH Zurich.
3% All rights reserved.
4%
5% This file is distributed under the terms in the attached LICENSE file.
6% If you do not find this file, copies can be found by writing to:
7% ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich.
8% Attn: Systems Group.
9%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10
11:- module(decoding_net).
12:- export load_net/1.
13:- export decodes_to/2.
14:- export resolve/2.
15:- export node/2.
16
17:- dynamic node/2.
18:- export enum_translate_range/3.
19:- export name_to_enum/2.
20
21
22:- export struct(node(id:node_id,spec:node_spec)).
23:- export struct(node_id(name,namespace)).
24:- export struct(node_spec(type,accept,translate)).
25:- local struct(map(src_block,dest_node,dest_base,dest_props)).
26:- local struct(block(base,limit,props)).
27
28:- export struct(name(node_id:node_id,address)).
29:- export struct(region(node_id:node_id,base,size)).
30:- export struct(meta(node_id:node_id,key,value)).
31
32%% Used to enumerate names on nodes, to use them in capabilities.
33:- local struct(region_enum_block(node_id:node_id, in_base, in_limit, enum_base, enum_limit)).
34
35
36:- lib(ic).
37
38:- set_flag(syntax_option,based_bignums).
39:- set_flag(syntax_option,iso_base_prefix).
40
41:- dynamic meta/3.
42:- dynamic region_enum_block/5.
43
44%% Load a precompiled decoding net
45load_net(File) :-
46    ensure_loaded(File).
47
48%% Convert from regions to names
49to_name(Region,Name) :-
50    region{
51        node_id:Id,
52        base:Base,
53        size:Size
54    } = Region,
55    Addr #>= Base,
56    Addr #< Base + Size,
57    Name = name{
58        node_id:Id,
59        address:Addr
60    }.
61
62%% Convert from names to regions
63to_region(Name,Region) :-
64    name{
65        node_id:Id,
66        address:Addr
67    } = Name,
68    get_bounds(Addr,Min,Max),
69    Size is Max - Min + 1,
70    ( get_domain_size(Addr,Size) ->
71            Region = region{
72            node_id:Id,
73            base:Min,
74            size:Size
75        }
76    ;
77        writeln(stderr,"Name conversion to region failed: Non continuous domain for address"),
78        fail
79    ).
80
81%% Address range in block
82block_range(Block,Range) :-
83    block{
84        base:Base,
85        limit:Limit
86    } = Block,
87    Range = Base..Limit.
88
89maps_to_name([Map|_],Addr,Name) :-
90        map{
91        src_block:SrcBlock,
92        dest_node:Dest,
93        dest_base:DestBase
94    } = Map,
95    name{
96        node_id:Dest,
97        address:DestAddr
98    } = Name,
99    block_range(SrcBlock,Range),
100    Addr :: Range,
101    block{base:SrcBase} = SrcBlock,
102    DestAddr #= Addr - SrcBase + DestBase.
103
104maps_to_name([_|Maps],Addr,Name) :-
105    maps_to_name(Maps,Addr,Name).
106
107translate(NodeSpec,Addr,Name) :-
108    node_spec{translate:Translate} = NodeSpec,
109    maps_to_name(Translate,Addr,Name).
110
111accept(NodeSpec,Addr) :-
112    node_spec{accept:Accept} = NodeSpec,
113    (
114        foreach(Block,Accept),
115        fromto([],Prev,Next,Ranges)
116    do
117        block_range(Block,Range),
118        Next = [Range|Prev]
119    ),
120    Addr :: Ranges.
121
122accepted_name(Name) :-
123    name{
124        node_id:NodeId,
125        address:Addr
126    } = Name,
127    node{
128        id:NodeId,
129        spec:NodeSpec
130    },
131    accept(NodeSpec,Addr).
132
133decode_step(SrcName,DestName) :-
134    name{
135        node_id:NodeId,
136        address:Addr
137    } = SrcName,
138    node{
139        id:NodeId,
140        spec:NodeSpec
141    },
142    translate(NodeSpec,Addr,DestName).
143
144% Reflexive, transitive closure of decode_step
145decodes_to(SrcName,DestName) :-
146    SrcName = DestName.
147
148decodes_to(SrcName,DestName) :-
149    decode_step(SrcName,Name),
150    decodes_to(Name,DestName).
151
152resolve(SrcName,DestName) :-
153    name{} = SrcName,
154    name{} = DestName,
155    decodes_to(SrcName,DestName),
156    accepted_name(DestName).
157
158resolve(SrcRegion,DestRegion) :-
159    to_name(SrcRegion,SrcName),
160    to_name(DestRegion,DestName),
161    resolve(SrcName,DestName),
162    to_region(SrcName,SrcRegion),
163    to_region(DestName,DestRegion).
164
165ic_add_pred(A,B, R) :-
166    R #= A + B.
167
168enum_translate_range_block(NodeId, InBase, InLimit, EnumBase, EnumLimit) :-
169    region_enum_block(NodeId, InBase, InLimit, EnumBase, EnumLimit) ;
170    (
171        findall((B,L), region_enum_block(_,_,_,B,L), LiPair),
172        (
173            foreach((_,InL), LiPair),
174            foreach(InBound, LiBound)
175        do
176            InBound #= InL + 1
177        ),
178        maxlist([0|LiBound], MaxEnumBase),
179
180        EnumBase = MaxEnumBase,
181        EnumLimit #= EnumBase + InLimit - InBase,
182        assert(region_enum_block(NodeId, InBase, InLimit, EnumBase, EnumLimit))
183    ).
184
185
186% enumerate all inputs of the nodeid. If one exists, return existing enumeration.
187% Assumes that accept and translate blocks are non overlapping.
188enum_translate_range(NodeId, Base, Limit) :-
189        node{id:NodeId, spec: node_spec{translate:TS}},
190        %% Extract blocks from translate set
191        (
192            foreach(TSSpec,TS),
193            foreach(RSSpec, RS)
194        do
195            TSSpec = map(block(Base, Limit, _), _, _, _),
196            RSSpec = (Base, Limit)
197        ),
198
199        %% TODO extract blocks from accept and append to Blocks
200
201        %% Pass blocks into enum_translate_range_block, return aggregate in
202        %% EnumBase and EnumLimit
203        (
204            foreach((Base, Limit),RS),
205            param(NodeId),
206            foreach(EBase, EBaseList),
207            foreach(EMax, EMaxList)
208        do
209            enum_translate_range_block(NodeId, Base, Limit, EBase, ELimit),
210            EMax #= ELimit
211        ),
212        maxlist(EMaxList, Limit),
213        minlist(EBaseList, Base).
214
215name_to_enum(Name, EnumInt) :-
216    EBase #=< EnumInt,
217    EnumInt #=< ELimit,
218    region_enum_block(NodeId, Base, Limit, EBase, ELimit),
219    Addr #= Base + EnumInt - EBase,
220    Name = name{node_id:NodeId, address: Addr}.
221