-- DecoderImpl.mesa
-- a program to run within Chipmonk

-- last modified by E. McCreight,  November 20, 1981  11:26 AM
-- written by E. McCreight, August 7, 1981  3:52 PM

DIRECTORY
  ChipUserInt,
  ppdefs,
  RomMakerDefs;

DecoderImpl: PROGRAM
  IMPORTS ChipUserInt, ppdefs, RomMakerDefs
  EXPORTS RomMakerDefs =
  BEGIN OPEN ChipUserInt, ppdefs, RomMakerDefs;


  DecodePatternPtr: TYPE = LONG POINTER TO DecodePattern ←
    NIL;
  DecodePattern: TYPE = RECORD[
    pattern: SEQUENCE max: INTEGER OF INTEGER];


  BuildDecoder: PUBLIC PROCEDURE[] =
    BEGIN
    decoder: DCellPr;

    decoderTopLeftCorner, decoderLeftMid,
      decoderBottomLeftCorner: Cell;
    decoderLeft, decoderTop, decoderBottom, decoderRight: DCell;
    decoderTopMid, decoderBottomMid: Cell;
    decoderMidV, decoderMidH, decoderMidVH: Cell;
    decoderTopRightCorner, decoderRightMid,
      decoderBottomRightCorner: Cell;

    decodeCell: Cell;  -- sample for measurements


    FindDecoderCells: PROCEDURE [cellFamily: STRING] =
      BEGIN
      decoder ← FindDCellPr[cellFamily: cellFamily, required: TRUE,
        memberPrefix: "Decode"L];
      decodeCell ← decoder[TRUE][FALSE];

      -- MidV is a vertical column of cells, MidH is a
      -- horizontal row of cells, and MidVH is the cell that
      -- happens at their intersections.

      decoderMidH ← FindCell[
        cellFamily: cellFamily, member: "MidH"L, hCompat: decodeCell];
      decoderMidV ← FindCell[
        cellFamily: cellFamily, member: "MidV"L, vCompat: decodeCell];
      decoderMidVH ← FindCell[
        cellFamily: cellFamily, member: "MidVH"L, hCompat: decoderMidV,
        vCompat: decoderMidH,
        required: decoderMidV#NIL AND decoderMidH#NIL];

      decoderLeft ← FindDCell[
        cellFamily: cellFamily, memberPrefix: "Left"L, vCompat: decodeCell];
      decoderLeftMid ← FindCell[
        cellFamily: cellFamily, member: "LeftMid"L, vCompat: decoderMidH,
        required: decoderMidH#NIL];
      decoderTopLeftCorner ← FindCell[
        cellFamily: cellFamily, member: "TopLeftCorner"L];
      decoderBottomLeftCorner ← FindCell[
        cellFamily: cellFamily, member: "BottomLeftCorner"L];

      decoderTop ← FindDCell[
        cellFamily: cellFamily, memberPrefix: "Top"L, hCompat: decodeCell];
      decoderTopMid ← FindCell[
        cellFamily: cellFamily, member: "TopMid"L, hCompat: decoderMidV,
        required: decoderMidV#NIL];
      decoderBottom ← FindDCell[
        cellFamily: cellFamily, memberPrefix: "Bottom"L, hCompat: decodeCell];
      decoderBottomMid ← FindCell[
        cellFamily: cellFamily, member: "BottomMid"L, hCompat: decoderMidV,
        required: decoderMidV#NIL];

      decoderRight ← FindDCell[
        cellFamily: cellFamily, memberPrefix: "Right"L,
        vCompat: decodeCell];
      decoderTopRightCorner ← FindCell[
        cellFamily: cellFamily, member: "TopRightCorner"L];
      decoderRightMid ← FindCell[
        cellFamily: cellFamily, member: "RightMid"L,
        vCompat: decoderMidH,
        required: decoderMidH#NIL];
      decoderBottomRightCorner ← FindCell[
        cellFamily: cellFamily, member: "BottomRightCorner"L];

      END; -- of FindDecoderCells

    bodyHeight, decoderRightX: locNum;
    decoderWidth, decoderHeight: INTEGER;
    midHGap, midVGap: locNum ← 0;
    pat: DecodePatternPtr;
    cellFamily, decoderName: STRING ← NIL;

      BEGIN ENABLE Punt => GOTO ExitDecoder;

      cellFamily ← RequestString["Cell family:"L];
      FindDecoderCells[cellFamily];

      decoderWidth ← RequestInteger["Decoder width in bits?"L];
      decoderHeight ← RequestInteger["Decoder height in cells?"L];
      pat ← uz.NEW[DecodePattern[decoderHeight]];
      IF HeSaysYes["Is decode pattern a 'FOR' loop?"L] THEN
        BEGIN
        start: INTEGER ← RequestInteger["Starting value?"L,
          "(at top)"L];
        step: INTEGER ← RequestInteger["Interval between values?"L,
          "(downward)"L];
        FOR i: INTEGER IN [0..decoderHeight) DO
          pat.pattern[i] ← start;
          start ← start+step;
          ENDLOOP;
        END
      ELSE
        BEGIN
        pat.pattern[0] ← RequestInteger["First decode value?"L,
          "(at top)"L];
        FOR i: INTEGER IN [1..decoderHeight) DO
          pat.pattern[i] ← RequestInteger["Next decode value?"L,
          "(downward)"L];
          ENDLOOP;
        END;

      IF decoderMidH#NIL THEN
        midHGap ← CellSize[decodeCell].y*
          RequestInteger["Cells vertically per mid cell row?"L];
      IF decoderMidV#NIL THEN
        midVGap ← CellSize[decodeCell].x*
          RequestInteger["Cells horizontally per mid cell column?"L];

      bodyHeight ← BlockSize[cell: decodeCell, rep: [x: 1, y: decoderHeight],
        midCell: decoderMidH, midGap: [midVGap, midHGap]].y;
      decoderRightX ← BlockSize[cell: decodeCell, rep: [x: decoderWidth, y: 1],
        midCell: decoderMidV, midGap: [midVGap, midHGap]].x;

      Repeat[
        cell: decoderLeft[FALSE], p: [0,0], corner: topRight,
        dir: down, rep: decoderHeight,
        midCell: decoderLeftMid, midGap: midHGap,
        altCell: decoderLeft[TRUE], altMod: 2];
      Repeat[
        cell: decoderTopLeftCorner, p: [0,0], corner: bottomRight];
      Repeat[
        cell: decoderBottomLeftCorner, p: [0, bodyHeight], corner: topRight];

      Repeat[
        cell: decoderTop[FALSE], p: [0,0], corner: bottomLeft,
        rep: decoderWidth,
        midCell: decoderTopMid, midGap: midVGap,
        altCell: decoderTop[TRUE], altMod: 2];
      Repeat[
        cell: decoderBottom[FALSE], p: [0, bodyHeight], corner: topLeft,
        dir: right, rep: decoderWidth,
        midCell: decoderBottomMid, midGap: midVGap,
        altCell: decoderBottom[TRUE], altMod: 2];

      Repeat[cell: decoderTopRightCorner,
        p: [decoderRightX, 0], corner: bottomLeft];
      Repeat[
        cell: decoderRight[FALSE], p: [decoderRightX, 0], dir: down, rep: decoderHeight,
        midCell: decoderRightMid, midGap: midHGap,
        altCell: decoderRight[TRUE], altMod: 2];
      Repeat[cell: decoderBottomRightCorner, p: [decoderRightX, bodyHeight]];

      MakeDecoderBlock[cells: decoder, p: [0, 0], rep: [decoderWidth, decoderHeight],
        midCellSize: [x: CellSize[decoderMidV].x, y: CellSize[decoderMidH].y],
        midGap: [midVGap, midHGap],
        invertAddress: HeSaysYes["Shall I invert address inputs?L"],
        pat: pat];

      MakeMidGrid[p: [0,0], cell: decodeCell, rep: [decoderWidth, decoderHeight],
        midVCell: decoderMidV, midHCell: decoderMidH, midVHCell: decoderMidVH,
        midGap: [midVGap, midHGap]];

      decoderName ← RequestString["Name of finished cell:"L];
      IF decoderName#NIL AND decoderName.length>0 THEN
        BEGIN
        DrawCell[MakeNewCell[decoderName, lpp].ob];
        decoderName ← NIL; -- gave list and string body to cell
        END
      ELSE AddToMasterList[lpp];
      lpp ← NIL; -- gave away the list

      EXITS ExitDecoder => NULL;
      END;

    flushDel[lpp];
    IF pat#NIL THEN uz.FREE[@pat];
    IF cellFamily # NIL THEN FreeString[cellFamily];
    IF decoderName # NIL THEN FreeString[decoderName];
    anyChanges ← sinceIOchanges ← TRUE;
    END; -- of BuildDecoder

  MakeDecoderBlock: PROCEDURE[cells: DCellPr, p, rep: Point,
    pat: DecodePatternPtr,
    midCellSize, midGap: Point ← [0,0],
    invertAddress: BOOLEAN ← FALSE] =
    BEGIN -- high-order bit on the left
    FOR iy: INTEGER IN [0..rep.y) DO
      loc: INTEGER ← pat.pattern[iy];
      FOR ix: INTEGER DECREASING IN
        [0..rep.x) DO
        PlaceCell[p, cells[((loc MOD 2)#0)#invertAddress]
          [((loc MOD 2)=0)#invertAddress],
          [ix, iy], midCellSize, midGap];
        loc ← loc/2;
        ENDLOOP;
      ENDLOOP;
    END;

  END. -- of DecoderImpl