[= Demo - Less Simple block diagram Command: chips.bat This may seen a lot of work for a single diagram but in practice a lot of the low level routines would be reused in other diagrams. =] [= main layout parameters =] Const Colour White = {100, 100, 100}; Const Number CPUWidth = 100; Const Number CPUHeight = 400; Const Number SupChipWidth = 160; [= supplementary chips =] Const Number SupChipHeight = 50; Const Number BusWidth = 20; Const Number ChipHorzSep = 2 * CPUWidth; [= derived layout parameters =] Const Number BusLength = ChipHorzSep + SupChipWidth / 2 + BusWidth / 2; Const Number SupChipX = CPUWidth + ChipHorzSep; Const Number MemChipY = 4 * BusWidth; Const Number IOChipY = CPUHeight - SupChipHeight; Program() Begin [= draw complete diagram at desired location =] Diagram() => {40, 40}; End; [= DIAGRAM ------- =] Shape Diagram() Number temp, length; Begin [= draw all the chips ( except I/O unit ) =] Chip(CPUWidth, CPUHeight, "CPU"); Chip(SupChipWidth, SupChipHeight, "MEM") => { SupChipX, MemChipY }; [= draw the main address bus =] Bus(BusLength, BusWidth, "Address Bus") => { CPUWidth, BusWidth }; [= close of the turn point =] LineTo({ 0, BusWidth}) => {SupChipX + SupChipWidth / 2 + BusWidth / 2, BusWidth}; [= arrow down to memory chip =] VertArrow(2 * BusWidth, BusWidth, True) => {SupChipX + SupChipWidth / 2, 2 * BusWidth }; [= data bus arrow down to the I/O chip =] temp := CPUHeight - 4 * BusWidth - 2 * SupChipHeight; VertArrow(temp, BusWidth, True, False) => {SupChipX + SupChipWidth / 2, 4 * BusWidth + SupChipHeight }; [= data bus back to the CPU =] temp := ( 4 * BusWidth + IOChipY ) / 2 + SupChipHeight / 2; length := ChipHorzSep + SupChipWidth/2 - BusWidth/2; HorzArrow(length, BusWidth, False, True) => { SupChipX + SupChipWidth/2 - BusWidth/2, temp} ; TextBlock("Data Bus", halign -> Centre, valign -> Centre) => { SupChipWidth/2 + SupChipX - length / 2, temp}; [= control lines into Memory chip =] InputLineHorz(ChipHorzSep, False, "MREQ", True) => {SupChipX, MemChipY + 10}; InputLineHorz(ChipHorzSep, False, "RD", True) => {SupChipX, MemChipY + SupChipHeight - 10}; [= draw the whoole I/O unit =] IOUnit(SupChipWidth, SupChipHeight, ChipHorzSep) => { SupChipX, IOChipY }; End; [= I O UNIT ----------- The whole I/O block can be isolated as a single unit. The shift parameter is distance to the CPU. The origin is the top left of the main chip. =] Shape IOUnit(Number width, Number height, Number shift) Const Number arrowlen = 60; Begin [= do the main chip =] Chip(width, height, "I/O"); [= centre I/O data arrows on middle of bottom edge =] With {width / 2, height} Do [= input bus =] VertArrow(arrowlen, BusWidth, True, False) => {-2 * BusWidth, 0}; TextBlock("Output Data", 3 * BusWidth, halign -> Centre, valign-> Top) => {-2 * BusWidth, arrowlen + 4}; [= output bus =] VertArrow(arrowlen, BusWidth, False) => {2 * BusWidth, arrowlen}; TextBlock("Input Data", 3 * BusWidth, halign -> Centre, valign-> Top) => { 2 * BusWidth, arrowlen + 4}; EndWith; [= control lines into I/O chip =] InputLineHorz(shift, False, "IORQ", True) => {0, 10}; InputLineHorz(shift, False, "M1", True) => {0, height - 10}; [= address lines into I/O chip =] InputLineHorz(40, True, "A0") => {width, 10}; InputLineHorz(40, True, "A1") => {width, height - 10}; End; [= HORZ ARROW ---------- The clear flag is for clearing the join with another bus. =] Shape HorzArrow(Number length, Number width, Logical right, Logical clear = True) Number sign; Number hwidth = width // 2; Number shaftlen = length - width; Begin [= see which direction the arrow points =] If right Then sign := 1; Else sign := -1; EndIf; [= clear the section of bus where arrow joins =] If clear Then Line( {0, -hwidth}, {0, hwidth} ) => Pen { colour -> White }; EndIf; [= the two sides of the shaft =] Line( {0, -hwidth}, { sign * shaftlen, -hwidth} ); Line( {0, hwidth}, {sign * shaftlen, hwidth} ); [= the two side arms =] Line( {sign * shaftlen, -hwidth}, {sign * shaftlen, -width} ); Line( {sign * shaftlen, hwidth}, { sign * shaftlen, width} ); [= the two sides of the tip =] Line ( {sign * shaftlen, -width}, {sign * length, 0} ); Line ( {sign * shaftlen, width}, {sign * length, 0} ); End; [= VERT ARROW ---------- Vertical arrow. Length = total length including hear Origin: Centre of the tail. =] Shape VertArrow(Number length, Number width, Logical down, Logical clear = True) Number sign; Number hwidth = width // 2; Number shaftlen = length - width; Begin [= see which direction the arrow points =] If down Then sign := 1; Else sign := -1; EndIf; [= clear the section of bus edge =] If clear Then Line( { -hwidth, 0}, { hwidth, 0} ) => Pen { colour -> { 100,100,100 } }; EndIf; [= the two sides of the shaft =] Line( { -hwidth, 0}, {-hwidth, sign * shaftlen} ); Line( { hwidth, 0}, {hwidth, sign * shaftlen} ); [= the two side arms =] Line( {-hwidth, sign * shaftlen}, {-width, sign * shaftlen} ); Line( {hwidth, sign * shaftlen}, { width, sign * shaftlen} ); [= the two sides of the tip =] Line ( {-width, sign * shaftlen}, { 0, sign * length }); Line ( { width, sign * shaftlen}, { 0, sign * length }); End; [= BOX --- =] Shape Chip(Number width, Number height, Text boxname) TPen workpen = Pen { width -> 3 }; Begin Rectangle(width, height) => workpen; TextBlock(boxname,halign -> Centre, valign -> Centre) => { width / 2, height / 2}; End; [= BUS --- This will be two parallel lines. =] Shape Bus(Number length, Number width, Text busname) Begin [= draw top line of width =] LineTo( { length, 0 } ); [= shift down by width =] LineTo( { length, 0 } ) => { 0, width }; [= write the name =] TextBlock(busname, halign -> Centre, valign -> Centre) => { length / 2, width / 2}; End; [= INPUT LINE HORZ --------------- Control line leading to a chip. The negate signifies that it is a negating input. The origin the the point on the chip where it connects. =] Shape InputLineHorz(Number length, Logical right, Text name, Logical negate = False) Const Number tagsize = 4; [= size of circle or arrowhead =] Number sign; Begin [= see which direction the arrow points =] If right Then sign := 1; Else sign := -1; EndIf; If negate Then [= set to a little circle =] Circle(tagsize) => {sign * ( tagsize + 1 ), 0}; Else [= set to arrow - use Polygon to draw a triagle =] Polygon([ {0,0} , {sign * 2 * tagsize, tagsize / 2} , {sign * 2 * tagsize, -tagsize / 2} ], Solid ); EndIf; [= draw the main contol line =] LineTo( { sign * ( length - 2 * tagsize - 1) , 0} ) => {sign * (2 * tagsize + 1) ,0 }; [= label the line above =] TextBlock(name, halign -> Centre, valign -> Bottom) => { sign * length / 2, 0}; End;