I've been thinking about how I'm going to write my sprite routine for a while now, and I'd like to share my methodology with this forum, and hopefully if there are any major issues with how I intend to do it, someone can point it out before I learn it the hard way. Very Happy

So, the sprites will be formatted as half-nibbles (2 bits per pixel). 0 is transparent, 1 is white, 2 is black, and 3 rapidly flashes on and off to simulate a shade of gray. I will be writing a simple Windows program for converting bitmaps into the 2-bit format.

I just thought I'd post this because I have this feeling that there's some glaring error with this concept. Does this look doable?
That is indeed the accepted way of doing what's called three-level grayscale (although I think adding transparency to the mix is a new twist). Normally transparency is implemented via a separate 1bpp mask, but your method should work admirably. There are quite a few established grayscale packages for ASM that might help you; are you hoping to write yours from scratch anyway for the sake of experience?
KermMartian wrote:
That is indeed the accepted way of doing what's called three-level grayscale (although I think adding transparency to the mix is a new twist). Normally transparency is implemented via a separate 1bpp mask, but your method should work admirably. There are quite a few established grayscale packages for ASM that might help you; are you hoping to write yours from scratch anyway for the sake of experience?


Yes, I will be writing it myself. I've written similar low-level codes that require lots of bit-shifting, just in a higher-level language (C++). It shouldn't be too hard, I just need to get used to what commands to do and the registers they use. Also, I like my entire codes to be written by me, since other coders have their own way of formatting code and that can throw me off sometimes, seeing odd formatting in my otherwise standard code. I just thought this method would be a little too good to be true, since it can handle both transparency and grayscale shades, and at the same time be lined up with the bytes of data. (Also, I think I'll switch the functions of 2 and 3 for the sake of continuity)

I was wondering, how would I go about getting the right rate of flashing to create the grayscale? That would take some good timing, and the rate would change depending on how many sprites are on-screen. Is there some known way of keeping the flashing constant?
Yes, that method is called an interrupt. Interrupts trigger a fixed number of times per second, and you'll use your interrupt to dump 96x64 pixels worth of data to the screen. You'll alternate between black and white for the grayscale pixels, set the black to black and white to white, and skip the transparent ones. You'll have to make sure your interrupt can finish executing in less than one interrupt cycle, otherwise your non-interrupt program code will never run.
KermMartian wrote:
Yes, that method is called an interrupt. Interrupts trigger a fixed number of times per second, and you'll use your interrupt to dump 96x64 pixels worth of data to the screen. You'll alternate between black and white for the grayscale pixels, set the black to black and white to white, and skip the transparent ones. You'll have to make sure your interrupt can finish executing in less than one interrupt cycle, otherwise your non-interrupt program code will never run.


Well, how does one create an interrupt? Is that an actual function of ASM or is it just terminology for a programming technique? (BTW, I know what an actual interrupt is as far as hardware -- it stops processing and jumps to something else for a few cycles... I think)
The 83+ has three interrupt modes (or four, if you count interrupts being turned off as an interrupt mode Wink), though only two are really useful. IM 1 is the default interrupt and what the OS uses. It basically jumps to $0038 and runs the code there. IM 2 is what is generally most interesting to us programmers, though it's a little awkward to get set up. Whenever an interrupt is triggered, the current PC is put onto the stack and an address is loaded into the PC using the "i" register as the MSB and a random byte as the LSB. So if the i register = $80, it will read two bytes from an address between $8000 and $80FF ($80 = i, $00-$FF = random value). What this means is that you'll need to make a table (if i = $80) that spans from $8000-$8100. $8100 is needed just in case it reads from $80FF, it will load $80FF and $8100 into the PC. What you generally do is fill the table with a single byte that points to an address in RAM where you've got either your interrupt routine stored or a jump to your interrupt routine in your program. There are a lot of places you can use: $8585 (textshadow/saferam3), $8A8A (statram/saferam2), $8080 (appdata), $8787/$8888/$8989 (saveSScreen/saferam1), $9898/$9999/$9A9A (appBackupScreen/saferamp), etc. You can check here for some saferam: http://ourl.ca/16406

So if you want the interrupt to jump to $9A9A, you might fill a table from $9900 to $9A00 with the byte $9A, load $99 into the i register (you have to use ld i,a, you can't load directly) then set your interrupt: im 2. You'll also want to make sure that either a) your interrupt is loaded/ldir'd to $9A9A or b) you have a jump stored at $9A9A that points to your interrupt routine.

EDIT: And a common practice in interrupt routines is to use the shadow registers. You can switch very quickly to the shadow registers using exx (bc', de', hl') and ex af,af' (af'). If you use the shadow registers, though, make sure you don't use them in your code otherwise their values will randomly change Wink If you use the shadow registers in your code you'll need to push/pop the registers you change.
WOAH. I'm not sure whether or not I'm ready for this... So when you fill that "safe RAM" with the interrupt's program code, can you do this in assembly, or do you have to do it in plain, compiled hex? This is suddenly very confusing. Crying
Of course you can do it in assembly Smile You can do something like this:

Code:
main_code:
    ld hl,interrupt_routine
    ld de,$9A9A
    ld bc,interrupt_end-interrupt_start ;this is the size of your interrupt routine
    ldir
    ret

interrupt_start:
    ex af,af'
    exx
    ld hl,timer
    dec (hl)
    jr nz,quit_interrupt
    ld hl,counter
    inc (hl)
quit_interrupt:
    exx
    ex af,af'
    ret
interrupt_end:
That will load your code into saferam. Another option would be this:

Code:
main_code:
    ld a,$C3   ;the hex code for jp
    ld ($9A9A),a
    ld hl,interrupt_start
    ld ($9A9B),hl
    ret


calc84maniac wrote this little piece of code to setup an interrupt building a table starting at $9900 and placing a jump to your interrupt at $9A9A:

Code:
    di
    ld a,$99
    ld bc,$0100
    ld h,a
    ld d,a
    ld l,c
    ld e,b
    ld i,a
    inc a
    ld (hl),a
    ldir
    ld l,a
    ld (hl),$c3
    inc l
    ld (hl),interrupt_start & $ff   ;LSB of interrupt address
    inc l
    ld (hl),interrupt_start >> 8   ;MSB of interrupt address
    im 2
    ei
Try writing a couple small interrupt routines that don't do much, like updating a counter or randomly moving a sprites coordinates. They're not that difficult to set up, the process is just a little awkward at first.
Quargzon wrote:
WOAH. I'm not sure whether or not I'm ready for this... So when you fill that "safe RAM" with the interrupt's program code, can you do this in assembly, or do you have to do it in plain, compiled hex? This is suddenly very confusing. Crying
Hex is assembly, and assembly is hex, just to be clear. You never have to write code directly in hex; that's the reason you use an assembler. Unlike compiled languages like C, where the code you type in will get optimized, rearranged, and converted to ASM that is assembled to the hex in your final binary, in ASM the opcodes you type are the exact same thing that ends up in your binary, except with things like labels removed and equates replaced with their numerical equivalent. You probably already knew that, but I wanted to drive the point home to save you the frustration that (most) people who try to write assembly as straight binaries encounter for anything longer than a trivial program.
  
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 1 of 1
» 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