Jump to content



0

Can someone test this on a Harmony cart?


21 replies to this topic

#1 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,545 posts
  • Location:Georgia, USA

Posted Tue May 24, 2011 2:51 AM

Can someone try this out on a real 2600 using a Harmony cart? It's a tiny bit of self-modifying executable code that's been placed in Superchip RAM.

If it works, the screen should cycle through all 128 colors.

It works fine in the Stella and z26 emulators, but of course that doesn't mean it will work on a real 2600.

I'm not so much interested in whether it will work with an actual Superchip (although that would be nice to know, too), more whether it will work on a Harmony/Melody cart running an F8SC ROM image-- because if it does, that means we can run executable code in Superchip games sold on Melody carts.

I can test it myself on a Cuttle Cart II and a Krokodile Cart-- not now (I *really* need to go to bed ASAP), but maybe tomorrow night-- although I'm specifically interested in the Melody cart, since that's what games would be sold on. (I'm assuming that if it works on a Harmony cart, it should also work on a Melody cart.)

If I remember correctly, I'd previously been told that executable code won't work on a real Superchip. But I'm pretty sure "Video Life" runs executable code in its on-cart expansion RAM (watch it in Stella's debugger and you'll see what I mean). I don't know if any executable code was ever used in expansion RAM with an M-Network or CBS RAM+ game.

I'm thinking the main trick is simply to remember to *modify* the RAM code using the write addresses, but remember to *execute* it using the read addresses.

Here's the code. The program is in batari Basic, but it should still be simple enough for any assembly folks to understand. :P The "w000" through "w008" variables are simply the first 9 write addresses of Superchip RAM, $F000 through $F008, and the code is executed by a JSR to $F080.

   rem * Superchip RAM Test for Executable Code

   set romsize 8kSC

   rem * LDX #$00
   w000 = $A2
   w001 = $00

   rem * STX COLUBK
   w002 = $86
   w003 = $09

   rem * INX
   w004 = $E8

   rem * STX $F001
   w005 = $8E
   w006 = $01
   w007 = $F0

   rem * RTS
   w008 = $60

loop

   asm
   JSR $F080
end

   drawscreen

   goto loop
Michael

Attached Files


Edited by SeaGtGruff, Tue May 24, 2011 2:52 AM.


#2 eshu OFFLINE  

eshu

    Chopper Commander

  • 163 posts

Posted Tue May 24, 2011 4:19 AM

I definitely remember reading somewhere that you can't run code off a superchip - is there any reason not to run it out of zero page? Use zero page for code and superchip for variables etc...?

Edit: Just noticed your using Batari basic - that could be the reason.....

Edited by eshu, Tue May 24, 2011 4:20 AM.


#3 ScumSoft OFFLINE  

ScumSoft

    Moonsweeper

  • 331 posts
  • Location:Polysorbate 60

Posted Tue May 24, 2011 4:53 AM

Tested just fine on my harmony cart.

#4 dwane413 OFFLINE  

dwane413

    Chopper Commander

  • 233 posts
  • Location:Oklahoma

Posted Tue May 24, 2011 6:40 AM

Yes, it works.

On Stella in addition to the score and the flashing colors, there are blocks on the screen. Stella 2.4.2 seems to have the same pattern of blocks every time while Stella 3.3 seems to show a random pattern each time. The blocks are completely missing on the Harmony cart.

#5 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,545 posts
  • Location:Georgia, USA

Posted Tue May 24, 2011 7:32 AM

View Postdwane413, on Tue May 24, 2011 6:40 AM, said:

Yes, it works.

On Stella in addition to the score and the flashing colors, there are blocks on the screen. Stella 2.4.2 seems to have the same pattern of blocks every time while Stella 3.3 seems to show a random pattern each time. The blocks are completely missing on the Harmony cart.
Yes, that's because on a real 2600 the machine powers up in a completely random state, including random garbage in the RAM, and Stella is trying to emulate that. If I remember correctly, I believe 2.4.2 used a fixed pattern that's the same every time, whereas 3.3 is random. Edit: And when using the Superchip option, batari Basic puts the playfield RAM in the Superchip RAM, partly to free up more zero-page RAM, and partly to allow a higher-res playfield.

On the other hand, I believe the Harmony cart initializes the RAM-- or maybe it powers up that way? Remember, the RAM on the cart is used to store the ROMs, emulate the Superchip, etc.

Anyway, my simple little program doesn't clear the Superchip RAM area first, nor does batari Basic, nor does the "clean start" subroutine everyone likes to use.

Thanks for testing!

Michael

Edited by SeaGtGruff, Tue May 24, 2011 7:35 AM.


#6 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,545 posts
  • Location:Georgia, USA

Posted Tue May 24, 2011 7:46 AM

View Posteshu, on Tue May 24, 2011 4:19 AM, said:

I definitely remember reading somewhere that you can't run code off a superchip - is there any reason not to run it out of zero page? Use zero page for code and superchip for variables etc...?
It's something someone else wanted to do and had just asked me about. I'd also heard that you can't execute code stored in Superchip RAM-- which I question, since "Video Life" did it. It's true that "Video Life" doesn't use a Superchip per se, but it does use a cart that has 1K RAM in the $F000-to-$F7FF area (read/write, as opposed to the usual write/read order), and 2K ROM in the $F800-to-$FFFF area. I don't pretend to understand about the differences between various types of RAM, but I don't really understand why "Video Life" can do it but the Superchip can't. After all, isn't the CPU just reading the RAM to fetch the instructions? What's the difference between the CPU reading the RAM to fetch instructions to execute, versus the CPU reading the RAM to retrieve the value of a memory address for some assembly instruction (load, add, or, and, compare, indirect jump, etc.)? :ponder:

Edit: I wonder if there's a way to test this with an actual Superchip? I suppose we'd have to burn it onto a ROM and put it on a board equipped with an old Superchip? It probably wouldn't be worth it, since just about all future Superchip games will probably be made using a Melody board or something similar-- although it would be nice to put the question to rest once and for all, just for posterity.

Michael

Edited by SeaGtGruff, Tue May 24, 2011 7:52 AM.


#7 eshu OFFLINE  

eshu

    Chopper Commander

  • 163 posts

Posted Tue May 24, 2011 8:10 AM

View PostSeaGtGruff, on Tue May 24, 2011 7:46 AM, said:

View Posteshu, on Tue May 24, 2011 4:19 AM, said:

I definitely remember reading somewhere that you can't run code off a superchip - is there any reason not to run it out of zero page? Use zero page for code and superchip for variables etc...?
It's something someone else wanted to do and had just asked me about. I'd also heard that you can't execute code stored in Superchip RAM-- which I question, since "Video Life" did it. It's true that "Video Life" doesn't use a Superchip per se, but it does use a cart that has 1K RAM in the $F000-to-$F7FF area (read/write, as opposed to the usual write/read order), and 2K ROM in the $F800-to-$FFFF area. I don't pretend to understand about the differences between various types of RAM, but I don't really understand why "Video Life" can do it but the Superchip can't. After all, isn't the CPU just reading the RAM to fetch the instructions? What's the difference between the CPU reading the RAM to fetch instructions to execute, versus the CPU reading the RAM to retrieve the value of a memory address for some assembly instruction (load, add, or, and, compare, indirect jump, etc.)? :ponder:

Edit: I wonder if there's a way to test this with an actual Superchip? I suppose we'd have to burn it onto a ROM and put it on a board equipped with an old Superchip? It probably wouldn't be worth it, since just about all future Superchip games will probably be made using a Melody board or something similar-- although it would be nice to put the question to rest once and for all, just for posterity.

Michael

I just read it and accepted it - the same as you I can't really see why........one of the big advantages with running code from superchip ram would be that you can run from the ram into the rom - this could save quite a few bytes (of ram) in a lot of self modifying code....

#8 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,545 posts
  • Location:Georgia, USA

Posted Tue May 24, 2011 9:50 AM

   asm
   JSR $F080
end
By the way, I had to switch to in-line assembly to call the self-modifying subroutine, because batari Basic doesn't like "gosub $F080" or "gosub r000" ("r000" being the "Superchip variable" that's mapped to $F080). I believe this is due to the way batari Basic adds a period in front of each of your program's line labels when generating the assembly code for your program. It should be possible for Fred to modify the compiler to let us "goto" or "gosub" to a hex address (if there's a dollar sign, don't add a period in front of it). But I suppose it would be too difficult to add the ability to "goto" or "gosub" to a variable name, since how would the compiler know the difference between a line label that needs a period added to it, versus a variable label that doesn't, unless the compiler were to make multiple passes through the program (if you don't find a matching line label, treat it as a variable label-- i.e., don't put a period in front of it-- and let the assembler try to resolve it).

Wait, I think I just answered my own question. All I needed to do was add a redefines-- "dim .r000 = r000" (if batari Basic will allow including a period in a "dim" like that)-- then I would have been able to say "gosub r000" and it would have been okay, since it would have been converted to "JSR .r000" by the compiler, and ".r000" would have been resolved by the assembler.

An in-line "JSR r000" would have worked, too, since "r000" is just a label. In fact, it's probably better/easier to use that format in a batari Basic program if you've set the Superchip RAM contents using the Superchip variables. For example, if you know that you put your executable code in "w052" through "w068," it would be much easier to simply "JMP r052" or "JSR r052" (whichever is appropriate for the RAM code), rather than trying to figure out which hexadecimal address corresponds to "w052," and therefore which hexadecimal address you need to "JMP" or "JSR" to.

But if batari Basic will let you include a period at the beginning of a "dim," "gosub r000" would be the easiest. If not, we could get around that by using in-line code to add the "period-fied" label:

   asm
.r000 = r000
end
Michael

Edited by SeaGtGruff, Tue May 24, 2011 9:51 AM.


#9 dwane413 OFFLINE  

dwane413

    Chopper Commander

  • 233 posts
  • Location:Oklahoma

Posted Tue May 24, 2011 1:25 PM

View PostSeaGtGruff, on Tue May 24, 2011 9:50 AM, said:

By the way, I had to switch to in-line assembly to call the self-modifying subroutine, because batari Basic doesn't like "gosub $F080" or "gosub r000" ("r000" being the "Superchip variable" that's mapped to $F080). I believe this is due to the way batari Basic adds a period in front of each of your program's line labels when generating the assembly code for your program. It should be possible for Fred to modify the compiler to let us "goto" or "gosub" to a hex address (if there's a dollar sign, don't add a period in front of it). But I suppose it would be too difficult to add the ability to "goto" or "gosub" to a variable name, since how would the compiler know the difference between a line label that needs a period added to it, versus a variable label that doesn't, unless the compiler were to make multiple passes through the program (if you don't find a matching line label, treat it as a variable label-- i.e., don't put a period in front of it-- and let the assembler try to resolve it).

What you said reminded me of how some computers used a different command than "goto" or "gosub" to start machine language code. Commodore BASIC used "SYS" and Applesoft used "CALL".

This would reset the VIC-20:
SYS 64802

When I got a Commodore 64, I never memorized the number to reset it, but knew it was 64 less than on the VIC-20. So I typed:
SYS 64802-64


#10 Wickeycolumbus OFFLINE  

Wickeycolumbus

    River Patroller

  • 4,064 posts
  • Location:Michigan

Posted Tue May 24, 2011 2:15 PM

View PostSeaGtGruff, on Tue May 24, 2011 7:46 AM, said:


Edit: I wonder if there's a way to test this with an actual Superchip? I suppose we'd have to burn it onto a ROM and put it on a board equipped with an old Superchip? It probably wouldn't be worth it, since just about all future Superchip games will probably be made using a Melody board or something similar-- although it would be nice to put the question to rest once and for all, just for posterity.

Michael

I have an F4SC EPROM board, so if I get the chance I'll try it out for you :)

#11 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,545 posts
  • Location:Georgia, USA

Posted Tue May 24, 2011 2:39 PM

View PostWickeycolumbus, on Tue May 24, 2011 2:15 PM, said:

I have an F4SC EPROM board, so if I get the chance I'll try it out for you :)
That would be great! Then we could finally put to bed the question of whether self-modifying executable code was possible in Superchip RAM.

By the way, you say F4SC. I compiled the program as F8SC. Since I included the code (as tremendously complex as it was :D), I guess you can recompile it as F4SC if you need to.

Michael

#12 batari OFFLINE  

batari

    )66]U('=I;B$*

  • 6,236 posts
  • begin 644 contest

Posted Tue May 24, 2011 2:45 PM

Yes, the way Superchip RAM is implemented in Harmony, there should be no issues running self-modifying code there. I can't say this will work with real Superchips, though - I expect code in RAM will run, but likely not self-modifying code in RAM (doing so would require more logic.)

Essentially, Harmony works by "latching" the data to be written, and writes it after any address change. A real Superchip might not detect all address changes, but only the address is not between $1000-$1100.

If your intended target is Melody, I wouldn't worry if it doesn't run on real Superchips.

#13 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,545 posts
  • Location:Georgia, USA

Posted Tue May 24, 2011 3:07 PM

View Postbatari, on Tue May 24, 2011 2:45 PM, said:

I can't say this will work with real Superchips, though - I expect code in RAM will run, but likely not self-modifying code in RAM (doing so would require more logic.)
See, I'm thinking it *should* work, at least if you're careful to update the code using the write addresses and execute it using the read addresses. But we'll hopefully know soon if Wickeycolumbus can test it on an actual Superchip.

View Postbatari, on Tue May 24, 2011 2:45 PM, said:

If your intended target is Melody, I wouldn't worry if it doesn't run on real Superchips.
Well, the question was posed to me by someone else, and I don't know whether he's planning on using the Melody cart or something else, but I would expect that any Superchip games (or CBS RAM+ games, or M-Network games, etc.) in the present and foreseeable future would most likely be on the Melody cart.

By the way, I need to get a Harmony cart *real* soon now, because I'm wanting to start some projects that will use DPC+. Should I PM you, or what is the best way to go about purchasing one? I take it you're using PayPal?

Michael

#14 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,545 posts
  • Location:Georgia, USA

Posted Tue May 24, 2011 6:22 PM

Here's an updated version of the program that's better written, at least from a batari Basic standpoint. And here are some general notes in case anyone wants to use executable RAM code (whether or not it's self-modifying). Since the sample program is in batari Basic (except for the actual RAM code, which is in machine code), this post really belongs in the batari Basic forum, but I'm leaving it here since the notes also apply to assembly programming.

(1) If you want to put executable code in RAM, be sensible about it. If the code can be put in ROM instead, don't waste time copying it to RAM just so you can execute it in RAM. For instance, my sample code could have accomplished the same result more easily by simply using a variable to store and update the value for COLUBK. The *only* reason I used self-modifying code in this case was to create a simple test that can be used to see if code can be stored and executed in Superchip RAM. In general, the main benefit of putting code in RAM is so you can modify it as needed when you want the code to change depending on the situation. And in many cases you'll really need only a small portion of code to be in RAM, in which case you can run regular ROM code, jump to the small bit of changeable RAM code, then jump back to ROM. Remember, you have to copy the code into RAM before you can execute it, and the more code you need to copy, the longer it will take to copy. Nevertheless, there may be times when it's beneficial to put code in RAM so you can modify it, such as if you want to use "LDA #immediate," "LDX #immediate," or "LDY #immediate" instructions for greater speed, but the values need to be variable. (Then again, you could use the Harmony's "fast fetch" mode to accomplish the same thing.)

(2) If you're putting code in RIOT (zero-page) RAM, you can read from and write to a RAM location using the same address. But for most on-cart expansion RAM, you need to read from RAM using one set of addresses, and write to RAM using another set of addresses. (One notable exception-- perhaps the only exception-- is the RAM in supercat's "4A50" bank-switched cart format.) From a practical standpoint, this means there will be certain things you can't do in Superchip RAM code, such as "INC absolute" or "DEC absolute" to modify the contents of RAM, since those instructions would require the CPU to read from and write to the same memory address. Also, remember that the CPU must fetch each instruction from memory so it can be executed, so you need to run the RAM code using the read addresses.

(3) If you want to add RAM code to a batari Basic program, be aware that the batari Basic compiler prefixes each line label with a dot (period), so you won't be able to "goto" or "gosub" to a RAM label unless you've defined the RAM label as having a dot prefix. Then you should leave off the dot prefix when you use the RAM label in a "goto" or "gosub," since batari Basic will automatically add the dot prefix when you compile your program. In my sample program, I "dim" a subroutine name with a dot prefix, equating it to one of the default Superchip RAM variable labels ("w000" through "w127" for the write addresses, and "r000" through "r127" for the read addresses).

(4) In my first sample program, I loaded the RAM code by essentially "poking" each hex value (or machine code instruction) into a Superchip write address, one at a time, without using a loop. That's okay for very short code, but for longer code it will be more efficient to load the code into RAM using a loop, as I've done in this revised sample program. Note that I've put the code into a "data" statement, and even included the equivalent assembly code as comments. Since batari Basic automatically creates a constant with the length of the data table by appending "_length" to the end of the data table name, I was able to use the length constant to help me load the code in a "for-next" loop without having to count the number of bytes first.

   rem * Superchip RAM Test for Executable Code

   set romsize 8kSC

   dim .Cycle_COLUBK = r000

   a = SC_RAM_code_length - 1
   for b = 0 to a
      w000[b] = SC_RAM_code[b]
   next

loop

   gosub Cycle_COLUBK
   drawscreen
   goto loop

   data SC_RAM_code
   $A2,$00     ; LDX #0
   $86,$09     ; STX COLUBK
   $E8         ; INX
   $8E,$01,$F0 ; STX $F001
   $60         ; RTS
end
Michael


Attached Files



#15 batari OFFLINE  

batari

    )66]U('=I;B$*

  • 6,236 posts
  • begin 644 contest

Posted Tue May 24, 2011 11:39 PM

When you say the code is self-modifying, do you mean that code running in Superchip RAM performs writes to Superchip RAM, or the self-modification is done from code running in ROM?

The former may not work on real Superchip hardware but the latter should.

#16 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,545 posts
  • Location:Georgia, USA

Posted Wed May 25, 2011 2:06 AM

View Postbatari, on Tue May 24, 2011 11:39 PM, said:

When you say the code is self-modifying, do you mean that code running in Superchip RAM performs writes to Superchip RAM, or the self-modification is done from code running in ROM?

The former may not work on real Superchip hardware but the latter should.
By "self-modifying" I mean the code in Superchip RAM modifies itself, as in my example where the RAM code loads the X register from read address $F081, then (after storing it in COLUBK) increments the X register and saves the new value to write address $F001 before returning to the ROM code.

Of course, the RAM code could also be modified by ROM code, but I wouldn't classify that as *self*-modifying code, unless we're thinking of the "code" as being the entire program, and not just whatever portion has been copied into RAM.

By the way, I made another "improvement" to the sample program. This time the original code is written as in-line assembly, so it will get converted to machine code by the assembler instead of the programmer having to look up the machine code manually (which is more prone to error). Another benefit is that the code isn't limited to 256 bytes or less-- i.e., the maximum size of a data table-- but of course there's only 128 bytes of Superchip RAM anyway (although other cart formats do have more than 256 bytes of expansion RAM), and copying over 256 bytes would require a different method than the "for-next" loop with subscripted variables. The drawback is that the programmer must manually tally how many bytes are used by the code, but of course that's the way it would be done in assembler. This is how I really should have done it in the first place.

No BIN this time, since it's functionally the same as the previous version.

I'm still hoping Wickeycolumbus can test it with an actual Superchip, just so we can see, even if it's of little or no consequence as long as it works on a Melody cart.

Michael

   rem * Superchip RAM Test for Executable Code

   set romsize 8kSC

   dim .Cycle_COLUBK = r000

   for a = 0 to 8
      w000[a] = SC_RAM_code[a]
   next

loop

   gosub Cycle_COLUBK
   drawscreen
   goto loop

   asm
SC_RAM_code
   LDX #0     ; +2 ; =2
   STX COLUBK ; +2 ; =4
   INX        ; +1 ; =5
   STX $F001  ; +3 ; =8
   RTS        ; +1 ; =9
end




#17 Wickeycolumbus OFFLINE  

Wickeycolumbus

    River Patroller

  • 4,064 posts
  • Location:Michigan

Posted Tue Jun 14, 2011 4:23 PM

I finally got around to testing some code out today. I did do several tests and I have concluded that it is not possible to run self modifying code from SC RAM, or basically any code for that matter. The most you can run is one byte. For example, you can do this:


INF
     jsr $1080
     inx
     stx COLUBK
     jmp INF

;in SC RAM

     rts


But this will not work:


INF
     jsr $1080
     stx COLUBK
     jmp INF

;in SC RAM

     inx
     rts



#18 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,545 posts
  • Location:Georgia, USA

Posted Tue Jun 14, 2011 5:51 PM

View PostWickeycolumbus, on Tue Jun 14, 2011 4:23 PM, said:

I finally got around to testing some code out today. I did do several tests and I have concluded that it is not possible to run self modifying code from SC RAM, or basically any code for that matter. The most you can run is one byte. For example, you can do this:


INF
     jsr $1080
     inx
     stx COLUBK
     jmp INF

;in SC RAM

     rts


But this will not work:


INF
     jsr $1080
     stx COLUBK
     jmp INF

;in SC RAM

     inx
     rts

Thank you for settling this question for me-- although it seems bizarre that you can execute a single-byte instruction, but not more than that. It's also weird that "Video Life" was/is able to run code in its expansion RAM. What's so different about the Sara chip's RAM versus "Video Life"'s RAM? But it's pretty much irrelevant, since the Harmony/Melody can do it. Still, it's good to know that this technique is unavailable with the Sara/Super(not-so-Super?)chip.


Michael

#19 Wickeycolumbus OFFLINE  

Wickeycolumbus

    River Patroller

  • 4,064 posts
  • Location:Michigan

Posted Tue Jun 14, 2011 5:53 PM

After doing some more thinking, I'm wondering if there isn't a limit to how many bytes can be executed but rather which instructions can be executed from SC RAM. When I tried my second example in the post above, the program did not crash but the background color did not change. I'll have to investigate this later.

#20 Wickeycolumbus OFFLINE  

Wickeycolumbus

    River Patroller

  • 4,064 posts
  • Location:Michigan

Posted Tue Jun 14, 2011 5:56 PM

View PostSeaGtGruff, on Tue Jun 14, 2011 5:51 PM, said:


Thank you for settling this question for me-- although it seems bizarre that you can execute a single-byte instruction, but not more than that. It's also weird that "Video Life" was/is able to run code in its expansion RAM. What's so different about the Sara chip's RAM versus "Video Life"'s RAM? But it's pretty much irrelevant, since the Harmony/Melody can do it. Still, it's good to know that this technique is unavailable with the Sara/Super(not-so-Super?)chip.


Michael

Looks like you posted as I was posting. Would you happen to have the Video Life code handy? It would be interesting to try something similar with the SC. Then again it could be that I just did something wrong :ponder:

#21 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,545 posts
  • Location:Georgia, USA

Posted Tue Jun 14, 2011 6:06 PM

View PostWickeycolumbus, on Tue Jun 14, 2011 5:56 PM, said:

Looks like you posted as I was posting. Would you happen to have the Video Life code handy? It would be interesting to try something similar with the SC. Then again it could be that I just did something wrong :ponder:
[Han Solo]I don't have it *with* me.[/Han Solo] But it's around online.

Michael

Edited by SeaGtGruff, Tue Jun 14, 2011 6:07 PM.


#22 batari OFFLINE  

batari

    )66]U('=I;B$*

  • 6,236 posts
  • begin 644 contest

Posted Wed Jun 15, 2011 2:47 AM

Some FA/CBS RAM+ games have code in RAM and it works fine. Superchip hardware must do something weird to break code execution. There was actually a note back in the day that said it wouldn't execute code, and it looks like they meant it.




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users