// SCI1.bcpl -- companion to SCI.bcpl // Last modified May 30, 1983 1:50 PM by Boggs get "SCI.decl" get "Streams.d" external [ // outgoing procedures WLFile; OtherFile ReadToken; OutPut; FlushBlock // incoming procedure -- SCI TSP // incoming procedures -- packages ConcatenateStrings; StringCompare PutTemplate; ExtractSubstring // incoming procedures -- OS OpenFile; Closes; Gets; Puts; Endofs EraseBits; CharWidth; Wss Allocate; Free; CallSwat // incoming statics -- OS sysZone; dsp; keys // incoming statics -- SCI lf; in; out; cpuType token; board; numBlocks block; blockCnt; record; recordCnt ] static termChar //---------------------------------------------------------------------------------------- let WLFile() be //---------------------------------------------------------------------------------------- // Reads 'Board.wl', the wirelist produced by Route, // and generates the PARTS & NETLIST subfiles for SCI. [ let wlName = ConcatenateStrings(board, ".wl") let wl = OpenFile(wlName, ksTypeReadOnly, charItem) Free(sysZone, wlName) test wl ifso [ PutTemplate(dsp, "*NReading $S.wl", board); in = wl ] ifnot [ PutTemplate(dsp, "*NFailed to open $S.wl", board); return ] Wss(dsp, "*NMultibus or Dandelion board (M or D): ") let boardType = Gets(keys) & 137b; Puts(dsp, boardType) ReadToken() //board type. discard. // Make parts list Wss(out, "*NPARTS") let width, length, pins = nil, nil, nil [ ReadToken() //part designator if token>>String.length eq 0 % (token>>String.length eq 1 & token>>String.char↑1 eq $@) break let desig = ExtractSubstring(token, (token>>String.char↑1 eq $#? 2, 1)) ReadToken() let firstSlash, lastSlash, len = 0, 0, token>>String.length for i = 1 to len if token>>String.char↑i eq $/ test firstSlash eq 0 ifso firstSlash = i ifnot lastSlash = i width = 3; for i = lastSlash+1 to len do if IsNumber(i, i) then width = token>>String.char↑i - $0 pins = 0; for i = firstSlash+1 to lastSlash-1 do pins = pins*10 + (token>>String.char↑i - $0) length = width eq 1? pins, pins/2 PutTemplate(out, "*NHOLE MODULE HM$2F0D$2F0D$2F0D $S", width, length, pins, desig) Free(sysZone, desig) ] repeat Wss(out, "*NEOS*N") // Make net list Wss(out, "*NNET LIST CONTINUE") let flush, nodeCnt, netName = false, 0, 0 [ //main loop manifest //token types [ calibrate = 1; signal = 2; boardLoc = 3 gnd = 4; gndNet = 5; gndNub = 6 vcc = 7; vccNet = 8; vccNub = 9 pointyBracket = 10; parenthesis = 11; curlyBracket = 12 edgePin = 13; connPin = 14 ] ReadToken() let len = token>>String.length; if len eq 0 break let tokenType = signal if StringCompare("CALIBRATE", token) eq 0 then tokenType = calibrate if StringCompare("GND", token) eq 0 then tokenType = gnd if StringCompare("GND", token) eq -2 test token>>String.char↑4 eq $- ifso if IsNumber(5, len) then tokenType = gndNet ifnot if IsNumber(4, len) then tokenType = termChar eq $:? gndNet, gndNub if StringCompare("VCC", token) eq 0 then tokenType = vcc if StringCompare("VCC", token) eq -2 test token>>String.char↑4 eq $- ifso if IsNumber(5, len) then tokenType = vccNet ifnot if IsNumber(4, len) then tokenType = termChar eq $:? vccNet, vccNub let firstChar, lastChar = token>>String.char↑1, token>>String.char↑len if firstChar eq $( & lastChar eq $) then tokenType = parenthesis if firstChar eq ${ & lastChar eq $} then tokenType = curlyBracket if firstChar eq $< & lastChar eq $> then tokenType = pointyBracket if (firstChar eq $E % firstChar eq $C) & IsNumber(2, len) then tokenType = firstChar eq $E? edgePin, connPin if tokenType eq signal & (termChar eq $*S % firstChar eq $#) then tokenType = boardLoc // NetList (cont'd) if tokenType eq edgePin % tokenType eq connPin % tokenType eq boardLoc then [ if flush loop if nodeCnt rem 5 eq 0 test nodeCnt ne 0 & nodeCnt rem 50 ne 0 ifso Wss(out, "$*N ") ifnot PutTemplate(out, "*NNN $S ", netName) nodeCnt = nodeCnt +1 ] switchon tokenType into [ case calibrate: [ flush = true; endcase ] case signal: [ if netName ne 0 then Free(sysZone, netName) netName = ExtractSubstring(token) flush, nodeCnt = false, 0 endcase ] case gndNet: token>>String.length = 3 case gnd: test StringCompare("GND", netName) ifso docase signal ifnot endcase case vccNet: token>>String.length = 3 case vcc: test StringCompare("VCC", netName) ifso docase signal ifnot endcase case edgePin: case connPin: [ switchon boardType into [ case $M: [ Multibus(); endcase ] case $D: test tokenType eq edgePin ifso [ DandelionE(); endcase ] ifnot [ DandelionC(); endcase ] default: [ Universal(); endcase ] ] endcase ] case boardLoc: [ let dot = 0; for i = 1 to len do if token>>String.char↑i eq $. then [ dot = i; break ] let firstChar = token>>String.char↑1 eq $#? 2, 1 for i = firstChar to dot-1 do Puts(out, token>>String.char↑i) Puts(out, $*S) for i = dot+1 to len-1 do Puts(out, token>>String.char↑i) Puts(out, $*S) endcase ] ] ] repeat Wss(out, "*NEOS*N") Closes(wl) ] //---------------------------------------------------------------------------------------- and Universal() be //---------------------------------------------------------------------------------------- [ Puts(out, token>>String.char↑1) Puts(out, $*S) for i = 2 to token>>String.length do Puts(out, token>>String.char↑i) Puts(out, $*S) ] //---------------------------------------------------------------------------------------- and DandelionE() be //---------------------------------------------------------------------------------------- [ let number = 0 for i = 2 to token>>String.length do number = number*10 + token>>String.char↑i -$0 let conn, side, pin = nil, nil, nil if number ge 1 & number le 50 then [ conn = $2; side = $T; pin = 51-number ] if number ge 51 & number le 100 then [ conn = $1; side = $T; pin = 101-number ] if number ge 101 & number le 150 then [ conn = $2; side = $B; pin = 151-number ] if number ge 151 & number le 200 then [ conn = $1; side = $B; pin = 201-number ] PutTemplate(out, "P$C-$C $D ", conn, side, pin) ] //---------------------------------------------------------------------------------------- and DandelionC() be //---------------------------------------------------------------------------------------- [ let number = 0 for i = 2 to token>>String.length do number = number*10 + token>>String.char↑i -$0 let conn = number ls 100? $1, $2 let pin = number ls 100? number, number-100 PutTemplate(out, "J$C $D ", conn, pin) ] //---------------------------------------------------------------------------------------- and Multibus() be //---------------------------------------------------------------------------------------- [ test token>>String.char↑1 eq $C ifso [ Puts(out, $J); Puts(out, token>>String.char↑2 -2) ] ifnot [ Puts(out, $P); Puts(out, token>>String.char↑2) ] Wss(out, (token>>String.char↑4 & 1) ne 0? "-T ", "-B ") let n = ((10*(token>>String.char↑3 -$0)) + (token>>String.char↑4 -$0) +1)/2 Puts(out, $0 + n/10) Puts(out, $0 + n rem 10) Puts(out, $*S) ] //---------------------------------------------------------------------------------------- and OtherFile() be //---------------------------------------------------------------------------------------- // Reads Board.other and writes it unmodified to tape. // Records are delimited by bare carriage returns. [ let otherName = ConcatenateStrings(board, ".other") let other = OpenFile(otherName, ksTypeReadOnly, charItem) Free(sysZone, otherName) test other ifso [ PutTemplate(dsp, "*NReading $S.other", board); in = other ] ifnot [ PutTemplate(dsp, "*NFailed to open $S.other", board); return ] until Endofs(other) do Puts(out, Gets(other)) Puts(out, $*N) Closes(other) ] //---------------------------------------------------------------------------------------- and OutPut(st, char) be //---------------------------------------------------------------------------------------- // ST.puts operation for the stream 'out'. // It feeds characters to a plain text listing file and to the tape. // Carriage returns are replaced by record boundaries on the tape. [ Puts(lf, char) Puts(dsp, char) if char ne $*N then [ record>>Byte↑recordCnt = char recordCnt = recordCnt +1 if recordCnt eq (cpuType eq $V? 80, 81) then CallSwat("Record too long") return ] // end of record test cpuType eq $V ifso //RecLen = var, max 74, BlkLen = 2048, Fortran carriage control [ if recordCnt eq 5 then recordCnt = 4 if 2048-blockCnt ls recordCnt then FlushBlock() record>>Byte↑0 = $0 record>>Byte↑1 = $0 record>>Byte↑2 = $0 + recordCnt/10 record>>Byte↑3 = $0 + recordCnt rem 10 record>>Byte↑4 = $*S //Fortran carriage control! for i = 0 to recordCnt-1 do block>>Byte↑(blockCnt+i) = record>>Byte↑i blockCnt = blockCnt + recordCnt recordCnt = 5 ] ifnot //RecLen = 80, BlkLen = 800 (Prime computer system) [ if blockCnt eq 800 then FlushBlock() for i = 0 to recordCnt-1 do block>>Byte↑(blockCnt+i) = record>>Byte↑i for i = recordCnt to 79 do block>>Byte↑(blockCnt+i) = $*S //pad record with $*S blockCnt = blockCnt + 80 recordCnt = 0 ] ] //---------------------------------------------------------------------------------------- and FlushBlock() be //---------------------------------------------------------------------------------------- // Flushes the current block to tape [ if blockCnt eq 0 return test cpuType eq $V ifso [ for i = blockCnt to 2047 do block>>Byte↑i = 136b //pad block with $*136 TSP(cmdWriteRecord, block, 0, 2048) ] ifnot [ for i = blockCnt to 799 do block>>Byte↑i = $*S //pad block with $*S TSP(cmdWriteRecord, block, 0, 800) ] numBlocks = numBlocks +1 blockCnt = 0 ] //---------------------------------------------------------------------------------------- and ReadToken() be //---------------------------------------------------------------------------------------- // Reads a token from the 'in' stream and puts it in 'token'. // Note that it may have 0 characters if EOF (disk stream) or <Del> (key stream). // Terminating character is left in static 'termChar'. [ let count = 0 until Endofs(in) & in ne keys do [ termChar = Gets(in) switchon termChar into [ case $*001: case $*010: [ if count ne 0 & in eq keys then [ EraseBits(dsp, -CharWidth(dsp, token>>String.char↑count)) count = count -1 ] endcase ] case $;: //flush input stream until CR until Endofs(in) % Gets(in) eq $*N loop //fall through case $*N: case $*S: case $*T: case $:: [ if count ne 0 break endcase ] case $*177: if in eq keys then [ Wss(dsp, " XXX "); count = 0; break ] default: [ count = count +1 if termChar ge $a & termChar le $z then termChar = termChar & 137b if termChar eq $← then termChar = $< token>>String.char↑count = termChar if in eq keys then Puts(dsp, termChar) endcase ] ] ] token>>String.length = count ] //---------------------------------------------------------------------------------------- and IsNumber(first, last) = valof //---------------------------------------------------------------------------------------- [ if last ls first resultis false for i = first to last do if token>>String.char↑i ls $0 % token>>String.char↑i gr $9 resultis false resultis true ]