Jump to content
IGNORED

WIP- Space Taxi


Just Jeff

Recommended Posts

Well I haven't posted an update in a couple of weeks so I'll put this .bin up even though its glitchy and incomplete.  Its been a significant amount of work, with little to show.  Basically, my previous uploads had some cut corners that needed to be dealt with.  I really wanted to get the program to run through all the screens- so a level intro, then a play screen, and so on.  Even if the play screens are identical.  But once I started, it seemed like I had to fix some things first or I'd be just duplicating messes.

 

Firstly, you may have noticed that the previous version always played the same- I think it was pad 2 to pad 3, then pad 3 to Up.  Now its randomized.  All of that code I posted on September 3rd was static- wasn't going to get me past the one screen and always the same order.  Now, that code is basically in table form, and the program can do those things in random order and future screens will just have their own tables.  I wonder if the C64 version is random..  I'm just assuming it is.

 

The other thing you'll notice is basic intro screens- this required me to redo my jump tables to make it more logical.  Intro screens end in 0 (D0), play screens end in 1.  This allowed me to split the jump tables in half- useful because a carry branch quickly gets to the proper bank with its own table.

 

So its does like 3 screens now before it goes off the rails.  I know why it does, I just haven't gotten around to writing the code.  Also- the "Itinerary" of the dashboard is a little confusing at this point.  The "Hey" and "Up" are gone at the moment, You'll always see a pad number when its generated- just remember- you don't see "Up" when its time to leave.  Just look for the gate to disappear.

 

  .bin below.

SpaceTaxi.asm.bin

  • Like 8
Link to comment
Share on other sites

image.thumb.png.c51bbf515b8b850f6836d05c1cb2961f.pngimage.thumb.png.384ff8e4da6140f0fe30bd4947b0a20e.png

 

Much better progress this week.  I achieved my major goal of having the game start with title screens, then run through 24 customizable play screens with 24 intros.  Now... to get through it all, I had to point to existing code, tables, and routines and just did a few color changes for the first few play screens just as a proof of concept, so its pretty much the same screen over and over.  But at this point the code is laid out nice and the customizations should be pretty straight forward.  I'll basically copy a screen, rename it, change pointers for the jump, then customize it.  I felt like this is the base point I had to reach and then build up from here.  I also fixed and finished most of the stuff I left undone last week such as:

 

Cab should be already occupied when screens start (except 1st)
Correct hailing-shout-outs

When you jump off a correct pad, then return, it no longer throws off the sequence

When the gate is open, you can no longer land on the (hidden) designated pad (incorrectly)

Passenger goes back into hailing state if you lift off prematurely

 

This week saw the return of my famous task grid- and I credit much of my progress to it:

image.thumb.png.4aa092d8b4292b5c52a4bc670422e29e.png
Not a lot of items on it but it did help me focus and recall.

 

-Jeff

 

SpaceTaxi.asm.bin

Edited by Just Jeff
  • Like 5
Link to comment
Share on other sites

11 minutes ago, Just Jeff said:

This week saw the return of my famous task grid- and I credit much of my progress to it:


Not a lot of items on it but it did help me focus and recall.

I am using a task list for the same reasons too, either on top of the code or as issues in GitHub. 

  • Like 1
Link to comment
Share on other sites

On 10/2/2022 at 2:20 PM, Thomas Jentzsch said:

I am using a task list for the same reasons too, either on top of the code or as issues in GitHub. 

Nice..  I based my grid loosely on Steven Covey stuff- perfect for large tasks, largely because it helps me determine what not to work on.

 

See the source image

Link to comment
Share on other sites

Greetings,

 

New .bin attached.. 

 

I laid out the dashboard to prep for adding the tip, bank, and fuel functions as well as to see how much I could realistically fit in.  Also trying some new colors which are more of a departure from the original.  Any opinions on the new dash colors or anything else?

image.thumb.png.d84f8f951c1749557adb173823ca0de6.png

 

 

SpaceTaxi.asm.bin

Edited by Just Jeff
  • Like 5
Link to comment
Share on other sites

On 1/14/2017 at 5:05 AM, Just Jeff said:

Has anyone ever attempted Space Taxi on the 2600? It think the 2600 could do a pretty decent version of it.

 

10 OCT 2022 Edit:  Latest .bin here.

 

 

 

 

 

SpaceTaxi.asm.bin 64 kB · 8 downloads

“Hey, taxi!” “Voice clips please!”

 

I understand if it won’t work though.

Edited by Ecernosoft
  • Like 1
Link to comment
Share on other sites

On 10/15/2022 at 4:41 AM, TIX said:

Looking smart, playing smoothly !

No big deal really, but some times the passengers move in the opposite direction from the one I was expecting..

Thanks!   Yeah that's going to take some effort because the RESP1 is taking place at different times in different locations.  The taxi's X position will need to be translated into distance from each RESP1, not to mention, converted to early HMOVE values.  So, when each screen is done, that's probably when I'll work on those.  Right now I simply AND the FrameCounter and store it in HMP1 so the movement is only just to make him wander around until he collides with the taxi.

 

22 hours ago, Ecernosoft said:

“Hey, taxi!” “Voice clips please!”

 

I understand if it won’t work though.

It will have voice for sure and I posted an example here some time ago, but like many other things, its probably something that is better done later.  I plan to get a working gas gauge and a death plummet crash sequence next.

 

 

 

I have the Tips and Score fields functioning now, so we're finally making some money:

 

image.thumb.png.5b28cd2d178a747057328bd7008c4e81.png

 

Its taking too much kernel time though.  I'm at 267 scan lines now- 26 of them for the dash.  And you can see the dash is a little distorted now as a result.  I'd really like to reduce the dash height to 24 scan lines.  The issue centers around setting up the digits for the Tips and the Score.   Does anyone have any ideas?

 


;Setup line #2  
;Load up RAM buffer with either pointers or graphics

      lda Tip           ;This is the Dollar sign and the 10s digit for the tip
      and #%11110000 
      lsr 
      lsr
      lsr
      lsr 
      tay 
      lda DollarGfxLo,y ;Store a pointer which will be accessed while drawing
      sta Sprite1
      lda DollarGfxHi,y
      sta Sprite1+1
 
;This is dollar 1s digit before the decimal.  The decimal will be manually added
      lda Tip
      and #%00001111 
      tax 
      lda DigitBlankGfxLo,x ;Store a pointer which will be accessed when loading a RAM buffer
      sta Sprite1+6 
      lda DigitBlankGfxHi,x
      sta Sprite1+7 

;Load and combine cents
      lda Tip+1
      and #%11110000 
      lsr
      lsr
      lsr
      lsr 
      tax
.loadCents10s
      lda DigitBlankGfxLo,x ;Store a pointer which will be accessed when loading a RAM buffer
      sta Sprite1+2
      lda DigitBlankGfxHi,x
      sta Sprite1+3

      lda Tip+1
      and #%00001111 
      tax 
      lda BlankDigitGfxLo,x ;Store a pointer which will be accessed when loading a RAM buffer
      sta Sprite1+4
      lda BlankDigitGfxHi,x
      sta Sprite1+5

      ldy #4
.loadSprites      ;Load the RAM buffer with full sprites
      lda (Sprite1+2),y       ;Load one of the penny digits
      ora (Sprite1+4),y       ;Combine it with the other
      sta Sprite3,y           ;Store the combo
      lda (Sprite1+6),y       ;Load the single dollar digit in front of the decial
      sta Sprite2,y           ;Store it, add the decimal to right nibble later
      dey
      bpl .loadSprites
      
      lda #%00000010          ;Add the decimal
      ora Sprite2
      sta Sprite2
 
;Set up the passenger's requests
      lda #>ShoutOuts         ;Set the big end of the pointers. Don't go over one page.
      sta PadPtr4+1
      sta PadPtr5+1
      ldy #11                 ;Load the offset for Hey!
      lda PassengerState
      bmi .storePtr           ;If PASSENGER_HAIL, then store the 11 (Hey!)

      ldy #10                 ;Load the offset for blank
      cmp #PASSENGER_ONBOARD  ;Is the passenger onboard
      bne .storePtr           ;If not, then don't display anything

      ldy #9                  ;Load the offset for Up! just in case
      lda StopNumber          ;Then check for which stop
      bmi .storePtr           ;#$ff means the screen is done, so store 9 for Up!
      ldy CurrentTarget       ;Otherwise, pick the message for the next stop 
.storePtr
      lda ShoutOuts4,y        ;This is the table for the left half of the word(s)
      sta PadPtr4 
      lda ShoutOuts5,y        ;This is the table for the right half of the word(s)
      sta PadPtr5 
 

 

 

SpaceTaxi.asm.bin

  • Like 3
Link to comment
Share on other sites

20 minutes ago, Just Jeff said:

It will have voice for sure and I posted an example here some time ago, but like many other things, its probably something that is better done later.

YES!!!

Thanks!

Edit: I know my jokes are terrible ;)

 

Edited by Ecernosoft
  • Like 1
Link to comment
Share on other sites

@Just Jeff

Did you find the cycles yourself by now? The code you posted can be slightly optimized, but that will not gain you 3 lines.

 

Either you setup before the kernel (probably needs more RAM). Or you reduce the scanlines used for vertical blank and/or overscan.

  • Thanks 1
Link to comment
Share on other sites

On 10/24/2022 at 10:39 AM, Thomas Jentzsch said:

@Just Jeff

Did you find the cycles yourself by now? The code you posted can be slightly optimized, but that will not gain you 3 lines.

 

Either you setup before the kernel (probably needs more RAM). Or you reduce the scanlines used for vertical blank and/or overscan.

Nothing really.  My plan at this point is to load up the most time consuming 10 bytes in vblank and just hold on to it during the kernel. That would be the cents at the right of the decimals for both the tip and the score.  Its the most time consuming because two nibbles need to be ora'd with each other then all stored as a sprite in RAM.  That's the best I could think of.  I think the rest could be set up inside the dashboard.  What do you think?

Link to comment
Share on other sites

The bottom row only needs 4 sprite copies, right? Can't you create that data on-the-fly? That would be 8 loads (8*5 = 40 cycles) and 4 stores (4*3 = 12 cycles). Should fit, no?

 

BTW: You don't have to AND before shifting right 4 times.

Edited by Thomas Jentzsch
Link to comment
Share on other sites

On 10/25/2022 at 5:56 PM, Thomas Jentzsch said:

The bottom row only needs 4 sprite copies, right? Can't you create that data on-the-fly? That would be 8 loads (8*5 = 40 cycles) and 4 stores (4*3 = 12 cycles). Should fit, no?

 

BTW: You don't have to AND before shifting right 4 times.

Well I have those 4 indicator lights on the same row which I have not even started on.  They require setup as well as time on those lines so I don't know what's going to happen there either.

 

To make your idea work, I need to also add some ORAs- right? Indirect load left nibble, ORA indirect address of right nibble?

 

Thanks for pointing out the ANDs..  I'll change that.

Link to comment
Share on other sites

45 minutes ago, Just Jeff said:

Well I have those 4 indicator lights on the same row which I have not even started on.  They require setup as well as time on those lines so I don't know what's going to happen there either.

Will they change between lines? 

45 minutes ago, Just Jeff said:

To make your idea work, I need to also add some ORAs- right? Indirect load left nibble, ORA indirect address of right nibble?

Yup, that is why I calculated 8 loads (4 LDA + 4 ORA) 

Link to comment
Share on other sites

  • 2 weeks later...

 OK..  I've gotten it back down to 192 scanlines and also the fuel gauge functioning now.  .bin attached

 

On 10/25/2022 at 12:56 PM, Thomas Jentzsch said:

The bottom row only needs 4 sprite copies, right? Can't you create that data on-the-fly? That would be 8 loads (8*5 = 40 cycles) and 4 stores (4*3 = 12 cycles). Should fit, no?

 

BTW: You don't have to AND before shifting right 4 times.

 

Thanks Thomas...  I converted several of the loads to this.  I wasn't able to do one of them on the top half (with the fuel gauge) because there isn't enough time.  I also created another set of digits 0-9 followed by a decimal in ROM so I could do a single load on those.  And I have the same thing for dollar sign with one digit.

 

.kernelLoop1                  ;Top half of the dashboard
      sta WSYNC               ;3 0
      lda (PadPtr5),y         ;5 5
      sta GRP0                ;3 8
      lda (PadPtr4),y         ;5 13
      sta GRP1                ;3 16
      lda (Sprite1+6),y       ;4 20 
      sta GRP0                ;3 23 VDELP0 is on
      lda FuelGaugeNUSIZ,y    ;4 27
      sta ENAM1               ;3 30
      sta NUSIZ1              ;3 33 After ~31
      lda (Sprite1),y         ;5 38
      ldx #RED                ;2 40
      stx COLUPF              ;3 43 $34   Turn red after 42      
      sta GRP1                ;3 46
      lda #GREEN              ;2 48 $B0
      SLEEP 3                 ;3 51
      sta COLUPF              ;3 54
      lda #3                  ;2 56      3 players close
      sta NUSIZ1              ;3 59 store after ~55
      lda Sprite3,y           ;4 63
      dey                     ;2 65
      sta GRP1                ;3 68
      bpl .kernelLoop1        ;2/3 70/73

-break-

.kernelLoop2                  ;Bottom half of the dashboard
      sta WSYNC         ;3 0
      lda (PadPtr4),y   ;5 5
      ora (PadPtr5),y   ;5 10 Combine the 100s and the 10s 
      sta GRP0          ;3 13
      lda (Sprite1),y   ;5 18
      sta GRP1          ;3 21
      lda (Sprite1+2),y ;5 26
      ora (Sprite1+4),y ;5 31
      sta GRP0          ;3 34 VDELP0 is on
      SLEEP 7           ;7 41
      lda (Sprite1+6),y ;4 45
      sta GRP1          ;3 48 
      dey               ;2 50
      bpl .kernelLoop2  ;2/3 52/53

 

SpaceTaxi.asm.bin

  • Like 5
Link to comment
Share on other sites

  • 5 weeks later...

Good afternoon!  Two things...

 

Firstly, YouTube suggested this video to me.  Freaked me out- in a good way: 

 

 

Secondly, I finally worked up the nerve to begin the voice code this morning after I had an epiphany...  Bit-Packing!

 

I believe I need to run through 50 AUDV1 register changes for every frame shown.  That's just in the kernel section which should be the most difficult part.  Since the data is spread over multiple banks, its impractical to grab any data while in the kernel, therefore it must be grabbed in VBLANK and Overscan, then stored in RAM and used every 4 scan lines while in the kernel.  But 50 bytes of RAM seemed impractical and wasteful, if not impossible.  Finally, this morning it occurred to me that I can get away with 25 bytes if I take existing RAM that is only used outside the kernel and store the right nibble of it in the left nibble of 25 bytes of designated VoiceRAM.  In this way, 50 right nibbles are available for use for the price of only 25 bytes.   Oh right-  it's important to note that only the right nibble is used by the Atari, so the left nibble will be ignored and can therefore still be used to store useful data for other things, which makes this whole scheme work.  Additionally, 25 is on the high end.  With some code changes, there are some bytes that can get wrecked entirely while speech is happening and therefore, don't even need the swap space (VoiceRAM). Also, some bytes don't need two nibbles to begin with, in those cases the data can simply stay in the left nibble full time.  After these code changes, I think I can bring the dedicated bytes needed down to 19 if necessary.

 

So here's my bit packing and unpacking code.  I'd be curious to know if it could be more efficient.  It does run in the time allowed as is but then again, all this is doing is splitting the bytes (in preparation for grabbing voice data), then putting them back together after the screen is drawn. 

 

The RepackingBits looks a little unwieldy to me.  What do you think?

 

;in Bank 1

UnpackBits  SUBROUTINE      ;added in TypicalPlayLogic.asm

;Sound registers only use the right nibble.  So preserve the right nibble in the left nibble of VoiceRAM while
;in the kernel.  Then restore it when out of the kernel


    ldx #31         ;This can probably be reduced to about 19 with some code modifications.
                    ;I have 10 RAM bytes that can probably be trashed during speech and 3 RAM bytes that are single
                    ;nibbles so they don't need swap space.  Additionally, I probably could have used #25 here to get
                    ;through the kernel to begin with. 
.ramSplit
    lda Voice+32,x  ;This area of RAM will be borrowed for voice
    asl
    asl
    asl
    asl
    sta Voice,x     ;The right nibble is stored in the left nibble of Voice.  Right nibble is zero which is convenient.
    dex
    bpl .ramSplit
    rts             ;Return, then jump to a voice bank

                    ;Added in Overscan
RepackBits          ;Restore the left nibble of Voice, to the right nibble of Voice+32 while preserving that left nibble.
    ldx #31
.ramCombine
    lda Voice+32,x
    and #$f0        ;Strip the right nibble of the RAM value
    sta Voice+32,x
    lda Voice,x     ;Right nibble of Voice+32 was stored in left nibble here.
    lsr
    lsr
    lsr
    lsr
    ora Voice+32,x
    sta Voice+32,x
    dex
    bpl .ramCombine
    rts

 

 

Any suggestions?

 

-Jeff

  • Like 3
Link to comment
Share on other sites

4 hours ago, Just Jeff said:

Any suggestions?

 

I can't help with RAM, but you can save some cycles by using lookup tables.

 

For unpack you only need a 16-byte table, and you'll save a byte of code. It saves 4 cycles per iteration in exchange for 15 bytes of ROM and clobbering Y.

 

.ramSplit
    ldy Voice+32,x  ;This area of RAM will be borrowed for voice
    lda leftshift4,y
    sta Voice,x     ;The right nibble is stored in the left nibble of Voice.  Right nibble is zero which is convenient.
    dex
    bpl .ramSplit
    rts             ;Return, then jump to a voice bank

leftshift4 ; this can go anywhere in any accessible bank
    .byte $00,$10,$20,$30,$40,$50,$60,$70,$80,$90,$A0,$B0,$C0,$D0,$E0,$F0

 

You could also set up a macro to generate the table.

 

Ideally, ensure that the table does not cross a page boundary, since each page crossing indirect load costs an extra cycle. If you use dasm you can use my prevsamehighas macro (from attachment in this post) to confirm that at build time.

 

For pack, the principle is the same, but you would need a full-page table, so if you're at all tight on ROM this is a tougher trade-off.

 

There may be other optimizations. This is the one that immediately came to my mind.

  • Like 1
Link to comment
Share on other sites

This saves you 4 cycles/loop:

RepackBits          ;Restore the left nibble of Voice, to the right nibble of Voice+32 while preserving that left nibble.
    ldx #31
.ramCombine
    lda Voice,x     ;Right nibble of Voice+32 was stored in left nibble here.
    lsr
    lsr
    lsr
    lsr
    eor Voice+32,x  ;Strip the right nibble of the RAM value
    and	#$0f        ; clear left nibble gets xored once, 
    eor Voice+32,x  ; right nibble twice (== not xored at all)
    sta Voice+32,x
    dex
    bpl .ramCombine
    rts

But as of now, your whole idea seems maybe overly complex. E.g. what happens with the right nibble of Voice? And why can't you e.g. duplicate the kernel for data access in different banks? Or why don't you use a more flexible bankswitching?

  • Like 1
Link to comment
Share on other sites

 

On 12/11/2022 at 5:34 PM, Pat Brady said:

 

.ramSplit
    ldy Voice+32,x  ;This area of RAM will be borrowed for voice
    lda leftshift4,y
    sta Voice,x     ;The right nibble is stored in the left nibble of Voice.  Right nibble is zero which is convenient.
    dex
    bpl .ramSplit
    rts             ;Return, then jump to a voice bank

leftshift4 ; this can go anywhere in any accessible bank
    .byte $00,$10,$20,$30,$40,$50,$60,$70,$80,$90,$A0,$B0,$C0,$D0,$E0,$F0

 

Thanks- this is a technique I wasn't familiar with, but it doesn't work here..  Looks like you are expecting y values of 0 to 15 but these bytes are 0 to 255.  Probably that's what you meant when you mentioned a 256-byte table being necessary?  Alternatively, I was able to get this code to work by loading the accumulator with Voice+32, then AND #$0f, then TAY, but at that point it saves no time.

 

On 12/11/2022 at 6:14 PM, Thomas Jentzsch said:

This saves you 4 cycles/loop:

RepackBits          ;Restore the left nibble of Voice, to the right nibble of Voice+32 while preserving that left nibble.
    ldx #31
.ramCombine
    lda Voice,x     ;Right nibble of Voice+32 was stored in left nibble here.
    lsr
    lsr
    lsr
    lsr
    eor Voice+32,x  ;Strip the right nibble of the RAM value
    and	#$0f        ; clear left nibble gets xored once, 
    eor Voice+32,x  ; right nibble twice (== not xored at all)
    sta Voice+32,x
    dex
    bpl .ramCombine
    rts

But as of now, your whole idea seems maybe overly complex. E.g. what happens with the right nibble of Voice? And why can't you e.g. duplicate the kernel for data access in different banks? Or why don't you use a more flexible bankswitching?

Thanks!  That's some crazy code, but it does work.  Note- it also saves 2 bytes.  Though I don't think the comment "Strip the right nibble of the RAM value" is correct- values are left in there, being various xors of one of the preserved RAM nibbles and a used voice nibble.

 

So to answer your questions..

 

The right nibble of voice-  The right nibble is the only relevant nibble when it comes to AUDV1- but I'm sure you knew that.  Here is an abridged, two byte explanation of what I'm doing:

 

Note below, VoiceCounter and VoicePointer are really the same counter- just a typo.

 

Voice			ds 1	;Left nibble stores right half of FrameCounter while in kernel
FrameCounter	ds 1	;Can be any value.  Left nibble is always FrameCounter's left nibble. Right nibble borrowed for voice nibbles

;So two pieces of voice data fit per 1 byte of RAM reserved..
;If FrameCounter's value is at, for example $A2, then for the kernel split that up so
;Voice = $20 and FrameCounter = $A0.  This is OK becasue FrameCounter is not used in the kernel

;Jump to a voice data bank
;The voice data is 4 bits, played right nibble first, then left nibble second
;Load a byte of Voice Data and store each nibble in the right nibble of Voice and FrameCounter
lda VoiceByte
and #$0F
ora Voice 
sta Voice
lda VoiceByte
lsr
lsr
lsr
lsr
ora FrameCounter 
sta FrameCounter

;Complicated here, so the kernel is fast and simple

Kernel
;This code every 4 scan lines
dec VoicePointer	5 5
ldx VoiceCounter	3 8
lda Voice,x			4 12
sta AUDV1			3 15

;or maybe
tya					2 2		;use the kernel index
lsr					2 4
lsr					2 6		;multiply by 4
tax					2 8
lda Voice,x			4 12
sta AUDV1			3 15

;Then when the kernel is done, put FramCounter back together

 

Secondly, duplicating the kernels is impractical since there are 24 screens and multiple kernel bands, and 8 voice data banks.  I'll probably end up with 100 to 200 kernel bands then duplicated on 8 banks = 800 to 1600 kernels.

 

I'll consider more flexible bank switching, but still I don't think that will help me inside the kernel.

 

How am I doing?

 

-Jeff

 

 

Edited by Just Jeff
  • Like 1
Link to comment
Share on other sites

5 minutes ago, Just Jeff said:

Thanks- this is a technique I wasn't familiar with, but it doesn't work here..  Looks like you are expecting y values of 0 to 15 but these bytes are 0 to 255.  Probably that's what you meant when you mentioned a 256-byte table being necessary?  Alternatively, I was able to get this code to work by loading the accumulator with Voice+32, then AND #$0f, then TAY, but at that point it saves no time.

 

Ah, you're right. On all counts. 256-byte table should work but maybe not worth the ROM cost. Sorry for the wild goose chase.

  • Like 1
Link to comment
Share on other sites

On 12/13/2022 at 5:23 PM, Just Jeff said:

I'll consider more flexible bank switching, but still I don't think that will help me inside the kernel.

Perhaps Thomas is thinking about a format with 2k banks, like 3F or 3E. That way your kernel can be in the non-ephemeral 2k bank, and your sample data can be swapped as desired in the ephemeral 2k bank.

 

Whether you go with ram or rom samples, you could stagger the samples every 4 bytes, since that way you can use the scanline index for your samples, without modification. If you stick to ram, you can use a few consecutive kernels to access the bytes that were skipped over in previous kernels, with the sample data being stored in an interleaved fashion.

  • Like 1
Link to comment
Share on other sites

On 12/14/2022 at 3:19 PM, RevEng said:

Perhaps Thomas is thinking about a format with 2k banks, like 3F or 3E. That way your kernel can be in the non-ephemeral 2k bank, and your sample data can be swapped as desired in the ephemeral 2k bank.

 

Whether you go with ram or rom samples, you could stagger the samples every 4 bytes, since that way you can use the scanline index for your samples, without modification. If you stick to ram, you can use a few consecutive kernels to access the bytes that were skipped over in previous kernels, with the sample data being stored in an interleaved fashion.

 

On 12/14/2022 at 3:19 PM, RevEng said:

Perhaps Thomas is thinking about a format with 2k banks, like 3F or 3E. That way your kernel can be in the non-ephemeral 2k bank, and your sample data can be swapped as desired in the ephemeral 2k bank.

 

Whether you go with ram or rom samples, you could stagger the samples every 4 bytes, since that way you can use the scanline index for your samples, without modification. If you stick to ram, you can use a few consecutive kernels to access the bytes that were skipped over in previous kernels, with the sample data being stored in an interleaved fashion.

OK I'm not familiar with those types of bankswitching.  Do I have this correct?--  I could have my current voice data in the lower 2K area as needed (these will need to be switched)  The upper 2K could contain game code that fetches from the lower 2K area with no bankswitch per each fetch?  The description I saw mentioned JMPs and JSRs but didn't specifically mention what I would want- indexed loads and indirect addressing to the lower bank.  Also, one person called it "RAM" is there RAM?

 

Can I have multiple upper banks?  The game code wouldn't fit into a single 2K upper bank.  I currently have 4K for VBLANK and Overscan, and 8K reserved for the play kernels alone.

Link to comment
Share on other sites

A disclaimer - while I've played around with a few banking formats, I haven't played around with these two specifically. That said, kevtris' mapper doc is pretty clear on how they work. Plus they're very similar to the 7800 supergame formats, which I have used once or twice.

9 hours ago, Just Jeff said:

OK I'm not familiar with those types of bankswitching.  Do I have this correct?--  I could have my current voice data in the lower 2K area as needed (these will need to be switched)  The upper 2K could contain game code that fetches from the lower 2K area with no bankswitch per each fetch? 

Yep, that's correct.

 

9 hours ago, Just Jeff said:

The description I saw mentioned JMPs and JSRs but didn't specifically mention what I would want- indexed loads and indirect addressing to the lower bank.  Also, one person called it "RAM" is there RAM?

However you've swapped them, the bank is there in address space for whatever kind of access you like.

 

3F was used back in the day by Tigervision, and only had ROM. 3E is the homebrew extension of 3F, and does have RAM in addition to ROM.

 

9 hours ago, Just Jeff said:

Can I have multiple upper banks?  The game code wouldn't fit into a single 2K upper bank.  I currently have 4K for VBLANK and Overscan, and 8K reserved for the play kernels alone.

Not with these schemes as they currently stand. You can go with a new scheme/variant, but then you're stuck with a heavier lift, with emulation and cart hardware needing to be updated to match your new scheme.

 

  • Thanks 1
Link to comment
Share on other sites

I suggest you have a look at 3E+. It is more flexible than 3E, which has its limits due to the fixed last segment. And having just two segments turned out to be a bottleneck too, when @Andrew Davie and I developer Boulder Dash.

 

Here is a brief description from the source code:

  Cartridge class for new tiling engine "Boulder Dash" format games with RAM.
  Kind of a combination of 3F and 3E, with better switchability.
  B.Watson's Cart3E was used as a template for building this implementation.

  Note: In descriptions $F000 is equivalent to $1000 -- that is, we only deal
  with the low 13 bits of addressing. Stella code uses $1000, I'm used to $F000
  So, mask with top bits clear :) when reading this document.

  In this scheme, the 4K address space is broken into four 1K ROM/512b RAM segments
  living at 0x1000, 0x1400, 0x1800, 0x1C00 (or, same thing, 0xF000... etc.),

  The destination segment (0-3) is held in the top bits of the value written to
  $3E (for RAM switching) or $3F (for ROM switching). The low 6 bits give
  the actual bank number (0-63) corresponding to 512 byte blocks for RAM and
  1024 byte blocks for ROM. The maximum size is therefore 32K RAM and 64K ROM.

  D7D6         indicate the segment number (0-3)
  D5D4D3D2D1D0 indicate the actual # (0-63) from the image/ram

  ROM:

  The last 1K ROM ($FC00-$FFFF) segment in the 6502 address space (ie: $1C00-$1FFF)
  is initialised to point to the FIRST 1K of the ROM image, so the reset vectors
  must be placed at the end of the first 1K in the ROM image.

  Note: This is DIFFERENT to 3E which switches in the UPPER segment and this
  segment is fixed.  This allows variable sized ROM without having to detect size.

  ROM switching (write of segment+bank number to $3F) D7D6 upper 2 bits of bank #
  indicates the destination segment (0-3, corresponding to $F000, $F400, $F800,
  $FC00), and lower 6 bits indicate the 1K bank to switch in.  Can handle 64
  x 1K ROM banks (64K total).

  D7 D6 D5D4D3D2D1D0
  0  0   x x x x x x   switch a 1K ROM bank xxxxxx to $F000
  0  1                 switch a 1K ROM bank xxxxxx to $F400
  1  0                 switch a 1K ROM bank xxxxxx to $F800
  1  1                 switch a 1K ROM bank xxxxxx to $FC00

  RAM switching (write of segment+bank number to $3E) with D7D6 upper 2 bits of
  bank # indicates the destination RAM segment (0-3, corresponding to $F000,
  $F400, $F800, $FC00).

  Can handle 64 x 512 byte RAM banks (32K total)

  D7 D6 D5D4D3D2D1D0
  0  0   x x x x x x   switch a 512 byte RAM bank xxxxxx to $F000 with write @ $F200
  0  1                 switch a 512 byte RAM bank xxxxxx to $F400 with write @ $F600
  1  0                 switch a 512 byte RAM bank xxxxxx to $F800 with write @ $FA00
  1  1                 switch a 512 byte RAM bank xxxxxx to $FC00 with write @ $FE00

Please, let me know if anything is not clear.

  • Like 1
Link to comment
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.
Note: Your post will require moderator approval before it will be visible.

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