summaryrefslogtreecommitdiff
path: root/cpu/netlist_proc.ml
blob: ae3acdb1742f899030fcdc3880863416cb04eef2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
open Netlist_ast

(* module Idm = Map.Make (String) *)
module Idm = Env
(*module Imap = Map.Make(struct type t = int let compare = compare end)*)
module Iset = Set.Make (struct type t = int let compare = compare end)

type res =
    | Arg of (arg * int)
    | Calc of (Iset.t -> equation list -> int Idm.t ->
        arg * int * equation list * int Idm.t)

type calc =
    unit -> res ref

let id =
    let cnt = ref 0 in
    fun s -> 
        let res = s ^ "_xoxo_" ^ (string_of_int !cnt) in
        incr cnt; res

let id2 =
    let cnt = ref 0 in
    fun () ->
        let v = !cnt in incr cnt; v

let value n =
    let l = String.length n in
    let v = Array.init l (fun i -> n.[i] = '1') in
    let res = ref (Arg (Aconst v,l)) in
    fun () -> res
    
let calc ids eqs vars e =
    let res = e () in
    match !res with
    | Calc c -> 
        let a,t,eqs,vars = c ids eqs vars in
        ( res := Arg (a,t); a, t, eqs, vars )
    | Arg (a,t) -> a,t,eqs,vars

(*let calc_rec t ids eqs vars e =
    let res,ide = e () in
    try let id,_ = Imap.find ide ids in
        Avar id, t, eqs, vars, ids
    with Not_found ->
        match !res with
        | Calc c ->
            let id = id "" in
            let a,t,eqs,vars = c (Imap.add ide (id,t) ids) eqs vars in
            ( res := Arg (a,t); a, t, eqs, vars )
        | Arg (a,t) -> a,t,eqs,vars*)

let ( ++ ) a b =
    let res = ref (Calc (
        fun ids eqs vars ->
            let arga,ta,eqs,vars = calc ids eqs vars a in
            let argb,tb,eqs,vars = calc ids eqs vars b in
            let res = id "" in
            Avar res, (ta+tb), (res,Econcat (arga, argb))::eqs, 
                Idm.add res (ta+tb) vars)) in
    fun () -> res
        
let ( ^^ ) a b =
    let res = ref (Calc (
        fun ids eqs vars ->
            let arga,ta,eqs,vars = calc ids eqs vars a in
            let argb,tb,eqs,vars = calc ids eqs vars b in
            if ta = tb then
                let res = id "" in 
                Avar res, (ta), (res,Ebinop (Xor,arga, argb))::eqs, Idm.add res (ta) vars
            else assert false)) in
    fun () -> res
    
let ( ^| ) a b =
    let res = ref (Calc (
        fun ids eqs vars ->
            let arga,ta,eqs,vars = calc ids eqs vars a in
            let argb,tb,eqs,vars = calc ids eqs vars b in
            if ta = tb then
                let res = id "" in 
                Avar res, (ta), (res,Ebinop (Or,arga, argb))::eqs, Idm.add res (ta) vars
            else assert false)) in
    fun () -> res
    
let ( ^& ) a b =
    let res = ref (Calc (fun ids eqs vars ->
        let arga,ta,eqs,vars = calc ids eqs vars a in
        let argb,tb,eqs,vars = calc ids eqs vars b in
        if ta = tb then
            let res = id "" in 
            Avar res, (ta), (res,Ebinop (And,arga, argb))::eqs, Idm.add res (ta) vars
        else assert false)) in
    fun () -> res

let ( ^$ ) a b =
    let res = ref (Calc (fun ids eqs vars ->
        let arga,ta,eqs,vars = calc ids eqs vars a in
        let argb,tb,eqs,vars = calc ids eqs vars b in
        if ta = tb then
            let res = id "" in 
            Avar res, (ta), (res,Ebinop (Nand,arga, argb))::eqs, Idm.add res (ta) vars
        else assert false)) in
    fun () -> res

let not a =
    let res = ref (Calc (fun ids eqs vars ->
        let arga,ta,eqs,vars = calc ids eqs vars a in
        let res = id "" in
        Avar res, ta, (res,Enot arga)::eqs, Idm.add res ta vars)) in
    fun () -> res
    
let mux a b c =
    let res = ref (Calc (fun ids eqs vars ->
        let arga,ta,eqs,vars = calc ids eqs vars a in
        let argb,tb,eqs,vars = calc ids eqs vars b in
        let argc,tc,eqs,vars = calc ids eqs vars c in
        if ta = 1 && tb = tc then
            let res = id "" in
            Avar res, tb, (res,Emux (arga,argb,argc))::eqs, Idm.add res tb vars
        else assert false)) in
    fun () -> res

let ( ** ) a n =
    let res = ref (Calc (fun ids eqs vars ->
        let arga,ta,eqs,vars = calc ids eqs vars a in
        if n >= ta then assert false
        else if ta = 1 then arga,ta,eqs,vars
        else let res = id "" in
            Avar res, 1, (res,Eselect (n,arga))::eqs, Idm.add res 1 vars)) in
    fun () -> res

let ( % ) a (i,j) =
    let res = ref (Calc (fun ids eqs vars ->
        let arga,ta,eqs,vars = calc ids eqs vars a in
        if j > ta then assert false
        else if i > j then assert false
        else if j-i+1 = ta then arga,ta,eqs,vars
        else let res = id "" in
            Avar res, (j-i+1), (res,Eslice (i,j,arga))::eqs,
                Idm.add res (j-i+1) vars)) in
    fun () -> res

let rom prefix a_s w_s a =
    let res = ref (Calc (fun ids eqs vars ->
        let arga,ta,eqs,vars = calc ids eqs vars a in
        if ta = a_s && w_s > 0 then
            let res = id prefix in
            Avar res, w_s, (res,Erom (a_s,w_s,arga))::eqs, Idm.add res w_s vars
        else assert false)) in
    fun () -> res

let ram a_s w_s ra we wa = 
    let id2 = id2 () in
    let id = id "" in
    fun d ->
    let res = ref (Calc (fun ids eqs vars ->
        if Iset.mem id2 ids then Avar id, w_s, eqs, vars
        else let argra,tra,eqs,vars = calc ids eqs vars ra in
        let ids = Iset.add id2 ids in
        let argwe,twe,eqs,vars = calc ids eqs vars we in
        let argwa,twa,eqs,vars = calc ids eqs vars wa in
        let argd,td,eqs,vars = calc ids eqs vars d in
        if tra = a_s && twa = a_s && td = w_s && twe = 1 then
            Avar id, w_s, (id,Eram (a_s,w_s,argra,argwe,argwa,argd))::eqs, Idm.add id w_s vars
        else assert false)) in
    fun () -> res

let reg n =
    let id2 = id2 () in
    let id = id "" in fun a ->
    let res = ref (Calc (fun ids eqs vars ->
        if Iset.mem id2 ids then Avar id, n, eqs, vars
        else let arga,ta,eqs,vars = calc (Iset.add id2 ids) eqs vars a in
            if ta = n then
                match arga with
                | Avar id' -> Avar id, n, (id,Ereg id')::eqs, Idm.add id n vars
                | _ -> assert false
            else assert false)) in
    fun () -> res

let init_string n f =
    let s = String.make n 'a' in
    for i = 0 to n - 1 do
        s.[i] <- f i
    done;
    s

(* value to string *)
let vts bits =
    init_string (Array.length bits) (fun i ->
        if bits.(i) then '1' else '0')

(* argument to string *)
let ats = function
    | Avar id -> id
    | Aconst n -> vts n
    
let s_op = function
    | Or -> "OR"
    | Xor -> "XOR"
    | And -> "AND"
    | Nand -> "NAND"

let print oc p =
    let print_eq oc (s,e) = 
        let s_e =
            match e with
            | Earg a -> ats a
            | Ereg s -> "REG " ^ s
            | Enot a -> "NOT " ^ (ats a)
            | Ebinop (b,a1,a2) -> (s_op b) ^ " " ^ (ats a1) ^ " " ^ (ats a2)
            | Emux (a1,a2,a3) ->
                "MUX " ^ (ats a1) ^ " " ^ (ats a2) ^ " " ^ (ats a3)
            | Erom (n1,n2,a3) ->
                "ROM " ^ (string_of_int n1) ^ " " ^ (string_of_int n2) ^
                    " " ^ (ats a3)
            | Eram (n1,n2,a3,a4,a5,a6) ->
                "RAM " ^ (string_of_int n1) ^ " " ^ (string_of_int n2) ^
                    " " ^ (ats a3) ^ " " ^ (ats a4) ^ " " ^ (ats a5) ^
                    " " ^ (ats a6)
            | Econcat (a1,a2) -> "CONCAT " ^ (ats a1) ^ " " ^ (ats a2)
            | Eslice (n1,n2,a3) -> "SLICE " ^ (string_of_int n1) ^ " " ^
                (string_of_int n2) ^ " " ^ (ats a3)
            | Eselect (n,a) -> "SELECT " ^ (string_of_int n) ^ " " ^ (ats a) in
        Printf.fprintf oc "%s = %s\n" s s_e in
    Printf.fprintf oc "INPUT ";
    if p.p_inputs <> [] then
        (Printf.fprintf oc "%s" (List.hd p.p_inputs); List.iter 
            (Printf.fprintf oc ", %s") (List.tl p.p_inputs));
    Printf.fprintf oc "\nOUTPUT ";
    if p.p_outputs <> [] then
        (Printf.fprintf oc "%s" (List.hd p.p_outputs); List.iter 
            (Printf.fprintf oc ", %s") (List.tl p.p_outputs));
    Printf.fprintf oc "\nVAR ";
    let stts s t = if t = 1 then s else s ^ " : " ^ (string_of_int t) in
    ignore (Idm.fold (fun s t b -> 
        if b then Printf.fprintf oc "%s" (stts s t)
        else Printf.fprintf oc ", %s" (stts s t);
        false) p.p_vars true);
    Printf.fprintf oc "\nIN\n";
    List.iter (print_eq oc) p.p_eqs