Jump to content
IGNORED

Can the DPC+ Stack Be Hacked and Turned Into Variables?


Random Terrain

Recommended Posts

Back when RevEng had more time, he made improvements to batari Basic. Would it be possible for another person who is good at assembly language programming to dive in and convert the DPC+ 256 stack locations into 256 variables? If all 256 spots couldn't be used as variables, how about 200 variables? If 200 would still be too many, how about 100 variables? I'll take what I can get.

 

 

Thanks.

Link to comment
Share on other sites

It's 800 variables RT - what happened to I'll take what I can get? ;)

 

It would be cool to see more variables in DPC+ but you can declare thousands of variables with virtual world BASIC's RAM arrays if you have a project that needs a lot of variables right now.

 

R.T. sometimes has his games physically published like Seaweed Assault. SuperCharger users are rare and CBS RAM donor carts are sometimes hard to find. He was thinking some of the RAM or EEPROM storage available to DPC+ carts could be re-purposed for batari BASIC.

 

Kind of a hard position DPC+ or not.

  • Like 1
Link to comment
Share on other sites

It's 800 variables RT - what happened to I'll take what I can get? ;)

 

It would be cool to see more variables in DPC+ but you can declare thousands of variables with virtual world BASIC's RAM arrays if you have a project that needs a lot of variables right now.

 

I'll take what I can get with the 10 multicolored single-height sprites and high resolution playfield with simultaneous multicolored foreground and background.

  • Like 2
Link to comment
Share on other sites

I'm using the stack as extra variables but it depends on how you use it. I use the stack command to position the location manually and store information there sort of like RAM. This range is for this thing, this range is for this thing, and so on. Where it gets tricky is manipulating the stack. The key is you need to first pull the data out in a variable. So while you can store more information, you can't use it all at once.

 

I go to the stack location and pull the data out using temp variables. Manipulate it as I need, then push it back. This is more cycle intensive than just changing a normal variable.

 

Thinking about it now though, maybe you can just manipulate the stack memory locations directly. I mean, we have the "stack" command, but maybe you don't have to use it that way and can use it like any other memory location. Hmm. Maybe the whole stack interface is unnecessary?

  • Like 1
Link to comment
Share on other sites

 

I'll take what I can get with the 10 multicolored single-height sprites and high resolution playfield with simultaneous multicolored foreground and background.

That's pretty cool!

 

 

R.T. sometimes has his games physically published like Seaweed Assault. SuperCharger users are rare and CBS RAM donor carts are sometimes hard to find. He was thinking some of the RAM or EEPROM storage available to DPC+ carts could be re-purposed for batari BASIC.

 

Kind of a hard position DPC+ or not.

To boot it looks like none of these technologies work on the new Atari portable - DPC+ or vwB, but plain batari BASIC does.

Link to comment
Share on other sites

The stack memory in question is locked up inside the ARM chip, and it's not normally accessible to the 6502 - except when the 6502 uses DPC+ functions to fetch it and put it back.

 

The closest you can get to random access with this memory is exactly what wallaby is doing, and yes, it's cumbersome and cycle-intensive.

 

There's no reason why a new standard - lets call it DPC++ - couldn't have RAM mapped into 6502 address space like the SARA chip. Just bear in mind you'll lose twice as much ROM as the RAM you get, and someone "just" needs to rewrite the ARM code and go through all of the testing.

  • Like 2
Link to comment
Share on other sites

The stack memory in question is locked up inside the ARM chip, and it's not normally accessible to the 6502 - except when the 6502 uses DPC+ functions to fetch it and put it back. So with the current DPC+ standard you won't be able

 

The closest you can get to random access with this memory is exactly what wallaby is doing, and yes, it's cumbersome and cycle-intensive. There's other way DPC+.

 

There's no reason why a new standard - lets call it DPC++ - couldn't have RAM mapped into 6502 address space like the SARA chip. Just bear in mind you'll lose twice as much ROM as the RAM you get, and someone "just" needs to rewrite the ARM code and go through all of the testing.

 

how does RAM on the cartridge port(?) know if you're reading or writing?

 

edit: you mention losing twice as much ROM so are you talking about using an address line for R/W

ie read a location at one address and write that location at another address?

Edited by bogax
Link to comment
Share on other sites

Back when RevEng had more time, he made improvements to batari Basic. Would it be possible for another person who is good at assembly language programming to dive in and convert the DPC+ 256 stack locations into 256 variables? If all 256 spots couldn't be used as variables, how about 200 variables? If 200 would still be too many, how about 100 variables? I'll take what I can get.

 

 

Thanks.

 

A couple assembly functions would probably do it for you. These are untested:

SetValue
    ; A = location 0-255
    ; Y = value
    clc
    adc #<STACKbegin
    sta DF7LOW
    lda #0
    adc #>STACKbegin
    sta DF7HI
    sty DF7WRITE
    RETURN
    
GetValue
    ; A = location 0-255
    clc
    adc #<STACKbegin
    sta DF7LOW
    lda #0
    adc #>STACKbegin
    sta DF7HI
    lda DF7DATA
    ; A is the return value
    RETURN

To use you'd do something like this:

 rem constants for locations the values are stored in the Stack RAM.  Use values from 0 to 255
 const SR_HitPoints = 0
 const SR_Strength = 1

 rem temp1 is the dummy return value for SetValue
 temp1 = SetValue(#SR_HitPoints, #10) : rem init hit points to 10
 temp1 = SetValue(#SR_Strength, #20) : rem init strength to 20

 REM take damage
 b = GetValue(#SR_HitPoints)
 b = b - 1
 temp1 = SetValue(#SR_HitPoints, b)

 REM workout successful
 b = GetValue(#SR_Strength)
 b = b + 4
 temp1 = SetValue(#SR_Strength, b)

 REM poisoned!
 b = GetValue(#SR_HitPoints)
 b = b - 5
 temp1 = SetValue(#SR_HitPoints, b)
 b = GetValue(#SR_Strength)
 b = b - 2
 temp1 = SetValue(#SR_Strength,b)

If you start at the bottom of the stack (location 0) for your values, you can still use the stack like normal. Just make sure you don't collide - if you push 100 values on the stack without pulling any off, it'd overwrite data you stored at location 156.

 

There's a bit of overhead for accessing these values, so save the most frequently used values in normal RAM and use these functions for things that aren't used as often.

  • Like 1
Link to comment
Share on other sites

If you start at the bottom of the stack (location 0) for your values, you can still use the stack like normal. Just make sure you don't collide - if you push 100 values on the stack without pulling any off, it'd overwrite data you stored at location 156.

On second thought that won't work. Data Fetcher 7 is what keeps track of where the stack is pointing at. Those functions would change that pointer.

 

Looks like when you call the DPC+ version of drawscreen it initializes the other datafetchers, so if you change those functions to use data fetcher 0 (or DF1, DF2, ..., DF6) then you can also use the stack as normal:

 

SetValue
    ; A = location 0-255
    ; Y = value
    clc
    adc #<STACKbegin
    sta DF0LOW
    lda #0
    adc #>STACKbegin
    sta DF0HI
    sty DF0WRITE
    RETURN
    
GetValue
    ; A = location 0-255
    clc
    adc #<STACKbegin
    sta DF0LOW
    lda #0
    adc #>STACKbegin
    sta DF0HI
    lda DF0DATA
    ; A is the return value
    RETURN
  • Like 1
Link to comment
Share on other sites

I see this in DPCplusbB.h:

 echo "DPC free RAM=",($1000-(USERSTACK&$0FFF))d



What value does that output when you compile your various bB DPC+ projects? Is it consistent? If not, is it always greater than 256?

What I'm looking at is if the last page ($0F00 - $0FFF) of DPC+ RAM is always free then you could use that RAM for variable storage and the functions would be shorter/faster:
SetValue
    ; A = location 0-255
    ; Y = value
    sta DF0LOW
    lda #$0f
    sta DF0HI
    sty DF0WRITE
    RETURN
    
GetValue
    ; A = location 0-255
    sta DF0LOW
    lda #$0f
    sta DF0HI
    lda DF0DATA
    ; A is the return value
    RETURN



If that value is greater than 256 then you can safely use these new functions, as well as use the stack like normal.

If the value is less than 256 you could just ignore the stack and use the new functions, or you could shrink the stack and use the new functions. If the value reported was 243 then you'd need to adjust the stack by 13 (256-243) and thus set the STACK to either 13 (0+13) or 242 (255-13). I'm not sure how the STACK command is implemented so don't know which of those 2 values would be correct.
  • Like 2
Link to comment
Share on other sites

On second thought that won't work. Data Fetcher 7 is what keeps track of where the stack is pointing at. Those functions would change that pointer.

 

Looks like when you call the DPC+ version of drawscreen it initializes the other datafetchers, so if you change those functions to use data fetcher 0 (or DF1, DF2, ..., DF6) then you can also use the stack as normal:

 

SetValue
    ; A = location 0-255
    ; Y = value
    clc
    adc #<STACKbegin
    sta DF0LOW
    lda #0
    adc #>STACKbegin
    sta DF0HI
    sty DF0WRITE
    RETURN
    
GetValue
    ; A = location 0-255
    clc
    adc #<STACKbegin
    sta DF0LOW
    lda #0
    adc #>STACKbegin
    sta DF0HI
    lda DF0DATA
    ; A is the return value
    RETURN

FastFetch Mode is off at this point, no? If not you can still safely use AND #0 instead of LDA #0 to get around this.

Link to comment
Share on other sites

FastFetch Mode is off at this point, no? If not you can still safely use AND #0 instead of LDA #0 to get around this.

 

 

Yep, it's off. The bB DPC+ kernel turns fast fetch on before it starts drawing the display, then back off when it's done. I suspect that's because it'd be too difficult to rewrite the existing bB framework to not use LDA #.

Link to comment
Share on other sites

I only have one current project, but it reports DPC Ram = 603.

 

I'll see if it changes as I add more code and stack manipulation.

 

Wow, way more than I was expecting. Time for a revision!

 

The following in DPCplusbB.h will output a value when you compile your bB program:

echo "DPC free RAM=",($1000-(USERSTACK&$0FFF))d

Considering the value reported by that - if you want to use the DPC+ Stack then:

  • If the value is >= 256 then you can use Set/GetValue1 to save 256 values
  • If the value is >= 512 then you can also use Set/GetValue2 for a total of 512 values
If you do not want to use the DPC+ Stack then:
  • If the value is >= 0 then you can use Set/GetValue1 to save 256 values
  • If the value is >= 256 then you can also use Set/GetValue2 for a total of 512 values
SetValue1
    ; A = location 0-255
    ; Y = value
    sta DF0LOW
    lda #$0f
    sta DF0HI
    sty DF0WRITE
    RETURN
    
GetValue1
    ; A = location 0-255
    sta DF0LOW
    lda #$0f
    sta DF0HI
    lda DF0DATA
    ; A is the return value
    RETURN


SetValue2
    ; A = location 0-255
    ; Y = value
    sta DF0LOW
    lda #$0e
    sta DF0HI
    sty DF0WRITE
    RETURN
    
GetValue2
    ; A = location 0-255
    sta DF0LOW
    lda #$0e
    sta DF0HI
    lda DF0DATA
    ; A is the return value
    RETURN

 

Example of using both sets of functions:

 rem constants for locations of values stored in last page of DPC+ RAM
 rem assign constants to unique values from 0 to 255
 rem V1_ helps to reinforce the use of GetValue1() and SetValue1()
 const V1_HitPoints = 0

 rem constants for locations of values stored in second-to-last page of DPC+ RAM
 rem assign constants to unique values from 0 to 255
 rem V2_ helps to reinforce the use of GetValue2() and SetValue2()
 const V2_Strength = 0

 rem temp1 is the dummy return value for SetValue
 temp1 = SetValue1(#V1_HitPoints, #10) : rem init hit points to 10
 temp1 = SetValue2(#V2_Strength, #20) : rem init strength to 20

 REM take damage
 b = GetValue1(#V1_HitPoints)
 b = b - 1
 temp1 = SetValue1(#V1_HitPoints, b)

 REM workout successful
 b = GetValue2(#V2_Strength)
 b = b + 4
 temp1 = SetValue2(#V2_Strength, b)

 REM poisoned!
 b = GetValue1(#V1_HitPoints)
 b = b - 5
 temp1 = SetValue1(#V1_HitPoints, b)
 b = GetValue2(#V2_Strength)
 b = b - 2
 temp1 = SetValue2(#V2_Strength,b)

Get/SetValue1 uses the last page, $0F, of DPC+ RAM. Get/SetValue2 uses the second-to-the-last page, $0E, of DPC+ RAM.

 

Items are on the same page when the high-byte of their addresses have the same value, so addresses $0F00 and $0FFF are both on the same page (page $0F) while $0EFF and $0F00 are on different pages (page $0E and $0F respectively).

  • Like 1
Link to comment
Share on other sites

EDIT Fixed it.

 

Here is the code adapted to bB

 

 

  function SetValue1
  asm
  ; A = location 0-255
  ; Y = value
  sta DF0LOW
  lda #$0f
  sta DF0HI
  sty DF0WRITE
end
  return
    
  function GetValue1
  asm
    ; A = location 0-255
    sta DF0LOW
    lda #$0f
    sta DF0HI
    ;lda DF0DATA
    ; A is the return value
end
  return DF0DATA

  function SetValue2
    asm
    ; A = location 0-255
    ; Y = value
    sta DF0LOW
    lda #$0e
    sta DF0HI
    sty DF0WRITE
end
  return
    
  function GetValue2
  asm
    ; A = location 0-255
    sta DF0LOW
    lda #$0e
    sta DF0HI
    ;lda DF0DATA
    ; A is the return value
end
  return DF0DATA

 

I commented out the last LDA on the Get functions because of how I return from the functions. If I leave the LDA in, the return value is 1 off. If I comment it out, it works as expected in bB.

Edited by wallaby
Link to comment
Share on other sites

Yep - doing LDA DF0DATA followed by RETURN DF0DATA would result in the next value being returned instead of the value you wanted as the Data Fetcher's pointer would have advanced to the next memory location after the first DF0DATA.

When I wrote the Sound Effect Driver a few years back I put the functions such as sfxtrigger in a file called sfx.asm:

sfxtrigger
    tay ; sound effect is passed in accumulator, move to Y
    ldx SFX_LEFT       ; test left channel
    lda sfxCV,x        ; CV value will be 0 if channel is idle 
    bne .leftnotfree   ; if not 0 then skip ahead
    sty SFX_LEFT       ; channel is idle, use it
    RETURN             ; all done
.leftnotfree 
    ldx SFX_RIGHT      ; test right channel
    lda sfxCV,x        ; CV value will be 0 if channel is idle
    bne .rightnotfree  ; if not 0 then skip ahead
    sty SFX_RIGHT      ; channel is idle, use it
    RETURN             ; all done
.rightnotfree
    cpy SFX_LEFT       ; test sfx priority with left channel
    bcc .leftnotlower  ; skip ahead if new sfx has lower priority than active sfx
    sty SFX_LEFT       ; new sfx has higher priority so use left channel
    RETURN
.leftnotlower 
    cpy SFX_RIGHT      ; test sfx with right channel
    bcc .rightnotlower ; skip ahead if new sfx has lower priority than active sfx
    sty SFX_RIGHT      ; new sfx has higher priority so use right channel
.rightnotlower
    RETURN


then included that file in a bB demo program via the inline statement. Doing it that way I didn't need to use function, asm, or end. My understanding, based on the documentation for function, is whatever was in the accumulator (A) would be the return value; though, the driver didn't have values to return so I never confirmed that was true.

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