SteveB Posted January 15, 2023 Share Posted January 15, 2023 There are some of us who can think in assembly language. I am none of them. Especially when it comes to adapt a given algorithm, it feels difficult to code it in assembly. I tried to do it directly with Bresenham's line-drawing algorithm. I found a generic BASIC implementation without any comments or explaination and my first attempt of a straight port failed. It didn't work and I found some, but not all bugs. So I tried something new. This was the code I found on the net: 10 REM === DRAW a LINE. Bresenham algorithm from (x1,y1) to (x2,y2) 20 DX = ABS(X2 - X1) :SX = -1 :IF X1 - x2 < 0 THEN SX = 1 30 DY = ABS(Y2 - Y1) :SY = -1 :IF Y1 - y2 < 0 THEN SY = 1 40 ER = -DY : IF DX - dy > 0 THEN ER = DX 50 ER = INT(ER / 2) 60 PLOT X1,Y1 70 IF X1 = X2 AND Y1 = Y2 THEN RETURN 80 E2 = ER 90 IF E2 +dx > 0 THEN ER = ER - DY:X1 = X1 + SX 100 IF E2 -dy < 0 THEN ER = ER + DX:Y1 = Y1 + SY 110 GOTO 60 It was easily adapted for XB, I used CALL HCHAR(Y1,X1,30,1) for the PLOT() , played around in the standard graphics mode and was quite pleased with the result. As mentioned, my direct attempt to code this in TMS9900 failed. So I started to change my BASIC program more and more to use only very simple statements, only one each line, to come closer to AL. One important difference between high level languages and AL is the logic behind IF: In XB you have a "IF - THEN - DO" logic, in Assembly you have a "IF NOT THEN SKIP", as you can only bypass some code with Jxx instructions. Assembly has no line-numbers, so I used labels in BASIC as well (as in TIdBiT, xbas99 and TiCodEd) and came to the following, with assembler OpCodes in my mind: SUB Bresenham(y1,x1,y2,x2,c) DX = ABS(X2 - X1) SX = 1 IF X1 < X2 THEN LINE3A SX = SX-2 LINE3A: DY = ABS(Y2 - Y1) SY = 1 IF Y1 < y2 THEN LINE3B SY = SY-2 LINE3B: ER = -DY IF DY > DX THEN LINE3C ER = DX LINE3C: ER = INT(ER / 2) LINE4: CALL HCHAR(Y1,X1,C,1) IF X1 <> X2 THEN LINE4A IF Y1 <> Y2 THEN LINE4A SUBEXIT LINE4A: E3 = ER - DY E2 = ER + DX IF E2 < 0 THEN LINE4B ER = ER - DY X1 = X1 + SX LINE4B: IF E3 >= 0 THEN LINE4 ER = ER + DX Y1 = Y1 + SY GOTO LINE4 SUBEND After testing this in all quadrants, I translated it line by line to assembly: [... skiped the paramater readings into PY,PX,PY2,PX2,PCOLOR ... ] LINE2 LIMI 0 MOV R11,@RETADR LINE3 MOV @PX2,R6 DX = ABS(X2 - X1) S @PX,R6 ABS R6 MOV R6,@PDX MOV @ONE,@PSX SX = 1 C @PX,@PX2 IF X1 < X2 THEN LINE3A JLT LINE3A DECT @PSX SX = SX-2 LINE3A MOV @PY2,R6 DY = ABS(Y2 - Y1) S @PY,R6 ABS R6 MOV R6,@PDY MOV @ONE,@PSY SY = 1 C @PY,@PY2 IF Y1 < y2 THEN LINE3B JLT LINE3B DECT @PSY SY = SY-2 LINE3B MOV @PDY,R6 ER = -DY NEG R6 MOV R6,@PER C @PDY,@PDX IF DY > DX THEN LINE3C JGT LINE3C MOV @PDX,@PER ER = DX LINE3C MOV @PER,R6 ER = INT(ER / 2) SRA R6,1 MOV R6,@PER LINE4 MOV @PY,R3 CALL PUTPIX(Y1,X1,C) MOV @PX,R4 BL @PUTPX3 ** Draw Pixel at row R3 and Col R4 C @PX,@PX2 IF X1 <> X2 THEN LINE4A JNE LINE4A ** No? Continue drawing C @PY,@PY2 IF Y1 <> Y2 THEN LINE4A JNE LINE4A ** No? Continue drawing MOV @RETADR,R11 SUBEXIT LIMI 2 RT LINE4A MOV @PER,@PE3 E3 = ER - DY // Part 1 - save PER to PE3 MOV @PER,R6 E2 = ER + DX // R6 as PE2 A @PDX,R6 JLT LINE4B IF E2 < 0 THEN LINE4B S @PDY,@PER ER = ER - DY A @PSX,@PX X1 = X1 + SX LINE4B MOV @PE3,R6 E3 = ER - DY // Part 2 - Subtract DY S @PDY,R6 JGT LINE4 IF E3 >= 0 THEN LINE4 JEQ LINE4 A @PDX,@PER ER = ER + DX A @PSY,@PY Y1 = Y1 + SY JMP LINE4 GOTO LINE4 It might not be the most elegant and efficient code, but it worked immediately. From here I might improve and optimize the code, but there is no substitute for running code. I wanted to share this approach with anyone who struggles with a direct port of a high-level algorithm to assembly. Steve 14 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted January 15, 2023 Share Posted January 15, 2023 You remind of an old byte magazine article about ADA. The author had the job of hand translating people's ADA code to Assembler in the time before a compiler was ready. You are that guy now! 1 Quote Link to comment Share on other sites More sharing options...
GDMike Posted January 16, 2023 Share Posted January 16, 2023 (edited) I couldn't tell what the assy code would be, but I knew it would be lengthy. Edited January 16, 2023 by GDMike Quote Link to comment Share on other sites More sharing options...
apersson850 Posted January 16, 2023 Share Posted January 16, 2023 (edited) Back in the days I frequently implemented algorithms in Pascal, tested them and then converted to assembly, if they worked as they should, just not fast enough. Since you can use integer variables in Pascal, it's possible to test the algorithm even more closely, as any issue that's masked by BASIC's floating point numbers only does show up. Assembly from the beginning I did when it wasn't possible to use this approach. Sometimes I wrote algorithms in a pseudo language, which was based on Pascal. I still do that occasionally today. The Quicksort program I've shown here earlier was first a Pascal program. My bitmap line drawing routine too. It doesn't implement Bresenham's algorithm, since I wasn't aware of it at the time. Still reasonably fast. Edited January 16, 2023 by apersson850 1 Quote Link to comment Share on other sites More sharing options...
+InsaneMultitasker Posted January 16, 2023 Share Posted January 16, 2023 It is great to see examples of this in practice. I believe that whether someone "thinks" in Assembly or not, programming pieces (or the whole) in a higher-level language can be extremely helpful to prove a concept and/or to give you a roadmap to follow, especially if the higher-level code works! I tested my 'wordle clone' routines in XB before writing them in assembly - it was easier to debug the concept over many iterations and gave me some relatively instant feedback. The opposite direction works as well: re-writing an existing assembly routine in XB can help you understand how the assembly code works. 1 1 Quote Link to comment Share on other sites More sharing options...
+Ksarul Posted January 16, 2023 Share Posted January 16, 2023 You might want to look at an old series of articles from Don Gronos (published in the Enthusiast99 magazine, IIRC): Assembly Translated BASIC. The series was never completed, but each installment approached a few more BASIC commands in much the same way you are doing. If nothing else, the articles may help you extend what you're doing here a little bit faster. I really liked the GATB concept, so your post here immediately piqued my interest. 1 Quote Link to comment Share on other sites More sharing options...
Reciprocating Bill Posted January 16, 2023 Share Posted January 16, 2023 (edited) I find BASIC very helpful in putting together my little assembly machines - in large part because it is devoid of data structures more abstract than variables and arrays. Upon translating BASIC to assembly, my comments are often the original BASIC statements to describe a routine that follows, supplemented by comments on each assembly statement. Example: etc. etc..... (I also use a lot of vertical white space to delineate small chunks of code). Edited January 16, 2023 by Reciprocating Bill 4 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted January 17, 2023 Share Posted January 17, 2023 In NEXT C, is there a reason for not doing JLE IFOR1, and only that, instead of having two JMP instructions to go through each loop? Quote Link to comment Share on other sites More sharing options...
Reciprocating Bill Posted January 17, 2023 Share Posted January 17, 2023 No, JLE is better, and I don't recall if I had a bad reason for doing it that way. Fortunately it is in an initialization loop the executes in a split instant, anyway. Quote Link to comment Share on other sites More sharing options...
apersson850 Posted January 17, 2023 Share Posted January 17, 2023 I just wanted to know if there were some hidden good reason for the construct. Besides, unless you need the memory locations TS and TW for other things too, or are out of free registers, you same cycles by comparing a register with a register, instead of with a memory location. Quote Link to comment Share on other sites More sharing options...
Reciprocating Bill Posted January 18, 2023 Share Posted January 18, 2023 On 1/17/2023 at 1:27 PM, apersson850 said: I just wanted to know if there were some hidden good reason for the construct. Besides, unless you need the memory locations TS and TW for other things too, or are out of free registers, you same cycles by comparing a register with a register, instead of with a memory location. Those (and some other memory locations) were used as global constants controlling several parameters referenced throughout several phases of the program (maze creation, display, and solution). Keeping that many registers otherwise untouched throughout would have made things tight, register-wise. Also, apropos the thread topic, the memory labels mirror several variable names used in the BASIC program I was converting to assembly. Quote Link to comment Share on other sites More sharing options...
apersson850 Posted January 19, 2023 Share Posted January 19, 2023 Always difficult to tell from a code snippet. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.