Static variable overflow (bug?)
Below is a slightly more elaborate variant that fixes the current bug in ORG.Put1a and makes MyViewers.Mod (see below) work on a Project Oberon 2013 system: PROCEDURE Put1a(op, a, b, im: LONGINT); VAR r: INTEGER; BEGIN (*same as Put1, but with range test -10000H <= im < 10000H*) IF (im >= -10000H) & (im <= 0FFFFH) THEN Put1(op, a, b, im) ELSIF op = Mov THEN Put1(Mov+U, a, 0, im DIV 10000H); IF im MOD 10000H # 0 THEN Put1(Ior, a, a, im MOD 10000H) END ELSE r := RH; IF b = RH THEN incR END ; Put1(Mov+U, RH, 0, im DIV 10000H); IF im MOD 10000H # 0 THEN Put1(Ior, RH, RH, im MOD 10000H) END ; Put0(op, a, b, RH); IF RH > r THEN DEC(RH) END END END Put1a; Comments: 1. Procedure incR is to be moved up to before procedure ORG.Put0 2. The use of incR ensures that in fact we do have enough registers available 3. Register optimization: But a new register is used only when needed (when b = RH) 4. Instruction optimization: For op = Mov, the extra MOV instruction at the end is avoided ---------------------------------------------------------------------------------------------------------------------- A simple fix to make the program “MyViewer” below work, i.e. to allow variable offsets < 64KB is to fix a bug in the current ORG.Put1a, by changing it From: PROCEDURE Put1a(op, a, b, im: LONGINT); BEGIN (*same as Put1, but with range test -10000H <= im < 10000H*) IF (im >= -10000H) & (im <= 0FFFFH) THEN Put1(op, a, b, im) ELSE Put1(Mov+U, RH, 0, im DIV 10000H); IF im MOD 10000H # 0 THEN Put1(Ior, RH, RH, im MOD 10000H) END ; Put0(op, a, b, RH) END END Put1a; To: PROCEDURE Put1a(op, a, b, im: LONGINT); BEGIN (*same as Put1, but with range test -10000H <= im < 10000H*) IF (im >= -10000H) & (im <= 0FFFFH) THEN Put1(op, a, b, im) ELSE Put1(Mov+U, RH+1, 0, im DIV 10000H); IF im MOD 10000H # 0 THEN Put1(Ior, RH+1, RH+1, im MOD 10000H) END ; Put0(op, a, b, RH+1) END END Put1a; i.e. by replacing RH with RH+1 in the ELSE clause. Note that this is a quick fix which neither checks whether there are in fact enough registers available (as incR does) nor does any register optimization. But it will make the program below work.. --------------------- MODULE MyViewer; (* Test of the menu line of a viewer *) IMPORT Display, Viewers, Oberon, MenuViewers, TextFrames; CONST max = 16377; (* If max >= 16367 the frame name disappears; If max >= 16377 the whole menu line disappears! *) menu = "System.Close System.Copy System.Grow"; TYPE XYframe = POINTER TO XYframeDesc; XYframeDesc = RECORD (Display.FrameDesc) END; VAR bitmap: ARRAY max OF SET; (* with this variable present the menu may remain empty! *) PROCEDURE Restore(F: XYframe); BEGIN Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); Display.ReplConst(Display.black, F.X, F.Y, F.W, F.H, Display.replace); (* clear *) END Restore; PROCEDURE Handle(F: Display.Frame; VAR M: Display.FrameMsg); VAR F1: XYframe; BEGIN CASE F OF XYframe: CASE M OF Oberon.InputMsg: IF M.id = Oberon.track THEN Oberon.DrawMouseArrow(M.X, M.Y) END | Oberon.CopyMsg: Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); NEW(F1); F1^ := F^; M.F := F1 | MenuViewers.ModifyMsg: IF (M.Y # F.Y) OR (M.H # F.H) THEN F.Y := M.Y; F.H := M.H; Restore(F) END END END END Handle; PROCEDURE Open*; VAR F: XYframe; V: Viewers.Viewer; x, y: INTEGER; BEGIN NEW(F); F.handle := Handle; Oberon.AllocateUserViewer(Oberon.Par.vwr.X, x, y); V := MenuViewers.New(TextFrames.NewMenu("MyViewer", menu), F, TextFrames.menuH, x, y) END Open; END MyViewer.
Andreas:
Below is a slightly more elaborate variant that fixes the current bug in ORG.Put1a and makes MyViewers.Mod (see below) work on a Project Oberon 2013 system:
How about CONST LIMIT = 10000H; ULIMIT = 0FFFFH; (* Upper limit = LIMIT -1 = 0FFFFH; *) PROCEDURE Put1a(op, a, b, im: LONGINT); VAR r: INTEGER; BEGIN (*same as Put1, but with range test -10000H<= im < 10000H*) (*same as Put1, but with range test -LIMIT <= im < LIMIT *) IF (im >= -LIMIT ) & (im <= ULIMIT) THEN Put1(op, a, b, im) ELSIF op = Mov THEN Put1(Mov+U, a, 0, im DIV LIMIT ); IF im MOD LIMIT # 0 THEN Put1(Ior, a, a, im MOD LIMIT ) END ELSE r := RH; IF b = RH THEN incR END ; Put1(Mov+U, RH, 0, im DIV LIMIT ); IF im MOD LIMIT # 0 THEN Put1(Ior, RH, RH, im MOD LIMIT ) END ; Put0(op, a, b, RH); IF RH > r THEN DEC(RH) END END END Put1a; Comments: 0. Using literal constants in the code is a universally condemned programming practice. 1. Procedure incR is to be moved up to before procedure ORG.Put0 2. The use of incR ensures that in fact we do have enough registers available 3. Register optimization: But a new register is used only when needed (when b = RH) 4. Instruction optimization: For op = Mov, the extra MOV instruction at the end is avoided
Thx. On a separate note: The fix below for ORG.Put1a only works for *non-imported* global variables. There, the offset from the static base can now be >64KB, both for loading the value of such variables and for determining their address. For *imported* global variables, there still is the 64KB restriction (actually, loading works, but not accessing the address of such variables). This could also be fixed.
On 27 Feb 2020, at 14:35, Skulski, Wojciech <skulski@pas.rochester.edu> wrote:
Andreas:
Below is a slightly more elaborate variant that fixes the current bug in ORG.Put1a and makes MyViewers.Mod (see below) work on a Project Oberon 2013 system:
How about CONST LIMIT = 10000H; ULIMIT = 0FFFFH; (* Upper limit = LIMIT -1 = 0FFFFH; *)
PROCEDURE Put1a(op, a, b, im: LONGINT); VAR r: INTEGER; BEGIN (*same as Put1, but with range test -10000H<= im < 10000H*) (*same as Put1, but with range test -LIMIT <= im < LIMIT *) IF (im >= -LIMIT ) & (im <= ULIMIT) THEN Put1(op, a, b, im) ELSIF op = Mov THEN Put1(Mov+U, a, 0, im DIV LIMIT ); IF im MOD LIMIT # 0 THEN Put1(Ior, a, a, im MOD LIMIT ) END ELSE r := RH; IF b = RH THEN incR END ; Put1(Mov+U, RH, 0, im DIV LIMIT ); IF im MOD LIMIT # 0 THEN Put1(Ior, RH, RH, im MOD LIMIT ) END ; Put0(op, a, b, RH); IF RH > r THEN DEC(RH) END END END Put1a;
Comments: 0. Using literal constants in the code is a universally condemned programming practice. 1. Procedure incR is to be moved up to before procedure ORG.Put0 2. The use of incR ensures that in fact we do have enough registers available 3. Register optimization: But a new register is used only when needed (when b = RH) 4. Instruction optimization: For op = Mov, the extra MOV instruction at the end is avoided
Andreas: thank you! I am suggesting to use global CONST because looking at the Oberon code I can see these literals and I do not know which 10000H is due to what? What happens if someone ports the compiler to the open source ARM core which is now available for FPGAs? Which 10000H is due to RISC5 architecture and should be changed to something else when porting? Which 10000H is due to something else and it should stay? So I am suggesting to take every opportunity to factor out these constants. Just put the declaration at the start of the module and put a comment why it is defined (the particular RISC5 instruction). This will improve the clarity in a big way. Thank you! Wojtek ________________________________________ From: Oberon [oberon-bounces@lists.inf.ethz.ch] on behalf of Andreas Pirklbauer [andreas_pirklbauer@yahoo.com] Sent: Thursday, February 27, 2020 9:47 AM To: Oberon List Subject: Re: [Oberon] Static variable overflow (bug?) Thx. On a separate note: The fix below for ORG.Put1a only works for *non-imported* global variables. There, the offset from the static base can now be >64KB, both for loading the value of such variables and for determining their address. For *imported* global variables, there still is the 64KB restriction (actually, loading works, but not accessing the address of such variables). This could also be fixed.
On 27 Feb 2020, at 14:35, Skulski, Wojciech <skulski@pas.rochester.edu> wrote:
Andreas:
Below is a slightly more elaborate variant that fixes the current bug in ORG.Put1a and makes MyViewers.Mod (see below) work on a Project Oberon 2013 system:
How about CONST LIMIT = 10000H; ULIMIT = 0FFFFH; (* Upper limit = LIMIT -1 = 0FFFFH; *)
PROCEDURE Put1a(op, a, b, im: LONGINT); VAR r: INTEGER; BEGIN (*same as Put1, but with range test -10000H<= im < 10000H*) (*same as Put1, but with range test -LIMIT <= im < LIMIT *) IF (im >= -LIMIT ) & (im <= ULIMIT) THEN Put1(op, a, b, im) ELSIF op = Mov THEN Put1(Mov+U, a, 0, im DIV LIMIT ); IF im MOD LIMIT # 0 THEN Put1(Ior, a, a, im MOD LIMIT ) END ELSE r := RH; IF b = RH THEN incR END ; Put1(Mov+U, RH, 0, im DIV LIMIT ); IF im MOD LIMIT # 0 THEN Put1(Ior, RH, RH, im MOD LIMIT ) END ; Put0(op, a, b, RH); IF RH > r THEN DEC(RH) END END END Put1a;
Comments: 0. Using literal constants in the code is a universally condemned programming practice. 1. Procedure incR is to be moved up to before procedure ORG.Put0 2. The use of incR ensures that in fact we do have enough registers available 3. Register optimization: But a new register is used only when needed (when b = RH) 4. Instruction optimization: For op = Mov, the extra MOV instruction at the end is avoided
Andreas and Jörg, Thanks to your suggestions I managed to make a port of Martin Reiser's XYplane.Mod code that runs on the 2019 version of PO, even without the fix below. The original XYplane.Mod appeared to use only the left (user) track for its bitmap, so a bitmap of 753 x 638 bits, needing only 15013 SETs = ceil(753 x 638 / 32). You can find the source code, along with IFS.Mod, Random.Mod and an IFS.Tool with parameters for a few more fractal images here: https://github.com/hansklav/Oberon-07 <https://github.com/hansklav/Oberon-07> Now starting Oberon-07 programmers can make the examples and exercises that use XYplane.Mod from the book Programming in Oberon by Reiser & Wirth. -- Hans
Andreas Pirklbauer wrote:
Thx. On a separate note: The fix below for ORG.Put1a only works for *non-imported* global variables. There, the offset from the static base can now be >64KB, both for loading the value of such variables and for determining their address.
For *imported* global variables, there still is the 64KB restriction (actually, loading works, but not accessing the address of such variables). This could also be fixed.
On 27 Feb 2020, at 14:35, Skulski, Wojciech <skulski@pas.rochester.edu> wrote:
Andreas:
Below is a slightly more elaborate variant that fixes the current bug in ORG.Put1a and makes MyViewers.Mod (see below) work on a Project Oberon 2013 system:
How about CONST LIMIT = 10000H; ULIMIT = 0FFFFH; (* Upper limit = LIMIT -1 = 0FFFFH; *)
PROCEDURE Put1a(op, a, b, im: LONGINT); VAR r: INTEGER; BEGIN (*same as Put1, but with range test -10000H<= im < 10000H*) (*same as Put1, but with range test -LIMIT <= im < LIMIT *) IF (im >= -LIMIT ) & (im <= ULIMIT) THEN Put1(op, a, b, im) ELSIF op = Mov THEN Put1(Mov+U, a, 0, im DIV LIMIT ); IF im MOD LIMIT # 0 THEN Put1(Ior, a, a, im MOD LIMIT ) END ELSE r := RH; IF b = RH THEN incR END ; Put1(Mov+U, RH, 0, im DIV LIMIT ); IF im MOD LIMIT # 0 THEN Put1(Ior, RH, RH, im MOD LIMIT ) END ; Put0(op, a, b, RH); IF RH > r THEN DEC(RH) END END END Put1a;
Comments: 0. Using literal constants in the code is a universally condemned programming practice. 1. Procedure incR is to be moved up to before procedure ORG.Put0 2. The use of incR ensures that in fact we do have enough registers available 3. Register optimization: But a new register is used only when needed (when b = RH) 4. Instruction optimization: For op = Mov, the extra MOV instruction at the end is avoided
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
participants (3)
-
Andreas Pirklbauer -
Hans Klaver -
Skulski, Wojciech