68k PC alignment - could somebody please explain?

Ask anything your want about Megadrive/Genesis programming.

Moderator: BigEvilCorporation

Post Reply
BigEvilCorporation
Very interested
Posts: 209
Joined: Sat Sep 08, 2012 10:41 am
Contact:

68k PC alignment - could somebody please explain?

Post by BigEvilCorporation » Mon Sep 15, 2014 10:28 am

Hi!

I've spent the last hell-knows-how-long trying to port my framework to real hardware. I have a Cross Products MegaCD kit with SNASM2 interface, assembler and debugger, and I'm very slowly making progress.

My latest hurdle is that when making subtle changes (adding a new palette, changing my memory map, etc) it produces spurious results - previously working (and simple) code would crash, and I think the problem is PC alignment. My assembler provides a CNOP macro, which injects NOPs to align the next instruction to a specified boundary, and sprinkling these in a few places changes the behavior (sometimes for the better, sometimes for the worse). I'd like to understand the problem fully before tackling it.

My experience with alignment is from a C/C++ background, I understand the hows and whys of vector/matrix alignment for floating point ops, audio buffer alignment, and that some hardware only has a limited amount of bits with which to represent an address, but PC alignment is new to me.

Why does PC alignment matter, where would I expect to need to explicitly align the PC (my current understanding is "after data"), to what boundaries, and how can I spot these problems before they happen?

Thanks in advance
A blog of my Megadrive programming adventures: http://www.bigevilcorporation.co.uk

twosixonetwo
Very interested
Posts: 58
Joined: Tue Feb 25, 2014 3:38 pm

Post by twosixonetwo » Mon Sep 15, 2014 11:22 am

I think this is due to the 16-bit bus. y guess would be that if you had a 16 bit instruction misaligned, you would need two bus cycles to fetch the instruction. This would be slower and makes instruction fetching a bit more complicated, than it would be if you just stick to the word-alignment. Furthermore I believe that all instructions are multiples of a word in length, so you only have to waste space for alignment, if you have data sections where data is stored in bytes.

Mask of Destiny
Very interested
Posts: 616
Joined: Thu Nov 30, 2006 6:30 am

Post by Mask of Destiny » Mon Sep 15, 2014 5:43 pm

Yes, this does have to do with the 16-bit bus . All word and long reads need to be word aligned on the 68000, including instruction fetch. Unaligned reads are slow and require a fair amount of extra transistors to implement so the 68000 does not support them. If you try to read a word from an odd address, this will trigger an exception (bus error IIRC).

BigEvilCorporation
Very interested
Posts: 209
Joined: Sat Sep 08, 2012 10:41 am
Contact:

Post by BigEvilCorporation » Mon Sep 15, 2014 9:34 pm

Awesome, I understand that bit then.

What can I do in code to ensure I stick to the alignment? Where and when would I expect to use a CNOP or ALIGN directive? Maybe some general rules about where data needs to be put?

So far I've reorganised everything so that no code at all is below any data, and it seems to have done the trick, but looking at things like the Sonic 1 disassemblies it seems to be chaos with no need for alignment or NOPs to sort it out. It even builds with the "-o ae-" option which tells the assembler to not automatically try to put code on even boundaries. Yet one little slip up in my own code and it falls over...
A blog of my Megadrive programming adventures: http://www.bigevilcorporation.co.uk

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Post by Chilly Willy » Mon Sep 15, 2014 10:20 pm

The folks working on the Sonic sources put a lot of work into making sure alignment issues don't creep in to avoid the inevitable "works on emulator only" issues.

Remember that both instructions AND data need to be on word alignments. People get caught up in making sure code is on even alignments and forget about the data. Only byte data can be on odd boundaries. If the data is words or longs, or maybe even a mix of lengths, all words and longs MUST be evenly aligned!

That means keeping track of the resources as well. For example, maybe you convert a sprite using a tool, then append that with some music, then append that with some collision data, etc. Is the sprite data accessed as words? If the music has words, was the preceding sprite data an even number of bytes or even started on a word boundary? Does the collision data need to be aligned? Was all the previous data aligned?

See, you need to know A LOT more about every single bit of the project than just aligning code. I know a few devs for the MD who simply put alignment ops between EVERYTHING. :lol:

Don't forget that there are other alignment needs on the MD as well. For example, VDP DMA cannot cross a 128KB boundary, so are you making sure your data blocks to be DMAd aren't crossing a boundary?

TmEE co.(TM)
Very interested
Posts: 2440
Joined: Tue Dec 05, 2006 1:37 pm
Location: Estonia, Rapla City
Contact:

Post by TmEE co.(TM) » Tue Sep 16, 2014 6:05 am

I stick an EVEN after every bit of data to make sure things line up.
Mida sa loed ? Nagunii aru ei saa ;)
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen

BigEvilCorporation
Very interested
Posts: 209
Joined: Sat Sep 08, 2012 10:41 am
Contact:

Post by BigEvilCorporation » Tue Sep 16, 2014 10:31 am

That's the kind of explanation I needed, cheers!

So far so good, a full reorganisation of my project seems to have eliminated all of the "subtle change = catastrophic results" cases I was getting frustrated with, and no need for ALIGN or CNOP so far.

I didn't know about word alignment of data, I've shoved all data to the bottom of my code so perhaps it'll need another sanity pass.

I haven't touched DMA yet, it's way further down my list of things to learn (you don't tend to run into many performance issues with a Pong clone, after all :D )
A blog of my Megadrive programming adventures: http://www.bigevilcorporation.co.uk

MintyTheCat
Very interested
Posts: 484
Joined: Sat Mar 05, 2011 11:11 pm
Location: Berlin, Germany

Post by MintyTheCat » Wed Sep 17, 2014 8:02 pm

It helps to use a Linker-Script to specify where code and data will reside as well as variables.

Depending on how things are for your toolchain and what not you may need to calculate where to place the next lot of data generated as raised by Chilly above.

The areas that change a lot during development and quick experiments is the variables and data section as you try things out and it becomes a hassle to juggle things around but if you can handle the maths (or write a tool) you can allocate areas for memory without a Linker-Script.

Sonic 1 has the Address, Type and Length for the Variables (unless I have forgotten but I recall it has) and you will see that the Variables take up a chunk and are calculated on size, type and length and of course some areas of memory are 'lost' to vars that have odd lengths.

It then gets interesting in how you read and write Bytes for odd in length sets of data :D You may find that to 'just add one to the end' requires in some cases for you to 'read back' the last value written at the current address, create a new Word out of the last Byte and the 'next to add in' and then write that back to the even location you read from initially :D

Note that this applies to machines like the 68K but again is a completely different story for other families. C/C++ (C++ especially) insulate us way too much but you get such insight at the Assembly level all the same :D
UMDK Fanboy

BigEvilCorporation
Very interested
Posts: 209
Joined: Sat Sep 08, 2012 10:41 am
Contact:

Post by BigEvilCorporation » Thu Sep 18, 2014 8:30 am

I might not use a script for th elong run but it would certainly help me learn where I'm going wrong at the moment.

My code is now behaving itself but when trying to load my "Hello world" character set it seems to be offset. I've added an EVEN before including the file and verified in the memory view that it lands on an even alignment, so I don't know what could be doing this.

If I move the INCLUDE to the top of my file (something I was trying to avoid for data) it works perfectly.

Just pushing ideas out there:

- Does LEA or MOVE have any trouble with the distance they have to jump to fetch data? The code and character set are quite far apart at this point, I have maps and all sorts included in between them
- When moving data to the VDP, does it have even stricter alignment requirements (ignoring DMA for the moment)?


I'll try to reproduce the problem in an isolated test case and post the code.
A blog of my Megadrive programming adventures: http://www.bigevilcorporation.co.uk

MintyTheCat
Very interested
Posts: 484
Joined: Sat Mar 05, 2011 11:11 pm
Location: Berlin, Germany

Post by MintyTheCat » Thu Sep 18, 2014 9:27 am

Ideas for debugging:

1. Generate List File.
2. Generate S-Record File.
3. Do the Files included have Data/Code on Even Addresses?
BigEvilCorporation wrote: My code is now behaving itself but when trying to load my "Hello world" character set it seems to be offset. I've added an EVEN before including the file and verified in the memory view that it lands on an even alignment, so I don't know what could be doing this.

If I move the INCLUDE to the top of my file (something I was trying to avoid for data) it works perfectly.
How do you mean 'seems to be offset' - in what sense? The Even directive will ensure even alignment IFF it would naturally have fallen on an Odd but if it was going to be an Even would do nothing and just leave it as it is as it is already Even.

You need a Listing to check where it falls as it will give you all the addresses for the Instructions and Data.

Yes, from what you said about moving your Include to the top of the file it sounds like it to me that your included File is not correctly aligned - put an Even directive in the File included and check the Listing before and after this and just diff to see the changes in the two Listing Files.
BigEvilCorporation wrote: Just pushing ideas out there:

- Does LEA or MOVE have any trouble with the distance they have to jump to fetch data? The code and character set are quite far apart at this point, I have maps and all sorts included in between them
- When moving data to the VDP, does it have even stricter alignment requirements (ignoring DMA for the moment)?


I'll try to reproduce the problem in an isolated test case and post the code.
No to the LEA and MOVE question unless I am mistaken - any one?
When you say "quite far apart" - what is the length?

Are you using Auto-Increment on the VDP's RAM locations or are you doing this manually each time?

If after writing to the CRAM, VRAM, VSRAM or SAT are you getting Dumps and seeing what goes in to the RAM? I would put in some test data and see what you find once you have written to the VDP's RAM(s).

Hope that helps but please get some Listing and S-Rec Files as sometimes it is necessary to see what is generated to get answers.
UMDK Fanboy

BigEvilCorporation
Very interested
Posts: 209
Joined: Sat Sep 08, 2012 10:41 am
Contact:

Post by BigEvilCorporation » Thu Sep 18, 2014 11:15 am

Cheers, I'll research into Listing files and see what I make of it.
How do you mean 'seems to be offset' - in what sense?
Only going by visuals, my characters' tiles start a few lines down (I should find the actual offset in bytes, that might help my case :lol:) - the only difference is where in my code I INCLUDE the art.
When you say "quite far apart" - what is the length?
I'll get back to you.
Are you using Auto-Increment on the VDP's RAM locations or are you doing this manually each time?
Autoincrement (set to 2 via register), and seems to work in all other cases.
If after writing to the CRAM, VRAM, VSRAM or SAT are you getting Dumps and seeing what goes in to the RAM? I would put in some test data and see what you find once you have written to the VDP's RAM(s).
I'll look into it, but my tools are very limited (MS-DOS 6.22, perhaps I should try bunging Windows 95 on the machine), and I can't reproduce any of these problems in an emulator.
A blog of my Megadrive programming adventures: http://www.bigevilcorporation.co.uk

Post Reply