Palasm.mesa
Last Edited by: Gasbarro, August 13, 1985 4:02:38 pm PDT
REMEMBER TO CHANGE HERALD IN ConvertPALToMB
DIRECTORY
Basics,
Buttons,
Commander,
Containers,
FS,
IO,
Rope,
Rules,
VFonts,
ViewerClasses,
ViewerIO,
ViewerOps,
ViewerTools;
Palasm: CEDAR PROGRAM
IMPORTS Basics, Buttons, Commander, Containers, FS, IO, Rope, Rules, VFonts, ViewerIO, ViewerOps, ViewerTools
= BEGIN
PALType: TYPE = { PTUndefined,
PT10H8, PT10L8, PT12H6, PT12L6, PT14H4, PT14L4, PT16H2, PT16L2,
PT16C1, PT16L8, PT16R8, PT16R6, PT16R4, PT16X4, PT16A4};
Token: TYPE = {
or, and, eq, neqXor, not, left, right, gets, getsNext,
if, then, true, false,
paldef, pindefs, begin, end,
carry0, carry1, carry2, carry3,
iopin, unknown, space,
endOfLine, endOfFile};
PinArray: TYPE = ARRAY [1..20] OF pinDesc;
pinDesc: TYPE = RECORD[
type: pinType ← Input,
name: Rope.ROPE,
nameinverted: BOOLEANFALSE,
outinverted: BOOLEANTRUE,
prodGrp: NAT[0..7] ← 0,
nofProds: NAT[2..8] ← 8,
in: NAT[0..31] ← 0,
used: BOOLEANFALSE ];
pinType: TYPE = {
Clock, FixedDisable, Power, Ground,
Input, BuiltIn,
Output, BuiltInClockedOut,
ClockedInOut,
EnabledOut, EnabledInOut};
FuseArray: TYPE = ARRAY [0..7] OF ProdGroup;
ProdGroup: TYPE = ARRAY [0..7] OF Product;
Product: TYPE = PACKED ARRAY [0..31] OF BOOLEANALL[FALSE]; -- FALSE => not blown
ptype: PALType ← PTUndefined;
PinArrayRef: TYPE = REF PinArray;
pa: PinArrayRef;
vfa, fa: FuseArray;
currentToken, lastToken: Token ← space;
currentPin,lastPin: NAT;
nextChar, nextTokenChar: CHARACTERIO.SP;
inStream, listStream, mbStream: IO.STREAMNIL;
pinsDefined: BOOLEANFALSE;
errorCalled: BOOLEANFALSE;
palString: Rope.ROPE;
currentStr: Rope.ROPE;
lastStr: Rope.ROPE;
viewerout: IO.STREAM;
rootFileName: Rope.ROPE;
entryHeight: CARDINAL = 15; -- how tall to make each line of items
entryVSpace: CARDINAL = 8;  -- vertical leading space between lines
entryHSpace: CARDINAL = 10;  -- horizontal space between items in a line
Handle: TYPE = REF PALToolRec;
PALToolRec: TYPE = RECORD [ -- the data for a particular tool instance
outer: Containers.Container ← NIL, -- handle for the enclosing container
height: CARDINAL ← 0,  -- height measured from the top of the container
pal: PALViewer];  -- the PAL viewer's state
PALViewer: TYPE = RECORD [
input: ViewerClasses.Viewer ← NIL,
output: IO.STREAM]; 
MakePALTool: Commander.CommandProc = BEGIN
my: Handle ← NEW[PALToolRec];
my.outer ← Containers.Create[[-- construct the outer container  
name: "PAL Tool",
iconic: TRUE,
column: left,
scrollable: FALSE ]];
MakePAL[my];
ViewerOps.SetOpenHeight[my.outer, my.height];
ViewerOps.PaintViewer[my.outer, all];
END;
MakePAL: PROC [handle: Handle] = BEGIN
promptButton, computeButton: Buttons.Button;
rule: Rules.Rule;
handle.height ← handle.height + entryVSpace;
promptButton ← Buttons.Create[
info: [
name: "Filename:",
wy: handle.height,
wh: entryHeight,
parent: handle.outer,
border: FALSE ],
proc: Prompt,
clientData: handle];
handle.pal.input ← ViewerTools.MakeNewTextViewer[ [
parent: handle.outer,
wx: promptButton.wx + promptButton.ww + entryHSpace,
wy: handle.height+2,
ww: 40*VFonts.CharWidth['0],
wh: entryHeight,
scrollable: FALSE,
border: FALSE]];
computeButton ← Buttons.Create[
info: [
name: "Convert PAL To MB",
wx: handle.pal.input.wx + handle.pal.input.ww + entryHSpace,
wy: handle.height,
ww:,
wh: entryHeight,
parent: handle.outer,
border: TRUE],
clientData: handle,
proc: ConvertPALToMB];
handle.height ← handle.height + entryHeight + entryVSpace;
rule ← Rules.Create[ [ -- create a bar to separate sections 1 and 2
parent: handle.outer,
wy: handle.height,
ww: handle.outer.cw,
wh: 2]];
Containers.ChildXBound[handle.outer, rule]; -- constrain rule to be width of parent
[ , viewerout] ← ViewerIO.CreateViewerStreams[name:"Fred", viewer:ViewerOps.CreateViewer[flavor: $TypeScript, info:[parent: handle.outer,
wy: handle.height+2,
ww: 100*VFonts.CharWidth['0],
wh: 56 * entryHeight,
scrollable: TRUE,
border: FALSE]]];
handle.height ← handle.height + 10 * entryHeight;
END;
Prompt: Buttons.ButtonProc = BEGIN
force the selection into the user input field
handle: Handle ← NARROW[clientData]; -- get our data
ViewerTools.SetSelection[handle.pal.input];  -- force the selection
END;
NextToken: PROCEDURE RETURNS[Token] =
BEGIN -- Condenses strings - requires one char memory
tstr: Rope.ROPE ← lastStr; lastStr ← currentStr; currentStr ← tstr;
lastToken ← currentToken;
lastPin ← currentPin;
DO
currentToken ← IdentifyTokenChar[nextTokenChar];
currentStr ← NIL;
SELECT currentToken FROM
space => {nextTokenChar ← GetChar[]; LOOP};
unknown => DO
currentStr ← Rope.Concat[currentStr, Rope.FromChar[nextTokenChar]];
nextTokenChar ← GetChar[];
IF IdentifyTokenChar[nextTokenChar] # unknown THEN
BEGIN
currentToken ← IdentifyTokenStr[currentStr];
RETURN[currentToken]; END;
ENDLOOP;
ENDCASE => EXIT;
ENDLOOP;
nextTokenChar ← GetChar[];
RETURN[currentToken];
END;
IdentifyTokenChar: PROCEDURE [char: CHARACTER] RETURNS[name: Token] =
BEGIN
SELECT char FROM
'+ =>  name ← or;
'* =>  name ← and;
'= =>  name ← eq;    -- equality test
'# =>  name ← neqXor;   -- not eq same as xor
'/ =>  name ← not;
'[,'( => name ← left;
'],') => name ← right;
'{ =>  name ← begin;
'} =>  name ← end;
'← =>  name ← gets;
'^ =>  name ← getsNext;
'; =>  name ← endOfLine;
IO.NUL => name ← endOfFile;
IO.SP,': => name ← space;   -- colon same as space
ENDCASE=> name ← unknown;
END;
IdentifyTokenStr: PROCEDURE
[ str: Rope.ROPE ] RETURNS[ name: Token ] =
BEGIN
i: NAT;
IF Rope.Equal[str, "IF", FALSE] THEN RETURN[if];
IF Rope.Equal[str, "THEN", FALSE] THEN RETURN[then];
IF Rope.Equal[str, "XOR", FALSE] THEN RETURN[neqXor];
IF Rope.Equal[str, "TRUE", FALSE] THEN RETURN[true];
IF Rope.Equal[str, "FALSE", FALSE] THEN RETURN[false];
IF Rope.Equal[str, "CARRY0", FALSE] THEN RETURN[carry0];
IF Rope.Equal[str, "CARRY1", FALSE] THEN RETURN[carry1];
IF Rope.Equal[str, "CARRY2", FALSE] THEN RETURN[carry2];
IF Rope.Equal[str, "CARRY3", FALSE] THEN RETURN[carry3];
IF Rope.Equal[str, "PinDefs", FALSE] THEN RETURN[pindefs];
IF Rope.Equal[str, "PALType", FALSE] THEN RETURN[paldef];
IF Rope.Equal[str, "BEGIN", FALSE] THEN RETURN[begin];
IF Rope.Equal[str, "END", FALSE] THEN RETURN[end];
IF pinsDefined THEN FOR i IN [1..20] DO
IF NOT Rope.Equal[str, pa[i].name, FALSE] THEN LOOP;
currentPin ← i; RETURN[iopin]; ENDLOOP;
RETURN[unknown];
END;
FindToken: PROCEDURE[token: Token] RETURNS[success: BOOLEAN] =
BEGIN
DO
IF currentToken = token THEN RETURN[TRUE];
IF currentToken = endOfFile THEN RETURN[FALSE];
[] ← NextToken[];
ENDLOOP;
END;
GetChar: PROCEDURE RETURNS[char: CHARACTER]=
BEGIN -- Condenses spaces - requires one char memory
BasicGetChar: PROCEDURE RETURNS[ CHARACTER ]=
BEGIN -- Removes ^z's, echos, < SP => SP
ptrchar, rtnchar: CHARACTER;
IF IO.EndOf[inStream] THEN RETURN[IO.NUL];
ptrchar ← rtnchar ← IO.GetChar[inStream];
SELECT rtnchar FROM
IO.LF, IO.CR, ',, IO.SP, IO.TAB => rtnchar ← IO.SP;
< IO.SP => BEGIN -- control z caught here
ptrchar ← IO.CR;
rtnchar ← IO.SP;
WHILE NOT IO.EndOf[inStream]
DO IF IO.GetChar[inStream]=IO.CR THEN EXIT ENDLOOP;
END;
ENDCASE;
PutF[v1: IO.char[ptrchar]];
RETURN[rtnchar];
END;
GetChar body
char ← nextChar;
nextChar ← BasicGetChar[];
IF char = IO.SP THEN WHILE nextChar = IO.SP DO
nextChar ← BasicGetChar[]; ENDLOOP;
END;
ReadEquations: PROCEDURE RETURNS[success: BOOLEAN] =
BEGIN
IF NOT FindToken[begin] THEN RETURN[FALSE];
DO
[] ← NextToken[];
ReadEquation[];
SELECT currentToken FROM end, endOfFile =>
RETURN[NOT errorCalled]; ENDCASE;
ENDLOOP;
END;
Error: PROCEDURE[str: Rope.ROPE] =
BEGIN
errorCalled ← TRUE;
PutF["\n<<%g>>\n", IO.rope[str]];
DO
SELECT currentToken FROM
endOfLine, endOfFile, end => RETURN;
ENDCASE => {[] ← NextToken[]; LOOP};
ENDLOOP;
END;
ReadEquation: PROCEDURE =
BEGIN
conditional: BOOLEANFALSE;
xorfound: BOOLEANFALSE;
condProd: Product ← ALL[TRUE];
pin: NAT [1..20];
p,pmax,pg: NAT;
Conditional Enable
DO
SELECT currentToken FROM
end, endOfFile, endOfLine => RETURN;
if => BEGIN
[] ← NextToken[];
IF conditional THEN {Error["Two 'IFs'"]; RETURN};
conditional ← TRUE;
condProd ← ReadProduct[condProd];
IF currentToken = then THEN [] ← NextToken[] ELSE PutF["<<THEN>>"];
EXIT; END;
not, iopin => EXIT;
ENDCASE => {Error["Bad 1st term"]; RETURN};
ENDLOOP;
Output pin check
IF currentToken = not THEN []←NextToken[];
pin ← currentPin;
IF currentToken # iopin OR pa[pin].type < Output THEN
{Error["Bad output pin specification"]; RETURN};
IF pa[pin].outinverted #
(pa[pin].nameinverted # (lastToken = not)) THEN
{Error["Bad output pin polarity"]; RETURN};
IF conditional AND pa[pin].type < EnabledOut THEN
{Error["Output is not 3-State"]; RETURN};
IF pa[pin].used THEN
{Error["Output already used"]; RETURN};
pa[pin].used ← TRUE;
pg ← pa[pin].prodGrp;
p ← 0;
IF pa[pin].type >= EnabledOut THEN
{fa[pg][0] ← condProd; p ← 1};
pmax ← pa[pin].nofProds-1;
Check assignment symbol
[]← NextToken[];
SELECT currentToken FROM
gets => IF pa[pin].type
IN[BuiltInClockedOut..ClockedInOut]
THEN PutF["<<^>>"];
getsNext => IF pa[pin].type
NOT IN[BuiltInClockedOut..ClockedInOut]
THEN PutF["<<←>>"];
eq => IF pa[pin].type IN[BuiltInClockedOut..ClockedInOut]
THEN PutF["<<^>>"]
ELSE PutF["<<←>>"];
ENDCASE => {Error["Strange token"]; RETURN};
Get Sum
[]← NextToken[];
DO
SELECT currentToken FROM
end, endOfLine, endOfFile => RETURN;
left, not, iopin => BEGIN
IF p > pmax THEN { Error["Product index too large"]; RETURN };
fa[pg][p] ← ReadProduct[ALL[TRUE]];
SELECT currentToken FROM
or => IF pa[pin].type = BuiltInClockedOut AND p >= 3 AND NOT xorfound THEN
{ Error["Missing XOR"]; RETURN };
neqXor => BEGIN
IF pa[pin].type # BuiltInClockedOut THEN
{ Error["No Xor's builtin"]; RETURN };
IF p >= 4 THEN
{ Error["Product index too large"]; RETURN };
xorfound ← TRUE;
p ← 3; END;
end, endOfLine, endOfFile => RETURN;
ENDCASE => { Error["Strange delimiter token"]; RETURN };
[]←NextToken[];
p ← p + 1;
END;
IN [carry0..carry3] => BEGIN
IF ptype # PT16A4 OR NOT (pa[pin].type = BuiltInClockedOut) THEN
{ Error["No builtin carrys"]; RETURN };
IF SELECT currentToken FROM
carry0 => pin # 17, carry1 => pin # 16,
carry2 => pin # 15, carry3 => pin # 14,
ENDCASE => TRUE THEN { Error["Wrong carry"]; RETURN };
IF p < 4 THEN
{ Error["Missing XOR"]; RETURN };
[] ← NextToken[];
IF currentToken # endOfLine OR currentToken # end THEN
{ Error["Missing ;"]; RETURN }; END;
ENDCASE => { Error["Illegal term"]; RETURN };
ENDLOOP;
END;
ReadProduct: PROCEDURE[prod: Product] RETURNS[Product] =
BEGIN
DO
IF currentToken = not THEN []←NextToken[];
SELECT currentToken FROM
true => { prod ← ALL[TRUE]; [] ← NextToken[] };
false => { prod ← ALL[FALSE]; [] ← NextToken[] };
left => prod ← ReadBuiltin[prod];
iopin => prod ← ReadTerm[prod];
ENDCASE => { Error["Illegal term"]; RETURN[prod] };
SELECT currentToken FROM
then, end, endOfLine, endOfFile, neqXor, or => EXIT;
and => []←NextToken[];
left, not, iopin => LOOP;
ENDCASE => { Error["Illegal term"]; RETURN[prod] };
ENDLOOP;
RETURN[prod];
END;
ReadTerm: PROCEDURE[prod: Product] RETURNS[Product] =
BEGIN
same: BOOLEAN;
SELECT pa[currentPin].type FROM
Input, ClockedInOut, EnabledInOut => NULL;
ENDCASE => { Error["Not an input"]; RETURN[prod] };
same ← pa[currentPin].nameinverted = (lastToken = not);
prod[pa[currentPin].in] ← NOT same;
prod[pa[currentPin].in+1] ← same;
[] ← NextToken[];
RETURN[prod];
END;
ReadBuiltin: PROCEDURE[prod: Product] RETURNS[Product] =
BEGIN
ipin, opin: NAT ← 0;
iinv, oinv, flip: BOOLEANFALSE;
ftoken: Token ← unknown;
DO
IF NextToken[] = not THEN []←NextToken[];
SELECT currentToken FROM
iopin => BEGIN
SELECT pa[currentPin].type FROM
BuiltIn => BEGIN
IF ftoken = unknown AND opin # 0 THEN {Error["Missing function"]; RETURN[prod]};
IF ipin # 0 THEN {Error["Not builtin output"]; RETURN[prod]};
ipin ← currentPin;
iinv ← (lastToken = not) # pa[ipin].nameinverted;
END;
BuiltInClockedOut => BEGIN
IF ftoken = unknown AND ipin # 0 THEN {Error["Missing function"]; RETURN[prod]};
IF opin # 0 THEN {Error["Not builtin input"]; RETURN[prod]};
opin ← currentPin;
oinv ← (lastToken = not) # pa[opin].nameinverted;
END;
ENDCASE => {Error["Not builtin i/o pin"]; RETURN[prod]};
END;
true, false => BEGIN
IF (opin # 0) OR (ipin # 0) OR ftoken # unknown OR lastToken # left OR NextToken[] # right THEN { Error["Bad fixed builtin"]; RETURN[prod] };
IF lastToken = true THEN { []←NextToken[]; RETURN[ALL[TRUE]] }
ELSE { []←NextToken[]; RETURN[ALL[FALSE]] }; END;
or, and, eq, neqXor => BEGIN
IF lastToken = not THEN { Error["Negation of function"]; RETURN[prod] };
IF ftoken # unknown THEN { Error["Two functions"]; RETURN[prod] };
IF (opin = 0) = (ipin = 0) THEN { Error["Function out of place"]; RETURN[prod] };
ftoken ← currentToken; END;
right => BEGIN
IF lastToken = not THEN { Error["Bad negation"]; RETURN[prod] };
IF (opin = 0) # (ipin = 0) THEN
IF ftoken # unknown THEN { Error["Missing argument"]; RETURN[prod] };
[] ← NextToken[];
EXIT; END;
ENDCASE => { Error["Strange builtin"]; RETURN[prod] };
ENDLOOP;
IF (ftoken # unknown) AND (ipin + opin # 21) THEN {Error["Builtin's do not match"]; RETURN[prod]};
flip ← (ftoken = and) OR (ftoken = eq);
iinv ← iinv # flip;
oinv ← oinv # flip;
SELECT ftoken FROM
and, or => BEGIN
prod[pa[ipin].in +0] ← ( iinv OR NOT oinv) # flip;
prod[pa[ipin].in +1] ← (NOT iinv OR NOT oinv) # flip;
prod[pa[ipin].in +2] ← ( iinv OR oinv) # flip;
prod[pa[ipin].in +3] ← (NOT iinv OR oinv) # flip;
END;
eq, neqXor => BEGIN
prod[pa[ipin].in +0] ← prod[pa[ipin].in +3]
← (iinv = oinv) # flip;
prod[pa[ipin].in +1] ← prod[pa[ipin].in +2]
← (iinv # oinv) # flip;
END;
unknown => -- one argument
BEGIN
IF ipin # 0 THEN BEGIN
prod[pa[ipin].in+0]←prod[pa[ipin].in+2] ← iinv;
prod[pa[ipin].in+1]←prod[pa[ipin].in+3] ←NOT iinv;
END;
IF opin # 0 THEN BEGIN
prod[pa[opin].in-2]←prod[pa[opin].in-1] ←NOT oinv;
prod[pa[opin].in+0]←prod[pa[opin].in+1] ← oinv;
END;
END;
ENDCASE;
RETURN[prod];
END;
ReadPALType: PROCEDURE RETURNS[success: BOOLEAN] =
BEGIN
IF NOT FindToken[paldef] THEN RETURN[FALSE];
IF NextToken[] # unknown THEN RETURN[FALSE];
ptype ← PTUndefined;
IF Rope.Equal[currentStr, "10H8", FALSE] THEN ptype ← PT10H8;
IF Rope.Equal[currentStr, "10L8", FALSE] THEN ptype ← PT10L8;
IF Rope.Equal[currentStr, "12H6", FALSE] THEN ptype ← PT12H6;
IF Rope.Equal[currentStr, "12L6", FALSE] THEN ptype ← PT12L6;
IF Rope.Equal[currentStr, "14H4", FALSE] THEN ptype ← PT14H4;
IF Rope.Equal[currentStr, "14L4", FALSE] THEN ptype ← PT14L4;
IF Rope.Equal[currentStr, "16H2", FALSE] THEN ptype ← PT16H2;
IF Rope.Equal[currentStr, "16L2", FALSE] THEN ptype ← PT16L2;
IF Rope.Equal[currentStr, "16C1", FALSE] THEN ptype ← PT16C1;
IF Rope.Equal[currentStr, "16L8", FALSE] THEN ptype ← PT16L8;
IF Rope.Equal[currentStr, "16R8", FALSE] THEN ptype ← PT16R8;
IF Rope.Equal[currentStr, "16R6", FALSE] THEN ptype ← PT16R6;
IF Rope.Equal[currentStr, "16R4", FALSE] THEN ptype ← PT16R4;
IF Rope.Equal[currentStr, "16X4", FALSE] THEN ptype ← PT16X4;
IF Rope.Equal[currentStr, "16A4", FALSE] THEN ptype ← PT16A4;
palString ← Rope.Concat[palString, currentStr];
success ← ptype # PTUndefined;
IF NOT success THEN BEGIN
PutF["\n<<Unknown PAL type - %g>>\n", IO.rope[currentStr]];
END;
END;
InitFuseArray: PROCEDURE RETURNS[FuseArray] =
BEGIN
fuses: FuseArray; -- not blown
i: NAT;
RemoveNonExistantInFuses: PROCEDURE[first, last: NAT] =
BEGIN
pg, p: NAT;
FOR pg IN [0..7] DO
FOR p IN [0..7] DO
FOR i ← first, i+4 WHILE i <= last DO
fuses[pg][p][i] ← fuses[pg][p][i+1] ← TRUE;
ENDLOOP; ENDLOOP; ENDLOOP; END;
SetPGroup: PROCEDURE[pg: NAT, fuseblown: BOOLEAN] =
BEGIN
i,p: NAT;
FOR p IN [0..7] DO
FOR i IN [0..31] DO
fuses[pg][p][i] ← fuseblown;
ENDLOOP; ENDLOOP; END;
SELECT ptype FROM
IN [PT10H8..PT10L8] => RemoveNonExistantInFuses[ 6, 26];
IN [PT12H6..PT12L6] => RemoveNonExistantInFuses[10, 22];
IN [PT14H4..PT14L4] => RemoveNonExistantInFuses[14, 18];
ENDCASE;
SELECT ptype FROM
PT12H6 => BEGIN SetPGroup[0,TRUE ];SetPGroup[7,TRUE ] END;
PT12H6 => BEGIN SetPGroup[0,FALSE];SetPGroup[7,FALSE] END;
PT14H4 => FOR i IN [0..1] DO SetPGroup[i,TRUE ];SetPGroup[7-i,TRUE ] ENDLOOP;
PT14L4 => FOR i IN [0..1] DO SetPGroup[i,FALSE];SetPGroup[7-i,FALSE] ENDLOOP;
PT16H2 => FOR i IN [0..2] DO SetPGroup[i,TRUE ];SetPGroup[7-i,TRUE ] ENDLOOP;
PT16C1 => FOR i IN [0..2] DO SetPGroup[i,TRUE ];ENDLOOP;
ENDCASE;
RETURN[fuses];
END;
OutputFuseArray: PROCEDURE[fuses: FuseArray] =
BEGIN
pg,p,i,j: NAT;
char: CHARACTER;
FOR pg IN [0..7] DO
FOR p IN [0..7] DO
FOR i ← 0, i+4 WHILE i < 32 DO
FOR j IN [i..i+3] DO
IF fuses[pg][p][j] THEN char ← '- ELSE char ← 'X;
PutF[v1: IO.char[char]];
ENDLOOP;
PutF[" "];
ENDLOOP;
PutF["\n"];
ENDLOOP;
PutF["\n"];
ENDLOOP;
END;
ReadPinDefs: PROCEDURE RETURNS[success: BOOLEAN] =
BEGIN
i: NAT;
IF NOT FindToken[pindefs] THEN RETURN[FALSE];
FOR i IN [1..20] DO
inverted: BOOLEANFALSE;
IF NextToken[] = not THEN
{inverted ← TRUE; [] ← NextToken[]};
IF currentToken # unknown THEN RETURN[FALSE];
pa[i].name ← Rope.Concat[pa[i].name, currentStr];
pa[i].nameinverted ← inverted;
ENDLOOP;
pinsDefined ← TRUE;
RETURN[TRUE];
END;
InitPinArray: PROCEDURE =
BEGIN
pg,i: NAT;
type and nofProds - default input and 8
pa[10].type ← Ground;
pa[20].type ← Power;
IF ptype IN [PT16R8..PT16A4] THEN {pa[1].type ← Clock; pa[11].type ← FixedDisable};
SELECT ptype FROM
IN [PT10H8.. PT10L8] => FOR i IN [12..19] DO
pa[i].type ← Output; pa[i].nofProds ← 2; ENDLOOP;
IN [PT12H6.. PT12L6] => BEGIN
pa[13].type ← pa[18].type ← Output;
pa[13].nofProds ← pa[18].nofProds ← 4;
FOR i IN [14..17] DO pa[i].type ← Output; pa[i].nofProds ← 2 ENDLOOP; END;
IN [PT14H4.. PT14L4] =>
FOR i IN [14..17]
DO pa[i].type ← Output; pa[i].nofProds ← 4 ENDLOOP;
IN [PT16H2.. PT16C1] =>
FOR i IN [15..16] DO
pa[i].type ← Output; ENDLOOP;
PT16L8 => BEGIN
pa[12].type ← pa[19].type ← EnabledOut;
FOR i IN [13..18] DO
pa[i].type ← EnabledInOut; ENDLOOP; END;
PT16R8 =>
FOR i IN [12..19] DO
pa[i].type ← ClockedInOut; ENDLOOP;
PT16R6 => BEGIN
pa[12].type ← pa[19].type ← EnabledInOut;
FOR i IN [13..18] DO
pa[i].type ← ClockedInOut; ENDLOOP; END;
PT16R4 => BEGIN
FOR i IN [12..19] DO
pa[i].type ← EnabledInOut; ENDLOOP;
FOR i IN [14..17] DO
pa[i].type ← ClockedInOut ENDLOOP; END;
IN [PT16X4.. PT16A4] => BEGIN
FOR i IN [ 4.. 7] DO
pa[i].type ← BuiltIn; ENDLOOP;
FOR i IN [12..19] DO
pa[i].type ← EnabledInOut; ENDLOOP;
FOR i IN [14..17] DO
pa[i].type ← BuiltInClockedOut; ENDLOOP; END;
ENDCASE => ERROR;
prodGrp - only used when pin is an output
FOR pg IN [0..7] DO pa[19-pg].prodGrp ← pg; ENDLOOP;
IF ptype = PT16C1 THEN pa[15].prodGrp ← 3;
Deleted space allocation for pa[].name here. JAG
outinverted - default TRUE;
SELECT ptype FROM
PT10H8,PT12H6,PT14H4,PT16H2 =>
FOR i IN [12..19] DO
pa[i].outinverted ← FALSE; ENDLOOP;
PT16C1 => pa[16].outinverted ← FALSE;
ENDCASE;
in - used only on inputs and inouts
FOR i IN [2..9] DO pa[i].in ← i*4-8 ENDLOOP;
pa[1].in ← 2;
FOR i IN [11..14] DO pa[i].in ← (14-i)*4+18 ENDLOOP;
FOR i IN [17..19] DO pa[i].in ← (19-i)*4+ 6 ENDLOOP;
IF ptype > PT16C1 THEN FOR i IN [12..19] DO pa[i].in ← (19-i)*4+ 2 ENDLOOP;
END;
ListPinDefs: PROCEDURE =
BEGIN
tstr: Rope.ROPE;
i,pin,max: INT ← Rope.Length[pa[1].name];
PutF["\n\n"];
PutF["Pin Definitions for PAL type: %g\n", IO.rope[palString]];
max ← Rope.Length[pa[1].name];
FOR pin IN [2..20] DO max ← MAX[max, Rope.Length[pa[pin].name]]; ENDLOOP;
FOR pin IN [1..20] DO
PutF[v1: IO.int[pin]];
IF pa[pin].nameinverted THEN PutF[" /"] ELSE PutF[" "];
PutF[pa[pin].name];
FOR i IN [Rope.Length[pa[pin].name]..max+1] DO PutF[" "]; ENDLOOP;
tstr ← SELECT pa[pin].type FROM
Clock      => "Clock ",
FixedDisable    => "FixedDisable ",
Power      => "Power ",
Ground     => "Ground ",
Input      => "Input ",
BuiltIn     => "BuiltIn ",
Output     => "Output ",
BuiltInClockedOut  => "BuiltInClockedOut ",
ClockedInOut   => "ClockedInOut ",
EnabledOut    => "EnabledOut ",
EnabledInOut   => "EnabledInOut ",
ENDCASE     => "???? " ;
PutF[v1: IO.rope[tstr]];
SELECT pa[pin].type FROM
Output, EnabledOut =>  PutF[" "];
IN [Input..EnabledInOut] => BEGIN
PutF[" index = "];
PutF[v1: IO.int[pa[pin].in]];
END;
ENDCASE;
IF pa[pin].type IN [Output..EnabledInOut] THEN BEGIN
IF pa[pin].outinverted THEN PutF[" /"] ELSE PutF[" "];
PutF["out gp = "];
PutF[v1: IO.int[pa[pin].prodGrp]];
PutF[" Nof prods = "];
PutF[v1: IO.int[pa[pin].nofProds]]; END;
PutF["\n"];
ENDLOOP;
END;
PutF: PROCEDURE [format: Rope.ROPENIL, v1, v2, v3, v4, v5: IO.Value ← [null[]]] =
BEGIN
IO.PutF[stream: viewerout, format: format, v1: v1, v2: v2, v3: v3, v4: v4, v5: v5];
IO.PutF[stream: listStream, format: format, v1: v1, v2: v2, v3: v3, v4: v4, v5: v5];
END;
WriteMBWord: PROCEDURE[item: WORD] = TRUSTED
BEGIN
base: LONG POINTER = @item;
IO.UnsafePutBlock[self: mbStream, block: [base: base, startIndex: 0, count: 2]];
END;
WriteMBFuseArray: PROCEDURE [f: FuseArray, memstr: Rope.ROPE, memindex: NAT] =
BEGIN
StrOut: PROCEDURE[index: NAT] RETURNS[CHARACTER] =
{IF index >= Rope.Length[memstr] THEN RETURN[IO.NUL]
ELSE RETURN[Rope.Fetch[memstr, index]]};
i,pgi,p: INT;
word: CARDINAL;
PutF["define memory\n"];
WriteMBWord[4];    -- Define memory
WriteMBWord[memindex]; -- Memory index
WriteMBWord[4];    -- word width
FOR i IN [0..(Rope.Length[memstr]+2)/2-1] DO
word ← Basics.BITOR[Basics.BITSHIFT[LOOPHOLE[StrOut[2*i]],8], LOOPHOLE[StrOut[2*i+1]]];
WriteMBWord[word];
ENDLOOP;
WriteMBWord[2];    -- Set Location
WriteMBWord[memindex]; -- Memory index
WriteMBWord[0];    -- Start location
FOR pgi IN[0..1] DO
FOR p IN[0..7] DO
FOR i IN[0..31] DO
word ← 0;
IF f[pgi*4 + 0][p][i] THEN word ← Basics.BITOR[word, 1000H];
IF f[pgi*4 + 1][p][i] THEN word ← Basics.BITOR[word, 2000H];
IF f[pgi*4 + 2][p][i] THEN word ← Basics.BITOR[word, 4000H];
IF f[pgi*4 + 3][p][i] THEN word ← Basics.BITOR[word, 8000H];
WriteMBWord[1]; -- Define data word
WriteMBWord[0]; -- Source line
WriteMBWord[word];
ENDLOOP;
ENDLOOP;
ENDLOOP;
END;
Init: PROCEDURE RETURNS[success: BOOLEAN] =
BEGIN
mbStream ← FS.StreamOpen[Rope.Concat[rootFileName, ".MB"], $create];
listStream ← FS.StreamOpen[Rope.Concat[rootFileName, ".List"], $create];
inStream ← FS.StreamOpen[Rope.Concat[rootFileName, ".pal"]];
ptype ← PTUndefined;
pa ← NEW[PinArray];
currentToken ← space;
lastToken ← space;
nextChar ← IO.SP;
nextTokenChar ← IO.SP;
pinsDefined ← FALSE;
errorCalled ← FALSE;
RETURN[TRUE];
END;
CloseFiles: PROCEDURE[str: Rope.ROPE] =
BEGIN
PutF["\n\n%g\n", IO.rope[str]];
IO.Close[inStream];
IO.Close[listStream];
WriteMBWord[0];
WriteMBWord[0];
IO.Close[mbStream];
END;
ConvertPALToMB: Buttons.ButtonProc = BEGIN
handle: Handle ← NARROW[clientData];
IO.PutF[viewerout, " -- PAL Assembler of August 1, 1985\n"];
rootFileName ← ViewerTools.GetContents[handle.pal.input];
DO
IF NOT Init[] THEN GOTO InitFilesFailed;
PutF[Rope.Cat["\n-- File: ", rootFileName, ".list\n-- Created by Palasm %g\n"], IO.time[]];
IF NOT ReadPALType[] THEN GOTO ReadPALTypeFailed;
InitPinArray[];
vfa ← fa ← InitFuseArray[];
IF NOT ReadPinDefs[] THEN GOTO ReadPinDefsFailed;
IF NOT ReadEquations[] THEN GOTO ReadEquationsFailed;
WHILE GetChar[] # IO.NUL DO LOOP ENDLOOP;
ListPinDefs[];
PutF["\n\nVirgin fuses\n"];
OutputFuseArray[vfa];
WriteMBFuseArray[vfa, "VirginPALFuses", 0];
PutF["\n\nProgrammed fuses\n"];
OutputFuseArray[fa];
WriteMBFuseArray[fa, "PALFuses", 1];
CloseFiles["<<No Errors>>"];
EXIT;
REPEAT
InitFilesFailed => CloseFiles["<<InitFiles Failed>>"];
ReadPALTypeFailed => CloseFiles["<<ReadPALType Failed>>"];
ReadPinDefsFailed => CloseFiles["<<ReadPinDefs Failed>>"];
ReadEquationsFailed => CloseFiles["<<ReadEquations Failed>>"];
ENDLOOP;
END;
Commander.Register[key: "///Commands/PALTool", proc: MakePALTool,
doc: "Create a PAL tool" ];
[ ] ← MakePALTool[NIL]; -- and create an instance
END.