Jump to content

Photo

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


32 replies to this topic

#1 Random Terrain OFFLINE  

Random Terrain

    Visual batari Basic User

  • 28,307 posts
  • Controlled Randomness
    Replay Value
    Nonlinear
  • Location:North Carolina (USA)

Posted Sun Sep 11, 2016 9:09 PM

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.



#2 Mr SQL OFFLINE  

Mr SQL

    Stargunner

  • 1,753 posts

Posted Sun Sep 11, 2016 9:13 PM

http://atariage.com/...-800-variables/ :)



#3 Random Terrain OFFLINE  

Random Terrain

    Visual batari Basic User

  • Topic Starter
  • 28,307 posts
  • Controlled Randomness
    Replay Value
    Nonlinear
  • Location:North Carolina (USA)

Posted Sun Sep 11, 2016 9:17 PM

http://atariage.com/...-800-variables/  :)

 
Thanks, but that's not batari Basic's DPC+.



#4 Mr SQL OFFLINE  

Mr SQL

    Stargunner

  • 1,753 posts

Posted Sun Sep 11, 2016 9:28 PM

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.



#5 Gemintronic OFFLINE  

Gemintronic

    Jason S. - Lead Developer & CEO

  • 8,854 posts

Posted Sun Sep 11, 2016 9:32 PM

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.



#6 Random Terrain OFFLINE  

Random Terrain

    Visual batari Basic User

  • Topic Starter
  • 28,307 posts
  • Controlled Randomness
    Replay Value
    Nonlinear
  • Location:North Carolina (USA)

Posted Sun Sep 11, 2016 9:38 PM

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.



#7 wallaby OFFLINE  

wallaby

    Chopper Commander

  • 100 posts

Posted Sun Sep 11, 2016 9:43 PM

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?



#8 Mr SQL OFFLINE  

Mr SQL

    Stargunner

  • 1,753 posts

Posted Sun Sep 11, 2016 9:45 PM

 
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.



#9 Gemintronic OFFLINE  

Gemintronic

    Jason S. - Lead Developer & CEO

  • 8,854 posts

Posted Sun Sep 11, 2016 9:54 PM

In the end I hope an AtariAge 2600 clone comes along with DPC+, extra RAM, AtariVox and SaveKey support built in.

 

Pending that I wonder why a stack instead of directly accessible RAM was used.  Maybe to maintain compatibility with the Activision DPC?



#10 RevEng ONLINE  

RevEng

    River Patroller

  • 4,722 posts
  • Bitnik
  • Location:Canada

Posted Sun Sep 11, 2016 10:06 PM

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.

#11 bogax OFFLINE  

bogax

    Dragonstomper

  • 724 posts

Posted Sun Sep 11, 2016 10:12 PM

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, Sun Sep 11, 2016 10:25 PM.


#12 wallaby OFFLINE  

wallaby

    Chopper Commander

  • 100 posts

Posted Sun Sep 11, 2016 10:18 PM

Regarding the current stack, I feel it's great for storing information that doesn't change every frame. You can use it like 256 extra variables this way.

 

It's funny, before I starting writing an Atari 2600 game, 256 bytes would have been completely inconsequential to me.



#13 RevEng ONLINE  

RevEng

    River Patroller

  • 4,722 posts
  • Bitnik
  • Location:Canada

Posted Sun Sep 11, 2016 10:29 PM

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?


Yeah, just like SARA.

#14 SpiceWare ONLINE  

SpiceWare

    Draconian

  • 11,645 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Mon Sep 12, 2016 9:32 AM

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.

#15 SpiceWare ONLINE  

SpiceWare

    Draconian

  • 11,645 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Mon Sep 12, 2016 11:23 AM

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


#16 SpiceWare ONLINE  

SpiceWare

    Draconian

  • 11,645 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Mon Sep 12, 2016 12:43 PM

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.



#17 wallaby OFFLINE  

wallaby

    Chopper Commander

  • 100 posts

Posted Mon Sep 12, 2016 7:40 PM

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

 

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.



#18 Omegamatrix OFFLINE  

Omegamatrix

    Quadrunner

  • 6,136 posts
  • Location:Canada

Posted Mon Sep 12, 2016 7:50 PM

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.



#19 SpiceWare ONLINE  

SpiceWare

    Draconian

  • 11,645 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Mon Sep 12, 2016 9:16 PM

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



#20 SpiceWare ONLINE  

SpiceWare

    Draconian

  • 11,645 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Tue Sep 13, 2016 8:57 AM

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

#21 SpiceWare ONLINE  

SpiceWare

    Draconian

  • 11,645 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Tue Sep 13, 2016 10:16 AM

I made some minor revisions to the above example - namely changed the constants from SR# (from the original "Stack RAM") to V# to denote Value.

#22 SpiceWare ONLINE  

SpiceWare

    Draconian

  • 11,645 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Tue Sep 13, 2016 1:39 PM

When you get around to testing these functions you can use Stella to make sure the values are being set like you expect.  

 

The values saved with SetValue1() should be found on page $0F of Cartridge RAM:

Value1.png

 

Those saved with SetValue2() should be on page $0E:

Value2.png



#23 Random Terrain OFFLINE  

Random Terrain

    Visual batari Basic User

  • Topic Starter
  • 28,307 posts
  • Controlled Randomness
    Replay Value
    Nonlinear
  • Location:North Carolina (USA)

Posted Tue Sep 13, 2016 3:00 PM

Thanks. I don't understand any of it, but I can link to it from the bB page for other people who might be able to use it.



#24 wallaby OFFLINE  

wallaby

    Chopper Commander

  • 100 posts

Posted Tue Sep 13, 2016 6:17 PM

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, Tue Sep 13, 2016 6:54 PM.


#25 SpiceWare ONLINE  

SpiceWare

    Draconian

  • 11,645 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Tue Sep 13, 2016 7:17 PM

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.






0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users