Thank you very much for your suggestion, Ben. I actually have the guide downloaded already, I just forget to consult it sometimes =/

Random question...
is:

Code:

abs_a:
   bit   7, a
   jr   z, return
   neg
   inc   a
return:
   ret

the shortest possible routine for calculating the absolute value value of an 8-bit number, or is there more optimization work I can do? Don't tell me how to do it!!! Just tell me if it can be better Smile
I was going to suggest `and %01111111', but then I realized that wouldn't work. Also, did you know that you can have conditional returns? Like,
Code:
AddFiveIfNotZero:
  or a
  ret z
  add 5
  ret
So, it checks if A is zero (or a), if it is, returns immediately (A is still 0), else, it adds 5 and returns with A = A + 5.
neg performs two's complement negation, so a = -a - no need to "inc a". (cpl performs one's complement negation, so you would need to inc a afterwards if you were intending to use it to calculate the negative value of a - this is useful if you need to negate a sixteen bit number, as there is no "neg" equivalent for 16-bit values). You can also ret z if the need arises:

Code:
abs_a:
   bit 7,a
   ret z
   neg
   ret
And in addition, WikiTI is a good resource for general ASM reference:

http://wikiti.brandonw.net/index.php?title=83Plus:Ports:10
I had a few questions about the .module directive:

1. b_call's don't work in different modules. Is there a std module that will let b_call work?

2. Is there a directive to end a module?

3. What would happen with the following code?

Code:
.module main
_loop:
  ;stuff goes on here that is arbitrary

.module bitmask
_loop:
  ;more arbitrary stuff

.module main
  ;even more arbitrary stuff
  jr _loop
Before I answer these questions, I'll start by asking what assembler you're using (TASM? SPASM? Or the totally awesome Brass?). Modules are kind of implementation-defined; they're directives, not defined at all by any z80 standards. So, I'll just start and assume you use Brass:

1. you would have to either somehow import them as .global, or just define then .global.

2. in Brass, .endmodule

3. That code wouldn't work, for two reasons: obviously, first of all, you're not ending those modules Wink secondly, maybe less obvious, is that you're calling local defined labels in different modules. To call another module's _loop label, you're going to have to push it to global scope with .global.
Sorry... I really should have mentioned that I'm using TASM. For some reason I can't get brass to run on my laptop =/

If brass is really that good, I can give it another shot.

and in response to your #3... if I were to use .endmodule, would it then be valid to do something like

Code:
.module main
_loop:
  ;stuff
.endmodule

.module randomModule1
_loop:
  ;more stuff
.endmodule

.module main
   jr z, _loop
   ;stuff
   ret
.endmodule


will the jr z, _loop jump back up to the label near the top of the main module?
Rascherite wrote:
Sorry... I really should have mentioned that I'm using TASM. For some reason I can't get brass to run on my laptop =/

If brass is really that good, I can give it another shot.


Well, it's just that good, and TASM is just that bad Wink (It's not terrible, but Brass is tailored directly towards making programming in z80 assembly on the 8x series of TI calculators easier, whereas TASM is just a generic assembler that can handle multiple architectures, but it's not tailored towards any platform out of the box)

Well, if you're willing to stay with TASM, I'll reanswer the questions for that:


1. you could possibly try #include'ing the ti8x defines header in the module itself; other than that, I don't know the answer.

2. you don't have to; once you do a second .MODULE after the first, it starts the new module on the spot.

3. same as with the Brass answer, except not ending the modules is okay (and what you have to do)


EDIT: answering your EDIT'd in question, yes, that's how you would do it in Brass Smile for doing it in TASM, no .endmodule is needed (see #2 above)
I tried adding the include after the .module, but tasm complained about duplicate labels Sad

3. so, just to clarify, it IS ok to have one module in several segments? Your answer the first time I asked seems to contradict what you're saying later on...

and, are there any known issues running brass on 64-bit win 7?
Rascherite wrote:
3. so, just to clarify, it IS ok to have one module in several segments? Your answer the first time I asked seems to contradict what you're saying later on...


I'm not sure what you mean by different segments, but basically, depending on the assembler, you may or may not have to use an .endmodule directive. Either way though, you still violate the label scope policy.

Quote:
and, are there any known issues running brass on 64-bit win 7?


Not from what I can tell, I use it on 64 bit Windows 7 and it seems just fine for me Smile
Ashbad wrote:
Rascherite wrote:
3. so, just to clarify, it IS ok to have one module in several segments? Your answer the first time I asked seems to contradict what you're saying later on...


I'm not sure what you mean by different segments, but basically, depending on the assembler, you may or may not have to use an .endmodule directive. Either way though, you still violate the label scope policy.


what I mean by segmenting is:

Code:
.module module_name_1
_label:

.module module_name_2
_label:

.module module_name_1
jr _label:


the second time I'm in module_name_1 (lines 7 and 8 in this random snippet), will it jump all the way up to line 2 on the jr, or will it have no clue where to go becuase I have module_name_1, then module_name_2, then module_name_1 AGAIN?
Why don't you use the Doors CS SDK? It includes Brass and has everything that you need to make it work properly. Smile
I know this is a pretty big request... but if anybody would be willing to help, that'd be pretty awesome.

I spent a while making vertical and horizontal line drawers. Please look over the code and tell me how clean/optimized they look. Thank you!! I want as much input as I can get.

Horizontal line drawer:

Code:
vertical_line:
;h = xstart, l = ystart, a = length

;negate length if it is less than 0 and move xstart and ystart to the top of the line.
   bit 7, a
   jr z, _posLength
   neg
   ;protect af so we can calculate the new ystart.
   push af
      ;ystart = ystart-length = -(length-ystart) = -(a-l)
      sub l
      neg
      inc a
      ld l, a
      pop af
   ;hl and length are corrected for negative length, carry on...
   
_posLength:
   ;calculate hl = (y0)*12
   push af
      push hl
         ld h, 0
         add   hl, hl      ;Because for each y coord we go down from y = 0, we are 12 bits further down, we will put y0*12 into hl
         add   hl, hl
         ld   d, h
         ld   e, l
         add   hl, hl
         add   hl, de   
   
         ld   de, PlotSScreen
         add   hl, de            ;bit to start writing at minus x coord now in hl.
         pop de
      push de
         ;now we have the x coord in d.  to get the starting bit, we add d/8 to hl.
         srl d
         srl d
         srl d
         ;store d/8 in de
         ld e, d
         ld d, 0
         add hl, de
         ;now we have the starting bit in hl, we need to get xstart mod 8 into
         ;b so we can bitshift a an appropriate number of times.  When we pop af,
         ;we get xstart in a, then all we have to do is and %07 to calculate
         ;xstart mod 7 (which will be in a) and then we store it in b.
         pop af
      and %00000111
      ld b, a
      ld   a, %10000000
      jr z, _noBitShft
_bitShft:
      srl a
      djnz   _bitshft

_noBitShft:

      ;now we have all the data taken from xstart and ystart in hl and a in the
      ;form of the starting bit in hl and the shifted line of bits in a.  Now
      ;all we have left to do is print out the line in a length times.  We pop bc
      ;in order to get the length into b
      pop bc
   ;we load 12 into de because each time we want to advance a row, we have to
   ;add 12 to hl becase each row on the screen is 96/8, 12 bytes.
   ld   de, 12
   
_drawline:
   ;we have to push af so that we don't ruin a each time we do or (hl).
   push   af
      or   (hl)
      ld   (hl), a
      add   hl, de
      pop   af
   djnz   _drawline
   

   ret


and

horizontal line drawer:

Code:
horizontal_line:
;again, h = xstart, l = ystart, and a = length
;check and see if length is negative.  If so, negate a and adjust hl accordingly.
   bit 7, a
   jr z, _posLength
   neg
   ;protect af so we can calculate the new ystart.
   push af
      ;xstart = xstart-length = -(length-xstart) = -(a-h)
      sub h
      neg
      inc a
      ld h, a
      pop af
   ;hl and length are corrected for negative length, carry on...
   
_posLength:
   ;protect initial data during arithmetic operations to find the first bit to write to.
   push   af
      push   hl      ;we push hl second so that it is on top of the stack so we can access xstart and ystart
         
         ;multiply y0 by 12
         ld   h, 0
         add   hl, hl
         add   hl, hl
         ld   d, h
         ld   e, l
         add   hl, hl
         add   hl, de
         ;now, hl contains y0 times 12.  The ystart data becomes useless.
         
         ;here, we have to find xstart/8 and add to ystart * 12
      ;load the xstart data into de, but be sure to re-preserve it.  xstart is now in d and ystart is now in e
         pop   de
      push   de
         ;now the row of the bit to be written at (ystart*12) is on top of the stack so we can retrive it once we divide xstart by 8
         ;divide xstart (d) by 8 and then add to the top member of the stack
         srl   d
         srl   d
         srl   d
         ld   e, d
         ld   d, 0
         add   hl, de
         ld   de, plotSScreen
         add   hl, de
         ;now, hl contains the starting bit.
         ;load xstart data into b
         pop   bc
      ;now do b mod 8
      ld   a, b
      and   %00000111
      ld   c, a      ;keep xstart mod 8 in c so that it isn't effected by djnz
      ld   b, a
      cp   0
      ;load a solid 8-bit line into a.
      ld   a, $FF
      jr   z, _noBitShft
      
_bitshft:
      srl      a
      djnz   _bitshft

_noBitShft:
      ;pop de loads length into d.  protect bitshifted $FF momentarily in e so that we can do arithmetic work with a.
      pop de
   ;push de
   ld e, a
   ld a, d
   add a, c
   sub 8
   jr nc, _noBitMask
   neg
   ld d, 0
   ;now a holds the number of bits to take off the end.
   ld b, a
   ld a, $FF
_bitMaskShft:
   sla a
   djnz _bitMaskShft
   
   ;do the actual bitmasking.
   and e
   ;now a contains the properly shortened line
   jr _dispFirstSeg
   
_nobitMask:
   ld d, a
   ld a, e

_dispFirstSeg:
   or (hl)
   ld (hl), a
   inc hl
   
   ld a, d
   ;if the remaining length is 0, return.
   cp 0
   ret z
   ;now both d and a contain the length of the remaining line.  We have to take a mod 8 and push it because we will need that for later.  (It's the length of the very end of the line)
   and   %00000111
   push   af
      srl   d
      srl   d
      srl   d
      ld   b, d
      ;now in b is how many times to print out a solid line in hl
      ;verify that b is greater than zero
      ld   a, b
      cp   0
      jr   z, _noSolidLine
_drawSolidLine:
      ld   (hl), $FF
      inc hl
      djnz   _drawSolidLine
      
_noSolidLine:
      ;put the remaining length of the line into af. should be less than 8 by this point.
      ;We will load $FF (%1111,1111) into a and then shift a left 8 - remaining_length times.  A length of 0 will result in 8 rotations and a length of 8 will result in 0 rotations.
      ;note from a bug fix: we used to shift a 7 - remaining_length times, but if the remaining length was ever 7, b would be 0 and on the first djnz leftBitShift, b would go to FF and a would get shifted 255 times.
      pop   af
   neg
   ret z
   ;if neg returns a 0, there is no more line to draw.  return.
   add   a, 8
   ld   b, a
   ld   a, $FF
_leftBitShift:
   sla   a
   djnz   _leftBitShift
   
   or   (hl)
   ld   (hl), a
   
   ret


Thanks so much Very Happy
Well, I see the general idea of what you're doing there. For the former, my own code (rather than modifying your code) would look something like this:


Code:
vertical_line:
;h = xstart, l = ystart, a = length

    push af
        ld a,h
        ld e,l
        call iGetPixel
        pop bc
    ld c,a
    ld de,12
vertical_line_setloop:
    ld a,(hl)
    or c
    ld (hl),a
    add hl,de
    djnz setloop
    ret


Edit: And for the sake of completeness, let me see what I can do with your second function:


Code:
horizontal_line:
;again, h = xstart, l = ystart, and a = length
    push af
        ld a,h
        ld e,l
        call iGetPixel
        pop bc
    ld c,a
horizontal_line_setloop:
    ld a,(hl)
    or c
    ld (hl),a
    rrc c
    jr nc,horizontal_line_setloop_nohlinc
    inc hl
horizontal_line_setloop_nohlinc:
    djnz horizontal_line_setloop
    ret
It would be a good idea for me to write my own iGetPixel. (I pretty much have it done).
It looks like the vertical_line is almost the same as mine.
I really like how you use

Code:
ld c, a
vertical_line_setloop:
ld a,(hl)
or c
ld (hl),a
;...etc

as opposed to my

Code:
push af
;code code code
pop af


As for the horizontal one... I need a minute. I'll edit this response later.
Sounds good. I had one small edit that I just corrected; rrc c had been rrc a, which was wrong.
ok... makes a TINY bit more sense now with the rrc c

Just to make sure, your drawers don't correct for negative numbers in the length, correct?

edit: OH!! now the horizontal line routine makes perfect sense!! I thought about writing it like that (and I probably should), but the z80 in 28 days said that way was really slow and I should do it differently. However, trying to do it differently than how you did it only resulted in an inflated mess for me! (though I checked for bugs and there are none that I could find on my code, even if it is an inflated mess.)

Your code is horizontal definitely faster for a relatively short line, but if a line is, like, 40 pixels or longer, maybe mine would be faster.
Rascherite wrote:
ok... makes a TINY bit more sense now with the rrc c

Just to make sure, your drawers don't correct for negative numbers in the length, correct?
No, mine just assume that the programmer wasn't failsome enough to specify negative inputs. Wink

Edit: if I did want to do so, I'd use this:


Code:
    bit 7,a
    jr z,noneg
    neg
noneg:


Edit #2: And I now see that you assume that negative a means to draw upwards, so let me amend that code:


Code:
    bit 7,a
    jr z,noneg
    push af
        add a,l
        ld l,a
        pop af
    neg
noneg:
but if you negate the length of the line and want to make the drawing program still work, you have to move xstart and ystart around, so a simple neg won't do it.

ah, ninja'd me! Evil or Very Mad

Here's the differences I analyzed between our horizantal code
the approach I took is this:
find the starting byte
place %0...01...1 in that byte and subtract length of that first segment from the length

place %FF at (hl) and increment hl until remainingLength/8 is 0.

|Remaining length|
then place %1............................10...0 in the final byte and return.

of course, then I had to add a seperate case entirely if the bit of the pixel + length is less than 8 (e.g. %00111110)

The only thing that's better about my code, like I said, is that it can do
$FF
instead of
%1000000
%0100000
%0010000
...
%0000001
if I need to make an entire byte black.

yours takes up about 25% the memory of mine, though. I'll just rewrite it like that.
Indeed. In the real line-drawing routines in Doors CS, it does the same kind of optimizations, doing the bits in the first byte, then whole bytes as much as possible, then bits in the final byte.

Also, please edit rather than double-post. Smile

Edit: And you did! Cheers for that.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 3 of 5
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement