MAPS 7873 Assignment 3 MAPS 7873 Assignment 3: Occam Programming This assignment concerns using occam to develop parallel programs. You should use the jEdit/Transterpreter IDE to complete this assignment. There are two parts to this assignment, in summary these are: 1. The Car Park Simulator Total Marks 50 You are asked to complete the functionality of the provided incomplete program (details later in this specification). A complete version of the program will be demonstrated to you so that you know how it should appear. There are two versions, one simple one that outputs the progress of the program with scrolling messages to the console , and a second more graphical one that simulates on screen the action of the car park. The simple version is useful as it has less obfuscating processes to get in the way of your understanding of the code. However, your efforts should be applied to the graphical version as it is this version that should be submitted. 2. The Super-Scalar Processor Simulator Total Marks 30 This sounds worse than it is! You are asked to write a complete occam program that simulates a dual-pipeline processor very simply – instructions are continually fed into the processor (as if they were being fetched) and are dispatched to one of two execution pipelines, whichever is ‘free’ (i.e. has finished executing the previous instruction). Each instruction is simply defined by a number, 1, 2 or 3, which represents its relative execution time, and this is generated randomly. The main constraint is that the instructions, although executed on either pipeline nondeterministically, must be ‘retired’ in the order they were originally generated (i.e. this is an ‘in-order’ processor). Submission Requirements Deadline: Wednesday, 19th May 2010, 11.59pm. There are 80 marks available. This assignment contributes 40% to the overall assessment of the module. You should submit the following occam source files to the MAPS Blackboard site (assignments area), contained in a single zip file called surname_assignment3.zip: surname_carpark.occ surname_processor.occ surname_DFDs.doc (or .docx) You should also submit paper listings of these two programs and DFD’s through ACES post-grad reception in Harmer as normal. Please ensure these are suitably formatted with no word-wrap and no inappropriate orphan/widow lines (use landscape printing if necessary), and are clearly labelled with their titles and your full name. If you have more than one version of these programs, feel free to add them to your submission for consideration – ensure you add comments to explain their differences and add a sequential number to their filenames (surname_carpark1.occ, surname_carpark2.occ, etc). Page 1 MAPS 7873 Assignment 3 1. The Car Park Simulator Tasks 50 Marks Obtain and inspect these incomplete listings from Bb: MAPS Car Park User Simple incomplete.occ MAPS Car Park User Graphic incomplete.occ These are listed along with a screen shot of the output later in this specification. The following tasks should be applied to the graphical version of the program eventually, although it is recommended that you trial your attempts on the simple version first as it has been provided to help you understand the function of the program more easily. 1. raw the DFD for the car park program (see below). D 2 marks 2. C omplete the missing parts of the program correctly. For this purpose comments with the format: -- ??? some useful comment here have been left in the listings as guidance to what is required. In this document they are highlighted in bold. Normal comments beginning with '--' alone are 'normal' comments and do not indicate anything's missing! The ???'s signal that something's missing in the program. There is generally one of these comments per line of code missing although you will need to add SEQ statements and correct the indentation as demanded by occam syntax. Additional information is given in the code where necessary to aid you. The programs will not compile as is although they could without all the missing code being inserted, they just won't work correctly! The program should eventually function correctly to get the full marks. You will need to understand the structure of the program from consideration of the DFD and existing code and use your (growing) knowledge of occam and message passing methods to get the program working properly. A reasonable starting point would be to get 'simulate.pads' implemented. It may also be a useful strategy to use separate test programs to independently test some processes outside of the main Car Park code. 30 marks 3. A lter the entrance.gate process so that a car driver will patiently wait 10 seconds at an entrance gate if the car park is full before driving off disappointed– if a car exits in the meantime they are allowed in. More cars should not arrive at this gate whilst waiting (the program does not implement queuing and you're not expected to add it!). 5 marks Page 2 MAPS 7873 Assignment 3 4. A dd functionality that provides random arrival and exit of cars at a suitable maximum interval (e.g. between 5 and 10 seconds) in addition to keyboard input. 5 marks 5. F or extra marks, show cars parking randomly in unoccupied parking slots in the car park. You are not expected to animate the cars moving from entrance gate to a parking slot, but simply show the legend 'CAR' appearing in a space (see below). Cars chosen to exit the car park (these should also be chosen randomly) should be removed (deleted in fact, overwritten with '...') from that parking place. You will need to add a data structure that records each parking place’s location and status. To make this a little easier implement a reduced version of this scheme using just one (regular shaped) area of the car park (e.g. see layout below). 8 marks The graphical car park layout is as follows(showing some 'parked' cars): ___________________ ___________________ |... ... ... exit 2 ... ... CAR| |... ... ... ... ... ...| |... ... ... CAR CAR ...| |... ... ... ... ... CAR| |... ... ... CAR ... ...| |... ... ... CAR ... ...| selected random parking zone for Task 5. (18 places) exit 1 exit 3 |... ... ... ... ...| |... ... ... ... ...| |... ... ... ... ...| |... ... ... ... ...| |... ... ... ... ...| |... ... ... ... ...| |_____Gate A______________________Gate B____| The DFD The data flow diagram should be deduced from this extract from the main process (with constants inserted); the process names are in bold: PROC simulate.car.park (CHAN OF BYTE keyb?, screen!, sink!) [2] [2] [3] [3] CHAN CHAN CHAN CHAN OF OF OF OF BYTE BOOL BOOL BYTE car.arrived, pad.in: request.space, open.gate: car.left, pad.out: screens: PAR PAR i=0 FOR 2 -- entrances PAR entrance.pad (pad.in[i]?, car.arrived[i]!) entrance.gate (car.arrived[i]?,request.space[i]!,open.gate[i]?,screens[i]!) PAR i=0 FOR 3 -- exits exit.pad (pad.out [i]?, car.left [i]!) car.park.control (request.space?,open.gate!,car.left?,screens[entrances]!) Page 3 MAPS 7873 Assignment 3 simulate.pads (pad.in!, pad.out!, keyb?) screen.handler (screens?, screen!) : Notes 1. The input library call that is generally employed to get characters from the keyboard: in.skip (keypress,keyb) can often be replaced by a rather more direct input from the keyboard: keyb ? keypress where keyb ? is the channel in the main process connected to the keyboard, and keypress is a BYTE variable. 2. Input from a keyboard is in ASCII (character) form, hence typing numbers such as 0 or 1 actually returns '0' and '1' which have decimal values 48 and 49! Hence if you wish to use '0' and '1' as integers, array indices or similar they must be converted by subtracting 48 from them. This can be done as follows, assuming the variable 'key' contains the character '0', '1', '2' (up to '9' in fact): INT index: VAL BYTE zero.char IS '0': -- ASCII '0' = 48 but this is more obvious SEQ index := INT (key - zero.char) -- convert from ASCII some.array [index] := foo -- can now use to index an array (Nb. this method will not work with multi-digit numbers!) Note also the use of the INT to retype the (key - zero.char) from BYTE type to INTeger for use as an array index. Page 4 MAPS 7873 Assignment 3 2. The Super-Scalar Processor Simulator Tasks 30 Marks You should develop an occam program that simulates a simple dual-pipeline processor. The program should generate a constant stream of ‘instructions’ which are fed to one of two execution pipelines, as depicted below: display generated instruction on the console Generate instructions randomly Each is either 1, 2 or 3 'Q' from keyboard terminates The program should only terminate when you enter a ‘Q’ or 'q' at the keyboard. To keep the program simple this only need terminate the process that is generating the instructions, and does not need to be propagated to the other running processes (these will subsequently 'crash' - most left pipeline probably due to the dreaded deadlock!). dispatcher right pipeline Delay by 1,2, Each 'instruction' should be generated randomly and or 3 time each should simply be represented as a number, units either a '1', a '2' or a '3', and echoed to the console display. This number simply indicates how long the instruction will take to execute in a pipeline. This means that if a ‘3’ instruction is in the left hand pipeline, the right-hand pipeline could potentially execute three ‘1’ instructions during the same time period. The execution ‘hardware’ (process) will be delayed 1, 2 or 3 time units depending on the instruction it has dispatched to it (there is no real execution going on in this simulation). Instructions should be dispatched to the first execution pipeline (left or right) that has finished ‘executing’ its current instruction, or non-deterministically if they are both free. You will need the occam ALT construct to provide this and other key features of the program. Delay by 1,2, or 3 time units retire instructions display retired instructions on console (in-order) or (OOO) The retirement ‘hardware’ (process) simply displays the instruction number 1, 2, or 3, on the screen. You could develop the program using just these requirements to begin with, and this would be a sort of OOO (out-of-order) processor as you’re not guaranteed that the order of arrival of instructions is the same as retirement. However, there is a major constraint in that the instructions must be displayed (retired) in the order they were originally generated. Hence, you will need to number (or otherwise tag) the generated instructions sequentially and communicate this somehow through the system so that the retirement hardware can hold up one of the pipelines when it needs to wait for the correct next instruction in sequence to come through the other (that is, synchronise them). The output can be simple messages to the console, however, extra credit will be given if a simple graphical simulation/depiction of instructions being generated and Page 5 MAPS 7873 Assignment 3 dispatched to the left or right pipelines, and showing them coming out of the retirement process in the correct (or out-of) order, is provided. esign a DFD for the processor program evelop a simple ‘out-of-order’ simulation program in occam evelop the ‘in-order’ simulation fully raphical simulation D 2 marks D 10 marks D 10 marks G 8 marks Code Documentation As always, to obtain full marks your code should be well commented, well-structured and understandable. BEER PRIZE of sorts If you are still thirsting for more - and I couldn't blame you! - consider how you would propagate the termination signal through the processor so that all of the processes halt gracefully. A few IF statements and adopting the number '9' as a halt 'instruction' in the pipeline and retirement processes is one possibility. A series of special 'terminate' channels paralleling the other data paths is another (then you will need ALT's!*). If you implement this, I'll buy you a beer (or equivalent)! * This termination problem can be subtly dealt with in occam by using tagged protocols, but this is beyond the scope of this module. Page 6 MAPS 7873 Assignment 3 Car Park Program (with simple console output) INCOMPLETE VERSION -- MAPS Car Park simulation A.Oram 2010 -- INCOMPLETE VERSION FOR MAPS ASSIGNMENT 3 -- This version is simple with single line console outputs. #INCLUDE "course.module" -- I/O library --------------- Constants etc ------------------------------------- This car park has only 5 spaces available, 2 entrances and 3 exits ------VAL num.spaces IS 5: -- Change this as desired VAL entrances IS 2: -- Entrances are identified as 'A', 'B' VAL exits IS 3: -- Exits identified as 0,1,2 --------------- Processes --------------------------------------PROC show.spaces.remaining (VAL INT car.count, CHAN OF BYTE screen!) SEQ IF car.count < num.spaces SEQ out.string ("Spaces = ",0,screen) out.int (num.spaces-car.count,0, screen) out.ch ('*n',0,screen) TRUE out.string ("Car park is FULL*n",0,screen) : ------------------------------------------------------------------------PROC entrance.pad (CHAN OF BYTE pad.in?, car.detected!) BYTE pad.id: -- ??? SEQ pad.in ? pad.id car.detected ! pad.id : -------------------------------------------------------PROC entrance.gate (CHAN OF BYTE -- ???, CHAN OF BOOL request.space!, open.up?, CHAN OF BYTE screen!) BYTE gate.id: BOOL answer: VAL BOOL yes IS TRUE: VAL BOOL any.space IS TRUE: -- ??? SEQ car.detected ? gate.id -- wait for a car to arrive at gate out.string ("Car at Gate ",0,screen) -- car has arrived out.ch (gate.id /\ #DF,0, screen) -- (force gate id to uppercase) out.string ("*n",0,screen) -- ??? ask controller if there's free space -- ??? get a response from controller IF -- ??? there's space SEQ out.string ("Gate ",0,screen) -- "open" the gate here out.ch (gate.id /\ #DF,0, screen) out.string (" open*n",0,screen) -- ??? no space left! Leave gate closed SKIP : Page 7 MAPS 7873 Assignment 3 --------------------------------------------------------------PROC exit.pad (CHAN OF BOOL pad.out?, car.detected!) BOOL car.left: -- ??? pad.out ? car.left car.detected ! car.left : ---------------------------------------------------------------PROC car.park.control ([]CHAN OF BOOL -- ???, []CHAN OF BOOL open.gate!, car.left?, CHAN OF BYTE screen!) INT num.cars.parked: VAL welcome IS TRUE: VAL sorry...full IS FALSE: BOOL request.space: BOOL car.has.left: SEQ num.cars.parked := 0 -- initialise car counter -- ??? park is 24/7 ! -- ??? deal with cars coming and going -- deal with cars wanting to get in --------------------------------ALT i = 0 FOR entrances -- ??? -- ??? car detected and there's space, let 'em in SEQ open.gate[i] ! welcome num.cars.parked := num.cars.parked + 1 out.string ("Car entered car park...*n",0,screen) -- ??? car detected but we're full, turn them away SEQ open.gate[i] ! sorry...full out.string ("FULL - Car refused entry...*n",0,screen) -- deal with cars leaving ------------------------------------------ALT i = 0 FOR exits -- ??? -- ??? a car has left the car park SEQ num.cars.parked := num.cars.parked - 1 out.string ("Car left car park...*n",0,screen) -- ??? a non-existent parked car is trying to leave! out.string ("Impossible! Car park is empty!*n",0,screen) -- after dealing with each entry/exit update the 'spaces' display ----show.spaces.remaining (num.cars.parked,screen) : Page 8 MAPS 7873 Assignment 3 ---------------------------------------------------------------------PROC simulate.pads ([]CHAN OF BYTE pad.in!, []CHAN OF BOOL pad.out!, CHAN OF BYTE keyb?) BYTE key: INT id: VAL BYTE zero.char -- ???: VAL entranceA IS 0: -- useful constants for indexing the channels VAL entranceB IS 1: -- ??? SEQ -- ??? Input a key from the keyboard - use variable 'key' -- ??? When 'A' or 'a' is entered -- ??? tell entrance A that a car has arrived -- ??? When 'B' or 'b' is entered -- ??? tell entrance B that a car has arrived -- ??? When '0', '1', or '2' is entered -- ??? tell exit pad at exit [0], exit [1] or exit [2] as appropriate that -- ??? car has exitted. -- ??? If any other key has been pressed, ignore it. : -----------------------------------------------------------------------PROC screen.handler ([]CHAN OF BYTE screen.channels, CHAN OF BYTE screen) BYTE data: WHILE TRUE ALT i = 0 FOR SIZE screen.channels screen.channels [i]? data screen ! data : ------------- CAR PARK main process here! -------------------------------------PROC simulate.car.park (CHAN OF BYTE keyb?, screen!, sink!) VAL []BYTE instructions IS "Use *'A*', *'B*' to indicate car arrivals.*nUse *'0*', *'1*' or *'2*' to indicate car departures.*n": [entrances] CHAN OF BYTE car.arrived, pad.in: [entrances] CHAN OF BOOL request.space, open.gate: [exits] CHAN OF BOOL car.left, pad.out: [entrances+1] CHAN OF BYTE screens: -- the +1 extra channel is for the controller! SEQ -- initialise everything and draw car park erase.screen (screen) out.string ("Simple Car Park Simulator (A,Oram 2010)*n",0, screen) out.string (instructions,0,screen) show.spaces.remaining (0,screen) out.ch (FLUSH,0,screen) -- ensure it displays -- now kick everything off in parallel! PAR PAR i=0 FOR entrances PAR entrance.pad (pad.in[i]?, car.arrived[i]!) entrance.gate (car.arrived[i]?, request.space[i]!, open.gate[i]?, screens[i]!) PAR i=0 FOR exits exit.pad (pad.out [i]?, car.left [i]!) car.park.control (request.space?, open.gate!, car.left?, screens[entrances]!) --------------- now the simulated pads and screen handler -------simulate.pads (pad.in!, pad.out!, keyb?) screen.handler (screens?, screen!) : Page 9 MAPS 7873 Assignment 3 Screen dumps whilst running the simple car park simulator Page 10 MAPS 7873 Assignment 3 Car Park Program (with graphical simulation) INCOMPLETE VERSION ----------------------- MAPS Car Park simulation A.Oram 2010 INCOMPLETE VERSION FOR MAPS ASSIGNMENT 3 This version uses more graphical simulation output. The number of exits and entrances are fixed. The car park looks like this: ___________________ ___________________ |... ... ... exit 2 ... ... ...| |... ... ... ... ... ...| |... ... ... ... ... ...| |... ... ... ... ... ...| |... ... ... ... ... ...| |... ... ... ... ... ...| exit 1 exit 3 |... ... ... ... ...| |... ... ... ... ...| |... ... ... ... ...| |... ... ... ... ...| |... ... ... ... ...| |... ... ... ... ...| |_____Gate A______________________Gate B____| #INCLUDE "course.module" -- I/O library --------------- Constants etc ------------------------------------------------VAL INT one.sec IS 500000: -- reduce this to speed things up! Nb 1,000,000 = 1 sec ---- This car park has 55 spaces available, 2 entrances and 3 exits ----------VAL num.spaces IS 5: -- Change this as desired for testing VAL entrances IS 2: -- Entrances are identified as 'A' and 'B' VAL exits IS 3: -- Exits identified as 1,2,3 VAL carpark IS [" ___________________ ___________________ ", "|... ... ... ... ... ...|", "|... ... ... ... ...|", "|_____Gate A______________________Gate B____|"]: places VAL VAL VAL VAL BYTE BYTE BYTE BYTE top IS 5: left IS 10: bottom IS 16: right IS 45: ----- y x y x ----- layout of car park need six of these lines need six of these lines ...'s indicate parking coord of top left corner of park coord dimension of car park dimension -- set up positions of entrances and exits VAL exit.pos IS [[left,top+7],[left+21,top+3],[left+44,top+7]]: VAL gates IS [[left+8,top+bottom],[left+36,top+bottom]]: -------------- Other constants --------------------------------------------VAL INT x IS 0: -- to distinguish coordinates in the array structures VAL INT y IS 1: VAL INT D1 IS 1: -- movement increments for animation VAL INT D0 IS 0: Page 11 MAPS 7873 Assignment 3 --------------- Screen and general purpose processes ----------------------PROC delay (VAL INT seconds) TIMER time: INT now: SEQ time ? now time ? AFTER now PLUS (seconds * one.sec) : ---------------------------------------------------------------------------PROC show.car.park.layout (CHAN OF BYTE screen) SEQ cursor.x.y (left,top,screen) -- library call out.string (carpark[0],0, screen) -- library call SEQ i = 1 FOR 6 -- draw top half of carpark BYTE ib: SEQ ib := BYTE i cursor.x.y (left,top+ib,screen) out.string (carpark[1],0,screen) SEQ i = 9 FOR 6 -- draw bottom half of carpark BYTE ib: SEQ ib := BYTE i cursor.x.y (left,top+ib,screen) out.string (carpark[2],0,screen) cursor.x.y (left,top+15,screen) out.string (carpark[3],0,screen) : ----------------------------------------------------------------PROC show.spaces.remaining (VAL INT car.count, CHAN OF BYTE screen!) SEQ cursor.x.y (left + 17, top+bottom,screen) IF car.count < num.spaces SEQ out.string ("Spaces = ",0,screen) out.int (num.spaces-car.count,0, screen) TRUE out.string (" FULL ",0,screen) : ----------------------------------------------------------------PROC out.string.x.y (VAL []BYTE string, VAL BYTE x,y, CHAN OF BYTE screen!) SEQ cursor.x.y (x,y,screen) -- library call out.string (string,0,screen) -- library call : ----------------------------------------------------------------PROC show.status (VAL []BYTE message, CHAN OF BYTE screen!) SEQ cursor.x.y (22,3, screen) -- library call erase.eol (screen) -- library call out.string (message,0,screen) -- library call : ----------------------------------------------------------------PROC show.car.x.y (VAL BYTE x,y, CHAN OF BYTE screen!) SEQ cursor.x.y (x,y,screen) out.string ("CAR",0,screen) cursor.x.y (1,1,screen) out.ch (FLUSH,0, screen) -- library call : Page 12 MAPS 7873 Assignment 3 -----------------------------------------------------------------PROC clear.car.x.y (VAL BYTE x,y, CHAN OF BYTE screen!) SEQ cursor.x.y (x,y,screen) out.string (" ",0,screen) cursor.x.y (1,1,screen) out.ch (FLUSH,0, screen) : -----------------------------------------------------------------PROC animate.car (VAL BYTE start.x,start.y, VAL INT delta.x, delta.y, VAL INT distance, CHAN OF BYTE screen) -- Set 'delta.x' to positive value to move right, negative value to move left. -- Set 'delta.y' to positive value to move down, negative value to move up. -- The value set will be the number of screen positions moved, so '1', '-1' -- or '0' (no move in that orientation) will be normal. -- 'distance' is the number of 'delta's to move. BYTE next.x, next.y: SEQ next.x := start.x next.y := start.y SEQ i = 1 FOR distance -- move this number of times SEQ show.car.x.y (next.x, next.y,screen) delay (1) -- leave on screen for a short period clear.car.x.y (next.x, next.y,screen) IF delta.x < 0 next.x := next.x - (BYTE (-delta.x)) TRUE next.x := next.x + (BYTE (delta.x)) IF delta.y < 0 next.y := next.y - (BYTE (-delta.y)) TRUE next.y := next.y + (BYTE (delta.y)) show.car.x.y (next.x, next.y, screen) -- leave car on screen : -----------------------------------------------------------------------------PROC show.car.leaving (VAL INT exit.num, CHAN OF BYTE screen) INT Dx,Dy: VAL INT steps IS 4: -- number of positions to move car through exit SEQ Dx := 0 Dy := 0 CASE exit.num -- set up movement direction depending on where exit is 0 Dx := -1 1 Dy := -1 2 Dx := 1 ELSE SKIP animate.car (exit.pos[exit.num][x],exit.pos[exit.num][y],Dx,Dy,steps,screen) Dx := (INT (exit.pos[exit.num][x])) + (steps*Dx) -- locate end point of Dy := (INT (exit.pos[exit.num][y])) + (steps*Dy) -- movement so we can clear.car.x.y (BYTE Dx,BYTE Dy,screen) -- clear it from the screen : Page 13 MAPS 7873 Assignment 3 -------------------- These are the car park processes ------------------------PROC entrance.pad (CHAN OF BYTE pad.in?, car.detected!) BYTE pad.id: -- ??? SEQ pad.in ? pad.id car.detected ! pad.id : -------------------------------------------------------PROC entrance.gate (CHAN OF BYTE -- ???, CHAN OF BOOL request.space!, open.up?, CHAN OF BYTE screen!) BYTE gate.id: INT gate.num: BOOL answer: VAL BOOL yes IS TRUE: VAL BOOL any.space IS TRUE: VAL BYTE char.A IS 'A': -- ??? SEQ car.detected ? gate.id -- wait for a car to arrive at gate gate.id := gate.id /\ #DF -- convert gate id to upper case gate.num := INT (gate.id - char.A) -- and then convert to 0 or 1 animate.car (gates[gate.num][x],gates[gate.num][y]+4,D0,-D1,4,screen) delay (3) -- show car at gate briefly -- ??? ask controller if there's free space -- ??? get a response from controller IF -- ??? there's space SEQ -- move car through the gate clear.car.x.y (gates[gate.num][x],gates[gate.num][y],screen) show.car.x.y (gates[gate.num][x],gates[gate.num][y]-2,screen) delay (3) -- "close" the gate after a short delay -- 'park' the car by clearing it from screen clear.car.x.y (gates[gate.num][x],gates[gate.num][y]-2,screen) -- ??? no space left! Leave gate closed and make car go away! SEQ animate.car (gates[gate.num][x],gates[gate.num][y],D0,D1,4,screen) clear.car.x.y (gates[gate.num][x],gates[gate.num][y]+3,screen) : --------------------------------------------------------------PROC exit.pad (CHAN OF BOOL pad.out?, car.detected!) BOOL car.left: -- ??? pad.out ? car.left car.detected ! car.left : Page 14 MAPS 7873 Assignment 3 ---------------------------------------------------------------PROC car.park.control ([]CHAN OF BOOL -- ???, []CHAN OF BOOL open.gate!, car.left?, CHAN OF BYTE screen!) INT num.cars.parked: VAL welcome IS TRUE: VAL sorry...full IS FALSE: BOOL request.space: BOOL car.has.left: SEQ num.cars.parked := 0 -- initialise car counter -- ??? park is 24/7 ! -- ??? deal with cars coming and going -- deal with cars wanting to get in --------------------------------ALT i = 0 FOR entrances -- ??? -- ??? car detected and there's space, let 'em in SEQ -- car detected and there's space, let 'em in open.gate[i] ! welcome num.cars.parked := num.cars.parked + 1 show.status ("Car entered car park...",screen) -- ??? car detected but we're full, turn them away SEQ -- car detected but we're full, turn them away open.gate[i] ! sorry...full show.status ("FULL - Car refused entry...",screen) -- deal with cars leaving ------------------------------------------ALT i = 0 FOR exits -- ??? -- ??? a car has left the car park SEQ num.cars.parked := num.cars.parked - 1 show.status ("Car left car park...",screen) show.car.leaving (i, screen) -- ??? a non-existent parked car is trying to leave! show.status ("Impossible! Car park is empty!",screen) -- after dealing with each entry/exit update the 'spaces' display ----show.spaces.remaining (num.cars.parked,screen) cursor.x.y (1,1,screen) -- park cursor (no pun intended) top,left corner out.ch (FLUSH,0,screen) -- make it all appear! : ---------------------------------------------------------------------PROC simulate.pads ([]CHAN OF BYTE pad.in!, []CHAN OF BOOL pad.out!, CHAN OF BYTE keyb?) BYTE key: INT id: VAL BYTE zero.char -- ???: VAL entranceA IS 0: -- useful constants for indexing the channels VAL entranceB IS 1: -- ??? SEQ -- ??? Input a key from the keyboard - use variable 'key' -- ??? When 'A' or 'a' is entered -- ??? tell entrance A that a car has arrived -- ??? When 'B' or 'b' is entered -- ??? tell entrance B that a car has arrived -- ??? When '0', '1', or '2' is entered -- ??? tell exit pad at exit [0], exit [1] or exit [2] as appropriate that -- ??? car has exitted. -- ??? If any other key has been pressed, ignore it. : Page 15 MAPS 7873 Assignment 3 -----------------------------------------------------------------------PROC screen.handler ([]CHAN OF BYTE screen.channels, CHAN OF BYTE screen) BYTE data: WHILE TRUE ALT i = 0 FOR SIZE screen.channels screen.channels [i]? data screen ! data : ------------- CAR PARK main process here! -------------------------------------PROC simulate.car.park (CHAN OF BYTE keyb?, screen!, sink!) VAL []BYTE instructions IS "Arrive: *'A*',*'B*' Depart: *'1*',*'2*'*'3*'": [entrances] CHAN OF BYTE car.arrived, pad.in: [entrances] CHAN OF BOOL request.space, open.gate: [exits] CHAN OF BOOL car.left, pad.out: [entrances+1] CHAN OF BYTE screens: -- the +1 extra screen channel is for the controller! SEQ -- initialise everything and draw car park erase.screen (screen) out.string.x.y ("CAR PARK SIMULATOR (A.Oram 2010)",22,1,screen) out.string.x.y (instructions,15,2,screen) show.car.park.layout (screen) show.spaces.remaining (0,screen) cursor.x.y (1,1,screen) -- park (!) cursor in top left corner out.ch (FLUSH,0,screen) -- ensure it displays -- now kick everything off in parallel! PAR PAR i=0 FOR entrances PAR entrance.pad (pad.in[i]?, car.arrived[i]!) entrance.gate (car.arrived[i]?,request.space[i]!,open.gate[i]?,screens[i]!) PAR i=0 FOR exits exit.pad (pad.out [i]?, car.left [i]!) car.park.control (request.space?,open.gate!,car.left?,screens[entrances]!) --------------- now the simulated pads and screen handler -------simulate.pads (pad.in!, pad.out!, keyb?) screen.handler (screens?, screen!) : Screen dump whilst running the graphical car park simulator Page 16 MAPS 7873 Assignment 3 Page 17