// // Vivio write-through cache coherency protocol animation // // Copyright 1997 - 2008 jones@cs.tcd.ie // // This program is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software Foundation; // either version 2 of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software Foundation Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // // 20/02/97 first version // 10/06/97 used SimpleButton // 07/12/01 added locks and parallel operation // 27/08/02 Vivio 2.0 // 23/01/06 Vivio 4.0 // 20/02/06 real x,y event parameters // 07/11/06 added extra wait(1) after getting bus lock // 07/11/06 modified animation of parallel accesses to make it easier to follow // 11/01/07 added Vivio logo // 14/01/07 used ImageButton for logo // 13/03/07 return EV_FORGET in event handlers which call getURL // 19/05/07 logo now uses a hand cursor // Djordje Jevdjic 8/11/08} // Last Revision: Marko Peric #include "standard.vin" #include "SimpleButton.vin" #include "imageButton.vin" const int WIDTH = 800; // virtual window width const int HEIGHT = 600; // virtual window height const int NCPU = 4; // number of CPUs setViewport(0, 0, WIDTH, HEIGHT, 1); bgbrush = SolidBrush(vellum); setBGBrush(bgbrush); smallFont = Font("Times New Roman", 14, 0); hintFont = Font("Times New Roman", 16, 0); titleFont = Font("Times New Roman", 24, 0); navybrush = SolidBrush(rgb(0, 0, 102)); title = Rectangle2(0, VCENTRE, 0, navybrush, 5, 5, WIDTH*7/12, 30, whitebrush, titleFont, "Write-Through Cache Coherency Protocol"); title.setTxtOff(2, 1); str = "Like real hardware, the CPUs can operate\n"; str += "in parallel - try pressing a button on each\n"; str += "CPU \"simultaneously\".\n"; hint = Txt(0, HLEFT | VTOP, 5, 80, blackbrush, hintFont, str); const int VALID = 0; // cache line states const int INVALID = 1; int wValue = 0; // value written into cache int buglevel = 0; // bug level buslock = 0; // bus lock cpulock[0] = 0; // CPU locks cpulock[1] = 0; cpulock[2] = 0; cpulock[3] = 0; SimpleButton lastButton[int]; class BusArrow(int x, int y, int whead, int wbody, int l, Brush brush) arrow = Polygon(0, AAFILL | ABSOLUTE, 0, blackbrush, x,y, 0,0, whead,whead, wbody,whead, wbody,l-whead, whead,l-whead, 0,l, -whead,l-whead, -wbody,l-whead, -wbody,whead, -whead,whead); int largewhead = whead; int largewbody = wbody; body = Rectangle2(0, 0, 0, brush, x-wbody, y, 2*wbody+1, l); body.setOpacity(0); up = Polygon(0, AAFILL | ABSOLUTE, 0, brush, 0,0, largewhead,0, 2*largewhead,whead, 0,whead); up.setOpacity(0); down = Polygon(0, AAFILL | ABSOLUTE, 0, brush, 0,0, 0,0, 2*largewhead,0, largewhead,whead); down.setOpacity(0); function reset() arrow.setBrush(blackbrush); up.setOpacity(0); body.setOpacity(0); down.setOpacity(0); arrow.setOpacity(255); end; // // animate up movement on vertical bus arrow // // may be called with ticks = 0 // function moveup(int ticks, int wflag) // // initial positions, size & opacity // up.setPos(x-largewhead, y+(l-largewhead)); body.setPos(x-largewbody, y+l); body.setSize(2*largewbody+1, 10); up.setOpacity(255); body.setOpacity(255); // // final positions, size & opacity // up.setPos(x-largewhead, y, ticks, 1, 0); body.setPos(x-largewbody, y+largewhead, ticks, 1, 0); body.setSize(2*largewbody+1, l+1-largewhead, ticks, 1, 0); arrow.setOpacity(0, ticks, 1, wflag); end; // // animate down movement on vertical bus arrow // // may be called with ticks = 0 // function movedown(int ticks, int wflag) // // initial positions, size & opacity // down.setPos(x-largewhead, y); body.setPos(x-largewbody, y); body.setSize(2*largewbody+1, 0); down.setOpacity(255); body.setOpacity(255); // // final positions, size & opacity // down.setPos(x-largewhead, y+l-largewhead, ticks, 1, 0); body.setSize(2*largewbody+1, l-largewhead+1, ticks, 1, 0); arrow.setOpacity(0, ticks, 1, wflag); end; end; class Memory(int x, int y) r = Rectangle2(0, 0, blackpen, gray192brush,x, y, 150, 100); t = Txt(0, HLEFT | VTOP, x+160, y+40, redbrush, 0, "memory"); abus = BusArrow(x+50, y+100, 10, 4, 59, bluebrush); dbus = BusArrow(x+100, y+100, 10, 4, 89, redbrush); for (int i = 0; i < 4; i++) mem[i] = 0; memR[i] = Rectangle2(0, 0, blackpen, whitebrush, x+5, y+4+i*24, 140, 20, blackbrush, 0, "address: a%d data: %d", i, mem[i]); memR[i].setTxtOff(0, 1); end; function highlight(int addr, int flag) memR[addr].setBrush((flag) ? greenbrush : whitebrush); end; function reset() for (int i = 0; i < 4; i++) highlight(i, 0); end; end; end; class Bus(int x, int y, int whead, int wbody, int l, Brush brush) arrow = Polygon(0, AAFILL | ABSOLUTE, 0, blackbrush, x,y, 0,0, whead,-whead, whead,-wbody, l-whead,-wbody, l-whead,-whead, l,0, l-whead,whead, l-whead,wbody, whead,wbody, whead,whead); function highlight(int flag) if (flag == 0) arrow.setBrush(blackbrush); else arrow.setBrush(brush); end; end; end; ddbus = Bus(25, 265, 12, 6, 750, redbrush); ddbusTxt = Txt(0, HLEFT | VTOP, 170, 242, redbrush, smallFont, "data bus"); aabus = Bus(20, 235, 12, 6, 750, bluebrush); aabusTxt = Txt(0, HLEFT | VTOP, 150, 212, bluebrush, smallFont, "address bus"); memory = Memory(325, 70); class Cache; // forward declaration Cache cache[NCPU]; class Cache(int x, int y, int cpu) r = Rectangle2(0, 0, blackpen, gray192brush, x, y, 150, 50); t = Txt(0, HLEFT | VTOP, x+130, y-20, redbrush, 0, "cache %d", cpu); for (int i = 0; i < 2; i++) state[i] = INVALID; stateR[i] = Rectangle2(0, 0, blackpen, whitebrush, x+5, y+6+i*20, 20+1, 17+1, blackbrush, 0, "I"); stateR[i].setTxtOff(0, 1); a[i] = -1; aR[i] = Rectangle2(0, 0, blackpen, whitebrush, x+25, y+6+i*20, 60+1, 17+1); aR[i].setTxtOff(0, 1); d[i] = 0; dR[i] = Rectangle2(0, 0, blackpen, whitebrush, x+85, y+6+i*20, 60+1, 17+1); dR[i].setTxtOff(0, 1); end; abus = BusArrow(x+50, y-84, 10, 4, 84, bluebrush); dbus = BusArrow(x+100, y-54, 10, 4, 54, redbrush); cpuabus = BusArrow(x+50, y+50, 10, 4, 50, bluebrush); cpudbus = BusArrow(x+100, y+50, 10, 4, 50, redbrush); function highlight(int set, int flag) if (flag == 1) stateR[set].setBrush(greenbrush); aR[set].setBrush(greenbrush); dR[set].setBrush(greenbrush); else stateR[set].setBrush(whitebrush); aR[set].setBrush(whitebrush); dR[set].setBrush(whitebrush); end; end; function resetbus() memory.abus.reset(); memory.dbus.reset(); ddbus.arrow.setBrush(blackbrush); aabus.arrow.setBrush(blackbrush); ddbus.arrow.setBrush(blackbrush); memory.reset(); for (int i = 0; i < NCPU; i++) cache[i].abus.reset(); cache[i].dbus.reset(); end; end; function resetStart() for (int i = 0; i < NCPU; i++) if ((cpulock[i] == 0) || (cpu == i)) cache[i].cpuabus.reset(); cache[i].cpudbus.reset(); cache[i].highlight(0, 0); cache[i].highlight(1, 0); lastButton[i].setpen(blackpen); end; end; if (buslock == 0) resetbus(); end; end; function resetEnd() for (int i = 0; i < NCPU; i++) if (cpulock[i] == 0) cache[i].cpuabus.reset(); cache[i].cpudbus.reset(); cache[i].highlight(0, 0); cache[i].highlight(1, 0); lastButton[i].setpen(blackpen); end; end; end; function watch(int addr, int rw) int set = addr % 2; abus.movedown(20, 1); if ((a[set] == addr) && (rw == 1) && (buglevel != 1)) if (state[set] == VALID) highlight(set, 1); end; state[set] = INVALID; stateR[set].setTxt("I"); end; end; function buswatch(int addr, int cpu, int rw) for (int i = 0; i < NCPU; i++) if (i != cpu) fork(cache[i].watch(addr, rw)); end; end; end; // // read // function read(int addr, int animateCpu) int set = addr % 2; // // miss // if ((state[set] == INVALID) || (a[set] != addr)) if(animateCpu) cpuabus.moveup(20, 1); // {joj 7/11/06} end; while (buslock) wait(1); end; buslock = 1; wait(1); // {joj 7/11/06} if(animateCpu) resetbus(); end; highlight(set, 1); abus.moveup(20, 1); aabus.highlight(1); buswatch(addr, cpu, 0); memory.abus.moveup(20, 1); memory.highlight(addr, 1); memory.dbus.movedown(20, 1); ddbus.highlight(1); dbus.movedown(20, 1); a[set] = addr; aR[set].setTxt("a%d", addr); d[set] = memory.mem[addr]; dR[set].setTxt("%d", d[set]); state[set] = VALID; stateR[set].setTxt("V"); if(animateCpu) cpudbus.movedown(20, 1); buslock = 0; // {Djordje Jevdjic GAY 28/11/08} end; else // hit cpuabus.moveup(20, 1); highlight(set, 1); cpudbus.movedown(20, 1); end; end; // // write - always write-through // function write(int addr) resetbus(); // {joj 7/11/06} int set = addr % 2; cpudbus.moveup(20, 0); cpuabus.moveup(20, 1); if(a[set]!= addr || state[set]==INVALID) read(addr,0); else while (buslock) wait(1); end; buslock = 1; end; wait(1); highlight(set, 1); a[set] = addr; aR[set].setTxt("a%d", addr); wValue++; d[set] = wValue; dR[set].setTxt("%d", wValue); abus.moveup(20, 0); dbus.moveup(20, 1); aabus.highlight(1); ddbus.highlight(1); memory.abus.moveup(20, 0); buswatch(addr, cpu, 1); memory.dbus.moveup(20, 1); state[set] = VALID; stateR[set].setTxt("V"); memory.mem[addr] = d[set]; memory.memR[addr].setTxt("address: a%d data: %d", addr, memory.mem[addr]); memory.highlight(addr, 1); buslock = 0; end; end; // // read operation // class readOp(int x, int y, int addr, int cpu, ref Rectangle r) b = SimpleButton(x, y, 65, 22, bgbrush, gray192brush, blackbrush, 0, "read"); b.button.setTxt("read a%d", addr); when b.buttonBG.eventLB(int down, real xx, real yy) if ((down == 0) && cpulock[cpu] == 0) cpulock[cpu] = 1; r.setPen(greenpen); cache[cpu].resetStart(); b.setpen(redpen); start(); lastButton[cpu] = b; cache[cpu].read(addr,1); r.setPen(blackpen); cache[cpu].resetEnd(); cpulock[cpu] = 0; checkPoint(); end; end; end; // // write operation // class writeOp(int x, int y, int addr, int cpu, ref Rectangle r) b = SimpleButton(x, y, 65, 22, bgbrush, gray192brush, blackbrush, 0, "write"); b.button.setTxt("write a%d", addr); when b.buttonBG.eventLB(int down, real xx, real yy) if (down == 0 && cpulock[cpu] == 0) cpulock[cpu] = 1; r.setPen(greenpen); cache[cpu].resetStart(); b.setpen(redpen); start(); lastButton[cpu] = b; cache[cpu].write(addr); r.setPen(blackpen); cache[cpu].resetEnd(); cpulock[cpu] = 0; checkPoint(); end; end; end; // // cpu object // class CPU(int x, int y, int cpu) r = Rectangle2(0, 0, blackpen, gray192brush, x, y, 150, 100); t = Txt(0, HLEFT | VTOP, x+130, y-20, redbrush, 0, "CPU %d", cpu); for (int i = 0; i < 4; i++) rb[i] = readOp(x+5, y+5+i*23, i, cpu, r); wb[i] = writeOp(x+80, y+5+i*23, i, cpu, r); end; end; // // user buttons & their event handlers // const int BH = 25; const int BW = 75; const int BGAP = 5; const int BDX = BW+BGAP; //Initialization for (int i=0;i