import [balsa.tree] import [balsa.types.basic] public (-- These two types are declared in [balsa.tree] They are listed here for reference only type lcd is record d : 8 bits; dataNctrl : bit end type kbdOp is enumeration star, hash, plus, minus end --) constant ScrollLeftCmd = {0x18, 0} : lcd -- declare as correct type constant ScrollRightCmd = lcd {0x1c, 0} -- or cast to correct type constant CursorLeftCmd = lcd { 0x10, 0} constant CursorRightCmd = lcd {0x14, 0} constant CursonOnCmd = lcd {0x0e, 0} constant CursorOffCmd = lcd {0x0c, 0} constant ClearDisplayCmd = lcd {0x01,0} constant DisplaySPACECmd = lcd {0x20, 1} constant DisplayCOLONCmd = lcd {0x3a, 1} constant DisplayStartAddr = 0xA8 -- The stack description procedure stack ( parameter depth : cardinal; input i : byte; output o : byte; sync pop ) is local variable v : byte begin if depth = 1 then loop select i then v := i | pop then o <- v; v := 0 end end else local channel nextI, nextO : byte sync nextPop begin stack over depth - 1 of nextI, nextO, nextPop || loop select i then nextI <- v; v := i | pop then o <- v; sync nextPop || nextO -> v end end end end end type nybbles is array 2 of nybble -- The calculator description procedure calc_body ( -- first external interfaces input i : nybble; input operator: kbdOp ; output o : lcd ; -- now channel connecting the stack -- make visible to enable procedure sharing output stackPush : byte; input stackPop : byte; sync stackPopAct ) is local variable Acc : nybbles variable DispAddr : byte variable tos : byte variable outDigit : nybble variable firstbit : bit -- Here is a useful procedure to output a single digit shared displayDigit is begin case outDigit of 0..9 then o <- {(nybbles {outDigit, 3} as byte), 1} | 10..15 then o <- {(nybbles {(outDigit - 9 as nybble), 4} as byte),1} end end -- Here is a useful procedure to output a single digit shared cls is begin o <- ClearDisplayCmd ; o <- CursorOffCmd end -- Here is a useful procedure for moving to a "home position" shared home is begin o <- {DispAddr , 0} end shared ScrollLeft is begin o <- ScrollLeftCmd; o <- ScrollLeftCmd; o <- ScrollLeftCmd; DispAddr := ( DispAddr + 3 as byte) end shared ScrollRight is begin o <- ScrollRightCmd; o <- ScrollRightCmd; o <- ScrollRightCmd; DispAddr := (DispAddr - 3 as byte ) end shared display is begin home (); outDigit := Acc[1]; displayDigit (); outDigit := Acc[0]; displayDigit (); o <- DisplayCOLONCmd end shared pushI is begin stackPush <- tos; tos := (Acc as byte); o <- CursorLeftCmd ; o <- DisplaySPACECmd end shared popIntoTos is begin sync stackPopAct || stackPop -> tos end shared clearAcc is begin Acc := {0, 0} end begin cls(); -- This may or may not be what you want depending on your display handling DispAddr := DisplayStartAddr ; ScrollRight() ; display(); firstbit := true; loop select i then if firstbit = true then firstbit := false ; pushI(); ScrollRight(); clearAcc() else firstbit := true end ; Acc[1] := Acc[0]; Acc[0] := i | operator then case operator of plus then Acc := (tos + (Acc as byte) as nybbles); popIntoTos (); ScrollLeft() | minus then Acc := (tos - (Acc as byte) as nybbles); popIntoTos (); ScrollLeft() | hash then pushI () ; ScrollRight() end end; display () end end -- The main calc procedure. DO NOT CHANGE THE CHANNEL INTERFACE procedure calc(input i: nybble; input operator: kbdOp ; output o: lcd) is local channel stackPush, stackPop: byte sync stackPopAct begin stack over 8 of stackPush, stackPop, stackPopAct || calc_body (i, operator, o, stackPush, stackPop, stackPopAct) end