Jump to content
retroclouds

spectra2 official 1.0 release

Recommended Posts

So I'm thinking on how to enhance spectra2 while keeping code size as small as possible.

 

Features I'm gonna include:

 

* Viewport handling

 

You may want to check out the map scroller I worked on for Owen. I spent a few days writing and rewriting the code, trying different methods of virtual window scrolling, and what I ended up with was the most efficient I could come up with at the time. The main theories I tested were focused on handling the "edge cases":

 

1. Keep the player in the middle of the window and having buffer data in the map. A lot of modern games (Diablo2 is an example I'm very familiar with... ;-) ) use this method, but they also don't have to worry about memory or speed so much.

 

2. Like #1, keep the player in the middle of the window, but instead of having a half-window worth of extra data around the map, there is just a default character that is used to draw any characters that are in the window but not part of the map.

 

3. Keep the player in the middle of the window until an edge is encountered, then the player moves from the middle up to the edges. This keeps the map data inside the window at all times.

 

4. The player moves freely in the map and scrolling happens when the player bumps in to a virtual edge, usually a character or two from the edge of the window. Like #3, the map data is inside the window at all times.

 

What I found was that the logic to handle edges (#1 and #2) was prohibitive and added a lot of extra code and time to process the window. The theory is easy, the implementation gets tricky to keep things simple and efficient.

 

I went with #3 because for a game like Owen's, you want to be able to see what is coming, and if you have to be right up against the edge to get the map to scroll (option #4), then it is easy to be surprised by a monster or something on the map popping up within 1 character of your current location. With option #3, you have half a window worth of map to see what is coming.

 

Anyway, the code is heavily commented and you may want to look at it.

 

* I'm gonna need to bug-fix my sound player to make it fully compatible with the sound player inside the console ISR. I currently don't support branches

in my player. Only learned that just today.

 

Again, thanks to working on something for Owen, you may want to look in to the sound player I wrote for his games. If I remember correctly, I made it compatible with the system ISR player, as well as adding additional features like looping within a sound (to save data in songs that have repeating parts), and some other things (I can't remember the details now.) One sound can stop another, but I didn't do any kind of "merging" of sounds. Another idea is to provide the user an single voice for each sound, or let them choose how many to use for a given sound, then you can more easily merge and play sounds simultaneously that are using separate voices. Also, you could do something like two voices for continuous game music, and one voice plus the noise voice for short sound effects.

Share this post


Link to post
Share on other sites

Et voila. This approach avoids the requirement of having to duplicate routines at identical memory addresses in both banks. You can treat the bank0/bank1 as though it's one big 16K address space. It's handled by the little helper routines.

 

Works for me ;-)

 

Mark

 

Something you have to keep in mind though, when making a program that runs from a cartridge, is that the logic to select a bank does not have a known state at power-on, so you don't know which bank will be initially selected. Typically all banks have a "banking" instruction at the start-up address (i.e. part of the cartridge header) that forces selection of the proper start-up bank.

 

The 64K multi-cart boards, and any bank-switching I have seen to date, use a TTL logic chips to manage the bank selection, and the flip-flops inside those ICs do not have resets and there is no facility within the chip to "initialize" it at power on. The selected bank at power on is not guaranteed.

Share this post


Link to post
Share on other sites

Something you have to keep in mind though, when making a program that runs from a cartridge, is that the logic to select a bank does not have a known state at power-on, so you don't know which bank will be initially selected. Typically all banks have a "banking" instruction at the start-up address (i.e. part of the cartridge header) that forces selection of the proper start-up bank.

 

The 64K multi-cart boards, and any bank-switching I have seen to date, use a TTL logic chips to manage the bank selection, and the flip-flops inside those ICs do not have resets and there is no facility within the chip to "initialize" it at power on. The selected bank at power on is not guaranteed.

 

Hi Matthew

 

Indeed. TF has code in bank 1 to force it to jump to bank 0 to do its initialisation.

 

Basically, I have duplicated the cart header exactly in both banks. Thus:

 

If the cart wakes up in bank 0: Selecting TF from the TI menu will cause it to run its normal init code

If the cart wakes up in bank 1: Selecting TF from the TI menu will cause it to run some code in bank 1 which does a bank switch to bank 0 and jumps to the normal init code. Works a treat ;)

 

Mark

Share this post


Link to post
Share on other sites

Again, thanks to working on something for Owen, you may want to look in to the sound player I wrote for his games. If I remember correctly, I made it compatible with the system ISR player, as well as adding additional features like looping within a sound (to save data in songs that have repeating parts), and some other things (I can't remember the details now.) One sound can stop another, but I didn't do any kind of "merging" of sounds. Another idea is to provide the user an single voice for each sound, or let them choose how many to use for a given sound, then you can more easily merge and play sounds simultaneously that are using separate voices. Also, you could do something like two voices for continuous game music, and one voice plus the noise voice for short sound effects.

 

Matthew, any chance I can see your code? I need something similar for TurboForth. It doesn't have to be compatible with the built in TI ISR player though (and it doesn't have to run from VDP).

 

Maybe I can steal, er, get some ideas from your code?

 

Mark

Share this post


Link to post
Share on other sites

Small update:

 

Today I got the "viewport" functionality in place. I wasn't able to do much assembly programming in the last few weeks, due to various real-life issues.

Anyway, this week I started doing some preparations and today I coded the viewport routine in one go.

It only took me 2 assembly cycles to get the thing working. I was happy about that :)

 

Ofcourse there is still a lot of testing to do :P

 

For those who don't know what the viewport is for: It is used to display part of a virtual screen on the physical screen.

You pretty much define a game map in a virtual screen (up to 255 columns and 255 rows) and you then use the viewport for displaying part of it on the physical screen.

 

You can easily build a "scroller" around this functionality. I won't include such high-level scroller as part of spectra2 though.

Remember spectra2 is only a basic functionality library. Perhaps I'll make an example on how to do that.

Actually Matthew made a great scroller for Owen.

Share this post


Link to post
Share on other sites

While working on the Tutankham title screen I needed some more subroutines.

 

I added the RLE2V subroutine (Decompress run-length encoded data to VRAM).

I use this subroutine to decompress an RLE encoded bit-map screen. It's compatible with the binary files generated by Tursi's convert9918 utility.

An excellent tool by the way. If you didn't have a chance yet check it out

 

 

Here the code

 

* RLE2V (DATA P0,P1,P2) ..:
***************************************************************
* RLE2V - RLE decompress to VRAM memory
***************************************************************
*  BL   @RLE2V
*  DATA P0,P1,P2
*--------------------------------------------------------------
*  P0 = ROM/RAM source address 
*  P1 = VDP target address
*  P2 = Length of RLE encoded data
*--------------------------------------------------------------
*  BL @RLE2VX
*
*  TMP0     = VDP target address
*  TMP2 (!) = ROM/RAM source address 
*  TMP3 (!) = Length of RLE encoded data
*--------------------------------------------------------------
*  Detail on RLE compression format:
*  - If high bit is set, remaining 7 bits indicate to copy 
*    the next byte that many times.
*  - If high bit is clear, remaining 7 bits indicate how many 
*    data bytes (non-repeated) follow.
********@*****@*********************@**************************
RLE2V   MOV   *R11+,TMP2            ; ROM/RAM source address
       MOV   *R11+,TMP0            ; VDP target address
       MOV   *R11+,TMP3            ; Length of RLE encoded data
RLE2VX  MOV   R11,@WAUX1            ; Save return address
       BL    @VDWA                 ; Setup VDP address from TMP0
       MOV   TMP2,TMP0             ; We can safely reuse TMP0 now
RLE2V0  MOVB  *TMP0+,TMP2           ; Get control byte into TMP2
       DEC   TMP3                  ; Update length
       SLA   TMP2,1                ; Check bit 0 of control byte
       JOC   RLE2V2                ; Yes, next byte is compressed
*--------------------------------------------------------------
*    Dump uncompressed bytes
*--------------------------------------------------------------         
RLE2V1  MOV   @RLEDAT,@MCLOOP       ; Setup machine code (MOVB *TMP0+,*R15)
       SRL   TMP2,9                ; Use control byte as counter
       S     TMP2,TMP3             ; Update length        
       BL    @MCLOOP               ; Write data to VDP
       JMP   RLE2V3                
*--------------------------------------------------------------
*    Dump compressed bytes
*--------------------------------------------------------------           
RLE2V2  MOV   @FILZZ,@MCLOOP        ; Setup machine code(MOVB TMP1,*R15)
       SRL   TMP2,9                ; Use control byte as counter
       DEC   TMP3                  ; Update length        
       MOVB  *TMP0+,TMP1           ; Byte to fill
       BL    @MCLOOP               ; Write data to VDP
*--------------------------------------------------------------
*    Check if more data to decompress
*--------------------------------------------------------------               
RLE2V3  MOV   TMP3,TMP3             ; Length counter = 0 ?
       JNE   RLE2V0                ; Not yet, process data
*--------------------------------------------------------------
*    Exit
*--------------------------------------------------------------         
RLE2VZ  MOV   @WAUX1,R11
       B     *R11                  ; Return
RLEDAT  DATA  >D7F4                 ; MOVB *TMP0+,*R15
* :..        

 

 

I use this little perl program, for generating the byte statements I can then include in my source code

 

###########################################
# bin2byte - Binary file dumper
# (c)2011 retroclouds
###########################################
# 03.07.2011 - Initial version
# 06.07.2011 - Fixed bug in file counter
###########################################

if (@ARGV == 0) {
  print "\n";
  print "bin2byte v1.1 - Dump binary file as TMS9900 byte statemens\n";
  print "Usage: bin2byte file1 file2 file3 ...\n\n";
  exit;
}
  
my $filecnt=0;
while (@ARGV > 0) {
  $filecnt++;
  my $label = '        BYTE ';
  my $bfile = shift;
  my $data  = '';
  my $cnt   = 0;
  open (FH,"<",$bfile)  || die("Couldn't open file \"$bfile\"\n");
  binmode(FH)           || die("Couldn't set binary mode on file \"$bfile\"\n");
  while (read(FH,$buf,2)) {
     if ($cnt % 8 == 0) { 
        $data .= "\n$label";
     } else {
        $data .= ",";
     }
     my $val = sprintf("%04X", unpack("n",$buf));
     $data .= ">" . substr($val,0,2) . ",";
     $data .= ">" . substr($val,2,2);
     # printf ("%X",unpack("n",$buf));
     $cnt+=2;
  };
  close(FH)             || die("Couldn't close file \"$bfile\"\n");

  substr($data,0,6) = 'DUMP' . $filecnt;
  print "* ", '#' x 74, "\n";
  print "* # Dump of binary file \"$bfile\"\n"; 
  print "* ", '#' x 74, "\n";
  print "LEN" . $filecnt . "    EQU  ", $cnt, "\n";
  print "$data\n";  
  print "        EVEN\n" if ($cnt % 2 == 1);
}

 

 

EDIT: I'm heading for a spectra2 v1.1 release. Probably to be released in the next two weeks. Just still have to update my documentation.

Edited by retroclouds
  • Like 2

Share this post


Link to post
Share on other sites

Time flies like an arrow; fruit flies like a banana :D

 

Those 2 weeks are more than 2 months ago and still haven't released,

Sorry guys, too much stuff on my plate right now. No more target dates, I'll release when it's done.

Edited by retroclouds

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...