Jump to content
Asmusr

Sabre Wulf

Recommended Posts

If you want to display a bitmap mode screen while loading the main program you only have a 2K file buffer available in VDP RAM. If you split an E/A#5 file into 2K segments, will it still load with E/A, and do we have any tools for doing the splitting? Or is it better to convert the main program into one or two IF128 files? What has other people done?

 

Thanks,

Rasmus

 

The loading of a full screen bitmap is very fast from disk using the load opcode, so I never needed to interleave the image and program loading process. What exactly are you trying to achieve here?

Share this post


Link to post
Share on other sites

If you want to display a bitmap mode screen while loading the main program you only have a 2K file buffer available in VDP RAM. If you split an E/A#5 file into 2K segments, will it still load with E/A, and do we have any tools for doing the splitting? Or is it better to convert the main program into one or two IF128 files? What has other people done?

 

Thanks,

Rasmus

 

Consecutively names segments can be loaded as you suggest. Each file contains a six-byte header specifying the load address, length, and a flag for last file in the sequence. You just need to be able to save your program in chunks. I don't know if any existing linker/loaders have that capability - RAG perhaps?

Share this post


Link to post
Share on other sites

A bit aside, is loading via VDP RAM buffers a Monitor or DSR requirement? I am just wondering why we cannot ourselves over-come this and load things into CPU RAM directly.

 

It is DSR-specific.

 

The TI, CorComp, CF7, NanoPEB device DSRs are locked into using VDP memory for buffers and peripheral access. Later cards including the Myarc FDC, Myarc HFDC, SCSI, and IDE default to VDP access for compatibility while giving the programmer an option to force non-VDP RAM access, allowing quicker load/save times by skipping the VDP<-->CPU transfers.

 

Since most level 3 IO (save/load/open/close/read/write) is usable by "all" devices without going through extra DSR hoops, programmers usually stick with VDP access. Level 2 IO (block file read/write, directory creation/deletion, rename, protect) requires some extra steps and coding to properly access HFDC, SCSI, and IDE hard-disk devices. This is the primary reason many terminal emulators and file transfer programs are limited to floppy access.

 

Most programmers who added hard drive support to their programs used VDP access, both for consistency and to future-proof their code in the event new cards did not allow CPU transfers. However, some programmers (including me) check the device type and perform direct CPU transfers where possible. :)

Share this post


Link to post
Share on other sites

 

 

The annoying thing about the Spectrum sprites is that the sizes are not multiples of 16x16 pixels, but often something like 24x18. This means many sprites are almost empty, and it wastes both CPU and VDP RAM. You could store the patterns in CPU RAM in their original sizes, of course, but that adds another level of complexity.

 

 

This was one of the reasons why 80s game conversions had a different look on each machine. :) Many times each conversion had unique look. :)

Share this post


Link to post
Share on other sites

I'm all out of RAM, so as for the disk version this is about as good as it's going to get.

 

 

The game can be played through to the end, but a few details from the original gameplay are still missing, for instance regarding the movement of the larger animals. Some of the sprite patterns are also missing, and I only had room for a few basic sound effects. And the two player mode and the high score table are missing entirely. All this could be rectified in a cartridge version.

 

If you run the game on a console with the F18A installed you can choose from the main menu to change the color palette to one with more vibrant colors. This option is also visible in Classic99 if you have the 'Enable F18A GPU' option checked, but here it won't do anything. It works in my own emulator js99er.net if you have the F18A option enabled.

 

I found the original game to be really hard to play, so I have made it a lot easier. You have more lives and the animals don't appear as quickly. Perhaps it's too easy now as you can see from video where I had trouble dying before the video became too long... :-)

 

Run the game using E/A#5 DSK1.SABREW or use the XB loader (provided by Tursi). If you want to copy the game to floppy disk you don't need the object file SW.

 

 

 

 

 

 

SabreWulf-1.0.zip

  • Like 9

Share this post


Link to post
Share on other sites

I'm simply blown away by your latest and greatest Rasmus. I can't play this game very well, but on the eye-candy scale it's off the charts!

gallery_35324_1027_3581568.jpg

 

You've got to be the most prolific game programmer around too. If you keep it up, I'm going to run out of either entries or space on my RASMUS DISK.

 

gallery_35324_1027_189742.jpg

  • Like 3

Share this post


Link to post
Share on other sites

Basic instructions:

 

The game is won by collecting 4 amulet pieces and entering the cave at the center of the maze. Until you have the 4 pieces the entrance is blocked by the Guardian.

 

Most animals/enemies can be defeated with the sword. Rhinos, boars, natives,and the Wulf can only be turned. Fire is lethal [note: in the original game fire appeared on all screens after a while, but I haven't implemented that yet].

 

The effects of the orchids are:

  • Red: immunity
  • Blue: speed
  • Yellow: paralysis
  • Magenta: confusion
  • White: remove other effect

Extra lives are generously scattered around the maze.

  • Like 3

Share this post


Link to post
Share on other sites

It draws the screens very quickly. Do you turn the screen off while it's drawing?

 

Yes I do.

Share this post


Link to post
Share on other sites

Just gorgeous! Well done again!!!

May I post this on the Gameshelf site?

 

Sure.

Share this post


Link to post
Share on other sites

It draws the screens very quickly. Do you turn the screen off while it's drawing?

 

Your question makes me wonder if turning off the screen is supposed to make faster screen updating possible. As far as I know it doesn't because you can already send data to the VDP as fast as possible (from unrolled loops in scratch pad) without overrunning the VDP. And turning off the screen doesn't remove the 8 bit RAM wait state for the VDPWD address, right?

Share this post


Link to post
Share on other sites
Your question makes me wonder if turning off the screen is supposed to make faster screen updating possible. As far as I know it doesn't because you can already send data to the VDP as fast as possible (from unrolled loops in scratch pad) without overrunning the VDP. And turning off the screen doesn't remove the 8 bit RAM wait state for the VDPWD address, right

 

I have the same question after reading Thierry's page on the VDP timing rules for CPU access window:

 

 

There are two exceptions to these rules, however:

  • When the screen is blank (because bit 1 in register 1 is set as 0) the VDP does not handle the screen and a CPU access window is permanently open. Consequently, there is no wait time.
  • When the VDP is done with drawing a frame and enters vertical refresh mode it issues an interrupt (if enabled) and opens a 4.3 milliseconds (4300 us) window for CPU access.

 

But given previous discussions, it seems that we cannot over-run the CPU in our environment. ¿Verdad?

 

Edited by OLD CS1

Share this post


Link to post
Share on other sites

 

Your question makes me wonder if turning off the screen is supposed to make faster screen updating possible. As far as I know it doesn't because you can already send data to the VDP as fast as possible (from unrolled loops in scratch pad) without overrunning the VDP. And turning off the screen doesn't remove the 8 bit RAM wait state for the VDPWD address, right?

 

Here's a link I had saved long ago that contains some good info from Paul Urbanus.

 

http://bifi.msxnet.org/msxnet/tech/tmsposting.txt

 

 

 

Subject: Re: Z80 emulator to learn assembly?From: Paul Urbanus <[email protected]>Date: 1997/01/31Message-ID: <[email protected]>References: <[email protected]> <[email protected]> <[email protected]>Content-Type: text/plain; charset=us-AsciiOrganization: OnRamp Technologies; ISP;  Dallas/Ft Worth/Houston, TX USAMime-Version: 1.0Newsgroups: comp.emulators.misc,comp.os.cpmX-Mailer: Mozilla 3.01 (Win16; I)Marcel de Kogel wrote:>> On 26 Jan 1997 23:59:23 GMT, [email protected] (Marat Fayzullin)> wrote:>> >Rogers Cadenhead ([email protected]) wrote:> >: I am learning Z80 assembly language programming so that I can write> >: some new Colecovision games and figure out how some of my old> >: favorites were written.> >> >: What's the best Z80 emulator I can find for DOS or Win95 that I can> >: use to run the programs I'm writing? I've read that CPM emulators are> >: the best choice.> >As you are going to write Colecovision programs, a crossassembler+ColEm> >combination will probably be the best. Also, check AdamEm, the Coleco> >Adam emulator by Marcel de Kogel.> >> >Marat>> I'm working on some as well, and while writing them I found some very> interesting features in the VDP design (e.g. there's no such thing as> truly seperate read and write addresses) I didn't find described> anywhere. While I've implemented most in ADAMEm, I didn't find out how> some of this really works (e.g. I get mixed results when reading VRAM> after setting a new write address). This is why I prefer using Mission> and an MSX for testing purposes; In fact, it's why I wrote Mission in> the first place. Of course, final testing is done on the CV itself,> and you'll need an MSX to run Mission natively>> MarcelMarcel,The VDP (Video Display Processor) chip used in the Colecovision and inthe early (MSX-1?) systems was the Texas Instruments TMS9918A, which wasalso used in the TI99/4A Home Computer. This machine came onto themarket in 1980, in the midst of the video game/home computer boom.During that time, I worked for TI as a student, and in 1982 Ico-authored (along with Jim Dramis) a game for the 99/4A called PARSEC,among other things. All of us game programmers always lamented the factthat the VDP memory was 'indirectly' mapped instead of direct, which ofcourse limited the amount of raw bit pushing we could do. Anyway, Ithink the following will (hopefully) clear up your confusion regardingaccessing VDP memory. Note that later versions of the MSX systems(MSX-2?) used a superset of the TI9918A, the YM9938, which was made byYamaha. The following discussion applies only to the TI9918A VDP chip.You are correct when you stated that there is only ONE memory addressregister in the VDP, and this is used for both reading and writing data.Thus, there must be a way to indicate to the VDP whether the addresswhich has been written is to be used for reading or writing data. Thisis done by using one of the upper address bits in the 16 bit address.Since the 9918A can only address 16k bytes of memory, the upper two bitsin the address (A14-A15) will always be zero. While bit 15 (the mostsignificant) is always set to zero, bit 14 is used to distinguishbetween a read and a write address. The following shows how this bitaffects subsequent VRAM data accesses.VRAM address bit 14  |         VRAM data access function------------------------------------------------------------------------         0           |   VRAM address specifies location to read                     | (initiate the read/increment the address counter)------------------------------------------------------------------------         1           |  VRAM address specifies location to write                     | (wait for data write to VDP before actual write                     |  to VRAM, then increment address counter)If you are simply calculating the address for writing data, then usingthat address as the write address without setting bit 14=1, this mightcause some unexpected behavior. If bit 14=0, this will cause the VDP toinitiate a read cycle and then increment the address counter, thusgiving the impression that the "write address" has been set to(address+1). As I stated before, there really is only one addressregister, so when you perform data reads/writes you are affecting thesame register.I'm sure that the VDP designers (at TI, anyway) didn't expect people tointerleave data reads and writes without resetting the address, so anyundocumented operation may or may not be supported on all revisions ofthe chip. As will any 'undocumented bugs/features', I'd be concernedabout the implementation of these 'features' in 9918A clones, such asthe Yamaha 9938.Another thing you should be aware of is the timing constraints placed onaddress and data accesses to the VDP RAM. Actual reading/writing of theVDP RAM (VRAM) by the CPU can only occur when the VDP is not reading thememory for the purpose of generating the screen image. In some displaymodes, most of the memory bandwidth is utilized for generating theimage, leaving little time (unfortunately) for the CPU to access memory.The worst case scenario is in graphics modes I,II, where the VDP usesalmost all of the memory bandwidth to generate the screen image. In thismode, only 1 memory access out of 16 is designated for the CPU - therest are allocated for screen refresh.According to the 9918A (VDP) Data Manual, there are two timingconstraints to be followed when access VRAM.1. After the second address byte (MSByte) has been written to the VDP,there must be a 2 microsecond wait before any data read/write accessescan occur. This constraint ALWAYS applies, no matter which display modeis in effect or which part of the screen (active video, verticalsync/blanking) is being displayed. In the table below, this is referredto as 'VDP Delay'.2. The second timing constraint depends on which display mode is activein the VDP, and which part of the screen (active video, verticalsync/blanking) is being displayed. The following table shows thesetiming constraints. In the table, this second delay constraint isreferred to as 'Time waiting for an access window'.                    |            |  VDP  | Time waiting for |  Total   Condition        |    Mode    | Delay | an access window |  time------------------------------------------------------------------------Active Display Area |   Text     | 2 us  |   0  -  1.1  us  | 2 - 3.1 us------------------------------------------------------------------------Active Display Area |  Graphics  | 2 us  |   0  -  5.95 us  | 2 - 8   us                    |    I,II    |       |                  |------------------------------------------------------------------------4300 us after       |    All     | 2 us  |      0       us  |   2     usVertical Interrupt  |            |       |                  |------------------------------------------------------------------------Register 1, bit 1=0 |    All     | 2 us  |      0       us  |   2     us(display is blanked)|            |       |                  |------------------------------------------------------------------------Active Display Area | Multicolor | 2 us  |    0  -  1.5 us  | 2 - 3.5 us------------------------------------------------------------------------Examination of the above access window table yields the followingobservations.1. Always try to do massive VRAM moves during the vertical retraceperiod, since that is when max memory bandwidth is available to the CPU,theoretically 500 Kbytes/sec. This is especially important in Graphicsmodes I & II, which will be used for almost ALL games. Theoretically,one can move (4300 us/2 us) 2150 bytes to/from the VRAM in one verticalblanking time.2. If you need to move lots of data, such as completely changingscreens, set the blanking bit it VDP register 1 to 0, then read/writethe data.   WHY DOES THE VDP NEED SO MUCH BANDWIDTH TO REFRESH THE SCREEN,   AND OTHER STUFF YOU REALLY DON'T NEED TO KNOW ABOUT THE 9918A?   --------------------------------------------------------------The following is provided as additional background information, and maybe considered excess, but I give for it those who might want tounderstand how the bandwidth is used in Graphics modes I & II.First, consider the overriding considerations for the guys who did the9918A chip design. Of course, the part must function, but moreimportantly, the die size must be as small as possible to keep the costdown. After all, this chip was targeted toward a consumer market.Now, a little background on VDP memory and pixel timing. The masterclock for the VDP is the color burst frequency X 3. All subsequentcalculations are for the NTSC version of the part, although the PALnumbers will be similar. The color burst frequency is 3.579545 MHz.While I don't know pi to this many digits, the color burst frequency isvery handy to know when working with NTSC video. So, the master clockfrequency is given byFmaster =  Fcolorburst * 3        =  3.579545 MHz * 3        = 10.7386 MHzThe period of the master clock is given byTmaster = 1/Fmaster        = 1/10.7386 MHz        = 93.12 ns (nanoseconds)Each memory access takes four master clock times, so the memory accesstime is given byTmem    = Tmaster * 4        = 93.12 ns * 4        = 372.5 ns = 0.3725 usThe horizontal line time, or the amount of time from the start of onehorizontal display line to the next horizontal display line is specifiedin the data sheet as Thorz = 63.695 us. So, the total number of timeswhich VDP memory can be accessed in a single horizontal scan line isgiven byMhorz  = Max number of memory accesses in a horizontal line       = Thorz/Tmem       = 63.695 us/0.3725 us       = 171 memory access per horizontal line, maxWe now know how many memory accesses are available to be allocated fordisplay refresh and CPU accesses combined.Next, let's find out how many memory accesses are requied to build up asingle horizontal scan line in Graphics modes I or II. Any unusedaccesses can theoretically be allocated to the CPU.Any one active scan line is composed of up to six layers of graphic data(listed in back to front hierarchy):1. Background color (from VDP register #7)2. Character pattern/color info3. Sprites (min number=0, max number=4)   NOTE: there may never be more than 4 sprites on a horizontal scanlineLet's see how many memory accesses are required to get the data for thethree different 'planes' described above.First, the background color requires zero memory accesses, as it is heldthe lower 4 bits of VDP register 7.Next, is the character data. There are 32 characters per scan line, andeach character in the scan line requires the following memory accessesto retrieve the data required to generate the pixel data for thatcharacter.1. Read character number from Pattern Name Table (PNT)2. Read character bitmap data from Pattern Generator Table (PGT)3. Read character color info from Pattern Color Table (PCT)As you can see, it takes three memory accesses for each character, andso the total number of memory accesses required per scan line to buildup the character display plane is given byMchar = 32 characters/scan line X 3 mem accesses/character      = 96 memory accesses per scan line for character planeFinally, the sprite planes must be processed. The 9918A allows up tofour sprites (out of 32) to be displayed on a scan line, and sprite #0has the highest priority - that is, it will be the frontmost.To determine which sprite will be visible on any given scan line, theY-position of all 32 sprites must be read from the Sprite AttributeTable (SAT) in VRAM and compared against the current scan line number.When doing the compare, the Mag bit from VDP register 1 must be takeninto account, since the magnification is in both the x and y directions.If the Y-location of the sprite is such that it is to be displayed onthis scan line, then the sprite number (0-32) is placed in one of fourtemporary holding registers (SR0-SR3), if all four registers are notalready filled. SR0 fills first, SR3 fills last, and SR0 specifies thefrontmost sprite plane and SR3 specifies the rearmost sprite plane.While the Y-locations of these active sprites may be saved inside theVDP, I suspect they are not. Keeping these Y-locations would require 4extra holding registers, which can be eliminated by refetching theY-locations later, albeit at the 'cost' of more memory access. However,4 registers affects the chip die size, but it is not clear that the VDPuser even knows about the 'cost' of these extra memory cycles.In the worst case, the first 28 sprites, 0-27, are not displayed on agiven scan line, but sprites 28-31 will be displayed. In this case, theY-location all 32 sprites may have to be read. For the purposes ofmemory access calculations, we must assume that all 32 spriteY-locations will have to be read. Therefore, we define the number ofmemory accesses required to test which sprites should be displayed on agiven scan line asMsprite_test = 32 memory cycles (1 Y-location per sprite)After it is determined which sprites need to be displayed, the data forthe four sprites (again, worst case) to be displayed must be fetched.For each sprite, there are 4 bytes (Y-location, X-location, patternnumber, color/early clock) which need to be fetched from the SpriteAttribute Table. When the Size bit in VDP Register is set to 1,indicating double size sprites, two bytes of sprite pattern data must beread from the Sprite Pattern Generator Table. Again, this is the worstcase. Therefore, six memory cycles are required for each sprites whichis to be displayed. So, we now define the maximum number of memorycycles required to fetch the data needed to display four sprites on ascan line asMsprite_data = 4 sprites line x 6 memory cycles/sprite             = 24 memory cyclesNow, let's summarize the maximum total number of accesses required fordisplaying four sprites on a scan line asMsprite = total number of memory accesses per scan line for spritedisplay        = test which sprites are on this line + sprite display dataaccess        = Msprite_test + Msprite_data        =     32       +     24        = 56 memory cyclesWhew! Finally, we can calculate the number of memory cycles used torefresh one active scan line in the display. This is given byMdisplay = Mchar + Msprite         =  96   +   56         = 152For those of you who I have not totally confused, the end is now insight. We are ready to compute the number of memory cycles available tothe CPU.Drum roll, please!Mcpu  = Mem accesses in one horizontal scan line - display mem accesses      = Mhorz - Mdisplay      =  171  -   152      = 19 memory accesses available for the CPUIf the CPU can access the memory every 5.95 us, then the total number ofCPU accesses allowed in a horizontal line time is given byMcpu_horz = horizontal line time/memory access time          = 63.695 us/5.95 us          = 10.7 CPU memory access per horizontal scan lineIf one rounds 10.7 up to 11, that would seem to indicate that there are8 memory cycles (19-11= which are unused.Perhaps those extra 8 cycles could have been used to allow a fifthsprite on a line, since each sprite costs a total of seven memory cycles(1 for y-test, then 6 more if displayed). However, that would only leaveone memory cycle to spare. Also, there are scheduling and sycronizationissues involved regarding the sprites, and it would have probablyrequired too much chip area to squeeze in that one extra sprite.Or, maybe those 19 cycles could have been all allocated to CPU accesses.However, remember the earlier statement that every 16th memory accessesis allocated for the CPU. It is relatively simple (cheap) to decode thisCPU access slot from the horizontal counter inside of the VDP which isused for overall horizontal timing. If, instead, we take the 19 cyclesand divide them into the horizontal line time, we getTaccess_best = 63.695 us/19 memory cyles             = 3.35 us between CPU data accessesIf memory cyclces take 372.5 ns, then the CPU could have every ninthmemory cycle (3.35/0.3725). Since this is not an integral power of two,a separate CPU access counter would be required and would take more chiparea (cost) than a simple decode of the lower four bits of thehorizontal counter.To summarize, the sprites take up slightly more than 1/3 of the displaybandwidth. Unfortunately, the chip designers did not incude a way toturn off the sprites and thus allow 1 of four memory accesses to beallocated to the CPU.I hope this information will be useful or educational to someone outthere. Maybe you now have a better understanding of how the videohardware in the Colecovision works.Paul [email protected]nix.comP.S. In anticipation of doing some work for the Colecovision, I built asingle-board computer (SBC) that used the TI processor. This SBCattached to the expansion port of the Colecovision and used DMA (DirectMemory Access) to access the hardware. Since we already had a debuggerwritten for the TI99/4A, I modified it for the SBC so we could learn howto access the Colecovision hardware. HERE'S THE PERVERSE PART - since wedidn't know any Z-80 assembly, we wanted to examine some of the code inColeco games. So we wrote a symbolic Z80 dissassembler IN TI9900ASSEMBLY LANGUAGE. What were we thinking???***                                                                ****                 Paul Urbanus    [email protected]                    **                                                                    **   Never wrestle with a hog - you get dirty and the hog likes it.   ****                                                                ***

 

 

Share this post


Link to post
Share on other sites

Great game again here! After reading Paul Urbanus's write-up, I got interested in how the VDP really accesses memory, since I suspected that memory accesses for different purpose somehow get interleaved, and I found a page where you can find the exact sequence of VDP RAM accesses by the VDP in a diagram:

 

http://map.grauw.nl/articles/vdp-vram-timing/vdp-timing-2.html

 

According to this diagram, at the start/end of each scanline, the CPU would theoretically have some additional accesses in sequence, but this can't be relied on, and not all of the accesses can be used because of the 2 yS VDP wait anyway. While the pattern data gets fetched, it's one CPU access about every 6 yS (and one VDP bus cycle seems to be 2 displayed pixels wide, so in these 6 yS 4 characters get displayed).

Share this post


Link to post
Share on other sites

... yS ...

 

You probably intended 10-6 seconds (‘µs’ or ‘us’, when Greek not available) rather than 10-24 seconds (‘ys’). FYI, you can get ‘µ’ by holding down ALT while typing 230 on the number keypad.

 

...lee

Share this post


Link to post
Share on other sites

Well... I have some ideas how, maybe, some memory could be saved...

 

First... the metatiles are given as full graphics. Are they not consisting of 8x8 tiles? Could there be some memory saved by breaking down the metatiles into 8x8 tiles?

Then I noticed that most metatiles are always appearing at the same row on the screen. This means that the screens are a bit overdefined in my opinion. I think the screens really consist of strips of metatiles spanning from left to right, so the definition could go roughly like this:

Screen 1:

DATA >0500 * Position of leftmost metatile to draw on that line

BYTE >00, >FF *Code for metatile to draw, FF denotes end of list

DATA >0238 * Position of leftmost metatile to draw on line 02

BYTE >03, >01, >02, >03, >02, >01, >FF * List of metatiles to draw, FF denotes end of list

DATA >0850

BYTE >07, >08, >19, >09, >08, >19, >07, >FF

DATA >1140

BYTE >0A, >0B, >0C, >0A, >0B, >0C, >FF

BYTE >FF * End of metatile list

BYTE 48, 56 + 3 * orchid y, orchid x + sprite layout

 

This would compress the definition of screen 1 from 62 to 35 bytes. Other screens could be similarly shrinked.

The following would have to be done in the drawing routine to make this work:

- Read the position of the first metatile first, then each subsequent byte gives a metatile number. That tile would be drawn starting on the same line, to the right of the metatile before it (you know how wide each one is, right?)

- If an FF is encountered, the next two bytes give the next coordinates where to start drawing metatiles.

- If the first of those bytes is an FF again, you read the orchid and sprite data. For the sprite layout, the lower 2 bits get stripped from orchid x and used as the sprite layout number.

- The metatiles would have to be reordered so that they always get drawn from left to right for all metatiles that share the same line. If there's a break (an empty space), you could still end a strip by an FF and start a new one on the same line.

One downside to this is that you'd have to have two additional small tables giving the addresses of the metatiles and the sprite layouts because they're only given as an index now, not as the full memory address.

That way, you could save about an estimated 30-40% of the screen definition size, at the cost of a bit more drawing code and some small tables.

Similarly, there could be a table for the addresses of screen definitions, and the map definition could consist of 1-byte indexes into it rather than full words giving the address directly. I don't know how many bytes that would save, though...

Share this post


Link to post
Share on other sites

And another compression idea... the position where to draw metatiles could also be further compressed. I noticed that as far as I can see, the upper byte of the address is always >02, >05, >08, >0D or >11. This are 5 positions which can be expressed in 3 bits. The lower byte is always divideable by 8, so the lower 3 bits are non-significant. Therefore, you'd only need one byte where you could strip the lower 3 bits and use them as an index into the possible upper byte table. In my example, this would save 4 more bytes in the definition of screen 1, bringing down the total from 35 to 31 bytes, exactly half of what it used to be.

Share this post


Link to post
Share on other sites

And another compression idea... ;-)

As I said, I noticed that most metatiles only appear at one height. So with the 3 bits in the position index, you could also select between different tables of metatiles permitted on that line. For instance, such a table could look like this:

 

Line_Tables *Table of line tables

Table_Line_2

Table_Line_5

Table_Line_8

Table_Line_D

Table_Line_11

 

Table_Line_2:

MTL01, MTL02, MTL03, MTL10

Table_Line_5:

MTL00, MTL0E, MTL10

Table_Line_8:

MTL07, MTL08, MTL09, MTL19

Table_Line_D:

MTL12, MTL15

Table_Line_11:

MTL0A, MTL0B, MTL0C, MTL14

 

These tables probably are not complete, but then the actual metatile list could consist of indexes into one of these tables. So if line 5 is given, a 0 would give MTL00, a 1 would give MTL0E, a 2 would give MTL10 and so on. This way, the actual metatile definition could be shortened to four bits (1 hex character) since I doubt that more than 16 distinct metatiles are ever appearing the same line on screen.

Share this post


Link to post
Share on other sites

Well... I have some ideas how, maybe, some memory could be saved...

 

First... the metatiles are given as full graphics. Are they not consisting of 8x8 tiles? Could there be some memory saved by breaking down the metatiles into 8x8 tiles?

 

...

 

Thanks, I really appreciate some technical feedback. However, I'm way beyond thinking about ripping up that part of the code. I have moved on to work on a 64K cartridge version where there's no problem with space, and I have made a first version. But at the moment I have lost interest in doing any further work on this game. I may come back to it later...

 

One problem with splitting the graphics into 8x8 tiles is that there are 1021 unique tiles in total and more than 480 unique tiles on a single screen, so you would need 10 bits for each map index. I'm not sure how often a tile is duplicated within a meta tile, but saving tiles was clearly not an issue when the graphics was designed.

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...