//Mmprgn.bcpl // 9 May 1983 get "mdecl.d" get "mcommon.d" external [ // OS Resets; Puts; Closes; DoubleAdd; SetBlock; Zero // MIDAS MidasSwat; Initialized // MASM Wss; @WssCSS; PutsCSS; RepPuts; StrSize; DummyCall @MBlock; VUsc; MoveLongField; SelfRel // MOVERLAY OverlayZone // MIOC DWns; Wns; SimpleTexttoDVec; GenlTexttoDVec; DataToStream // MSYM EvalAText; SearchBlocks // MTXTBUF InputTextBuffer; InputStream // MDISP Blink; DisplayOff // MRGN RegionTable // MMENU CreateAction; MarkMenus; FormMenu; LookUpMenu @WsMarkA; WssMAct; @ItemV; ItemStream // MCMD WnsCSS; CmdCommentStream; ErrorAbort // xxACTIONS BugAddrAct; BugValAct; Plus1Act; Minus1Act; ColumnAct OctAct; DecAct; HexAct; SearchAct; SymbolicAct; NumericAct BadAText; @LongOne // Machine interface MGetRegData; MGetMemData; MPutRegData; MPutMemData; HWEveryTime @REGFORMS; @REGWID; @REGCON; AltRForms; AltRInput; @ScreenWidth @MEMFORMS; @MEMWID; @MEMCON; AltMForms; AltMInput; @MEMNAM; @MEMLEN HWShowAddr; HWAlwaysUpdate; @VirtualP // Defined here UpdateMPDValues; MPDdeSelect; ShowAddr; RDatatoCSS; MDatatoCSS GetRadix; BadAltIn; MPDMChange // Defined here for init and MMPRGNOV only MPDs; @MPDVVec; MPDEveryTime; FirstMPD; LastMPD SetAddr; SetValue; StepAddr; FormMPDmenu; FixForm ] static [ MPDs; @MPDVVec; FirstMPD = 0; LastMPD ] //HOW NAME-VALUE MENU UPDATING WORKS //SetAddr and StepAddr actions put new items on the display, obtaining //the value by calling MGetRegData or MGetMemData (except during Init0 //MGetxx are not called). These and actions which modify display mode //or menu for an MPD set RebuildText true. //Subsequently, UpdateMPDValues() updates all values displayed. If an MPD //menu changes because a new value is different, RebuildText is set true //in MPD. UpdateMPDValues should be called by machine-dependent Init2, //after it is prepared to deliver values, and at other times when displayed //values might be wrong, such as after step or go. //DriverLoop calls MPDEveryTime() each time around to rebuild any MPD //menus which have changed. MPDEveryTime will do this for any MPD menu //with RebuiltText true. Subsequently, DriverLoop calls UpdateDisplay() //to build bit buffers. //When command files are in execution, MPDEveryTime is not called unless //the display is on. When overlays are loaded the MPD display area is //blank; MPDEveryTime checks for this case and defers screen rebuilding //until the display is rebuilt by ReUseDispSpace(). //Update all values that are on the display, setting the RebuildText //flag in the MPD structure, if display update required. let UpdateMPDValues(AlwaysOnly; numargs NA) be [ if NA eq 0 then AlwaysOnly = false let Val = vec ValSize for Rn = FirstMPD to LastMPD do [ let MPD = RegionTable!Rn let MenuMode = MPD>>MPD.MDFS.MenuMode if MenuMode ne 0 do //If not idle... [ if AlwaysOnly then unless MPD>>MPD.AlwaysUpdate ne 0 do loop let V = lv MPD>>MPD.Value MBlock(Val,V,ValSize) let MGet = MPD>>MPD.AVal.TypeStorage eq RegTypeStorage ? MGetRegData,MGetMemData //Make sure that the "*" or "&" preliminary character remains for //AlwaysOnly updates. //The MGet procedure returns false iff the hardware cannot deliver the //value now for some reason (e.g., machine running). let Prelim = 0 test MGet(MPD>>MPD.AVal.X,V,lv MPD>>MPD.AVal.Addr, MPD>>MPD.Extension) ifso [ if VUsc(Val,V,ValSize) ne 0 then [ Prelim = 2 if MenuMode eq StandardMenu then MPD>>MPD.RebuildText = 1 ] ] ifnot Prelim = 1 if Prelim ne MPD>>MPD.Prelim do [ if AlwaysOnly & (Prelim < 2) & (MPD>>MPD.Prelim ge 2) then loop MPD>>MPD.RebuildText = 1 MPD>>MPD.Prelim = Prelim ] ] ] ] and MPDEveryTime(nil,BuildingDisplay; numargs NA) be [ if (NA le 1) & (OverlayZone ne 0) then return HWEveryTime() for Rn = FirstMPD to LastMPD do [ let MPD = RegionTable!Rn if MPD>>MPD.RebuildText ne 0 do [ FormMenu(MPD,FormMPDmenu); MPD>>MPD.RebuildText = 0 ] ] ] and WssFA(Action,BlankSpace) be [ Wss(ItemStream,Action>>Action.Name) RepPuts(ItemStream,$ ,BlankSpace); MarkMenus(Action) ] and FormMPDmenu(S,MPD) be [ let BlankSpace = MPD>>MPD.TextSpace let X = MPD>>MPD.AVal.X let Radix = GetRadix(MPD) let DisplayMode = MPD>>MPD.AVal.DisplayMode let Action = 0 switchon MPD>>MPD.MDFS.MenuMode into [ case 0: //Idle Puts(S,$ ); MarkMenus(0); RepPuts(S,$ ,BlankSpace-1) MarkMenus(BugAddrAct); return case RadixMenu: //Two of "Oct", "Dec", and "Hex" WsMarkA((Radix eq 8 ? DecAct,OctAct)) WssFA((Radix eq 16 ? DecAct,HexAct),BlankSpace-7); return case DisplayModeMenu: //Two of "Num", "Search", and "Sym" WsMarkA((DisplayMode eq 0 ? SearchAct,NumericAct)) WssFA((DisplayMode eq 2 ? SearchAct,SymbolicAct), BlankSpace-(DisplayMode eq 1 ? 7,10)) return case FillCMenu: //"FillC" WssFA(ColumnAct,BlankSpace-5); return case AddressMenu: //"A+1","A-1" if MPD>>MPD.AVal.TypeStorage eq MemTypeStorage do [ let Last = vec 1; Last!0 = -1; Last!1 = -1 DoubleAdd(Last,MEMLEN+X+X) if VUsc(Last,lv MPD>>MPD.AVal.Addr,2) > 0 do [ BlankSpace = BlankSpace-3; Action = Plus1Act ] if VUsc(lv MPD>>MPD.AVal.Addr,LongOne,2) ge 0 do [ if Action ne 0 then WsMarkA(Action) BlankSpace = BlankSpace-4; Action = Minus1Act ] WssFA(Action,BlankSpace); return ] default: endcase //StandardMenu ] //Normal picture--print "~" if value unknown else "*" if different //from last time. Puts(S,table [ $ ; $~; $**; $& ] ! (MPD>>MPD.Prelim)) MarkMenus(0) BlankSpace = BlankSpace-1 //Show name if MPD>>MPD.NoName eq 0 then Wss(S,lv MPD>>MPD.AVal.SName) let Form,Width = nil,nil test MPD>>MPD.AVal.TypeStorage eq RegTypeStorage ifso [ Form,Width = REGFORMS!X,REGWID!X ] //Show offset for memory names and addresses //**Would like to allow separate address and value radices here ifnot [ if MPD>>MPD.NoName eq 0 do [ let ARadix = nil test MPD>>MPD.AVal.Sign eq 0 ifso //Unsigned [ Puts(S,$ ); ARadix = Radix //Unsigned ] ifnot ARadix = -Radix //Signed DWns(S,lv MPD>>MPD.AVal.Offset,32,0,ARadix,1,0) ] Form,Width = MEMFORMS!X,MEMWID!X ] //Select correct form for items with extensions Form = FixForm(Form,MPD>>MPD.Extension) //Show value Resets(MPDs) let AVec,Value = vec 1,lv MPD>>MPD.Value switchon DisplayMode into [ //Convert SearchBlocks to numeric if absolute mode case 1: if VirtualP do [ Zero(AVec,2); MoveLongField(Value,0,Width,AVec,32-Width) SearchBlocks(MPDs,Form!-1,AVec,-1,0,Radix,#177); endcase ] default: DataToStream(MPDs,Form,Width,Value,Radix) endcase case 2: (rv Form!-2)(MPDs,X,Value,lv MPD>>MPD.AVal.Addr); endcase ] //If the name and value do not fill the text space available, the //code below leaves a null zone no bigger than 2 chars between them. //If the name is less than 5 characters, extra blanks extend the name //up to 5 characters. Any more blanks beyond that extend the value. //If the value overlaps the name, then the name is truncated except that //one character of name is always printed (unless the NoName flag is set, //in which case no name characters are ever printed). let ALim = ItemV!0 //Size of name BlankSpace = BlankSpace - ALim - MPDVVec!0 let VStart = 1 //If overlap, flush any leading 0's or blanks in the value. while (BlankSpace < 0) & (VStart < MPDVVec!0) & ((MPDVVec!VStart eq $*S) % (MPDVVec!VStart eq $0)) do [ VStart = VStart+1; BlankSpace = BlankSpace+1 ] if BlankSpace < 0 do //Overlap? [ ALim = ALim + BlankSpace //Then truncate name BlankSpace = 0 if ALim < 0 do //Name completely overlapped? [ VStart = 1 - ALim; ALim = 0 ] ] if MPD>>MPD.NoName eq 0 do //Extend name up to 5 chars [ if ALim le 0 do [ ALim = 1; VStart = VStart+1 ] while (BlankSpace > 2) & (ALim < 5) do [ Puts(S,$ ); BlankSpace = BlankSpace-1; ALim = ALim+1 ] ItemV!0 = ALim; MarkMenus(BugAddrAct) if BlankSpace > 0 do //But leave gap if possible //2 char gap if value big enough [ Puts(S,$ ); BlankSpace = BlankSpace-1 if (BlankSpace > 0) & ((MPDVVec!0 + BlankSpace) ge 5) do [ Puts(S,$ ); BlankSpace = BlankSpace-1 ] MarkMenus(0) ] ] RepPuts(S,$ ,BlankSpace) //Rest of blanks extend value for I = VStart to MPDVVec!0 do Puts(S,MPDVVec!I) MarkMenus(BugValAct) ] //Called from MenuMChange //Since the buttons may not go down and up concurrently, show the menu //appropriate for MBunion until all mouse buttons go up and then switch //to the menu for all mouse buttons up. When the mouse buttons go up, //DoAction will be called before the menu change occurs. and MPDMChange(lvTable,MPD,MBunion,MB) be [ if MB eq 0 then MBunion = 0 let MTable = SelfRel(rv lvTable) let NewMode = MTable!MBunion let MenuMode = MPD>>MPD.MDFS.MenuMode if MenuMode ne 0 then if MenuMode ne NewMode do [ MPD>>MPD.MDFS.MenuMode = NewMode; MPD>>MPD.RebuildText = true ] ] and MPDdeSelect(MPD) be [ if MPD>>MPD.MDFS.MenuMode > StandardMenu do [ MPD>>MPD.MDFS.MenuMode = StandardMenu MPD>>MPD.RebuildText = true ] ] and SetValue(nil,MBunion,MPD) be [ let X = MPD>>MPD.AVal.X //RegX or MemX //A little tricky: Some methods of setting the value modify the existing //value, so the call to TextToData below must pass the existing value as an //argument. However, cannot pass lv MPD>>MPD.Value directly because a //read-only register's current value will be smashed by TextToData prior //to the call on MPutMemData. Hence, copy current value into VValue first. let VValue = vec ValSize MBlock(VValue,lv MPD>>MPD.Value,ValSize) let Addr = lv MPD>>MPD.AVal.Addr let Con,Form,Width,AltIn,AltOut,MPut = nil,nil,nil,nil,nil,nil test MPD>>MPD.AVal.TypeStorage eq RegTypeStorage ifso [ Form,Width = REGFORMS!X,REGWID!X AltIn,AltOut = AltRInput,AltRForms Con,MPut,Addr = REGCON,MPutRegData,0 ] ifnot [ Form,Width = MEMFORMS!X,MEMWID!X AltIn,AltOut = AltMInput,AltMForms Con,MPut = MEMCON,MPutMemData ] let Radix,Extension = GetRadix(MPD),MPD>>MPD.Extension Form = FixForm(Form,Extension) switchon MBunion into [ case TopButton: //Value←InputTextBuffer unless (Form eq 0 ? SimpleTexttoDVec(InputTextBuffer,Width,VValue,Radix), GenlTexttoDVec(InputTextBuffer,Form,VValue,Radix)) do [ MBlock(VValue,lv MPD>>MPD.Value,ValSize) DummyCall(AltIn!X,X,Addr,VValue,InputTextBuffer,Radix) ] MPut(X,VValue,Addr,Extension) //Pretty-print the new value when appropriate. if DisplayOff % (MPD>>MPD.Prelim eq 1) % ((Con+X)>>MRType.AutoPrettyPrint eq 0) then return //**The Extension is needed on Dorado Midas for PIPE and ROW. case MiddleButton: //Alternate printout DummyCall(AltOut!X,X,lv MPD>>MPD.Value,Addr, Radix+(Extension lshift 8)) return case BottomButton: //Append to InputTextBuffer DataToStream(InputStream,Form,Width,VValue,Radix); return ] ] and FixForm(Form,Extension) = valof [ if Form eq 0 then resultis 0 if Form!0 ge 0 then resultis Form if Extension ge (-Form!0) then MidasSwat(BadExtension) resultis SelfRel(Form+Extension+1) ] //Alternate input procedure for regs/mems that don't have one and BadAltIn(TV,DVec,Radix) be ErrorAbort() //Pretty-print procedures for registers and memories that don't have //anything special implemented. and RDatatoCSS(RegX,DVec,AVec,ExtRadix) be DataToStream(CmdCommentStream,FixForm(REGFORMS!RegX,ExtRadix<<lh), REGWID!RegX,DVec,ExtRadix<<rh) and MDatatoCSS(MemX,DVec,AVec,ExtRadix) be DataToStream(CmdCommentStream,FixForm(MEMFORMS!MemX,ExtRadix<<lh), MEMWID!MemX,DVec,ExtRadix<<rh) and SetAddr(nil,MBunion,MPD) be [ let X = 1 //Note that the alternate menu actions are handled by MPDMChange, not here if MPD>>MPD.MDFS.MenuMode ne 0 do [ if (MBunion & MiddleButton) ne 0 do [ ShowAddr(lv MPD>>MPD.AVal); return ] ] let Letter,L = MPD>>MPD.MDFS.Letter,MPD>>MPD.MDFS.LineN test InputTextBuffer!0 eq 0 ifso [ MPD>>MPD.MDFS.MenuMode = 0; MPD>>MPD.RebuildText = true ] ifnot [ let AVal = vec size AVal/16 unless EvalAText(InputTextBuffer,lv X,AVal,0) do ErrorAbort() let CON,MGet,Form,X = nil,nil,nil,AVal>>AVal.X test AVal>>AVal.TypeStorage eq MemTypeStorage ifso [ CON,MGet,Form = MEMCON!X,MGetMemData,MEMFORMS!X ] ifnot [ CON,MGet,Form = REGCON!X,MGetRegData,REGFORMS!X ] let LastExtension = (Form ne 0) & (Form!0 < 0) ? -1-Form!0,0 //Fail unless all extensions fit in column unless LookUpMenu(Letter,L+LastExtension) do ErrorAbort("Extensions won't fit") AVal>>AVal.DisplayMode = CON<<MRType.DefMode AVal>>AVal.Radix = CON<<MRType.DefRadix let Extension = 0 [ MBlock(lv MPD>>MPD.AVal,AVal,size AVal/16) MPD>>MPD.AlwaysUpdate = HWAlwaysUpdate(CON,X,lv MPD>>MPD.AVal.Addr) MPD>>MPD.MDFS.MenuMode = StandardMenu //The extension kludge allows items occupying several consecutive lines //in a column to be put on/taken off the display as a unit. However, //MGet/MPut procedures must deal with the component on each line //separately. MPD>>MPD.Extension = Extension MPD>>MPD.NoName = Extension ne 0 MPD>>MPD.Prelim = Initialized ? (MGet(X,lv MPD>>MPD.Value,lv MPD>>MPD.AVal.Addr, Extension) ? 0,1),1 MPD>>MPD.RebuildText = true if Extension eq LastExtension then break Extension = Extension+1 L = L+1 MPD = LookUpMenu(Letter,L) if MPD eq 0 then return ] repeat ] //Flush extensions of the last item overwritten. [ L = L+1 MPD = LookUpMenu(Letter,L) if MPD eq 0 then return if MPD>>MPD.Extension eq 0 then return MPD>>MPD.MDFS.MenuMode = 0 MPD>>MPD.RebuildText = true ] repeat ] //The +1 and -1 menu items only come up when they are legal, but //error checks needed for command files. and StepAddr(lvTable,MBUnion,MPD) be [ if (MPD>>MPD.MDFS.MenuMode ne 0) & (MPD>>MPD.AVal.TypeStorage eq MemTypeStorage) & (MPD>>MPD.Extension eq 0) do [ let AVec,DVec,X = vec 1,vec ValSize,MPD>>MPD.AVal.X MBlock(AVec,lv MPD>>MPD.AVal.Addr,2) DoubleAdd(AVec,(lvTable eq 0 ? LongOne,(rv lvTable)+2)) //Show new address symbolically if possible Resets(InputStream) SearchBlocks(InputStream,X,AVec,-1,true,GetRadix(MPD)) //Update the MPD structure for the new item SetAddr(nil,TopButton,MPD) //Prettyprint its value if the display is on and the value is ok if (not DisplayOff) & (lvTable ne 0) & (MPD>>MPD.Prelim ne 1) & ((MEMCON+X)>>MRType.AutoPrettyPrint ne 0) then SetValue(nil,MiddleButton,MPD) return ] ErrorAbort(BadAText) ] and GetRadix(MPD) = table [ 8; 10; 16; 8 ] ! (MPD>>MPD.AVal.Radix) and ShowAddr(AVal) be [ let X = AVal>>AVal.X test AVal>>AVal.TypeStorage eq RegTypeStorage ifso [ WssCSS("Register "); WnsCSS(X) ] ifnot [ if SearchBlocks(CmdCommentStream,X,lv AVal>>AVal.Addr) do [ WssCSS(" = "); WssCSS(MEMNAM!X) PutsCSS($ ); DWns(CmdCommentStream,lv AVal>>AVal.Addr) ] //HWShowAddr is called to print things such as the cache row and map //entry corresponding to a particular VM address on Dorado. HWShowAddr(X,lv AVal>>AVal.Addr) ] ]