Sfoglia il codice sorgente

Lola-2 -> Verilog translator added

Alexander Shiryaev 10 anni fa
parent
commit
13dff196a1

BIN
BlackBox/Po/Docu/ru/Quick-Start.odc


+ 4 - 0
BlackBox/Po/Files/DCMX3.v

@@ -0,0 +1,4 @@
+module DCMX3 (input CLKIN, output CLKFX);
+(* LOC = "DCM_X1Y1" *) DCM #(.CLKFX_MULTIPLY(3), .CLK_FEEDBACK("NONE"))
+  dcm(.CLKIN(CLKIN), .CLKFX(CLKFX));
+endmodule

+ 24 - 0
BlackBox/Po/Files/Divider.Lola.txt

@@ -0,0 +1,24 @@
+MODULE Divider(
+  IN clk, run: BIT;
+  OUT stall: BIT;
+  IN x, y: WORD;  (*32 bit, y > 0*)
+  OUT quot, rem: WORD);
+  REG S: [5] BIT;
+    R, Q: WORD;
+  VAR pos: BIT;
+    x0, r0, r1, r2, q0, q1, d: WORD;
+BEGIN stall := run & ~(S = 31);
+  pos := ~x.31;
+  x0 := pos -> x : ~x + y;    (* -x + (y-1) *)
+  r0 := (S = 0) -> 0'32 : R;
+  d := r1 - y;
+  r1 := {r0[30:0], q0.31};
+  r2 := d.31 -> r1 : d;
+  q0 := (S = 0) -> x0 : Q;
+  q1 := {q0[30:0], ~d.31};
+  quot := pos -> q1 : -q1;
+  rem := pos -> r2 : ~r2 + y;   (*(y-1) - r2*)
+  R := r2;
+  Q := q1;
+  S := run -> S+1 : 0
+END Divider.

+ 98 - 0
BlackBox/Po/Files/FPAdder.Lola.txt

@@ -0,0 +1,98 @@
+MODULE FPAdder(   (*NW 2.11.2014*)
+  IN clk, run, u, v: BIT; x, y: WORD;
+  OUT stall: BIT; z: WORD);
+
+  REG Sum: [27] BIT;  (*pipe reg*)
+    stallR: BIT;
+
+  VAR xs, ys: BIT;  (*signs*)
+    xe, ye: [9] BIT;  (*exponents*)
+    xm, ym: [25] BIT;  (*mantissas*)
+
+    dx, dy, e0, e1: [9] BIT;
+    sx, sy: [9] BIT;  (*shift counts*)
+    sx0, sx1, sy0, sy1: [2] BIT;
+    sxh, syh: BIT;
+    x0, x1,x2, x3, y0, y1, y2, y3: [25] BIT;
+    s: [27] BIT;
+
+    z24, z22, z20, z18, z16, z14, z12, z10, z8, z6, z4, z2: BIT;
+    sc: [5] BIT;  (*shift count*)
+    sc0, sc1: [2] BIT;
+    t1, t2, t3: [25] BIT;
+
+BEGIN  (*unpack*)
+  xs := x.31;
+  xe := u -> 150'9 : {0'1, x[30:23]};
+  xm := {(~u | x.23), x[22:0], 0'1};
+  ys := y.31;
+  ye := {0'1, y[30:23]};
+  ym := {(~u & ~v), y[22:0], 0'1};
+  dx := xe - ye; dy := ye - xe;
+  e0 := dx.8 -> ye : xe;
+  sx := dy.8 -> 0 : dy; sy := dx.8 -> 0 : dx;
+  sx0 := sx[1:0]; sx1 := sx[3:2];
+  sy0 := sy[1:0]; sy1 := sy[3:2];
+  sxh := sx.7 | sx.6 | sx.5;  syh := sy.7 | sy.6 | sy.5;
+
+(*denormalize; right shift*)
+  x0 := (xs & ~u) -> -xm : xm;
+  x1 := (sx0 = 3) -> {xs!3, x0[24:3]} :
+    (sx0 = 2) -> {xs!2, x0[24:2]} :
+    (sx0 = 1) -> {xs, x0[24:1]} : x0;
+  x2 := (sx1 = 3) -> {xs!12, x1[24:12]} :
+    (sx1 = 2) -> {xs!8, x1[24:8]} :
+    (sx1 = 1) -> {xs!4, x1[24:4]} : x1;
+  x3 := sxh -> {xs!25} : sx.4 -> {xs!16, x2[24:16]} : x2;
+
+  y0 := (ys & ~u) -> -ym : ym;
+  y1 := (sy0 = 3) -> {ys!3, y0[24:3]} :
+    (sy0 = 2) -> {ys!2, y0[24:2]} :
+    (sy0 = 1) -> {ys, y0[24:1]} : y0;
+  y2 := (sy1 = 3) -> {ys!12, y1[24:12]} :
+    (sy1 = 2) -> {ys!8, y1[24:8]} :
+    (sy1 = 1) -> {ys!4, y1[24:4]} : y1;
+  y3 := syh -> {ys!25} : (sy.4 -> {ys!16, y2[24:16]} : y2);
+  
+(*addition*)
+  Sum := {xs, xs, x3} + {ys, ys, y3}; s := (Sum.26 -> -Sum : Sum) + 1;   (*round*)
+
+(*post-normalize, shift left;  sc = shift count*)
+  z24 := ~s.25 & ~s.24;
+  z22 := z24 & ~s.23 & ~s.22;
+  z20 := z22 & ~s.21 & ~s.20;
+  z18 := z20 & ~s.19 & ~s.18;
+  z16 := z18 & ~s.17 & ~s.16;
+  z14 := z16 & ~s.15 & ~s.14;
+  z12 := z14 & ~s.13 & ~s.12;
+  z10 := z12 & ~s.11 & ~s.10;
+  z8 := z10 & ~s.9 & ~s.8;
+  z6 := z8 & ~s.7 & ~s.6;
+  z4 := z6 & ~s.5 & ~s.4;
+  z2 := z4 & ~s.3 & ~s.2;
+
+  sc := {z10,
+    z18 & (s.17 | s.16 | s.15 | s.14 | s.13 | s.12 | s.11 | s.10) | z2,
+    z22 & (s.21 | s.20 | s.19 | s.18)  |  z14 & (s.13 | s.12 | s.11 | s.10)  |  z6 & (s.5 | s.4 | s.3 | s.2),
+    z24 & (s.23 | s.22)  |  z20 & (s.19 | s.18)  |  z16 & (s.15 | s.14)  |  z12 & (s.11 | s.10)  |  z8 & (s.7 | s.6)  |  z4 & (s.3 | s.2),
+    ~s.25 & s.24 | z24 & ~s.23 & s.22 | z24 & ~s.23 & s.22 |  z22 & ~s.21 & s.20 | z20 & ~s.19 & s.18 | z18 & ~s.17 & s.16 |  
+      z16 & ~s.15 & s.14 | z14 & ~s.13 & s.12 | z12 & ~s.11 & s.10 | z10 & ~s.9 & s.8 | z8 & ~s.7 & s.6 | z6 & ~s.5 & s.4 | z4 & ~s.3 & s.2};
+
+  e1 := e0 - {0'4, sc} + 1;
+  sc0 := sc[1:0]; sc1 := sc[3:2];
+  t1 := (sc0 = 3) -> {s[22:1], 0'3} :
+    (sc0 = 2) -> {s[23:1], 0'2} :
+    (sc0 = 1) -> {s[24:1], 0'1} : s[25:1];
+  t2 := (sc1 = 3) -> {t1[12:0], 0'12} :
+    (sc1 = 2) -> {t1[16:0], 0'8} :
+    (sc1 = 1) -> {t1[20:0], 0'4} : t1;
+  t3 := sc.4 -> {t2[8:0], 0'16} : t2;
+
+  stall := run & ~stallR;
+  stallR := stall;
+
+  z := v -> {Sum.26 ! 7, Sum[25:1]} :   (*FLOOR*)
+    x[30:0] = 0 -> (~u -> y : 0) :
+    y[30:0] = 0 -> x :
+    (t3 = 0) | e1.8 -> 0 : {Sum.26, e1[7:0], t3[23:1]}
+END FPAdder.

+ 35 - 0
BlackBox/Po/Files/FPDivider.Lola.txt

@@ -0,0 +1,35 @@
+MODULE FPDivider(
+  IN clk, run: BIT; x, y: WORD;
+  OUT stall: BIT; z: WORD);
+
+  REG S: [5] BIT;   (*state*)
+    R, Q: [24] BIT;   (*remainder, quotient*)
+
+  VAR sign: BIT;
+    xe, ye: [8] BIT;
+    e0, e1: [9] BIT;
+    q0, q1, q2: [24] BIT;
+    r0, r1, r2, d: [25] BIT;
+
+BEGIN sign := x.31 ^ y.31;   (*xor*)
+  xe := x[30:23]; ye := y[30:23];
+  e0 := {0'1, xe} - {0'1, ye};
+  e1 := e0 + 126 + q1.23;
+
+  r0 := (S = 0) -> {1'2, x[22:0]} : r2;
+  d := r0 - {1'2, y[22:0]};
+  r1 := d.24 -> r0 : d;
+  r2 := {R, 0'1};
+  q0 := (S = 0) -> 0 : Q;
+  q1 := {q0[22:0], ~d.24};
+  q2 := q1.23 -> q1[23:0] : {q1[22:0], 0'1};
+
+  z := (xe = 0) -> 0 :
+    (ye = 0) -> {sign, $FF'8, 0'23} :  (*divide by 0*)
+    ~e1.8 -> {sign, e1[7:0], q2[22:0]} :
+    ~e1.7 -> {sign, $FF'8, q2[22:0]} : 0;   (*overflow*)
+  stall := run & (S # 23);
+
+  R := r1[23:0]; Q := q1;
+  S := run -> S+1 : 0
+END FPDivider.

+ 34 - 0
BlackBox/Po/Files/FPMultiplier.Lola.txt

@@ -0,0 +1,34 @@
+MODULE FPMultiplier(
+  IN clk, run: BIT; x, y: WORD;
+  OUT stall: BIT; z: WORD);
+
+  REG S: [5] BIT;   (*state*)
+    B2, A2: [24] BIT;
+
+  VAR sign: BIT;
+    xe, ye: [8] BIT;
+    e0, e1: [9] BIT;
+    B0: [25] BIT;
+    B00, B01, B1, A1, A0, z0: [24] BIT;
+
+BEGIN sign := x.31 ^ y.31;   (*xor*)
+  xe := x[30:23]; ye := y[30:23]; e0 := {0'1, xe} + {0'1, ye};
+  B00 := (S = 0) -> 0 : B2;
+  B01 := A0.0 -> {1'1, y[22:0]} : 0;
+  B0 := {0'1, B00} + {0'1, B01};
+  B1 := B0[24:1];
+  A0 := (S = 0) -> {1'1, x[22:0]} : A2;
+  A1 := {B0.0, A0[23:1]};
+
+  e1 := e0 - 127 + B1.23;
+  z0 := B1.23 -> B1 : {B1[22:0], A1.23};
+  z := (xe = 0) | (ye = 0) -> 0 :
+    ~e1.8 -> {sign, e1[7:0], z0[22:0]} :
+    ~e1.7 -> {sign, $FF'8, z0[22:0]} : 0;  (*overflow*)
+  stall := run & (S # 23);
+
+  B2 := B1; A2 := A1;
+  S := run -> S+1 : 0;
+END FPMultiplier.
+
+  

+ 9 - 0
BlackBox/Po/Files/IOBUF32.v

@@ -0,0 +1,9 @@
+module IOBUF32 (input [31:0] I, output [31:0] O, inout [31:0] IO, input T);
+genvar k;
+generate // tri-state buffer for SRAM
+  for (k = 0; k < 32; k = k+1)
+  begin: bufblock
+    IOBUF SRbuf (.I(I[k]), .O(O[k]), .IO(IO[k]), .T(T));
+  end
+endgenerate
+endmodule

+ 10 - 0
BlackBox/Po/Files/IOBUF8.v

@@ -0,0 +1,10 @@
+module IOBUF8 (input [7:0] I, output [7:0] O, inout [7:0] IO, input [7:0] T);
+genvar k;
+generate // tri-state buffer for parallel port
+  for (k = 0; k < 8; k = k+1)
+  begin: gpioblock
+    IOBUF gpiobuf (.I(I[k]), .O(O[k]), .IO(IO[k]), .T(T[k]));
+  end
+endgenerate
+endmodule
+

+ 52 - 0
BlackBox/Po/Files/LSB.Mod.txt

@@ -0,0 +1,52 @@
+MODULE LSB;  (*Lola System Compiler Base, 16.11.2014*)
+  IMPORT Texts, Oberon;
+  
+  CONST
+    bit* = 0; array* = 1; unit* = 2;   (*type forms*)
+    
+    (*tags in output*) const* = 1; typ* = 2; var* = 3; lit* = 4; sel* = 7; range* = 8; cons* = 9;
+    repl* = 10; not* = 11; and* = 12; mul* = 13; div* = 14; or* = 15; xor* = 16; add* = 17; sub* = 18;
+    eql* = 20; neq* = 21; lss* = 22; geq* = 23; leq* = 24; gtr* = 25;
+    then* = 30; else* = 31; next* = 32;
+
+  TYPE
+    Item* = POINTER TO ItemDesc;
+    Object* = POINTER TO ObjDesc;
+    Type* = POINTER TO TypeDesc;
+    ArrayType* = POINTER TO ArrayTypeDesc;
+    UnitType* = POINTER TO UnitTypeDesc;
+
+    ItemDesc* = RECORD
+      tag*: INTEGER;
+      type*: Type;
+      val*, size*: LONGINT;
+      a*, b*: Item
+    END ;
+
+    ObjDesc* = RECORD (ItemDesc)
+      next*: Object;
+      name*: ARRAY 32 OF CHAR;
+      marked*: BOOLEAN
+    END ;
+
+    TypeDesc* = RECORD len*, size*: LONGINT; typobj*: Object END ;
+    ArrayTypeDesc* = RECORD (TypeDesc) eltyp*: Type END ;
+    UnitTypeDesc* = RECORD (TypeDesc) firstobj*: Object END ;
+
+  VAR top*, root*: Object;
+    bitType*, integer*, string*: Type;
+    byteType*, wordType*: ArrayType;
+    modname*: ARRAY 32 OF CHAR;
+
+  PROCEDURE Record*(name: ARRAY OF CHAR; list: Object);
+  BEGIN modname := name; root := list
+  END Record;
+
+BEGIN NEW(bitType); bitType.len := 0; bitType.size := 1; NEW(integer); NEW(string);
+  NEW(byteType); byteType.len := 8; byteType.size := 8; byteType.eltyp := bitType;
+  NEW(wordType); wordType.len := 32; wordType.size := 32; wordType.eltyp := bitType;
+  NEW(root); root.tag := typ; root.name := "WORD"; root.type := wordType; root.next := NIL;
+  NEW(top); top.tag := typ; top.name := "BYTE"; top.type := byteType; top.next := root; root := top;
+  NEW(top); top.tag := typ; top.name := "BIT"; top.type := bitType; top.next := root; root := top
+END LSB.
+

+ 501 - 0
BlackBox/Po/Files/LSC.Mod.txt

@@ -0,0 +1,501 @@
+MODULE LSC;  (*Lola System Compiler, NW 8.1.95 / 18.11.2014*)
+  IMPORT Texts, Oberon, LSB, LSS;
+  
+  VAR sym: INTEGER;
+    err: BOOLEAN;  (*used at end of Unit*)
+    top, bot, undef: LSB.Object;
+    factor: PROCEDURE (VAR x: LSB.Item);  (*to avoid forward references*)
+    expression: PROCEDURE (VAR x: LSB.Item);
+    Unit: PROCEDURE (VAR locals: LSB.Object);
+    W: Texts.Writer;
+
+  PROCEDURE Err(n: INTEGER);
+  BEGIN LSS.Mark("type error"); Texts.WriteInt(W, n, 4);
+    Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
+  END Err;
+
+  PROCEDURE Log(m: LONGINT): LONGINT;
+    VAR n: LONGINT;
+  BEGIN n := 1;
+    WHILE m > 1 DO m := m DIV 2; INC(n) END ;
+    RETURN n
+  END Log;
+
+  PROCEDURE New(tag: INTEGER; a, b: LSB.Item): LSB.Item;
+    VAR z: LSB.Item;
+  BEGIN NEW(z); z.tag := tag; z.a := a; z.b := b; z.val := b.val; RETURN z
+  END New;
+
+  PROCEDURE NewObj(class: INTEGER): LSB.Object; (*insert at end, before BIT*)
+    VAR new, x: LSB.Object;
+  BEGIN x := top;
+    WHILE (x.next # bot) & (x.next.name # LSS.id) DO x := x.next END ;
+    IF x.next = bot THEN
+      NEW(new); new.name := LSS.id; new.tag := class; new.next := bot; x.next := new
+    ELSE LSS.Mark("mult def"); new := x
+    END ;
+    RETURN new
+  END NewObj;
+
+  PROCEDURE ThisObj(id: LSS.Ident): LSB.Object;  (*find object with name = identifier last read*)
+    VAR x: LSB.Object;
+  BEGIN x := top.next;
+    WHILE (x # NIL) & (x.name # id) DO x := x.next END ;
+    IF x = NIL THEN LSS.Mark("undef"); x := undef END ;
+    RETURN x
+  END ThisObj;
+
+  PROCEDURE CheckTypes(x, y, z: LSB.Item);  (*z.type = result type*)
+    VAR xtyp, ytyp: LSB.Type;
+  BEGIN xtyp := x.type; ytyp := y.type; z.type := xtyp; z.size := x.size; z.val := x.val;
+    IF xtyp = LSB.bitType THEN z.type := xtyp;
+      IF ytyp = LSB.integer THEN  (* b + 0 *)
+        IF y.val >= 2 THEN Err(20); LSS.Mark("only 0 or 1") END
+      ELSIF ytyp = LSB.string THEN (* b + {...} *) Err(21)
+      ELSIF ytyp # LSB.bitType THEN Err(22)
+      END
+    ELSIF xtyp IS LSB.ArrayType THEN
+      IF xtyp(LSB.ArrayType).eltyp = LSB.bitType THEN
+        IF (ytyp IS LSB.ArrayType) & (xtyp(LSB.ArrayType).eltyp = LSB.bitType) THEN
+          IF xtyp.size # ytyp.size THEN Err(33) END  (* x + y *)
+        ELSIF ytyp = LSB.integer THEN   (* w + 5 *)
+          IF xtyp.size < Log(y.val) THEN Err(30) END
+        ELSIF ytyp = LSB.string THEN   (*x + {...} *)
+          IF xtyp.size # y.size THEN Err(31) END
+        ELSIF ytyp # LSB.bitType THEN Err(34)
+        END
+      ELSIF (ytyp IS LSB.ArrayType) & (xtyp(LSB.ArrayType).eltyp = ytyp(LSB.ArrayType).eltyp) THEN
+        IF (xtyp.size # ytyp.size) THEN Err(40) END
+      ELSE Err(41)
+      END 
+    ELSIF xtyp = LSB.string THEN
+      IF ytyp = LSB.bitType THEN  (* {...} + b *) Err(12)
+      ELSIF (ytyp IS LSB.ArrayType) & (ytyp(LSB.ArrayType).eltyp = LSB.bitType) THEN  (* {...} + w *)
+        IF x.size # ytyp.size THEN Err(13) END
+      ELSIF ytyp = LSB.integer THEN  (* {...} + 5*)
+        IF x.size < Log(y.val) THEN Err(10) END
+      ELSIF ytyp = LSB.string THEN  (* {...} + {...} *)
+        IF x.size # y.size THEN Err(11) END ;  
+      ELSE Err(14)
+      END
+    ELSIF xtyp = LSB.integer THEN
+      IF (ytyp IS LSB.ArrayType) & (ytyp(LSB.ArrayType).eltyp = LSB.bitType) THEN  (* 5 + w *)
+        IF Log(x.val) > ytyp.size THEN Err(3); LSS.Mark("const too large") END
+      ELSIF ytyp = LSB.bitType THEN (* 5 + b *)
+        IF x.val >= 2 THEN Err(2) END
+      ELSIF ytyp = LSB.integer THEN  (* 5 + 5 *)
+      ELSIF ytyp = LSB.string THEN  (* 5 + {...} *)
+        IF Log(x.val) > y.size THEN Err(12) END
+      ELSE Err(4)
+      END
+    END
+  END CheckTypes;
+
+  PROCEDURE selector(VAR x: LSB.Item);
+    VAR y, z: LSB.Item; obj: LSB.Object;
+      eltyp: LSB.Type; len: LONGINT;
+  BEGIN
+    WHILE (sym = LSS.lbrak) OR (sym = LSS.period) DO
+      IF sym = LSS.lbrak THEN
+        eltyp := x.type(LSB.ArrayType).eltyp; LSS.Get(sym); expression(y);
+        IF sym = LSS.colon THEN (*range*)
+          LSS.Get(sym); expression(z);
+          IF (y.tag = LSB.lit) & (z.tag = LSB.lit) THEN
+            len := y.val - z.val + 1; y := New(LSB.range, y, z); x := New(LSB.sel, x, y); x.type := LSB.string; x.size := len
+          END
+        ELSE x := New(LSB.sel, x, y); x.type := eltyp
+        END ;
+        IF sym = LSS.rbrak THEN LSS.Get(sym) ELSE LSS.Mark("rbrak ?") END
+      ELSE (*sym = LSS.period*) LSS.Get(sym); factor(y);
+        IF (y.tag = LSB.lit) & (y.val >= x.type.len) THEN LSS.Mark("too large") END ;
+        eltyp := x.type(LSB.ArrayType).eltyp; x := New(LSB.sel, x, y); x.type := eltyp
+      END
+    END
+  END selector;
+
+  PROCEDURE elem(VAR x: LSB.Item; VAR len: LONGINT);
+    VAR y, z: LSB.Item; m, n: LONGINT;
+  BEGIN expression(x);
+    IF (x.type = LSB.integer) OR (x.type = LSB.string) THEN m := x.size ELSE m := x.type.size END ;
+    IF sym = LSS.repl THEN
+      LSS.Get(sym);
+      IF sym = LSS.integer THEN
+        NEW(y); y.tag := LSB.lit; n := LSS.val; y.val := n; y.type := LSB.integer; LSS.Get(sym);
+        x := New(LSB.repl, x, y)
+      END
+    ELSE n := 1
+    END ;
+    len := m*n
+  END elem;
+
+  PROCEDURE constructor(VAR x: LSB.Item);
+    VAR y: LSB.Item; n, len: LONGINT;
+  BEGIN elem(x, len);
+    WHILE sym = LSS.comma DO
+      LSS.Get(sym); elem(y, n); INC(len, n); x := New(LSB.cons, x, y); x.val := len
+    END ;
+    x.size := len; x.type := LSB.string;
+    IF sym = LSS.rbrace THEN LSS.Get(sym) ELSE LSS.Mark("rbrace ?") END
+  END constructor;
+
+  PROCEDURE factor0(VAR x: LSB.Item);
+    VAR obj: LSB.Object; y, z: LSB.Item;
+      n, len: LONGINT; t: LSB.ArrayType;
+  BEGIN
+    IF sym = LSS.ident THEN
+      x := ThisObj(LSS.id); LSS.Get(sym);
+      IF x.tag = LSB.var THEN selector(x)
+      ELSIF x.tag = LSB.const THEN n := x.b.val; NEW(x); x.tag := LSB.lit; x.val := n; x.type := LSB.integer
+      ELSE LSS.Mark("bad factor")
+      END
+    ELSIF sym = LSS.lparen THEN
+      LSS.Get(sym); expression(x);
+      IF sym = LSS.rparen THEN LSS.Get(sym) ELSE LSS.Mark("rparen ?") END
+    ELSIF sym = LSS.integer THEN
+      NEW(x); x.tag := LSB.lit; x.val := LSS.val; x.type := LSB.integer; LSS.Get(sym);
+      IF sym = LSS.apo THEN LSS.Get(sym);
+        IF sym = LSS.integer THEN
+          len := LSS.val; LSS.Get(sym);
+          IF len < Log(x.val) THEN LSS.Mark("value too large") END
+        ELSE LSS.Mark("integer ?"); len := 0
+        END ;
+        x.size := len
+      ELSE len := 0
+      END ;
+      x.size := len
+    ELSIF sym = LSS.not THEN
+      LSS.Get(sym); factor(x); y := New(LSB.not, NIL, x); y.type := x.type; y.size := x.size; x := y
+    ELSIF sym = LSS.lbrace THEN LSS.Get(sym); constructor(x)
+    ELSE LSS.Mark("bad factor")
+    END
+  END factor0;
+
+  PROCEDURE term(VAR x: LSB.Item);
+    VAR y, z: LSB.Item; op: INTEGER;
+  BEGIN factor(x);
+    WHILE (sym >= LSS.times) & (sym <= LSS.and) DO
+      IF sym = LSS.and THEN op := LSB.and
+      ELSIF sym = LSS.times THEN op := LSB.mul
+      ELSIF sym = LSS.div THEN op := LSB.div
+      END ;
+      LSS.Get(sym); factor(y); z := New(op, x, y); CheckTypes(x, y, z); x := z
+    END
+  END term;
+
+  PROCEDURE SimpleExpression(VAR x: LSB.Item);
+    VAR y, z: LSB.Item; op: INTEGER;
+  BEGIN
+    IF sym = LSS.minus THEN LSS.Get(sym); term(y);
+      IF y.tag = LSB.lit THEN x := y; x.val := -y.val ELSE x := New(LSB.sub, NIL, y); x.type := y.type END
+    ELSIF sym = LSS.plus THEN LSS.Get(sym); term(x);
+    ELSE term(x)
+    END ;
+    WHILE (sym >= LSS.plus) & (sym <= LSS.xor) DO
+      IF sym = LSS.or THEN op := LSB.or
+      ELSIF sym = LSS.xor THEN op := LSB.xor
+      ELSIF sym = LSS.plus THEN op := LSB.add
+      ELSIF sym = LSS.minus THEN op := LSB.sub
+      END ;
+      LSS.Get(sym); term(y); z := New(op, x, y); CheckTypes(x, y, z); x := z
+    END
+  END SimpleExpression;
+
+  PROCEDURE UncondExpression(VAR x: LSB.Item);
+    VAR y, z: LSB.Item; rel: INTEGER;
+  BEGIN SimpleExpression(x);
+    IF (sym >= LSS.eql) & (sym <= LSS.geq) THEN
+      IF sym = LSS.eql THEN rel := LSB.eql
+      ELSIF sym = LSS.neq THEN rel := LSB.neq
+      ELSIF sym = LSS.lss THEN rel := LSB.lss
+      ELSIF sym = LSS.geq THEN rel := LSB.geq
+      ELSIF sym = LSS.leq THEN rel := LSB.leq
+      ELSE rel := LSB.gtr
+      END ;
+      LSS.Get(sym); SimpleExpression(y); z := New(rel, x, y); CheckTypes(x, y, z); z.type := LSB.bitType; x := z
+    END
+  END UncondExpression;
+
+  PROCEDURE expression0(VAR x: LSB.Item);
+    VAR y, z, w: LSB.Item;
+  BEGIN UncondExpression(x);
+    IF sym = LSS.then THEN
+      IF x.type # LSB.bitType THEN LSS.Mark("Boolean?") END ;
+      LSS.Get(sym); expression(y);
+      IF sym = LSS.colon THEN
+        LSS.Get(sym); expression(z); w := New(LSB.else, y, z); CheckTypes(y, z, w);
+        x := New(LSB.then, x, w); x.type := w.type; x.size := w.size
+      ELSE LSS.Mark("colon ?")
+      END
+    END
+  END expression0;
+
+  PROCEDURE CheckAssign(x, y: LSB.Item);
+    VAR xtyp, ytyp: LSB.Type;
+  BEGIN xtyp := x.type; ytyp := y.type;
+    IF xtyp # ytyp THEN
+      IF xtyp = LSB.bitType THEN
+        IF (ytyp # LSB.integer) OR (y.val >= 2) THEN Err(70); END
+      ELSIF xtyp IS LSB.ArrayType THEN
+        IF xtyp(LSB.ArrayType).eltyp = LSB.bitType THEN
+          IF (ytyp IS LSB.ArrayType) & (xtyp(LSB.ArrayType).eltyp = LSB.bitType) THEN (*w := w*)
+            IF xtyp.size # ytyp.size THEN Err(71) END  (* x + y *)
+          ELSIF ytyp = LSB.integer THEN   (* w := 5 *)
+            IF xtyp.size < Log(y.val) THEN Err(72) END
+          ELSIF ytyp = LSB.string THEN   (* w := {...} *)
+            IF xtyp.size # y.size THEN Err(73) END
+          ELSE Err(74)
+          END
+        ELSE Err(74)
+        END
+      END
+    END
+  END CheckAssign;
+
+  PROCEDURE Param(fpar: LSB.Object; VAR apar: LSB.Item);
+    VAR y, z: LSB.Item;
+  BEGIN expression(y); apar := New(LSB.next, NIL, y); CheckAssign(fpar, y);
+    IF fpar.val IN {3, 4} THEN  (*OUT or INOUT parameter*)
+      IF y.tag # 3 THEN  (*actual param is expression?*) LSS.Mark("bad actual param")
+      ELSIF y.b = NIL THEN y.b := undef
+      ELSE LSS.Mark("mult def")
+      END
+    END
+  END Param;
+
+  PROCEDURE Statement;
+    VAR x, y, z, apar, npar: LSB.Item;
+      unit: LSB.UnitType; fpar: LSB.Object;
+  BEGIN
+    IF sym < LSS.ident THEN LSS.Mark("bad factor");
+      REPEAT LSS.Get(sym) UNTIL sym >= LSS.ident
+    END ;
+    IF sym = LSS.ident THEN
+      x := ThisObj(LSS.id); z := x; LSS.Get(sym); selector(z);
+      IF sym = LSS.becomes THEN LSS.Get(sym);
+        IF x.val >= 5 THEN LSS.Mark("assignment to read-only") END ;
+        IF x.b # NIL THEN LSS.Mark("mult assign") END ;
+        expression(y); CheckAssign(z, y); x.b := y; (*tricky*)
+        IF z # x THEN
+          IF x.val = 0 THEN x.a := z.b ELSE LSS.Mark("illegal assignment") END
+        END
+      ELSIF sym = LSS.lparen THEN LSS.Get(sym);  (*unit instantiation*)
+        IF x.type IS LSB.UnitType THEN
+          unit := x.type(LSB.UnitType); fpar := unit.firstobj;
+          IF sym # LSS.rparen THEN
+            Param(fpar, apar); x.b := apar; fpar := fpar.next;
+            WHILE sym # LSS.rparen DO
+              IF sym = LSS.comma THEN LSS.Get(sym) END ;
+              Param(fpar, npar);
+              IF fpar.tag >= 3 THEN fpar := fpar.next; apar.a := npar; apar := npar
+              ELSE LSS.Mark("too many params")
+              END
+            END ;
+            IF fpar.val >= 3 THEN LSS.Mark("too few params") END
+          END ;
+          IF sym = LSS.rparen THEN LSS.Get(sym) ELSE LSS.Mark("rparen ?") END
+        ELSE LSS.Mark("not a module")
+        END
+      ELSE LSS.Mark("bad statement")
+      END
+    END
+  END Statement;
+
+  PROCEDURE StatSequence;
+  BEGIN Statement;
+    WHILE sym <= LSS.semicolon DO
+      IF sym = LSS.semicolon THEN LSS.Get(sym)
+      ELSIF sym < LSS.semicolon THEN LSS.Mark("semicolon missing?");
+      END ; 
+      Statement
+    END ;
+    IF sym = LSS.end THEN LSS.Get(sym) ELSE LSS.Mark("END ?") END
+  END StatSequence;
+
+  (*---------------------------------------------------*)
+  
+  PROCEDURE ConstDeclaration;
+    VAR obj: LSB.Object;
+  BEGIN
+    IF sym = LSS.ident THEN
+      obj := NewObj(LSB.const); LSS.Get(sym);
+      IF (sym = LSS.becomes) OR (sym = LSS.eql) THEN LSS.Get(sym) ELSE LSS.Mark(":= ?") END ;
+      expression(obj.b); obj.type := LSB.integer;
+      IF sym = LSS.semicolon THEN LSS.Get(sym) ELSE LSS.Mark("semicolon ?") END
+    ELSE LSS.Mark("ident ?")
+    END
+  END ConstDeclaration;
+
+  PROCEDURE Type0(VAR type: LSB.Type);
+    VAR obj: LSB.Object; len, size: LONGINT;
+      eltyp: LSB.Type; arrtyp: LSB.ArrayType;
+  BEGIN len := 1;
+    IF sym = LSS.lbrak THEN (*array*) LSS.Get(sym);
+      IF sym = LSS.integer THEN len := LSS.val; LSS.Get(sym)
+      ELSIF sym = LSS.ident THEN obj := ThisObj(LSS.id); len := obj.val
+      END ;
+      IF sym = LSS.rbrak THEN LSS.Get(sym) ELSE LSS.Mark("rbrak ?") END ;
+      Type0(eltyp); NEW(arrtyp); size := eltyp.size * len;
+      arrtyp.eltyp := eltyp; type := arrtyp; type.len := len; type.size := size
+    ELSIF sym = LSS.ident THEN
+      obj := ThisObj(LSS.id); LSS.Get(sym);
+      IF obj # NIL THEN
+        IF obj.tag = LSB.typ THEN type := obj.type ELSE LSS.Mark("not a type"); type := LSB.bitType END
+      ELSE LSS.Mark("type ?")
+      END
+    ELSE type := LSB.bitType; LSS.Mark("ident or [")
+    END
+  END Type0;
+
+  PROCEDURE TypeDeclaration;
+    VAR obj: LSB.Object; utyp: LSB.UnitType;
+  BEGIN
+    IF sym = LSS.ident THEN
+      obj := NewObj(LSB.typ); LSS.Get(sym);
+      IF (sym = LSS.becomes) OR (sym = LSS.eql) THEN LSS.Get(sym) ELSE LSS.Mark(":= ?") END ;
+      IF sym = LSS.module THEN
+        LSS.Get(sym); NEW(utyp); Unit(utyp.firstobj); obj.type := utyp; obj.type.typobj := obj
+      ELSE Type0(obj.type)
+      END ;
+      IF sym = LSS.semicolon THEN LSS.Get(sym) ELSE LSS.Mark("semicolon ?") END
+    ELSE LSS.Mark("ident ?")
+    END
+  END TypeDeclaration;
+
+  PROCEDURE VarList(kind: INTEGER; clk: LSB.Item);
+    VAR first, new, obj: LSB.Object; type: LSB.Type;
+  BEGIN obj := NIL;
+    WHILE sym = LSS.ident DO
+      new := NewObj(LSB.var); new.name := LSS.id; new.val := kind; first := new; LSS.Get(sym);
+      IF sym = LSS.comma THEN LSS.Get(sym) ELSIF sym = LSS.ident THEN LSS.Mark("comma missing") END ;
+      WHILE sym = LSS.ident DO
+        new := NewObj(LSB.var); new.name := LSS.id; new.val := kind; LSS.Get(sym);
+        IF sym = LSS.comma THEN LSS.Get(sym) ELSIF sym = LSS.ident THEN LSS.Mark("comma missing") END
+      END ;
+      IF sym = LSS.colon THEN
+        LSS.Get(sym); Type0(type); obj := first;
+        WHILE obj # bot DO obj.type := type; obj.a := clk; obj := obj.next END
+      ELSE LSS.Mark("colon ?")
+      END ;
+      IF sym = LSS.semicolon THEN LSS.Get(sym)
+      ELSIF sym # LSS.rparen THEN LSS.Mark("semicolon or rparen missing")
+      END
+    END
+  END VarList;
+
+  PROCEDURE ParamList;
+    VAR kind: INTEGER;
+  BEGIN
+    IF sym = LSS.in THEN kind := 6 ELSIF sym = LSS.out THEN kind := 3 ELSIF sym = LSS.inout THEN kind := 4 END ;
+    LSS.Get(sym); VarList(kind, NIL)
+  END ParamList;
+
+  PROCEDURE Traverse(x: LSB.Item);
+  BEGIN
+    IF x # NIL THEN
+      IF x IS LSB.Object THEN
+        IF (x.tag = LSB.var) & (x.val >= 2) THEN  (*not reg*) 
+          IF x(LSB.Object).marked THEN (*loop*)
+            Texts.WriteString(W, x(LSB.Object).name); Texts.Write(W, "|"); err := TRUE  (*global*)
+          ELSIF x.b # NIL THEN x(LSB.Object).marked := TRUE; Traverse(x.b)
+          END ;
+          x(LSB.Object).marked := FALSE
+        END
+      ELSE Traverse(x.a); Traverse(x.b)
+      END
+    END
+  END Traverse;
+
+  PROCEDURE Unit0(VAR locals: LSB.Object);
+    VAR obj, oldtop: LSB.Object; kind: INTEGER; clock: LSB.Item;
+  BEGIN oldtop := top.next; top.next := LSB.top;  (*top is dummy*)
+    IF sym = LSS.lparen THEN LSS.Get(sym) ELSE LSS.Mark("lparen ?") END ;
+    WHILE (sym = LSS.in) OR (sym = LSS.out) OR (sym = LSS.inout) DO ParamList END ;
+    IF sym = LSS.rparen THEN LSS.Get(sym) ELSE LSS.Mark("rparen ?") END ;
+    IF sym = LSS.xor (*arrow*) THEN LSS.Get(sym); locals := top.next
+    ELSE
+      IF sym = LSS.semicolon THEN LSS.Get(sym) ELSE LSS.Mark("semicolon ?") END ;
+      IF sym = LSS.const THEN LSS.Get(sym);
+        WHILE sym = LSS.ident DO ConstDeclaration END
+      END ;
+      IF sym = LSS.type THEN LSS.Get(sym);
+        WHILE sym = LSS.ident DO TypeDeclaration END
+      END ;
+      WHILE sym = LSS.var DO LSS.Get(sym);
+        WHILE sym = LSS.ident DO VarList(2, NIL) END
+      END ;
+      WHILE sym = LSS.reg DO LSS.Get(sym);
+        IF sym = LSS.lparen THEN (*clock*)
+          LSS.Get(sym); kind := 1; expression(clock);
+          IF sym = LSS.rparen THEN LSS.Get(sym) ELSE LSS.Mark("rparen ?") END
+        ELSE kind := 0; clock := NIL
+        END ;
+        WHILE sym = LSS.ident DO VarList(kind, clock) END
+      END ;
+      WHILE sym = LSS.var DO LSS.Get(sym);
+        WHILE sym = LSS.ident DO VarList(2, NIL) END
+      END ;
+      locals := top.next;
+      IF sym = LSS.begin THEN LSS.Get(sym); StatSequence END ;
+      obj := locals; err := FALSE;  (*find unassigned variables*)
+      WHILE obj # LSB.top DO
+        IF (obj.tag = LSB.var) & (obj.val < 5) THEN
+          IF (obj.b = NIL) & (obj.val < 4) THEN Texts.WriteString(W, obj.name); Texts.Write(W, " "); err := TRUE
+          ELSIF obj.b = undef THEN obj.b := NIL
+          END
+        END ;
+        obj := obj.next
+      END ;
+      IF err THEN LSS.Mark(" unassigned variables") END ;
+      obj := locals; err := FALSE;  (*find combinatorial loops*)
+      WHILE obj # LSB.top DO
+        IF obj.tag = LSB.var THEN obj.marked := TRUE; Traverse(obj.b); obj.marked := FALSE END ;
+        obj := obj.next
+      END ;
+      IF err THEN Texts.WriteLn(W); Texts.WriteString(W, " variables in comb. loops") END
+    END ;
+    top.next := oldtop
+  END Unit0;
+
+  PROCEDURE Module(T: Texts.Text; pos: LONGINT);
+    VAR root: LSB.Object; modname: ARRAY 32 OF CHAR;
+  BEGIN Texts.WriteString(W, "compiling Lola ");
+    bot := LSB.top; top.next := bot; LSS.Init(T, pos); LSS.Get(sym);
+    IF sym = LSS.module THEN
+      LSS.Get(sym);
+      IF sym = LSS.ident THEN
+        modname := LSS.id; Texts.WriteString(W, LSS.id); LSS.Get(sym);
+        Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf);
+      ELSE LSS.Mark("ident ?")
+      END ;
+      Unit(root); LSB.Record(modname, root);
+      IF sym = LSS.ident THEN LSS.Get(sym);
+        IF LSS.id # modname THEN LSS.Mark("no match") END
+      END ;
+      IF sym # LSS.period THEN LSS.Mark("period ?") END ;
+      IF LSS.error THEN Texts.WriteString(W, "compilation failed"); Texts.WriteLn(W) END
+    ELSE LSS.Mark("module ?")
+    END ;
+    Texts.Append(Oberon.Log, W.buf)
+  END Module;
+
+  PROCEDURE Compile*;
+    VAR beg, end, time: LONGINT;
+      S: Texts.Scanner; T: Texts.Text;
+  BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
+    IF S.class = Texts.Char THEN
+      IF S.c = "*" THEN
+      ELSIF S.c = "@" THEN
+        Oberon.GetSelection(T, beg, end, time);
+        IF time >= 0 THEN Module(T, beg) END
+      END
+    ELSIF S.class = Texts.Name THEN
+      NEW(T); Texts.Open(T, S.s); Module(T, 0)
+    END ;
+    Texts.Append(Oberon.Log, W.buf)
+  END Compile;
+
+BEGIN Texts.OpenWriter(W);
+  Texts.WriteString(W, "Lola compiler; NW 18.11.2014"); Texts.WriteLn(W);
+  NEW(top); bot := LSB.top; NEW(undef); undef.tag := 2; undef.type := LSB.bitType;
+  factor := factor0; expression := expression0; Unit := Unit0
+END LSC.

+ 80 - 0
BlackBox/Po/Files/LSP.Mod.txt

@@ -0,0 +1,80 @@
+MODULE LSP;  (*display data structure;  NW 7.9.2014*)
+  IMPORT Texts, Oberon, LSB;
+
+  VAR W: Texts.Writer;
+    C: ARRAY 64, 6 OF CHAR;
+
+  PROCEDURE PrintType(typ: LSB.Type);
+    VAR obj: LSB.Object;
+  BEGIN
+    IF typ IS LSB.ArrayType THEN
+      Texts.Write(W, "["); Texts.WriteInt(W, typ.len, 1); Texts.Write(W, "]"); PrintType(typ(LSB.ArrayType).eltyp)
+    ELSIF typ IS LSB.UnitType THEN
+      Texts.WriteString(W, "UnitType "); obj := typ(LSB.UnitType).firstobj;
+    ELSE Texts.WriteString(W, "BIT")
+    END ;
+    Texts.Append(Oberon.Log, W.buf)
+  END PrintType;
+
+  PROCEDURE PrintTree(x: LSB.Item; n: INTEGER);
+    VAR i: INTEGER;
+  BEGIN
+    IF x # NIL THEN  i := n;
+      IF x IS LSB.Object THEN
+        WHILE i > 0 DO Texts.Write(W, 9X); DEC(i) END ;
+        Texts.WriteString(W, x(LSB.Object).name); Texts.WriteLn(W)
+      ELSE
+        PrintTree(x.a, n+1);
+        WHILE i > 0 DO Texts.Write(W, 9X); DEC(i) END ;
+        IF x.tag = LSB.lit THEN Texts. WriteInt(W, x.val, 1) ELSE Texts.WriteString(W, C[x.tag]); END ;
+        Texts.WriteLn(W);
+        PrintTree(x.b, n+1)
+      END
+    END
+  END PrintTree;
+
+  PROCEDURE PrintObj(obj: LSB.Object; n: INTEGER);
+    VAR apar: LSB.Item; obj1: LSB.Object;
+  BEGIN
+    IF n > 0 THEN Texts.Write(W, 9X) END ;
+    Texts.WriteString(W, C[obj.tag]); Texts.Write(W, " "); Texts.WriteString(W, obj.name);
+    IF obj.tag = LSB.const THEN Texts.WriteString(W, " = "); PrintTree(obj.b, 1); Texts.WriteLn(W)
+    ELSIF obj.tag = LSB.typ THEN
+      IF obj.type IS LSB.UnitType THEN  (*formal param list*)
+        obj1 := obj.type(LSB.UnitType).firstobj;
+        Texts.WriteString(W, " BEGIN "); Texts.WriteLn(W);
+        WHILE (obj1 # NIL) & (obj1 # LSB.top) DO PrintObj(obj1, 0); obj1 := obj1.next END ;
+        Texts.WriteString(W, "END"); Texts.WriteLn(W)
+      ELSE PrintType(obj.type)
+      END
+    ELSE (*var*) Texts.WriteString(W, ": ");
+      IF obj.type IS LSB.UnitType THEN
+        Texts.WriteString(W, obj.type.typobj.name);
+        apar := obj.b; Texts.WriteString(W, " [");  (*actual param list*)
+        WHILE apar # NIL DO PrintTree(apar.b, 1); apar := apar.a END ;
+        Texts.Write(W, "]"); Texts.WriteLn(W)
+      ELSE PrintType(obj.type);
+        Texts.WriteString(W, " #"); Texts.WriteInt(W, obj.val, 1);
+        IF obj.a # NIL THEN (*indexed*) Texts.WriteString(W, " SEL"); PrintTree(obj.a, 1) END ;
+        IF obj.b # NIL THEN Texts.WriteString(W, " := "); Texts.WriteLn(W); PrintTree(obj.b, 1)
+        ELSE Texts.WriteLn(W)
+        END
+      END
+    END
+  END PrintObj;
+
+  PROCEDURE List*;
+    VAR obj: LSB.Object;
+  BEGIN obj := LSB.root;
+    WHILE obj # LSB.top DO PrintObj(obj, 0); obj := obj.next END ;
+    Texts.Append(Oberon.Log, W.buf)
+  END List;
+
+BEGIN Texts.OpenWriter(W);
+  C[LSB.const] := "CONST"; C[LSB.typ] := "TYPE"; C[LSB.var] := "VAR";
+  C[LSB.lit] := "LIT"; C[LSB.sel] := "MUX"; C[LSB.range] := ": "; C[LSB.cons] := ", "; C[LSB.repl] := "**";
+  C[LSB.or] := "| "; C[LSB.xor] := "^ "; C[LSB.and] := "& ";  C[LSB.not] := "~ ";
+  C[LSB.add] := "+ "; C[LSB.sub] := "- "; C[LSB.mul] := "* "; C[LSB.div] := "/ ";
+  C[LSB.eql] := "= "; C[LSB.neq] := "# "; C[LSB.lss] := "< "; C[LSB.geq] := ">="; C[LSB.leq] := "<="; C[LSB.gtr] := "> ";
+  C[LSB.then] := " -> "; C[LSB.else] := " :: "; C[LSB.next] := "--"
+END LSP.

+ 159 - 0
BlackBox/Po/Files/LSS.Mod.txt

@@ -0,0 +1,159 @@
+MODULE LSS; (* NW 16.10.93 / 22.9.2014*)
+  IMPORT Texts, Oberon;
+  
+  CONST IdLen* = 32; NofKeys = 10;
+    (*symbols*) null = 0;
+    arrow* = 1; times* = 2; div* = 3; and* = 4; plus* = 5; minus* = 6; or* = 7; xor* = 8;  not* = 9;
+    eql* = 10; neq* = 11; lss* = 12; leq* = 13; gtr* = 14; geq* = 15;
+    at* = 16; apo* = 17; period* = 18; comma* = 19; colon* = 20; rparen* = 21; rbrak* = 22; rbrace* = 23; 
+    then* = 24; lparen* = 26; lbrak* = 27; lbrace* = 28; repl* = 29; becomes* = 30;
+    ident* = 31; integer* = 32; reg* = 35; semicolon* = 40; end* = 41;
+    const* = 51; type* = 52; var* = 53; out* = 54; inout* = 55; in* = 56;
+    begin* = 57; module* = 58; eof = 59;
+
+  TYPE Ident* = ARRAY IdLen OF CHAR;
+
+  VAR val*: LONGINT;
+    id*: Ident;
+    error*: BOOLEAN;
+
+    ch: CHAR;
+    errpos: LONGINT;
+    R: Texts.Reader;
+    W: Texts.Writer;
+    key: ARRAY NofKeys OF Ident;
+    symno: ARRAY NofKeys OF INTEGER;
+
+  PROCEDURE Mark*(msg: ARRAY OF CHAR);
+    VAR p: LONGINT;
+  BEGIN p := Texts.Pos(R);
+    IF p > errpos+2 THEN
+      Texts.WriteString(W, "  pos "); Texts.WriteInt(W, p, 1);
+      Texts.WriteString(W, "  err:  "); Texts.WriteString(W, msg);
+      Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
+    END ;
+    errpos := p; error := TRUE
+  END Mark;
+  
+  PROCEDURE identifier(VAR sym: INTEGER);
+    VAR i: INTEGER;
+  BEGIN i := 0;
+    REPEAT
+      IF i < IdLen THEN id[i] := ch; INC(i) END ;
+      Texts.Read(R, ch)
+    UNTIL (ch < "0") OR (ch > "9") & (ch < "A") OR (ch > "Z") & (ch < "a") OR (ch > "z");
+    IF ch = "'" THEN
+      IF i < IdLen THEN id[i] := ch; INC(i) END ;
+      Texts.Read(R, ch)
+    END ;
+    IF i = IdLen THEN Mark("ident too long"); id[IdLen-1] := 0X
+    ELSE id[i] := 0X
+    END ;
+    i := 0;
+    WHILE (i < NofKeys) & (id # key[i]) DO INC(i) END ;
+    IF i < NofKeys THEN sym := symno[i] ELSE sym := ident END
+  END identifier;
+
+  PROCEDURE Number(VAR sym: INTEGER);
+  BEGIN val := 0; sym := integer;
+    REPEAT
+      IF val <= (7FFFFFFFH - ORD(ch) + ORD("0")) DIV 10 THEN
+        val := 10 * val + ORD(ch) - ORD("0")
+      ELSE Mark("integer too large"); val := 0
+      END ;
+      Texts.Read(R, ch)
+    UNTIL (ch < "0") OR (ch > "9")
+  END Number;
+  
+  PROCEDURE HexNum(VAR sym: INTEGER);
+    VAR d: LONGINT;
+  BEGIN val := 0; sym := integer;
+    WHILE (ch >= "0") & (ch <= "9") OR (ch >= "A") & (ch <= "F") DO
+      IF ch >= "A" THEN d := ORD(ch) - 37H ELSE d := ORD(ch) - 30H END ;
+      val := 16 * val + d; Texts.Read(R, ch)
+    END
+  END HexNum;
+  
+  PROCEDURE comment;
+  BEGIN Texts.Read(R, ch);
+    REPEAT
+      WHILE ~R.eot & (ch # "*") DO
+        IF ch = "(" THEN Texts.Read(R, ch);
+          IF ch = "*" THEN comment END
+        ELSE Texts.Read(R, ch)
+        END
+      END ;
+      WHILE ch = "*" DO Texts.Read(R, ch) END
+    UNTIL (ch = ")") OR R.eot;
+    IF ~R.eot THEN Texts.Read(R, ch) ELSE Mark("comment not terminated") END
+  END comment;
+
+  PROCEDURE Get*(VAR sym: INTEGER);
+  BEGIN
+    REPEAT
+      WHILE ~R.eot & (ch <= " ") DO Texts.Read(R, ch) END;
+      IF ch < "A" THEN 
+        IF ch < "0" THEN
+          IF ch = "!" THEN Texts.Read(R, ch); sym := repl
+          ELSIF ch = "#" THEN Texts.Read(R, ch); sym := neq
+          ELSIF ch = "$" THEN Texts.Read(R, ch); HexNum(sym)
+          ELSIF ch = "&" THEN Texts.Read(R, ch); sym := and
+          ELSIF ch = "'" THEN Texts.Read(R, ch); sym := apo
+          ELSIF ch = "(" THEN Texts.Read(R, ch); 
+            IF ch = "*" THEN sym := null; comment ELSE sym := lparen END
+          ELSIF ch = ")" THEN Texts.Read(R, ch); sym := rparen
+          ELSIF ch = "*" THEN Texts.Read(R, ch); sym := times
+          ELSIF ch = "+" THEN Texts.Read(R, ch); sym := plus
+          ELSIF ch = "," THEN Texts.Read(R, ch); sym := comma
+          ELSIF ch = "-" THEN Texts.Read(R, ch);
+            IF ch = ">" THEN Texts.Read(R, ch); sym := then ELSE sym := minus END
+          ELSIF ch = "." THEN Texts.Read(R, ch); sym := period
+          ELSIF ch = "/" THEN Texts.Read(R, ch); sym := div
+          ELSE sym := null
+          END
+        ELSIF ch <= "9" THEN Number(sym)
+        ELSIF ch = ":" THEN Texts.Read(R, ch);
+          IF ch = "=" THEN Texts.Read(R, ch); sym := becomes ELSE sym := colon END
+        ELSIF ch = ";" THEN Texts.Read(R, ch); sym := semicolon
+        ELSIF ch = "<" THEN Texts.Read(R, ch);
+          IF ch = "=" THEN Texts.Read(R, ch); sym := leq ELSE sym := lss END
+        ELSIF ch = "=" THEN Texts.Read(R, ch); sym := eql
+        ELSIF ch = ">" THEN Texts.Read(R, ch);
+          IF ch = "=" THEN Texts.Read(R, ch); sym := geq ELSE sym := gtr END
+        ELSIF ch = "?" THEN Texts.Read(R, ch); sym := then
+        ELSIF ch = "@" THEN Texts.Read(R, ch); sym := at
+        ELSE sym := null
+        END
+      ELSIF ch <= "Z" THEN identifier(sym)
+      ELSIF ch < "a" THEN
+        IF ch = "[" THEN Texts.Read(R, ch); sym := lbrak
+        ELSIF ch = "]" THEN Texts.Read(R, ch); sym := rbrak
+        ELSIF ch = "^" THEN Texts.Read(R, ch); sym := xor
+        ELSE sym := null
+        END
+      ELSIF ch <= "z" THEN identifier(sym)
+      ELSIF ch <= "{" THEN Texts.Read(R, ch); sym := lbrace
+      ELSIF ch <= "|" THEN Texts.Read(R, ch); sym := or
+      ELSIF ch <= "}" THEN Texts.Read(R, ch); sym := rbrace
+      ELSIF ch <= "~" THEN Texts.Read(R, ch); sym := not
+      ELSE sym := null
+      END
+    UNTIL sym # null
+  END Get;
+
+  PROCEDURE Init*(T: Texts.Text; pos: LONGINT);
+  BEGIN error := FALSE; errpos := pos; Texts.OpenReader(R, T, pos); Texts.Read(R, ch)
+  END Init;
+  
+BEGIN Texts.OpenWriter(W);
+  key[ 0] := "BEGIN"; symno[0] := begin;
+  key[ 1] := "CONST"; symno[1] := const;
+  key[ 2] := "END"; symno[2] := end;
+  key[3] := "IN"; symno[3] := in;
+  key[4] := "INOUT"; symno[4] := inout;
+  key[5] := "MODULE"; symno[5] := module;
+  key[6] := "OUT"; symno[6] := out;
+  key[7] := "REG"; symno[7] := reg;
+  key[8] := "TYPE"; symno[8] := type;
+  key[9] := "VAR"; symno[9] := var;
+END LSS.

+ 222 - 0
BlackBox/Po/Files/LSV.Mod.txt

@@ -0,0 +1,222 @@
+MODULE LSV;  (*Lola System: display Verilog; generate txt-File; NW 26.10.2014*)
+  IMPORT Files, Texts, Oberon, LSB;
+
+  VAR W: Texts.Writer;
+    Constructor: PROCEDURE (VAR x: LSB.Item);   (*to avoid forward reference*)
+    F: Files.File; R: Files.Rider;
+    C: ARRAY 64, 6 OF CHAR;
+
+  PROCEDURE Write(ch: CHAR);
+  BEGIN Files.Write(R, ch)
+  END Write;
+
+  PROCEDURE WriteLn;
+  BEGIN Files.Write(R, 0DX); Files.Write(R, 0AX)
+  END WriteLn;
+
+  PROCEDURE WriteInt(x: LONGINT);  (* x >= 0 *)
+    VAR i: INTEGER; d: ARRAY 14 OF LONGINT;
+  BEGIN i := 0;
+    IF x < 0 THEN Files.Write(R, "-"); x := -x END ;
+    REPEAT d[i] := x MOD 10; x := x DIV 10; INC(i) UNTIL x = 0;
+    REPEAT DEC(i); Files.Write(R, CHR(d[i] + 30H)) UNTIL i = 0
+  END WriteInt;
+
+  PROCEDURE WriteHex(x: LONGINT);  (*x >= 0*)
+    VAR i: INTEGER; d: ARRAY 8 OF LONGINT;
+  BEGIN i := 0;
+    REPEAT d[i] := x MOD 10H; x := x DIV 10H; INC(i) UNTIL (x = 0) OR (i = 8);
+    REPEAT DEC(i);
+      IF d[i] >= 10 THEN Files.Write(R, CHR(d[i] + 37H)) ELSE Files.Write(R, CHR(d[i] + 30H)) END
+    UNTIL i = 0
+  END WriteHex;
+
+  PROCEDURE WriteString(s: ARRAY OF CHAR);
+    VAR i: INTEGER;
+  BEGIN i := 0;
+    WHILE s[i] # 0X DO Files.Write(R, s[i]); INC(i) END
+  END WriteString;
+
+  (* ------------------------------- *)
+
+  PROCEDURE Type(typ: LSB.Type);
+    VAR obj: LSB.Object;
+  BEGIN
+    IF typ IS LSB.ArrayType THEN
+      IF typ(LSB.ArrayType).eltyp # LSB.bitType THEN
+        Write("["); WriteInt(typ.len - 1); WriteString(":0]"); Type(typ(LSB.ArrayType).eltyp)
+      END
+    ELSIF typ IS LSB.UnitType THEN (* obj := typ(LSB.UnitType).firstobj; *)
+    END
+  END Type;
+
+  PROCEDURE BitArrLen(typ: LSB.Type);
+    VAR eltyp: LSB.Type;
+  BEGIN
+    IF typ IS LSB.ArrayType THEN
+      eltyp := typ(LSB.ArrayType).eltyp;
+      WHILE eltyp IS LSB.ArrayType DO typ := eltyp; eltyp := typ(LSB.ArrayType).eltyp END ;
+      IF eltyp = LSB.bitType THEN
+        Write("["); WriteInt(typ.len - 1);WriteString(":0] ")
+      END
+    END
+  END BitArrLen;
+
+  PROCEDURE Expression(x: LSB.Item);
+    VAR z: LSB.Item;
+  BEGIN
+    IF x # NIL THEN
+      IF x IS LSB.Object THEN WriteString(x(LSB.Object).name)
+      ELSIF x.tag = LSB.cons THEN
+        Write("{"); Constructor(x); Write("}")
+      ELSE
+        IF x.tag = LSB.repl THEN
+          Write("{"); WriteInt(x.b.val); Write("{"); Expression(x.a);
+          Write("}"); Write("}")
+        ELSE
+          IF (x.tag >= LSB.and) & (x.tag <= LSB.gtr) THEN Write("(") END ;
+          Expression(x.a);
+          IF x.tag = LSB.sel THEN Write("["); Expression(x.b); Write("]")
+          ELSIF x.tag = LSB.lit THEN
+            IF x.size # 0 THEN
+              WriteInt(x.size); Write("'"); Write("h"); WriteHex(x.val)
+            ELSE WriteInt(x.val)
+            END
+          ELSE WriteString(C[x.tag]); Expression(x.b)
+          END ;
+          IF (x.tag >= LSB.and) & (x.tag <= LSB.gtr) THEN Write(")") END
+        END
+      END
+    END
+  END Expression;
+
+  PROCEDURE Elem(VAR x: LSB.Item);
+  BEGIN
+    IF x.tag = LSB.repl THEN
+      Write("{"); WriteInt(x.b.val); Write("{"); Expression(x.a);  WriteString("}}")
+    ELSE Expression(x)
+    END
+  END Elem;
+
+  PROCEDURE Constructor0(VAR x: LSB.Item);
+  BEGIN
+    IF x.tag = LSB.cons THEN Constructor(x.a); WriteString(", "); Elem(x.b) ELSE Elem(x) END
+  END Constructor0;
+
+  PROCEDURE Declaration(obj: LSB.Object);
+    VAR apar: LSB.Item; typ: LSB.Type;
+  BEGIN typ := obj.type;
+    IF obj.type IS LSB.UnitType THEN WriteString("unit ") ELSE Type(obj.type) END ;
+    IF obj.tag = LSB.var THEN
+      IF obj.type IS LSB.UnitType THEN
+        apar := obj.a; WriteLn; Write("[");
+        WHILE apar # NIL DO Expression(apar.b); apar := apar.a END ;
+        Write("]")
+      END
+    ELSIF obj.tag = LSB.const THEN WriteString(" = "); WriteInt(obj.val)
+    END
+  END Declaration;
+
+  PROCEDURE ObjList0(obj: LSB.Object);  (*declarations*)
+    VAR obj1: LSB.Object; param: BOOLEAN;
+  BEGIN param := TRUE;
+    WHILE obj # LSB.top DO
+      IF (obj.tag = LSB.var) & ~(obj.type IS LSB.UnitType) THEN
+        IF obj.val <= 1 THEN WriteString("reg ")
+        ELSIF obj.val = 2 THEN WriteString("wire ")
+        ELSIF obj.val = 3 THEN WriteString("output ")
+        ELSIF obj.val = 4 THEN WriteString("inout ")
+        ELSIF obj.val = 6 THEN WriteString("input ")
+        ELSE WriteString("??? ")
+        END ;
+        BitArrLen(obj.type); WriteString(obj.name);
+        obj1 := obj.next;
+        WHILE (obj1 # LSB.top) & (obj1.type = obj.type) & (obj1.val = obj.val) DO
+          WriteString(", "); obj := obj1; WriteString(obj.name); obj1 := obj.next
+        END ;
+        IF param & (obj.val >= 3) & (obj1.val < 3) THEN  (*end param list*) param := FALSE; Write(")")
+        END ;
+        IF (obj.type # LSB.bitType) & (obj.type(LSB.ArrayType).eltyp # LSB.bitType) THEN Type(obj.type) END ;
+        IF param THEN Write(",") ELSE Write(";") END ;
+        WriteLn
+      ELSIF obj.tag = LSB.const THEN
+      END ;
+      obj := obj.next
+    END
+  END ObjList0;
+
+  PROCEDURE ActParam(VAR x: LSB.Item; fpar: LSB.Object);
+  BEGIN Write("."); WriteString(fpar.name); Write("("); Expression(x); Write(")")
+  END ActParam;
+
+  PROCEDURE ObjList1(obj: LSB.Object);  (*assignments to variables*)
+    VAR apar: LSB.Item; fpar: LSB.Object;
+  BEGIN
+    WHILE obj # LSB.top DO
+      IF (obj.tag = LSB.var) OR (obj.tag = LSB.const) THEN
+        IF obj.type IS LSB.UnitType THEN
+          WriteString(obj.type.typobj.name); Write(" "); WriteString(obj.name);
+          apar := obj.b; fpar := obj.type(LSB.UnitType).firstobj;
+          Write("("); ActParam(apar.b, fpar); apar := apar.a; fpar := fpar.next;  (*actual param list*)
+          WHILE apar # NIL DO WriteString(", "); ActParam(apar.b, fpar); apar := apar.a; fpar := fpar.next END ;
+          Write(")"); Write(";"); WriteLn
+        ELSIF (obj.b # NIL) & (obj.val >= 2) THEN
+          WriteString("assign "); WriteString(obj.name); WriteString(" = ");
+          Expression(obj.b); Write(";"); WriteLn
+        END
+      ELSIF obj.tag = LSB.typ THEN (*instantiation; actual parameters*)
+      END ;
+      obj := obj.next
+    END
+  END ObjList1;
+
+  PROCEDURE ObjList2(obj: LSB.Object);  (*assignments to registers*)
+    VAR apar: LSB.Item; fpar: LSB.Object;
+  BEGIN WriteString("always @ (posedge clk) begin"); WriteLn;
+    WHILE obj # LSB.top DO
+      IF (obj.tag = LSB.var) & ~(obj.type IS LSB.UnitType) & (obj.val = 0) & (obj.b # NIL) THEN
+        WriteString(obj.name);
+        IF obj.a # NIL THEN Write("["); Expression(obj.a); Write("]") END ;
+        WriteString(" <= "); Expression(obj.b); Write(";"); WriteLn
+      END ;
+      obj := obj.next
+    END ;
+    WriteString("end"); WriteLn
+  END ObjList2;
+
+  PROCEDURE ObjList3(obj: LSB.Object);  (*assignments to registers with explicit clocks*)
+    VAR apar: LSB.Item; fpar: LSB.Object;
+  BEGIN
+    WHILE obj # LSB.top DO
+      IF (obj.tag = LSB.var) & ~(obj.type IS LSB.UnitType) & (obj.val = 1) & (obj.b # NIL) THEN
+        WriteString("always @ (posedge "); Expression(obj.a); WriteString(") begin ");
+        WriteString(obj.name);
+        WriteString(" <= "); Expression(obj.b); WriteString("; end"); WriteLn
+      END ;
+      obj := obj.next
+    END
+  END ObjList3;
+
+  PROCEDURE List*;
+    VAR S: Texts.Scanner;
+  BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
+    IF (S.class = Texts.Name) OR (S.class = Texts.String) THEN
+      Texts.WriteString(W, LSB.modname); Texts.WriteString(W, " translating to  "); Texts.WriteString(W, S.s);
+      F := Files.New(S.s); Files.Set(R, F, 0);
+      WriteString("`timescale 1ns / 1 ps"); WriteLn;
+      WriteString("module "); WriteString(LSB.modname); WriteString("(   // translated from Lola"); WriteLn;
+      ObjList0(LSB.root); ObjList1(LSB.root);
+      ObjList2(LSB.root); ObjList3(LSB.root);
+      WriteString("endmodule"); WriteLn;
+      Files.Register(F); Texts.WriteString(W, " done"); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
+    END
+  END List;
+
+BEGIN Texts.OpenWriter(W); Constructor := Constructor0;
+  C[LSB.const] := "CONST"; C[LSB.typ] := "TYPE"; C[LSB.var] := "VAR";
+  C[LSB.lit] := "LIT"; C[LSB.sel] := "SEL"; C[LSB.range] := ":"; C[LSB.cons] := ",";
+  C[LSB.or] := " | "; C[LSB.xor] := " ^ "; C[LSB.and] := " & ";  C[LSB.not] := "~";
+  C[LSB.add] := " + "; C[LSB.sub] := " - "; C[LSB.mul] := " * "; C[LSB.div] := " / ";
+  C[LSB.eql] := " == "; C[LSB.neq] := " != "; C[LSB.lss] := " <  "; C[LSB.geq] := " >= "; C[LSB.leq] := " <= "; C[LSB.gtr] := " >  ";
+  C[LSB.then] := " ? "; C[LSB.else] := " : "; C[LSB.next] := "--"
+END LSV.

+ 31 - 0
BlackBox/Po/Files/MouseP.Lola.txt

@@ -0,0 +1,31 @@
+MODULE MouseP (
+  IN clk, rst: BIT;
+  INOUT io: [2] BIT;
+  OUT out: [28] BIT);
+
+  (* init mouse cmd F4 (start reporting) with start, parity and stop bits added *)
+  CONST InitBuf := $FFFFFDE8;  (* 1...1 1 0 1111 0100 0 *)
+  TYPE PS2BUF = MODULE (OUT O: [2] BIT; INOUT IO: [2] BIT; IN T: [2] BIT) ^;
+  REG x, y: [10] BIT;   (*counters*)
+    btns: [3] BIT;
+    Q0, Q1, run: BIT;
+    shreg: [32] BIT;
+  VAR shift, endbit, reply: BIT;
+    dx, dy: [10] BIT;
+    in: [2] BIT;
+    ps2buf: PS2BUF;
+BEGIN ps2buf(in, io, {run | shreg[0], rst});  (*open-collector wiring*)
+  shift := Q1 & ~Q0;   (*falling edge detector*)
+  reply := ~run & ~shreg.11;   (*start bit of echoed initBuf, if response*)
+  endbit := run & ~shreg.0;   (*normal packet received*)
+  dx := {shreg.5 !2, shreg.7 -> 0'8 : shreg[19:12]};   (*sign + ovfl*)
+  dy := {shreg.6 !2, shreg.8 -> 0'8 : shreg[30:23]};   (*sign + ovfl*)
+  out := {run, btns, 0'2, y, 0'2, x};
+
+  run := rst & (reply | run);
+  Q0 := in[0]; Q1 := Q0;
+  shreg := ~rst -> InitBuf : (endbit | reply) -> $FFFFFFFF'32 : shift -> {in[1], shreg[31:1]} : shreg;
+  x := ~rst -> 0'10 : endbit -> x + dx : x;
+  y := ~rst -> 0'10 : endbit -> y + dy : y;
+  btns := ~rst -> 0'3 : endbit -> {shreg.1, shreg.3, shreg.2} : btns
+END MouseP.

+ 24 - 0
BlackBox/Po/Files/Multiplier.Lola.txt

@@ -0,0 +1,24 @@
+MODULE Multiplier (     (*NW 5.10.2014*)
+  IN clk, run, u: BIT;
+  OUT stall: BIT;
+  IN x, y: WORD;   (*32 bit*)
+  OUT z: [64] BIT);
+
+  TYPE MULT18X18 := MODULE (OUT P: [36] BIT; IN A, B: [18] BIT) ^;
+
+  VAR M0, M1, M2, M3: MULT18X18;
+    p0, p1, p2, p3: [36] BIT;
+  REG S: BIT;   (*state*)
+    z0: [16] BIT; z1, z2: [48] BIT;
+BEGIN 
+  M0(p0, {0'2, x[15:0]}, {0'2, y[15:0]});
+  M1(p1, {u&x.31, u&x.31, x[31:16]}, {0'2, y[15:0]});
+  M2(p2, {0'2, x[15:0]}, {u&y.31, u&y.31, y[31:16]});
+  M3(p3, {u&x.31, u&x.1, x[31:16]}, {u&y.31, u&y.31, y[31:16]});
+  stall := run & ~S;
+  z := {z1 + z2, z0};
+  S := stall;
+  z0 := p0[15:0];
+  z1 := {0'32, p0[31:16]} + {(u&p1.31)!16, p1[31:0]};
+  z2 := {u&p2.31!16, p2[31:0]} + {p3[31:0], 0'16}
+END Multiplier.

+ 24 - 0
BlackBox/Po/Files/PS2.Lola.txt

@@ -0,0 +1,24 @@
+MODULE PS2 (
+  IN clk, rst, done: BIT;
+  OUT rdy, shift: BIT;
+  OUT data: BYTE;
+  IN PS2C, PS2D: BIT);
+
+  REG Q0, Q1: BIT;   (*synchronizer and falling edge detector*)
+    shreg: [11] BIT;
+    inptr, outptr: [4] BIT;
+    fifo: [16] BYTE;
+  VAR endbit: BIT;
+
+BEGIN endbit := ~shreg.0;   (*start bit reached correct pos*)
+  shift := Q1 & ~Q0;
+  Q0 := PS2C; Q1 := Q0;
+  data := fifo[outptr];
+  rdy := (inptr # outptr);
+
+  shreg := (~rst | endbit) -> $7FF'11 :
+    shift -> {PS2D, shreg[10:1]} : shreg;
+  outptr := ~rst -> 0 : rdy & done -> outptr + 1 : outptr;
+  inptr := ~rst -> 0 : endbit -> inptr + 1 : inptr;
+  fifo[inptr] := endbit -> shreg[8:1] : fifo[inptr];
+END PS2.

+ 6 - 0
BlackBox/Po/Files/PS2BUF.v

@@ -0,0 +1,6 @@
+//PS/2 2-wire open-collector interface from tri-state buffers PDR 26.11.14
+//if T[x]=0, drive the IO[x] line with a 0; if I[x]=1, be tri-state (PULLUP in ucf)
+module PS2BUF (output [1:0] O, inout [1:0] IO, input [1:0] T);
+  IOBUF buf0 (.I(0), .O(O[0]), .IO(IO[0]), .T(T[0]));
+  IOBUF buf1 (.I(0), .O(O[1]), .IO(IO[1]), .T(T[1]));    
+endmodule

+ 201 - 0
BlackBox/Po/Files/RISC5.Lola.txt

@@ -0,0 +1,201 @@
+MODULE RISC5 (IN clk, rst, stallX: BIT;  (*NW 31.10.2014*)
+  IN inbus, codebus: WORD;
+  OUT adr: [20] BIT;
+    rd, wr, ben: BIT;
+    outbus: WORD);
+  
+  CONST StartAdr = $3F800'18;
+
+  TYPE PROM := MODULE (IN adr: [11] BIT; OUT data: WORD; IN clk: BIT) ^;
+
+    Multiplier := MODULE (IN clk, run, u: BIT;
+      OUT stall: BIT;
+      IN x, y: WORD;
+      OUT z: [64] BIT) ^;
+
+    Divider := MODULE (IN clk, run: BIT;
+      OUT stall: BIT;
+      IN x, y: WORD;
+      OUT quot, rem: WORD) ^;
+
+    FPAdder := MODULE (IN clk, run, u, v: BIT; OUT stall: BIT;
+      IN x, y: WORD; OUT z: WORD) ^;
+
+    FPMultiplier := MODULE (IN clk, run: BIT; OUT  stall: BIT;
+      IN x, y: WORD; OUT z: WORD) ^;
+
+    FPDivider := MODULE (IN clk, run: BIT; OUT stall: BIT;
+      IN x, y: WORD; OUT z: WORD) ^;
+
+
+  REG PC: [18] BIT;
+    IRBuf: WORD;
+    N, Z, C, OV: BIT;
+    stall1, PMsel: BIT;
+    R: [16] WORD;
+    H: WORD;
+
+  VAR IR, pmout: WORD;
+    pcmux, nxpc: [18] BIT;
+    cond, S: BIT;
+    sa, sb, sc: BIT;
+
+    p, q, u, v, w: BIT;
+    op, ira, ira0, irb, irc: [4] BIT;
+    cc: [3] BIT;
+    imm: [16] BIT;
+    off: [20] BIT;
+    
+    regwr, stall, stallL, stallM, stallD, stallFA, stallFM, stallFD: BIT;
+    sc1, sc0: [2] BIT;  (*shift counts*)
+    
+    A, B, C0, C1, aluRes, regmux: WORD;
+    s1, s2, s3, t1, t2, t3: WORD;
+    quotient, remainder: WORD;
+    product: [64] BIT;
+    fsum, fprod, fquot: WORD;
+    
+    Mov, Lsl, Asr, Ror, And, Ann, Ior, Xor, Add, Sub, Mul, Div: BIT;
+    Fadd, Fsub, Fmul, Fdiv, Ldr, Str, Br: BIT;
+
+    PM: PROM;
+    mulUnit: Multiplier;
+    divUnit: Divider;
+    faddUnit: FPAdder;
+    fmulUnit: FPMultiplier;
+    fdivUnit: FPDivider;
+
+BEGIN
+  PM (pcmux[10:0], pmout, clk);
+  mulUnit (clk, Mul, ~u, stallM, B, C1, product);
+  divUnit (clk, Div, stallD, B, C1, quotient, remainder);
+  faddUnit (clk, Fadd|Fsub, u, v, stallFA, B, {Fsub^C0.31, C0[30:0]}, fsum);
+  fmulUnit (clk, Fmul, stallFM, B, C0, fprod);
+  fdivUnit (clk, Fdiv, stallFD, B, C0, fquot);
+
+  IR := PMsel -> pmout : IRBuf;
+  p := IR.31;  (*instruction fields*)
+  q := IR.30;
+  u := IR.29;
+  v := IR.28;
+  w := IR.16;
+  cc:= IR[26:24];
+  ira := IR[27:24];
+  irb := IR[23:20];
+  op := IR[19:16];
+  irc := IR[3:0];
+  imm := IR[15:0];
+  off := IR[19:0];
+
+  Mov := ~p & (op = 0);  (*instruction signals*)
+  Lsl := ~p & (op = 1);
+  Asr := ~p & (op = 2);
+  Ror := ~p & (op = 3);
+  And := ~p & (op = 4);
+  Ann := ~p & (op = 5);
+  Ior := ~p & (op = 6);
+  Xor := ~p & (op = 7);
+  Add := ~p & (op = 8);
+  Sub := ~p & (op = 9);
+  Mul := ~p & (op = 10);
+  Div := ~p & (op = 11);
+  Fadd := ~p & (op = 12);
+  Fsub := ~p & (op = 13);
+  Fmul := ~p & (op = 14);
+  Fdiv := ~p & (op = 15);
+
+  Ldr := p & ~q & ~u;
+  Str := p & ~q & u;
+  Br := p & q;
+
+  A := R[ira0];  (*main data path*)
+  B := R[irb];
+  C0 := R[irc];
+
+  (*ALU*)
+  ira0 := Br -> 15'4 : ira;
+  C1 := q -> {v!16, imm} : C0 ;
+  adr := stallL -> B[19:0] + off : {pcmux, 0'2};
+  rd := Ldr & ~stallX & ~stall1;
+  wr := Str & ~stallX & ~stall1;
+  ben := p & ~q & v & ~stallX & ~stall1; (*byte enable*)
+  outbus := A;
+
+  sc0 := C1[1:0];
+  sc1 := C1[3:2];
+  
+  (*right shifter*)
+  s1 := (sc0 = 3) -> {(w -> B[2:0] : {B.31 ! 3}), B[31:3]} :
+      (sc0 = 2) -> {(w -> B[1:0] : {B.31 ! 2}), B[31:2]} :
+      (sc0 = 1) -> {(w -> B.0 : B.31), B[31:1]} : B;
+  s2 := (sc1 = 3) -> {(w -> s1[11:0] : {B.31 ! 12}), s1[31:12]} :
+      (sc1 = 2) -> {(w -> s1[7:0] : {B.31 ! 8}), s1[31:8]} :
+      (sc1 = 1) -> {(w -> s1[3:0] : {B.31 ! 4}), s1[31:4]} : s1;
+  s3 := C1.4 -> {(w -> s2[15:0] : {s2.31 ! 16}), s2[31:16]} : s2;
+
+  (*left shifter*)
+  t1 := (sc0 = 3) -> {B[28:0], 0'3} :
+      (sc0 = 2) -> {B[29:0], 0'2} :
+      (sc0 = 1) -> {B[30:0], 0'1} : B;
+  t2 := (sc1 = 3) -> {t1[19:0], 0'12} :
+      (sc1 = 2) -> {t1[23:0], 0'8} :
+      (sc1 = 1) -> {t1[27:0], 0'4} : t1;
+  t3 := C1.4 -> {t2[15:0], 0'16} : t2;
+  
+  aluRes :=
+    Mov -> (q ->
+      (~u -> {v!16, imm} : {imm, 0'16}) :
+      (~u -> C0 : (~v -> H : {N, Z, C, OV, 0'20, $54'8}))):
+    Lsl -> t3 :
+    (Asr | Ror) -> s3 :
+    And -> B & C1 :
+    Ann -> B & ~C1 :
+    Ior -> B | C1 :
+    Xor -> B ^ C1 :
+    Add -> B + C1 + (u&C) :
+    Sub -> B - C1 - (u&C) :
+    Mul -> product[31:0] :
+    Div -> quotient :
+    (Fadd|Fsub) -> fsum :
+    Fmul -> fprod :
+    Fdiv -> fquot : 0;
+
+  regwr := ~p & ~stall | (Ldr & ~stallX & ~stall1) | (Br & cond & v);
+  regmux := Ldr -> inbus : (Br & v) -> {0'12, nxpc, 0'2} : aluRes;
+
+  (*control unit*)
+  S := N ^ OV;
+  nxpc := PC + 1;
+  cond := IR.27 ^ (
+      (cc = 0) & N  |  (*MI, PL*)
+      (cc = 1) & Z  |  (*EQ, NE*)
+      (cc = 2) & C  |  (*CS, CC*)
+      (cc = 3) & OV  |  (*VS, VC*)
+      (cc = 4) & (C|Z)  |  (*LS, HI*)
+      (cc = 5) & S  |  (*LT, GE*)
+      (cc = 6) & (S|Z) | (*LE, GT*)
+      (cc = 7));
+  pcmux := ~rst -> StartAdr :
+    stall -> PC :
+    (Br & cond & u) -> off[17:0] + nxpc :
+    (Br & cond & ~u) -> C0[19:2] : nxpc;
+
+  sa := aluRes.31;
+  sb := B.31;
+  sc := C1.31;
+  stall := stallL | stallM | stallD | stallFA | stallFM | stallFD | stallX;
+  stallL := (Ldr | Str) & ~stall1;
+  
+  PC := pcmux;
+  PMsel := ~rst | (pcmux[17:11] = $7F'7);
+  IRBuf := stall -> IRBuf : codebus;
+  stall1 := stallX -> stall1 : stallL;
+  R[ira0] := regwr -> regmux : A;
+  N := regwr -> regmux.31 : N;
+  Z := regwr -> (regmux = 0) : Z;
+  C := Add -> (~sb&sc&~sa) | (sb&sc&sa) | (sb&~sa) :
+    Sub -> (~sb&sc&~sa) | (sb&sc&sa) | (~sb&sa) : C;;
+  OV := Add -> (sa&~sb&~sc) | (~sa&sb&sc) :
+    Sub -> (sa&~sb&sc) | (~sa&sb&~sc) : OV;;
+  H := Mul -> product[63:32] : Div -> remainder : H
+END RISC5.

+ 201 - 0
BlackBox/Po/Files/RISC5Top.Lola.txt

@@ -0,0 +1,201 @@
+MODULE RISC5Top(   (*NW 2.11.2014*)
+  IN CLK50M: BIT;
+  IN btn: [4] BIT;
+  IN swi: BYTE;
+  IN RxD: BIT;
+  OUT TxD: BIT;
+  OUT leds: BYTE;
+  OUT SRce0, SRce1, SRwe, SRoe: BIT;  (*SRAM*)
+  OUT SRbe: [4] BIT;
+  OUT SRadr: [18] BIT;
+  OUT SRdat: WORD;
+  IN MISO: [2] BIT;   (*SPI - SD card & network*)
+  OUT SCLK, MOSI, SS: [2] BIT;
+  OUT NEN: BIT;   (*network enable*)
+  OUT hsync, vsync: BIT;   (*video control*)
+  OUT RGB: [3] BIT;
+  INOUT PS2C, PS2D: BIT;   (*keyboard*)
+  IN mouse: [7] BIT;
+(* INOUT mouse: [2] BIT; *)
+  INOUT gpio: BYTE);
+
+(* I/O addresses:
+  0  millisconds / --
+  1  switches / LEDs
+  2  RS232 data / data (start)
+  3  RS232 status / control
+  4  SPI data / data (start)
+  5  SPI status / control
+  6  PS2 keyboard data
+  7  mouse
+  8  general-purpose I/O data
+  9  general-purpose I/O tri-state control *)
+
+TYPE RISC5 := MODULE (
+    IN clk, rst, stallX: BIT;
+      inbus, codebus: WORD;
+    OUT adr: [20] BIT;
+      rd, wr, ben: BIT;
+      outbus: WORD) ^;
+
+  RS232R := MODULE (
+    IN clk, rst, done, RxD, fsel: BIT;
+    OUT rdy: BIT; data: BYTE) ^;
+
+  RS232T := MODULE (
+    IN clk, rst, start, fsel: BIT; data: BYTE;
+    OUT rdy, TxD: BIT) ^;
+
+  SPI := MODULE (
+    IN clk, rst, start, fast: BIT; dataTx: WORD;
+    OUT dataRx: WORD; rdy: BIT;
+    IN MISO: BIT; 
+    OUT MOSI, SCLK: BIT)  ^;
+
+  VID := MODULE (
+    IN clk, clk25, inv: BIT; viddata: WORD;
+    OUT req: BIT; vidadr: [18] BIT;
+      hsync, vsync: BIT; RGB: [3] BIT) ^;
+
+  MouseX := MODULE ( 
+    IN clk: BIT; in: [7] BIT;
+    OUT out: [28] BIT) ^;
+
+(* MouseP := MODULE ( 
+    IN clk, rst: BIT; INOUT io: [2] BIT;
+    OUT out: [28] BIT) ^; *)
+
+  PS2 = MODULE (
+    IN clk, rst, done: BIT;
+    OUT rdy, shift: BIT; data: BYTE;
+    IN PS2C, PS2D: BIT) ^;
+
+  IOBUF32 = MODULE (
+    IN I: WORD; OUT O: WORD; INOUT IO: WORD; IN T: BIT) ^;
+
+  IOBUF8 = MODULE (
+    IN I: BYTE; OUT O: BYTE; INOUT IO: BYTE; IN T: BYTE) ^;
+
+  IBUFG := MODULE (IN I: BIT; OUT O: BIT) ^;
+  BUFG := MODULE (IN I: BIT; OUT O: BIT) ^;
+  IOBUF := MODULE (IN I: BIT; OUT O: BIT; INOUT IO: BIT; IN T: BIT) ^;
+
+VAR clk, clk50: BIT;
+REG (clk50) clk25: BIT;
+REG rst: BIT;
+  bitrate: BIT;   (*RS-232*)
+  Lreg: BYTE;  (*LED*)
+  cnt0: [16] BIT;
+  cnt1: WORD;  (*milliseconds*)
+  spiCtrl: [4] BIT;
+  gpout, gpoc: BYTE;
+
+VAR riscx: RISC5;
+  receiver: RS232R;
+  transmitter: RS232T;
+  spi: SPI;  (*CD-ROM and net*)
+  vid: VID;
+  kbd: PS2;
+  Ms: MouseX;
+(* Ms: MouseP; *)
+  clkInBuf: IBUFG;
+  clk150buf: BUFG;
+  sramBuf: IOBUF32;
+  gpioBuf: IOBUF8;
+
+  dmy: BIT;
+  adr: [20] BIT;
+  iowadr: [4] BIT;  (*word adress*)
+  rd, wr, be, ioenb, dspreq: BIT;
+  be0, be1: BIT;
+  a0, a1, a2, a3: BIT;
+  inbus, inbus0, inbus1, outbus, outbus1: WORD;
+  inbusL, outbusB0, outbusB1, outbusB2, outbusB3: BYTE;
+  inbusH: [24] BIT;
+
+  dataTx, dataRx, dataKbd: BYTE;
+  rdyRx, doneRx, startTx, rdyTx, rdyKbd, doneKbd: BIT;
+  dataMs: [28] BIT;   (*mouse*)
+  limit: BIT;   (*of cnt0*)
+  spiRx: WORD;
+  spiStart, spiRdy, MOSI1, SCLK1: BIT;
+  vidadr: [18] BIT;
+  gpin: BYTE;
+
+BEGIN
+  riscx (clk, rst, dspreq, inbus, inbus1, adr, rd, wr, be, outbus);
+  receiver (clk, rst, doneRx, RxD, bitrate, rdyRx, dataRx);
+  transmitter (clk, rst, startTx, bitrate, dataTx, rdyTx, TxD);
+  spi (clk, rst, spiStart, spiCtrl.2, outbus, spiRx, spiRdy, MISO.0 & MISO.1, MOSI1, SCLK1); 
+  vid (clk, clk25, swi.7, inbus1, dspreq, vidadr, hsync, vsync, RGB);
+  kbd (clk, rst, doneKbd, rdyKbd, dmy, dataKbd, PS2C, PS2D);
+  Ms (clk, mouse, dataMs);
+(* Ms (clk, rst, mouse, dataMs); *)
+  sramBuf (outbus1, inbus1, SRdat, ~wr);
+  gpioBuf (gpout, gpin, gpio, ~gpoc);
+
+  iowadr := adr[5:2];
+  ioenb := (adr[19:6] = $3FFF'14);
+  inbus := ~ioenb -> inbus0 :
+    ((iowadr = 0) -> cnt1 :
+    (iowadr = 1) -> {0'20, btn, swi} :
+    (iowadr = 2) -> {0'24, dataRx} :
+    (iowadr = 3) -> {0'30, rdyTx, rdyRx} :
+    (iowadr = 4) -> spiRx :
+    (iowadr = 5) -> {0'31, spiRdy} :
+    (iowadr = 6) -> {0'3, rdyKbd, dataMs} :
+    (iowadr = 7) -> {0'24, dataKbd} :
+    (iowadr = 8) -> {0'24, gpin} :
+    (iowadr = 9) -> {0'24, gpoc} : 0'32);
+
+(*access to SRAM*)
+  a0 := ~adr[1] & ~adr[0];
+  a1 := ~adr[1] & adr[0];
+  a2 := adr[1] & ~adr[0];
+  a3 := adr[1] & adr[0];
+  be0 := be & adr.0;
+  be1 := be & ~adr.0;
+  SRce0 := be & adr[1];
+  SRce1 := be & ~adr[1];
+  SRwe := ~wr | clk25;
+  SRoe := wr;
+  SRbe := {be1, be0, be1, be0};
+  SRadr := dspreq -> vidadr : adr[19:2];
+
+  inbusL := (~be | a0) -> inbus1[7:0] :
+    a1 -> inbus1[15:8] :
+    a2 -> inbus1[23:16] : inbus1[31:24];
+  inbusH := ~be -> inbus1[31:8] : 0'24;
+  inbus0 := {inbusH, inbusL};
+
+  outbusB0 := outbus[7:0];
+  outbusB1 := be & a1 -> outbus[7:0] : outbus[15:8];
+  outbusB2 := be & a2 -> outbus[7:0] : outbus[23:16];
+  outbusB3 := be & a3 -> outbus[7:0] : outbus[31:24];
+  outbus1 := {outbusB3, outbusB2, outbusB1, outbusB0};
+
+  dataTx := outbus[7:0];
+  startTx := wr & ioenb & (iowadr = 2);
+  doneRx := rd & ioenb & (iowadr = 2);
+  spiStart := wr & ioenb & (iowadr = 4);
+  doneKbd := rd & ioenb & (iowadr = 7);
+  limit := (cnt0 = 24999);
+  leds := Lreg;
+  SS := ~spiCtrl[1:0];   (*active low slave select*)
+  MOSI := {MOSI1, MOSI1}; SCLK := {SCLK1, SCLK1};
+  NEN := spiCtrl[3];
+
+  rst := (cnt1[4:0] = 0'5) & limit -> ~btn[3] : rst;
+  Lreg := ~rst -> 0 : (wr & ioenb & (iowadr = 1)) -> outbus[7:0] : Lreg;
+  spiCtrl := ~rst -> 0 : (wr & ioenb & (iowadr = 5)) -> outbus[3:0] : spiCtrl;
+  bitrate := ~rst -> 0 : (wr & ioenb & (iowadr = 3)) -> outbus[0] : bitrate;
+  gpout := ~rst -> 0 : (wr & ioenb & (iowadr = 8)) -> outbus[7:0] : gpout;
+  gpoc := ~rst -> 0 : (wr & ioenb & (iowadr = 9)) -> outbus[7:0] : gpoc;
+  cnt0 := limit -> 0 : cnt0 + 1;
+  cnt1 := cnt1 + limit;
+
+(* The clocks *)
+  clkInBuf (CLK50M, clk50);
+  clk25 := ~clk25;  (* @ 50 MHz *)
+  clk150buf (clk25, clk);
+END RISC5Top.

+ 26 - 0
BlackBox/Po/Files/RS232R.Lola.txt

@@ -0,0 +1,26 @@
+MODULE RS232R (    (*NW 15.9.2014*)
+  IN clk, rst, done, RxD, fsel: BIT;
+  OUT rdy: BIT; data: BYTE);
+  REG run, stat: BIT;
+    tick: [12] BIT;
+    bitcnt: [4] BIT;
+    shreg: BYTE;
+  VAR endtick, midtick, endbit: BIT;
+    limit: [12] BIT;
+BEGIN
+  limit := fsel -> 217 : 1302;
+  endtick := tick = limit;
+  midtick := tick = {0'1, limit[11:1]};   (*limit/2*)
+  endbit := bitcnt = 8;
+  data := shreg;
+  rdy := stat;
+
+  run := ~RxD | ~(~rst | endtick & endbit) & run;
+  tick := (run & ~endtick) -> tick + 1 : 0;
+  bitcnt := (endtick & ~endbit) -> bitcnt + 1 :
+    (endtick & endbit) -> 0 : bitcnt;
+  shreg := midtick -> {RxD, shreg[7:1]} : shreg;
+  stat := (endtick & endbit) | ~(~rst | done) & stat
+END RS232R.
+
+  

+ 23 - 0
BlackBox/Po/Files/RS232T.Lola.txt

@@ -0,0 +1,23 @@
+MODULE RS232T (IN clk, rst: BIT;   (*NW 15.9.2014*)
+  IN start, fsel: BIT;  (*request to send a byte / freq select*)
+  IN data: BYTE; OUT rdy, TxD: BIT);
+  REG run: BIT;
+    tick: [12] BIT;
+    bitcnt: [4] BIT;
+    shreg: [9] BIT;
+  VAR endtick, endbit: BIT;
+    limit: [12] BIT;
+BEGIN limit := fsel -> 217 : 1302;
+  endtick := tick = limit;
+  endbit := bitcnt = 9;
+  rdy := ~run;
+  TxD := shreg.0;
+
+  run := (~rst | endtick & endbit) -> 0 : start -> 1 : run;
+  tick := (run & ~endtick) -> tick + 1 : 0;
+  bitcnt := (endtick & ~endbit) -> bitcnt + 1 :
+    (endtick & endbit) -> 0'4 : bitcnt;
+  shreg := ~rst -> 1 :
+    start -> {data, 0'1} :
+    endtick -> {1'1, shreg[8:1]} : shreg;
+END RS232T.

+ 25 - 0
BlackBox/Po/Files/SPI.Lola.txt

@@ -0,0 +1,25 @@
+MODULE SPI (
+  IN clk, rst, start, fast: BIT; dataTx: WORD;
+  OUT dataRx: WORD; rdy: BIT;
+  IN MISO: BIT;
+  OUT MOSI, SCLK: BIT);
+
+  REG rdyR: BIT;
+    shreg: WORD;
+    tick: [6] BIT;
+    bitcnt: [5] BIT;
+  VAR endbit, endtick: BIT;
+
+BEGIN endtick := fast -> (tick = 1) : (tick = 63);    (*25 MHz clock*)
+  endbit := fast -> (bitcnt = 31) : (bitcnt = 7);
+  rdy := rdyR;
+  dataRx := fast -> shreg : {0'24, shreg[7:0]};
+  MOSI := (~rst | rdyR) -> 1 : shreg.7;
+  SCLK := (~rst | rdyR) -> 1 : (fast -> tick.0 : tick.5);
+
+  tick := (~rst | rdyR | endtick) -> 0 : tick + 1;
+  rdyR := (~rst | endtick & endbit) | ~start & rdyR;
+  bitcnt := (~rst | start) -> 0 : (endtick & ~endbit) -> bitcnt + 1 : bitcnt;
+  shreg := ~rst -> $FFFFFFFF'32 : start -> dataTx :
+    endtick -> {shreg[30:24], MISO, shreg[22:16], shreg[31], shreg[14:8], shreg[23], shreg[6:0], (fast -> shreg[15] : MISO)} : shreg;
+END SPI.

+ 73 - 0
BlackBox/Po/Files/VID.Lola.txt

@@ -0,0 +1,73 @@
+MODULE VID (
+  IN clk, inv: BIT;
+    viddata: WORD;
+  OUT  req: BIT;  (*SRAM read request*)
+      vidadr: [18] BIT;
+    hsync, vsync: BIT;  (*to display*)
+    RGB: [3] BIT);
+
+  CONST Org := $37FC0; (* DFF00: adr of vcnt=1023 *)
+  TYPE DCMX3 = MODULE (IN CLKIN: BIT; OUT CLKFX: BIT) ^;
+  VAR hend, vend, vblank, xfer, vid, pclk: BIT;
+    dcmx3: DCMX3;
+  REG (pclk) hcnt: [11] BIT;
+      vcnt: [10] BIT;
+    hblank: BIT;
+    pixbuf, vidbuf: WORD;
+  REG req1: BIT;
+    hword: [5] BIT;  (*from hcnt, but latched in the clk domain*)
+
+BEGIN dcmx3 (clk, pclk);  (* pixel clock generation *)
+  hend := (hcnt = 1343); vend := (vcnt = 801);
+  vblank := (vcnt.8 & vcnt.9);   (*vcnt >= 768*)
+  hsync := ~((hcnt >= 1086) & (hcnt < 1190));   (*-ve polarity*)
+  vsync := (vcnt >= 771) & (vcnt < 776);   (*+ve polarity*)
+  xfer := (hcnt[4:0] = 6'5);   (*data delay > hcnt cycle + req cycle*)
+  vid := (pixbuf.0 ^ inv) & ~hblank & ~ vblank;
+  RGB := {vid, vid, vid};
+  vidadr := Org + {0'3, ~vcnt, hword};
+(*on pclk:*)  
+  hcnt := hend -> 0 : hcnt + 1;
+  vcnt := hend -> (vend -> 0 : vcnt + 1) : vcnt;
+  hblank := xfer -> hcnt.10 : hblank;  (*hcnt >= 1024*)
+  pixbuf := xfer -> vidbuf : {0'1, pixbuf[31:1]};
+(*on clk:*)
+  hword := hcnt[9:5];
+  req := req1; req1 := ~vblank & ~hcnt.10 & (hcnt.5 ^ hword.0);
+  vidbuf := req -> viddata : vidbuf
+END VID.
+
+MODULE VID (
+  IN clk, inv: BIT;
+    viddata: WORD;
+  OUT  req: BIT;   (*SRAM read request*)
+    vidadr: [18] BIT;
+    hsync, vsync: BIT;
+    RGB: [3] BIT);
+
+  CONST Org := $DFF00;
+  REG hcnt, vcnt: [10] BIT;
+    buffer: WORD;  (*from hcnt, but latched in the clk domain*)
+    hblank1: BIT;
+  VAR hend, vend, hblank, vblank, pixel, vid: BIT;
+    
+BEGIN (*25MHz clock; 2 pixels per cycle*)
+  hend := (hcnt = 591);
+  vend := (vcnt = 791);
+  hblank := hcnt.9;  (*hcnt = 512*)
+  vblank := vcnt.8 & vcnt.9;  (*vcnt >= 768*)
+  hsync := (hcnt >= 537) & (hcnt < 553);
+  vsync := ~((vcnt >= 772) & (vcnt < 776));
+
+  vidadr := {0'3, ~vcnt, hcnt[8:4]} + $37FC0'18;
+  req := ~vblank & ~hcnt.9 & (hcnt[3:0] = 0'4);
+  pixel := clk -> buffer.0 : buffer.1;
+  vid := (pixel ^ inv) & ~hblank1 & ~vblank;
+  RGB := {vid, vid, vid};
+
+  hcnt := hend -> 0 : hcnt+1;
+  vcnt := hend -> (vend -> 0 : vcnt+1) : vcnt;
+  hblank1 := hblank;
+  buffer := req -> viddata : {0'2, buffer[31:2]}
+END VID.
+

BIN
BlackBox/Po/Mod/EBNF.odc


BIN
BlackBox/Po/Mod/LSB3.odc


BIN
BlackBox/Po/Mod/LSC3.odc


BIN
BlackBox/Po/Mod/LSP3.odc


BIN
BlackBox/Po/Mod/LSS3.odc


BIN
BlackBox/Po/Mod/LSV3.odc