Jump to content
IGNORED

Program does not compile any more.


PuzZLeR

Recommended Posts

So I googled a little further, and came up with a potential answer in the thread at

 

https://atariage.com/forums/topic/230132-intellivision-rom-bankswitching-cartridge-ram-questions

 

In particular these two passages from @intvnut:

 

"Also, the EXEC and ECS boot sequences probe for ROM at $7000 and $4800; if they detect ROM at either location (upper bits of the data at the location are all 0s), they'll short-circuit the boot sequence. So, programmers will need to be aware of this, either expecting to intercept the boot sequence, or plugging values like $FFFF at these locations to fool the ROM detection."

 

"For ROM at $2xxx, $7xxx and $Exxx, it's perfectly safe to map ROM in those locations on an unexpanded Intellivision. If the EXEC detects ROM at $7xxx (upper 6 bits of location $7000 are 0), it will jump to $7000 directly, very early in the EXEC boot sequence. But, there are no bus conflicts or anything else."

 

So, even a "regular" Intellivision, i.e. one without ECS, will look at $7000 during boot.

 

My "bad" ROM, as well as those others I listed (Congo Bongo, etc), all have 0's in the upper 6 bits of the 16-bit word at $7000.

 

So presumably those games are designed such that they desire the boot sequence to jump to $7000,

but my game is not.  (Or perhaps those games override the boot sequence somehow, and avoid this

issue altogether.)

Link to comment
Share on other sites

2 minutes ago, Peripheral said:

So I googled a little further, and came up with a potential answer in the thread at

 

https://atariage.com/forums/topic/230132-intellivision-rom-bankswitching-cartridge-ram-questions

 

In particular these two passages from @intvnut:

 

"Also, the EXEC and ECS boot sequences probe for ROM at $7000 and $4800; if they detect ROM at either location (upper bits of the data at the location are all 0s), they'll short-circuit the boot sequence. So, programmers will need to be aware of this, either expecting to intercept the boot sequence, or plugging values like $FFFF at these locations to fool the ROM detection."

 

"For ROM at $2xxx, $7xxx and $Exxx, it's perfectly safe to map ROM in those locations on an unexpanded Intellivision. If the EXEC detects ROM at $7xxx (upper 6 bits of location $7000 are 0), it will jump to $7000 directly, very early in the EXEC boot sequence. But, there are no bus conflicts or anything else."

 

So, even a "regular" Intellivision, i.e. one without ECS, will look at $7000 during boot.

 

Yes, that was my point when I said that it was the "EXEC of the Master Component" the one in question.  It's not the ECS that causes the issue, it's the fact that the bootstrap sequence of the Master Component EXEC checks $4800 (Keyboard Component) and $7000 (ECS) looking for expansion peripherals to allow them to take over the initialization of the system.  That's Mattel future-proofing their static OS boot code.

 

As @carlsson suggested, and I concurred, it seems that your program started working again because for some reason, whatever spilled over to $7000 did not look like bootable ROM.  But when it did, the EXEC jumped to that location and broke the program, since there was no usable bootstrap code there.

 

In this case, the default (inert) state of those ranges is $FFFF, so anything different will look like purposely placed code, and as far as the EXEC thinks (which was assembled in 1979 by Mattel and designed with an eye towards future expansion), code in those locations are the bootstrapping sequences of expansion modules.

 

Sorry if none of that was apparent.  It was not clear to me that you were actually looking for that level of detail rather than just "why is my code breaking and how do I work around it?"

 

Here's the actual relevant code during the EXEC's bootstrap, taken from a CPU dump in the debugger:

5014 0000 0000 0000 01FE 103C 02F1 101D -Z----i-  MVI@ R5,R1              604   ; Get potential bootstrap address from $103C
5014 0070 0000 0000 01FE 103D 02F1 101E -Z----i-  SWAP R1                 612   ; Byte-swap it to reconstruct address ($7000)
5014 7000 0000 0000 01FE 103D 02F1 101F --------  MVI@ R1,R0              618   ; \_ Peek($7000)
0001 7000 0000 0000 01FE 103D 02F1 1020 ------i-  SWAP R0                 626   ; /
0100 7000 0000 0000 01FE 103D 02F1 1021 --------  ANDI #$00FC,R0          632   ; Does the first word have the upper 6 bits set?
0000 7000 0000 0000 01FE 103D 02F1 1023 -Z----i-  BNEQ $1003              640   ;   No? Skip
0000 7000 0000 0000 01FE 103D 02F1 1025 -Z----i-  JR   R1                 647   ;   Yes? Jump to $7000 and let it continue booting

 

2 minutes ago, Peripheral said:

My "bad" ROM, as well as those others I listed (Congo Bongo, etc), all have 0's in the upper 6 bits of the 16-bit word at $7000.

Yes, that was what we were suggesting.

 

2 minutes ago, Peripheral said:

So presumably those games are designed such that they desire the boot sequence to jump to $7000,

but my game is not.  (Or perhaps those games override the boot sequence somehow, and avoid this

issue altogether.)

 

I haven't looked at the code of those games, so I cannot comment on what they do or what they have there.  That said, considering that those are all non-Mattel titles, it seems reasonable to assume that they did not fully understand the bootstrap sequence or the tests for expansion modules; so they could have just worked around that by simply adding code to initialize the system and start their program, or jump back to a known point in the EXEC to do so.

 

Many planned or imagined expansions never came to be, so those gaps in the map may seem alien to us now, but Mattel engineers were aware of them.  I suppose that anybody who reverse-engineered the EXEC back in the day, like Coleco programmers, were also aware of the pitfalls.

 

 

Link to comment
Share on other sites

6 minutes ago, carlsson said:

So it would boil down to two options: skip from $7000 to $7100 and give up 256 decles (or is that bytes??) of space, or run along and make sure to have $FFFF at address $7000 and then you have 255 more locations to use?

It seems so.  But you also need to be aware of the ECS if you plan to release a cartridge.  It has ROM at $7000, so it will try to take over.

 

IntyBASIC takes care of that by flipping it to another page already, though.

 

(From the epilogue file)

	IF DEFINED intybasic_ecs
	ORG $4800	; Available up to $4FFF

	; Disable ECS ROMs so that they don't conflict with us
	MVII    #$2A5F, R0
	MVO     R0,     $2FFF
	MVII    #$7A5F, R0
	MVO     R0,     $7FFF
	MVII    #$EA5F, R0
	MVO     R0,     $EFFF

	B       $1041       ; resume boot

	ENDI

 

That hijacks the other expansion monitor (PlayCable?  Keyboard Component?) at $4800 to page-flip the ECS EXEC and other problem addresses.

 

    -dZ.

Edited by DZ-Jay
  • Like 1
Link to comment
Share on other sites

Sorry, $4800 is the PlayCable monitor.  The Keyboard Component monitor is the one at $7000.  It's just that when Mattel cancelled and recalled the KC, they took that spot for the ECS ROM.  So now it's the ECS monitor. :)

 

   -dZ.

Link to comment
Share on other sites

  • 2 weeks later...

Hey, there. I really am trying to understand this stuff. I have a clue, but still, I ask for a bit of patience.

 

I was on my way after a little help from Kiwi in post #8, with just adding the ASM ORG $A000, and the problem was at least temporarily solved.

On 2/3/2021 at 5:55 AM, DZ-Jay said:

As your program gets bigger we could help figuring out how to split it and where to fit it.

In post #13 I said I'd carry on as is until...

 

I just added some music. Bang. Program crashes. Now again I ask for help.

 

Here is a simple idea of how my program looks now, similar to before, and with only one ORG statement after the game loop:

 

include "constants.bas"

wait
stack_check
wait

wait
play volume 15
play full
wait
play tune_intro
wait

REM Title Screen:

title_screen_control_1:
<"print title screen text">

if (CONT.LEFT+CONT.RIGHT+CONT.UP+CONT.DOWN)=0 then goto title_screen_control_1

play none
sound 0,1,0
sound 1,1,0
sound 2,1,0
sound 4,1,$38

cls

wait
define DEF00,16,gramchars1
wait
define DEF16,16,gramchars2
wait
define DEF32,16,gramchars3
wait
define DEF48,16,gramchars4
wait

<"some initialized variables">

SCREEN level_01_cards

gameloop:
for i=1 to 240
wait
gosub <"this procedure">
gosub <"that procedure">
gosub <"another procedure">
next i
goto gameloop

ASM ORG $A000

include "game_procedures_01_sprites.bas"
include "game_procedures_02_movement.bas"
include "game_procedures_03.bas"
include "game_sfx.bas"
include "game_data.bas"
include "game_screens.bas"
include "game_cards_gfx.bas"
include "game_music.bas"

 

The last good compile generated this CFG file:

 

[mapping]
$0000 - $0599 = $5000
$059A - $1599 = $A000
$159A - $2599 = $B000
$259A - $3599 = $C000
$359A - $4599 = $D000
$459A - $5599 = $E000
$559A - $64FB = $F000

 

The crash generated this one (but not sure if it's legit as a crashed program may generate bad data, but anyhow...):

 

[mapping]
$0000 - $0684 = $5000
$0685 - $1684 = $A000
$1685 - $2684 = $B000
$2685 - $3684 = $C000
$3685 - $4684 = $D000
$4685 - $5684 = $E000
$5685 - $60B2 = $F000

 

All I did this time is add actual music in the "game_music.bas" file, which was previously just an empty placeholder.

 

I tried several things, and no luck. Any help?

 

Thanks for reading.

 

 

Edited by PuzZLeR
Added some code for better question.
Link to comment
Share on other sites

The last line of your working CFG file said $559a - $64fb = $f000 this means there are $0f62 words inside the $f000 segment, so you have only 158 words free there. Adding almost anything would make your program to crash.

 

But your first segment $5000 only uses $059a words, and you don't use the $6000 segment. So you can move your ASM ORG $A000 line further ahead on your code, so you see the $5000 filled completely and automatically starts using the $6000 segment.

  • Like 1
Link to comment
Share on other sites

9 hours ago, PuzZLeR said:

$259A - $3599 = $C000

$C000-C050 is not safe to map there since it's an alias of the registers.  I believe reading specific address strobes switch mode if I remember poorly.  I usually have asm org $C100 or asm org $C050 if I need more space. You do have address $2000-$2FFF, $7100-$7fff, and $4800-$4fff(Don't let the overflow or it'll spill over the cartridge boot address at $5000) available.

I never seen .cfg looks like that before.  Mine usually looks like,

 

[mapping]
$0000 - $0CFF = $2000
$0D00 - $2CFF = $5000
$2D00 - $36FF = $7100
$3700 - $4BFF = $A000
$4C00 - $75FF = $C100


Here's a link to detailed mapping, http://spatula-city.org/~im14u2c/intv/jzintv-1.0-beta3/doc/programming/memory_map.txt
 

  • Like 1
Link to comment
Share on other sites

Hi again guys.

 

I have tried, and tried, with different ASM ORG statements, and moving them all over my program as well as in different spots. No luck. The only thing that works is ASM ORG $A000 exactly as I have it in post #31. Nothing else.

 

I have re-read previous posts, even went through Kiwi's link. I understand it much better (thanks!), but still can't implement it in my program with good results.

 

What would you guys suggest given the code I have in post #31? I honestly really tried on my own before coming back here and asking again. I did. ?

On 2/13/2021 at 11:22 PM, nanochess said:

So you can move your ASM ORG $A000 line further ahead on your code, so you see the $5000 filled completely and automatically starts using the $6000 segment.

How can I move it any higher? It's right underneath my gameloop. If I move it anywhere in the gameloop the program crashes. Any higher than the gameloop, again it crashes. ?

 

On 2/14/2021 at 3:05 AM, Kiwi said:

Mine usually looks like,
 


[mapping]
$0000 - $0CFF = $2000
$0D00 - $2CFF = $5000
$2D00 - $36FF = $7100
$3700 - $4BFF = $A000
$4C00 - $75FF = $C100

 

That looks nicely spread and optimized to me. Wish I could acheive this.

 

On 2/14/2021 at 3:05 AM, Kiwi said:

 

This was very interesting. Thanks. Although I have not had success yet, at least I now have better background to understand what's next now. ?

Link to comment
Share on other sites

Perhaps the problem is that you are looking for a single ASM ORG directive to save you.  If your program is big enough, you'll have to split it into multiple segments.

 

Back in post #11, I offered the five-segment memory map I've used in assembly programs (taken from Joe Z. "cart.mac" library), along with the size of each segment.

 

You can use the techniques others have offered to figure out where your program is overflowing, but bear in mind that it is possible that it is overflowing in multiple places.  If that is the case, then you may want to split the set of "INCLUDE" directive with your data files into multiple segments using an ASM ORG directive for each set.

 

     -dZ.

  • Like 1
Link to comment
Share on other sites

1 hour ago, PuzZLeR said:

The only thing that works is ASM ORG $A000 exactly as I have it in post #31. Nothing else.

Oh now I remember running into an issue from making Depth of Nitemare.  If a segment is too big and over fill, then next segment won't be listed in cfg.  So if I have this listed below,

 

On 2/14/2021 at 2:05 AM, Kiwi said:

$3700 - $58FF = $A000

If you take the scientific calculator and subtract 58ff by 3700, you will get $21FF or 8703 in decimal.  That segment is over 8224 and spilled into C000-C1FF.  Then "$4C00 - $75FF = $C100" will not appear in .cfg.

  • Like 1
Link to comment
Share on other sites

Hey guys, thanks for chiming in. This is still a learning experience for me grasping how the Intellivision allocates memory, and how ORG really works, and what it all does coming together. Just bear with me a tad. ?

 

I do fully understand what decimal vs hex vs binary is, and have math background - so there's hope! ?

 

I'm the type that will try on his own first, not just blindly ask stupid questions. I will go through the information, new and go through the old again (which includes the excellent info in post #11).

 

Thanks so much guys. I will report back with, legitimate questions, or, hopefully with my success.

 

Thanks. Great Community here. Very helpful. ?

 

(If anybody else has some more info - feel free. I'll read it.)

Link to comment
Share on other sites

Back in a previous post, I tried to explain in general how the memory map works and what ASM ORG does.

 

Let me know if you have specific questions, but the important bits is:

  • Generally, there are 42K words of memory available for program code and data.
  • Unfortunately, this space is not available in a single chunk.
  • Due to historical and technical reasons, the full memory space of 42K words is splintered into various areas, only some of which are available to use for your program code and data.
  • One common scheme splits the memory map into five segments, each of various length.
  • In order to fit a very large program into memory, you need to split it into various parts and tell the assembler to put them at the different segments.
  • The ORG directive instructs the assembler to put everything following the directive at the given address.  Because it is an assembler directive, you must invoke it with "ASM" in IntyBASIC, thus "ASM ORG xxx".
  • To put parts of your program into different segments, one easy way is to split it into different modules, then group a set of modules headed with an ASM ORG with the start of a segment, then another group of modules headed with another ASM ORG directive for another segment.
  • All the modules included after an ASM ORG directive will be assembled starting at that address.

 

I know it is a bit complicated, but some people have already offered some ideas on ways to determine the size of your code and how to know when a segment has overflown.  Remember, there is a limited number of segments, and each segment has a limited size.  A sufficiently large program may end up using all segments.


In assembly language programs in the past, I've used intvnut's "cart.mac" macro to help me with segment allocation.  He suggested that it could be easily integrated into IntyBASIC programs as well, so you may want to look into that.

 

Other than that, if you are struggling with some particular concept or have a specific question, please ask.

 

   dZ.

 

 

 

Edited by DZ-Jay
  • Like 1
Link to comment
Share on other sites

Hey guys, and thanks DZ-Jay and Kiwi for the explanations. It's making more and more sense now. ?

 

Working on this still, and my biggest focus now is in the following advice:

On 2/15/2021 at 2:54 PM, Kiwi said:

If you take the scientific calculator and subtract 58ff by 3700, you will get $21FF or 8703 in decimal.  That segment is over 8224 and spilled into C000-C1FF.  Then "$4C00 - $75FF = $C100" will not appear in .cfg.

...and..

On 2/15/2021 at 2:48 PM, DZ-Jay said:

Perhaps the problem is that you are looking for a single ASM ORG directive to save you.  If your program is big enough, you'll have to split it into multiple segments.

I do have a question however for now, and hopefully it's not a stupid one.

 

I am going through 42k.bas, and notice that the procedures in the program are called before the game loop. The ones I'm working on, and splitting, etc, are in the game loop. Is it Ok to assume that there would be no difference in applying some of these methods with ASM ORG when so? Just curious.

Link to comment
Share on other sites

 

35 minutes ago, PuzZLeR said:

I am going through 42k.bas, and notice that the procedures in the program are called before the game loop. The ones I'm working on, and splitting, etc, are in the game loop. Is it Ok to assume that there would be no difference in applying some of these methods with ASM ORG when so? Just curious.


Not a stupid question at all, but perhaps a bit murky.

 

When you say "called," do you mean actually invoking the subroutine via GOSUB, or do you mean declared with a label and the PROCEDURE keyword?

 

If it is the former (GOSUB), then the order in which you call the procedures does not really matter.  As a matter of fact, you can declare a procedure in one segment, and call it from any other segment, even from those that come earlier in the memory space.

 

The reason for this is that the assembler performs two passes through the code:  first it identifies all labels and keeps track of them, creating an internal map of all symbols (variable and procedure names, labels, etc.), and noting everywhere in which they are referenced.  Then, it goes through the entire thing again and "fills in the blanks" by replacing the references with the proper addresses of where they ended up.

 

So, if a call to a procedure is found, but the assembler has not seen that procedure yet, it will note it, then come back to it with the actual address once it sees it later on.  If it never found it, it'll issue an error that the symbol is undefined or something like that.

 

I hope this makes sense.  If this is not what you asked, please try to articulate the question again with additional details.

 

    dZ.

 

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