[SOLVED] Bitfields in GCC vs Visual Studio C/C++

Go To Last Post
37 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hy all,

I encountered strange behaviour between GCC and Visual Studio C/C++ :

typedef struct Token
{
	uint8_t		Fgnd  : 4;
	uint8_t		Bkgnd : 4;
} __attribute__((__packed__)) Token;

This code describles an 8 bits wide structure, where the first nibble contains Fgnd and the second nibble Bkgnd.

When compiled with VS (without the attribute), the nibbles are switched, then the first nibble contains Bkgnd and the second Fgnd...

I wonder what the standard imposes.. Anybody a suggestion ?

Thanks,

Paul

PS : using ARM gcc toolchain, if that bothers... :wink:

"As simple as possible, but not simpler"

GUI Framework for Atmel Xplained Pro

Last Edited: Fri. Aug 15, 2014 - 03:50 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I believe the order of bits in a bitfield is "implementation dependent" so not something you can rely on.

EDIT: Good old Stack Overflow. Plenty to chew on here:

http://stackoverflow.com/questio...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PS of course:

Token = ((Bkgnd & 0xF) << 4) | (Fgnd & 0xF);

on the transmitter and:

Fgnd = Token & 0xF;
Bkgnd = Token >> 4;

On the receiver achieve similar packing and will work with any C compiler

(I'm assuming all are "unsigned").

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So, It's not correct to use the same sourcefiles in GCC as in VS ? I'm writing a font conversion routine on VS and use the same struct definitions in GCC and this gives a clash... I'm disappointed...

BTW, This is a fantastic forum : A reply in 0ne minute!!

"As simple as possible, but not simpler"

GUI Framework for Atmel Xplained Pro

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

So, It's not correct to use the same sourcefiles in GCC as in VS ?

Yes you can do that (I do it professionally all the time - we develop vision processing software on Windows/PCs usin MSVC and then build the same code for a target using arm-gcc).

What you can't do is rely on any compiler feature that is "implementation defined". While you can generally share struct{}'s as long as they are packed to the same byte alignment on all targets you can't rely on things like bitfields.

See my second post above - as far as I know that's a solution to pack two 4 bits into 8 that will work on any C compiler.

Back on that Stack Overflow page read the very last answer. I know it's a bit string to say "stupid". But he's right that if you just write code to output stuff as a well organised bit stream and the other end just decodes it based on knowing the same ordering then it works. If it didn't it's unlikely I could be typing this reply to you and expecting TCP/IP to get it from my computer to yours! TCP/IP (amongst many other things) is created and interpreted by all kinds of computing devices using many architectures and loads of different compilers. But they all "talk" ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PaulVdBergh wrote:
So, It's not correct to use the same sourcefiles in GCC as in VS ?

Only if those source files completely avoid anything which is implementation-defined!

K&R wrote:
Almost everything about bitfields is implementation-dependent

Byte-ordering is implementation-defined.

You should not be using structures & bitfields if you want this to be portable - write proper serialisation routines.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, here is the 'problem' at hand.

I'have converted some fonts with Mikroelektronika's GLCD Font Creator and copy/pasted the output as C source in the MSVC source file.

In MSVC the fonts are converted into a more suitable format for my application. I'm using some sort of compression (RLE-ish). It is this compression that uses the FontToken struct.

I append the MSVC code (quick and dirty programming ;) )

// FontConvertor.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include 
#include 

uint8_t Lucida_Console10x16[] = {
	0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char
	0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char !
	0x07, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char "
	0x09, 0x00, 0x01, 0x20, 0x19, 0xA0, 0x07, 0x78, 0x01, 0x26, 0x19, 0xA0, 0x07, 0x78, 0x01, 0x26, 0x01, 0x20, 0x01, 0x00, 0x00,  // Code for char #
	0x08, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x18, 0x26, 0x10, 0x42, 0x10, 0xFF, 0x3F, 0x82, 0x11, 0x02, 0x0F, 0x00, 0x00, 0x00, 0x00,  // Code for char $
	0x0A, 0x1C, 0x10, 0x22, 0x08, 0x22, 0x04, 0x22, 0x03, 0x9C, 0x00, 0x40, 0x0E, 0x30, 0x11, 0x08, 0x11, 0x04, 0x11, 0x02, 0x0E,  // Code for char PERCENT_SIGN
	0x0A, 0x00, 0x07, 0x80, 0x08, 0x5C, 0x10, 0x62, 0x10, 0xA2, 0x11, 0x32, 0x13, 0x1C, 0x1C, 0x00, 0x18, 0x00, 0x16, 0x80, 0x01,  // Code for char &
	0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char '
	0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x0C, 0x30, 0x04, 0x20, 0x02, 0x40, 0x02, 0x40, 0x00, 0x00,  // Code for char (
	0x07, 0x00, 0x00, 0x02, 0x40, 0x02, 0x40, 0x04, 0x20, 0x0C, 0x30, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char )
	0x08, 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0xF0, 0x00, 0x4E, 0x00, 0xF0, 0x00, 0x18, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char *
	0x09, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x1F, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00,  // Code for char +
	0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char ,
	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,  // Code for char -
	0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char .
	0x09, 0x00, 0x00, 0x00, 0x40, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, 0xC0, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x02, 0x00, 0x00, 0x00,  // Code for char /
	0x08, 0x00, 0x00, 0xF0, 0x03, 0x0C, 0x0C, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x0C, 0x0C, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00,  // Code for char 0
	0x08, 0x00, 0x00, 0x04, 0x10, 0x04, 0x10, 0x04, 0x10, 0xFE, 0x1F, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,  // Code for char 1
	0x07, 0x00, 0x00, 0x06, 0x18, 0x02, 0x14, 0x02, 0x12, 0x02, 0x11, 0xC2, 0x10, 0x3C, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char 2
	0x07, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x42, 0x10, 0x42, 0x10, 0x42, 0x10, 0xBC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char 3
	0x08, 0x00, 0x03, 0xC0, 0x02, 0x20, 0x02, 0x18, 0x02, 0x04, 0x02, 0xFE, 0x1F, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,  // Code for char 4
	0x07, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x10, 0x22, 0x10, 0x22, 0x10, 0x42, 0x08, 0x82, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char 5
	0x08, 0x00, 0x00, 0xF0, 0x07, 0x4C, 0x08, 0x22, 0x10, 0x22, 0x10, 0x22, 0x10, 0x42, 0x08, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,  // Code for char 6
	0x08, 0x00, 0x00, 0x02, 0x00, 0x02, 0x18, 0x02, 0x07, 0xC2, 0x00, 0x32, 0x00, 0x0A, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char 7
	0x08, 0x00, 0x00, 0x1C, 0x0F, 0xA2, 0x10, 0x42, 0x10, 0x42, 0x10, 0xA2, 0x10, 0xA2, 0x09, 0x1C, 0x06, 0x00, 0x00, 0x00, 0x00,  // Code for char 8
	0x08, 0x00, 0x00, 0x78, 0x00, 0x84, 0x10, 0x02, 0x11, 0x02, 0x11, 0x02, 0x11, 0x84, 0x0C, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00,  // Code for char 9
	0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x18, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char :
	0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x98, 0x60, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char ;
	0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x80, 0x04, 0x80, 0x04, 0x40, 0x08, 0x40, 0x08, 0x20, 0x10, 0x00, 0x00,  // Code for char <
	0x09, 0x00, 0x00, 0x80, 0x04, 0x80, 0x04, 0x80, 0x04, 0x80, 0x04, 0x80, 0x04, 0x80, 0x04, 0x80, 0x04, 0x80, 0x04, 0x00, 0x00,  // Code for char =
	0x08, 0x00, 0x00, 0x20, 0x10, 0x40, 0x08, 0x40, 0x08, 0x80, 0x04, 0x80, 0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,  // Code for char >
	0x08, 0x00, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x02, 0x1B, 0x82, 0x00, 0x42, 0x00, 0x26, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char ?
	0x0A, 0xF0, 0x03, 0x18, 0x0C, 0x04, 0x18, 0xE2, 0x13, 0x12, 0x14, 0x0A, 0x16, 0x8A, 0x1B, 0xFC, 0x07, 0x00, 0x04, 0x00, 0x04,  // Code for char @
	0x0A, 0x00, 0x10, 0x00, 0x0E, 0x80, 0x03, 0x70, 0x02, 0x18, 0x02, 0x30, 0x02, 0xC0, 0x02, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x10,  // Code for char A
	0x08, 0x00, 0x00, 0xF8, 0x1F, 0x88, 0x10, 0x88, 0x10, 0x88, 0x10, 0x88, 0x10, 0x48, 0x11, 0x30, 0x0E, 0x00, 0x00, 0x00, 0x00,  // Code for char B
	0x08, 0xC0, 0x03, 0x30, 0x0C, 0x10, 0x08, 0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0x18, 0x10, 0x00, 0x00, 0x00, 0x00,  // Code for char C
	0x08, 0x00, 0x00, 0xF8, 0x1F, 0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0x10, 0x08, 0xE0, 0x07, 0x00, 0x00, 0x00, 0x00,  // Code for char D
	0x08, 0x00, 0x00, 0xF8, 0x1F, 0x08, 0x11, 0x08, 0x11, 0x08, 0x11, 0x08, 0x11, 0x08, 0x11, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00,  // Code for char E
	0x08, 0x00, 0x00, 0xF8, 0x1F, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char F
	0x09, 0x00, 0x00, 0xC0, 0x03, 0x30, 0x0C, 0x10, 0x08, 0x08, 0x10, 0x08, 0x10, 0x08, 0x11, 0x08, 0x11, 0x18, 0x1F, 0x00, 0x00,  // Code for char G
	0x08, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xF8, 0x1F, 0x00, 0x00, 0x00, 0x00,  // Code for char H
	0x08, 0x00, 0x00, 0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0xF8, 0x1F, 0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00,  // Code for char I
	0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char J
	0x09, 0x00, 0x00, 0xF8, 0x1F, 0x80, 0x00, 0x80, 0x01, 0x40, 0x02, 0x20, 0x04, 0x10, 0x04, 0x08, 0x08, 0x00, 0x10, 0x00, 0x00,  // Code for char K
	0x08, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,  // Code for char L
	0x08, 0xF8, 0x1F, 0x38, 0x00, 0xE0, 0x01, 0x00, 0x07, 0x00, 0x06, 0xC0, 0x01, 0x38, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0x00, 0x00,  // Code for char M
	0x08, 0x00, 0x00, 0xF8, 0x1F, 0x10, 0x00, 0x60, 0x00, 0x80, 0x01, 0x00, 0x06, 0x00, 0x08, 0xF8, 0x1F, 0x00, 0x00, 0x00, 0x00,  // Code for char N
	0x09, 0x00, 0x00, 0xE0, 0x07, 0x10, 0x08, 0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0x10, 0x08, 0xE0, 0x07, 0x00, 0x00,  // Code for char O
	0x08, 0x00, 0x00, 0xF8, 0x1F, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x88, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char P
	0x09, 0x00, 0x00, 0xE0, 0x07, 0x10, 0x08, 0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08, 0x30, 0x10, 0x48, 0xE0, 0x47, 0x00, 0x00,  // Code for char Q
	0x08, 0x00, 0x00, 0xF8, 0x1F, 0x08, 0x01, 0x08, 0x01, 0x08, 0x03, 0x88, 0x04, 0x70, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,  // Code for char R
	0x08, 0x00, 0x00, 0x70, 0x18, 0x48, 0x10, 0x88, 0x10, 0x88, 0x10, 0x08, 0x11, 0x08, 0x09, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x00,  // Code for char S
	0x09, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x1F, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,  // Code for char T
	0x08, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x18, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x08, 0xF8, 0x07, 0x00, 0x00, 0x00, 0x00,  // Code for char U
	0x0A, 0x08, 0x00, 0x30, 0x00, 0xC0, 0x01, 0x00, 0x06, 0x00, 0x18, 0x00, 0x18, 0x00, 0x07, 0xC0, 0x00, 0x30, 0x00, 0x08, 0x00,  // Code for char V
	0x0A, 0x18, 0x00, 0xE0, 0x03, 0x00, 0x1C, 0x00, 0x0F, 0xE0, 0x00, 0xC0, 0x01, 0x00, 0x0E, 0x00, 0x1C, 0xE0, 0x03, 0x18, 0x00,  // Code for char W
	0x0A, 0x08, 0x10, 0x10, 0x08, 0x20, 0x04, 0x40, 0x02, 0x80, 0x01, 0x80, 0x01, 0x40, 0x02, 0x20, 0x04, 0x10, 0x08, 0x08, 0x10,  // Code for char X
	0x0A, 0x08, 0x00, 0x10, 0x00, 0x60, 0x00, 0x80, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00,  // Code for char Y
	0x09, 0x00, 0x00, 0x08, 0x18, 0x08, 0x14, 0x08, 0x12, 0x08, 0x11, 0x88, 0x10, 0x48, 0x10, 0x28, 0x10, 0x18, 0x10, 0x00, 0x00,  // Code for char Z
	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x7F, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,  // Code for char [
	0x09, 0x00, 0x00, 0x02, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x00, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x40, 0x00, 0x00,  // Code for char BackSlash
	0x06, 0x00, 0x00, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0xFE, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char ]
	0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x03, 0xE0, 0x00, 0x38, 0x00, 0x0E, 0x00, 0x70, 0x00, 0x80, 0x03, 0x00, 0x04, 0x00, 0x00,  // Code for char ^
	0x0A, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,  // Code for char _
	0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char `
	0x08, 0x00, 0x00, 0x00, 0x0C, 0x20, 0x12, 0x20, 0x11, 0x20, 0x11, 0x20, 0x09, 0xC0, 0x1F, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,  // Code for char a
	0x08, 0x00, 0x00, 0xFE, 0x1F, 0x40, 0x08, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x60, 0x08, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,  // Code for char b
	0x08, 0x00, 0x00, 0x80, 0x07, 0x40, 0x08, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00,  // Code for char c
	0x08, 0x00, 0x00, 0x80, 0x07, 0x40, 0x18, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x40, 0x08, 0xFE, 0x1F, 0x00, 0x00, 0x00, 0x00,  // Code for char d
	0x08, 0x00, 0x00, 0x80, 0x07, 0x40, 0x09, 0x20, 0x11, 0x20, 0x11, 0x20, 0x11, 0x20, 0x11, 0xC0, 0x11, 0x00, 0x00, 0x00, 0x00,  // Code for char e
	0x09, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0xFC, 0x1F, 0x24, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x00, 0x00,  // Code for char f
	0x08, 0x00, 0x00, 0x80, 0x07, 0x40, 0x98, 0x20, 0x90, 0x20, 0x90, 0x20, 0x90, 0x40, 0x48, 0xE0, 0x3F, 0x00, 0x00, 0x00, 0x00,  // Code for char g
	0x08, 0x00, 0x00, 0xFE, 0x1F, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0x00,  // Code for char h
	0x05, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x26, 0x00, 0xE6, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char i
	0x06, 0x00, 0x00, 0x00, 0x80, 0x20, 0x80, 0x20, 0x80, 0x26, 0x80, 0xE6, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char j
	0x08, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x01, 0x00, 0x03, 0x80, 0x04, 0x40, 0x04, 0x40, 0x08, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00,  // Code for char k
	0x06, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xFE, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char l
	0x09, 0xE0, 0x1F, 0x40, 0x00, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x1F, 0x40, 0x00, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x1F, 0x00, 0x00,  // Code for char m
	0x08, 0x00, 0x00, 0xE0, 0x1F, 0xC0, 0x00, 0x40, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x00, 0x00,  // Code for char n
	0x08, 0x00, 0x00, 0x80, 0x07, 0x40, 0x08, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x40, 0x08, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,  // Code for char o
	0x08, 0x00, 0x00, 0xE0, 0xFF, 0x40, 0x08, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x60, 0x08, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,  // Code for char p
	0x08, 0x00, 0x00, 0x80, 0x07, 0x40, 0x18, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x40, 0x08, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,  // Code for char q
	0x08, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char r
	0x07, 0x00, 0x00, 0xC0, 0x18, 0x20, 0x11, 0x20, 0x11, 0x20, 0x12, 0x20, 0x12, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char s
	0x08, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0xF8, 0x0F, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00,  // Code for char t
	0x07, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x08, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char u
	0x09, 0x20, 0x00, 0xC0, 0x01, 0x00, 0x06, 0x00, 0x18, 0x00, 0x10, 0x00, 0x0C, 0x00, 0x03, 0xC0, 0x00, 0x20, 0x00, 0x00, 0x00,  // Code for char v
	0x0A, 0x60, 0x00, 0x80, 0x07, 0x00, 0x18, 0x00, 0x0E, 0xC0, 0x01, 0x80, 0x01, 0x00, 0x0E, 0x00, 0x18, 0x80, 0x07, 0x60, 0x00,  // Code for char w
	0x09, 0x00, 0x00, 0x20, 0x10, 0x40, 0x08, 0x80, 0x04, 0x00, 0x03, 0x00, 0x03, 0x80, 0x04, 0x40, 0x08, 0x20, 0x10, 0x00, 0x00,  // Code for char x
	0x0A, 0x20, 0x80, 0xC0, 0x80, 0x00, 0x83, 0x00, 0x46, 0x00, 0x38, 0x00, 0x18, 0x00, 0x06, 0x00, 0x01, 0xC0, 0x00, 0x20, 0x00,  // Code for char y
	0x09, 0x00, 0x00, 0x20, 0x10, 0x20, 0x18, 0x20, 0x14, 0x20, 0x12, 0x20, 0x11, 0xA0, 0x10, 0x60, 0x10, 0x20, 0x10, 0x00, 0x00,  // Code for char z
	0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xFC, 0x3E, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,  // Code for char {
		0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char |
	0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0xFC, 0x3E, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,  // Code for char }
	0x0A, 0x00, 0x03, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x80, 0x01,  // Code for char ~
	0x03, 0xF0, 0x1F, 0x10, 0x10, 0xF0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   // Code for char 
};

typedef struct FontToken
{
	uint8_t		Bkgnd : 4;
	uint8_t		Fgnd  : 4;
}FontToken;

typedef struct Glyph
{
	uint8_t		Width;
	uint8_t		NbrOfTokens;
	FontToken	Tokens[0x100];
} Glyph;

typedef struct Font
{
	uint8_t		Width;
	uint8_t		Height;
	char		FirstGlyph;
	uint8_t		NbrOfGlyphs;
	uint32_t	GlyphOffsets[0x100];
	Glyph		Glyphs[0x100];
} Font;

bool GetPixelAtOffset(uint8_t* GlyphLine, uint8_t FontHeight, uint16_t pixelPos)
{
	uint8_t BytesPerHorizontalLine = FontHeight / 8;
	if (0 != FontHeight PERCENT_SIGN 8)
	BytesPerHorizontalLine++;
	uint8_t GlyphWidth = GlyphLine[0];
	uint16_t BitVerticalPosition = FontHeight - 1 - (pixelPos / GlyphWidth);
	uint8_t	BitHorizontalPosition = pixelPos PERCENT_SIGN GlyphWidth;
	uint8_t ByteOffset = 1 + (BitHorizontalPosition * BytesPerHorizontalLine) + (BytesPerHorizontalLine - 1 - (BitVerticalPosition / 8));
	uint8_t Mask = (1 << (7 - (BitVerticalPosition PERCENT_SIGN 8)));
	return (Mask == (GlyphLine[ByteOffset] & Mask));
}

int _tmain(int argc, _TCHAR* argv[])
{
	Font font;
	font.Height = 16;
	font.Width = 10;
	font.NbrOfGlyphs = 96;

	uint8_t BytesPerRow = font.Width / 8;
	if (0 != font.Width PERCENT_SIGN 8)
	BytesPerRow++;

	for (int i = 0; i < 96; i++)
	{
		Glyph* pGlyph = &(font.Glyphs[i]);
		pGlyph->NbrOfTokens = 0;
		uint8_t counter = 0;
		uint8_t NbrOfPixels = 0;
		bool	bForeGround = false;
		uint8_t* pLineData = &(Lucida_Console10x16[i * (font.Width * BytesPerRow + 1)]);
		pGlyph->Width = pLineData[0];
		uint8_t	GliphWidth = pLineData[0];

		uint16_t BitCounter = 0;
		do
		{
			uint8_t BkgndCount = 0;
			uint8_t FgndCount = 0;
			while ((false == GetPixelAtOffset(pLineData, font.Height, BitCounter)) && (BitCounter < (GliphWidth * font.Height)))
			{
				BkgndCount++;
				BitCounter++;
			}

			while ((true == GetPixelAtOffset(pLineData, font.Height, BitCounter)) && (BitCounter < (GliphWidth * font.Height)))
			{
				FgndCount++;
				BitCounter++;
			}
			
			while (BkgndCount > 0x0F)
			{
				pGlyph->Tokens[pGlyph->NbrOfTokens].Bkgnd = 0x0F;
				pGlyph->Tokens[pGlyph->NbrOfTokens].Fgnd = 0x00;
				pGlyph->NbrOfTokens++;
				BkgndCount -= 0x0f;
			}

			while (FgndCount > 0x0F)
			{
				pGlyph->Tokens[pGlyph->NbrOfTokens].Bkgnd = 0x00;
				pGlyph->Tokens[pGlyph->NbrOfTokens].Fgnd = 0x0F;
				pGlyph->NbrOfTokens++;
				FgndCount -= 0x0F;
			}

			pGlyph->Tokens[pGlyph->NbrOfTokens].Bkgnd = BkgndCount;
			pGlyph->Tokens[pGlyph->NbrOfTokens].Fgnd = FgndCount;
			pGlyph->NbrOfTokens++;

		} while (BitCounter < (GliphWidth * font.Height));

		while (pGlyph->NbrOfTokens && (0 == pGlyph->Tokens[pGlyph->NbrOfTokens - 1].Fgnd))
		{
			pGlyph->NbrOfTokens--;
		}
	}

	FILE* output;
	fopen_s(&output, "FontOutput.c", "w");
	if (output)
	{
		char	szBuffer[1024];
		sprintf_s(szBuffer, 1024, "const uint8_t FontPERCENT_SIGNixPERCENT_SIGNi[] = {\n/* Width */ \t0xPERCENT_SIGN02x,\n/* Height */ \t0xPERCENT_SIGN02x,", font.Width, font.Height, font.Width, font.Height);
			fwrite(szBuffer, sizeof(char), strlen(szBuffer), output);
			for (uint16_t currentGlyph = 0; currentGlyph < font.NbrOfGlyphs; currentGlyph++)
			{
				sprintf_s(szBuffer, 1024, "\n/* PERCENT_SIGNc */ \t0xPERCENT_SIGN02x, 0xPERCENT_SIGN02x,\t", 32 + currentGlyph, font.Glyphs[currentGlyph].Width, font.Glyphs[currentGlyph].NbrOfTokens);
				fwrite(szBuffer, sizeof(char), strlen(szBuffer), output);

				for (uint8_t currentToken = 0; currentToken < font.Glyphs[currentGlyph].NbrOfTokens; currentToken++)
				{
					sprintf_s(szBuffer, 1024, "\t0xPERCENT_SIGN02x,", (font.Glyphs[currentGlyph].Tokens[currentToken].Bkgnd * 0x10) + font.Glyphs[currentGlyph].Tokens[currentToken].Fgnd);
					fwrite(szBuffer, sizeof(char), strlen(szBuffer), output);
				}
			}
		sprintf_s(szBuffer, 1024, "\n}\n");
		fwrite(szBuffer, sizeof(char), strlen(szBuffer), output);
	}

	_fcloseall();
	return 0;
}

And the GCC code to draw a character on a SSD1963 based TFT controller (Not complete jet, has to solve the offset thing) (replace PERCENT_SIGN with a percent sign)

typedef struct FontToken
{
	uint8_t		Fgnd  : 4;
	uint8_t		Bkgnd : 4;
} __attribute__((__packed__)) FontToken;

uint8_t SPg_SSD1963::DrawCompressedChar(const SPg_Point& location, const char ch)
{
	uint8_t* pFontData = const_cast(Lucida_Console10x16_Compressed);
	uint8_t	 FontWidth = *pFontData++;
	uint8_t  Height = *pFontData++;
	
	for(char lookup = 32; lookup != ch; lookup++)
	{
		pFontData++;
		pFontData += *pFontData++;
	}
	
	uint8_t GlyphWidth = *pFontData++;
	uint8_t NbrOfTokens = *pFontData++;
	uint16_t NbrOfPixelsToGo = GlyphWidth * Height;
	
	uint16_t	StartColumn = location.m_X;
	uint16_t	StartRow	= location.m_Y;
	uint16_t	EndColumn	= StartColumn + GlyphWidth -1;
	uint16_t	EndRow		= StartRow + Height -1;
	
	*m_pCmd = SSD1963_CMD_SET_COLUMN_ADDRESS;
	*m_pData = StartColumn / 0x100;
	*m_pData = StartColumn PERCENT_SIGN 0x100;
	*m_pData = EndColumn / 0x100;
	*m_pData = EndColumn PERCENT_SIGN 0x100;
	
	*m_pCmd = SSD1963_CMD_SET_PAGE_ADDRESS;
	*m_pData = StartRow / 0x100;
	*m_pData = StartRow PERCENT_SIGN 0x100;
	*m_pData = EndRow / 0x100;
	*m_pData = EndRow PERCENT_SIGN 0x100;
	
	*m_pCmd = SSD1963_CMD_WRITE_MEMORY_START;
	
	while(NbrOfTokens)
	{
		FontToken CurrentToken = *(FontToken*)pFontData++;
		NbrOfPixelsToGo -= (CurrentToken.Bkgnd + CurrentToken.Fgnd);
		
		for(uint8_t i = 0; i < CurrentToken.Bkgnd; i++)
		{
			//	Set bkgnd pixel
			*m_pData = 0x00;	//	BackgroundColor.Red
			*m_pData = 0x00;	//	BackgroundColor.Green
			*m_pData = 0x00;	//	BackgroundColor.Blue
		}
		
		for(uint8_t j = 0; j < CurrentToken.Fgnd; j++)
		{
			//	Set fgnd pixels
			*m_pData = 0xFF;	//	ForegroundColor.Red
			*m_pData = 0xFF;	//	ForegroundColor.Green
			*m_pData = 0xFF;	//	ForegroundColor.Blue
		}
		
		NbrOfTokens--;
	}
	
	while(NbrOfPixelsToGo--)
	{
		*m_pData = 0x00;	//	BackgroundColor.Red
		*m_pData = 0x00;	//	BackgroundColor.Green
		*m_pData = 0x00;	//	BackgroundColor.Blue
	}
	
	return GlyphWidth;
}

void SPg_SSD1963::DrawString(const SPg_Point& location, const char* s)
{
	SPg_Point CurrentLocation(location);
	
	while(*s)
	{
		CurrentLocation.m_X += DrawChar(CurrentLocation, *s++);
	}
}

void SPg_SSD1963::DrawCompressedString(const SPg_Point& location, const char* s)
{
	SPg_Point CurrentLocation(location);
	
	while (*s)
	{
		CurrentLocation.m_X += DrawCompressedChar(CurrentLocation, *s++);
	}
}

To make things work I had to define two different structs describling the same data...

=============================================================================================================================================================

"As simple as possible, but not simpler"

GUI Framework for Atmel Xplained Pro

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
To make things work I had to define two different structs describling the same data

That's because you're relying upon implementation-defined features - and the implementations are different :!:

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bit fields are portable, at least I've always found it to be so. However the order of the fields are different for big endian and little endian. As AVRs and PCs are both back asswords endian, it should work.

I send bit fields all the time between AVRs and my Windows PC. I use the same structs (actually classes) at both ends.

I don't use the attribute stuff though. I would have thought it wouldn't be portable, and I don't know what it does for you. I also don't know about uint8_t. That wasn't around when I started programming so I have my own typedefs for portability.

typedef struct Token 
 { 
    uint8_t      Fgnd  : 4;     // Low order bits on little endian machines.   High order bits on big endian machines.
    uint8_t      Bkgnd : 4; 
 } ; 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

steve17 wrote:
Bit fields are portable

You are arguing with Messrs Kernighan and Ritchie!

:shock:

Quote:
at least I've always found it to be so.

That just means that you just happen to have stumbled upon cases which just happen to "work".

As a general rule, they are not portable!

Like crossing the road blindfold, the fact that you might have got away with it once does not make it a generally safe thing to do :!:

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In the GCC code it seems to me the only place you actually use the FontToken is in this loop:

   while(NbrOfTokens)
   {
      FontToken CurrentToken = *(FontToken*)pFontData++;
      NbrOfPixelsToGo -= (CurrentToken.Bkgnd + CurrentToken.Fgnd);
      
      for(uint8_t i = 0; i < CurrentToken.Bkgnd; i++)
      {
         //   Set bkgnd pixel
         *m_pData = 0x00;   //   BackgroundColor.Red
         *m_pData = 0x00;   //   BackgroundColor.Green
         *m_pData = 0x00;   //   BackgroundColor.Blue
      }
      
      for(uint8_t j = 0; j < CurrentToken.Fgnd; j++)
      {
         //   Set fgnd pixels
         *m_pData = 0xFF;   //   ForegroundColor.Red
         *m_pData = 0xFF;   //   ForegroundColor.Green
         *m_pData = 0xFF;   //   ForegroundColor.Blue
      }
      
      NbrOfTokens--;
   }

So why not simply code that as:

uint8_t Fgnd, Bkgnd;
   while(NbrOfTokens)
   {
      uint8_t CurrentByte = *(uint8_t*)pFontData++;
      Fgnd = CurrentByte >> 4; // if I got the bit order wrong reverse these two lines
      BGnd = CurrentByte & 0xF;
      NbrOfPixelsToGo -= (Bkgnd + Fgnd);
      
      for(uint8_t i = 0; i < Bkgnd; i++)
      {
         //   Set bkgnd pixel
         *m_pData = 0x00;   //   BackgroundColor.Red
         *m_pData = 0x00;   //   BackgroundColor.Green
         *m_pData = 0x00;   //   BackgroundColor.Blue
      }
      
      for(uint8_t j = 0; j < Fgnd; j++)
      {
         //   Set fgnd pixels
         *m_pData = 0xFF;   //   ForegroundColor.Red
         *m_pData = 0xFF;   //   ForegroundColor.Green
         *m_pData = 0xFF;   //   ForegroundColor.Blue
      }
      
      NbrOfTokens--;
   }

Then GCC doesn't need to know about FontToken at all. If you want you can keep it in the encoder to do the packing or you could modify the packing code too to just pack the nibbles using shifts and OR.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
pack the nibbles using shifts and OR.

Yes - that's the way to go if you want it portable.

In many (most?) cases, there is no size/speed advantage to using bitfields; in some (many?) cases, using bitfields is actually worse :!:

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

there is no size/speed advantage to using bitfields;

Yup, it's just syntactic sugar really. Saves typing lots of those messy << and & characters! ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all,

Thanks for the suggestions.

Quote:
You are arguing with Messrs Kernighan and Ritchie!

Well, I have to much respect for these guys to do this myself ;)

The reason I implemented this in a bitfield struct was that I wasn't sure about the best common ration between foreground and background pixels in fonts. As implemented now, I only have to change the typdedef to vary this ratio.

As mentioned earlier, this is 'Quick & Dirty' programming, which is never a good idea I realize now...

Maybe I have to considder Cliffs suggestion to shift values.

Thanks

"As simple as possible, but not simpler"

GUI Framework for Atmel Xplained Pro

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
As a general rule, [bitfields] are not portable!

In particular, they tend to be endian-dependent. big-endian systems (68000) will tend to allocate bitfields starting from the most significant bit, and little-endian systems (x86) from the least significant bit. Or so I discovered (the hard way) porting code from 68k to x86 (Hmm. Different compiler vendors, at the time, too. So maybe that had nothing to do with it?) Even on 32-bit CPUs with bitfield instructions, there's no real reason to choose one over the other; it's just ... arbitrary.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

In particular, they tend to be endian-dependent. big-endian systems (68000) will tend to allocate bitfields starting from the most significant bit, and little-endian systems (x86) from the least significant bit.

Yeah but what Paul says he has discovered here is that the little endian x86 (or rather MSVC's view of it) orders differently to the (ostensibly) little endian AVR.

However here's a quick test of GCC (Linux AMD64):

$ cat test3.c
#include 

typedef struct {
 int foo:4;
 int bar:4;
} field_t;

typedef union {
 int val;
 field_t field;
} join_t;

join_t join;

int main(void) {
	join.field.foo = 0xA;
	join.field.bar = 0x5;
	printf("result = %04X\n", join.val);
	return 0;
}
$ gcc test3.c -o test3
$ ./test3
result = 005A

And the very same code built with MSVC:

e:\>type test3.c
#include 

typedef struct {
 int foo:4;
 int bar:4;
} field_t;

typedef union {
 int val;
 field_t field;
} join_t;

join_t join;

int main(void) {
        join.field.foo = 0xA;
        join.field.bar = 0x5;
        printf("result = %04X\n", join.val);
        return 0;
}

e:\>cl test3.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

test3.c
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test3.exe
test3.obj

e:\>test3
result = 005A

So same result there. When I do the same for avr-gcc:

$ avr-gcc -mmcu=atmega16 -Os -g -save-temps test3.c -o test3.elf
$ avr-source test3.s
file 1 = test3.c
file 2 = /home/uid23021/windows/avr8-gnu-toolchain-linux_x86_64/avr/include/stdio.h
$ cat test3.source.s 
	.file	"test3.c"
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__SREG__ = 0x3f
__tmp_reg__ = 0
__zero_reg__ = 1
	.text
.Ltext0:

	.section	.rodata.str1.1,"aMS",@progbits,1
.LC0:
	.string	"result = %04X\n"

	.section	.text.startup,"ax",@progbits
.global	main
	.type	main, @function
main:
//==> int main(void) {
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
//==> 	join.field.bar = 0x5;
	ldi r24,lo8(90)
	sts join,r24
...

It's not so easy to actually run/show output bit that's putting 90 (0x5A) in location "join"

So, to be honest, I'm a bit confused here. It seems to me that all three compilers all use the same ordering? What am I missing here?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To be precise :

Quote:
the little endian x86 (or rather MSVC's view of it) orders differently to the (ostensibly) little endian AVR.

I stated in the opening post :
Quote:
PS : using ARM gcc toolchain, if that bothers... Wink

"As simple as possible, but not simpler"

GUI Framework for Atmel Xplained Pro

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is that -mlittle-endian or -mbig-endian? (little is the default).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well Cliff, that's a very good question. I only have little notion about endianness ( :oops: ) let alone how different compilers handle these thing. (I know, it's a shame....) This is of course basic knowledge, but the time since I went to school has faded basic knowledge...

"As simple as possible, but not simpler"

GUI Framework for Atmel Xplained Pro

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK so I just tried test3 with a 4.7 arm-gcc compiler and gave the "-march=armv7e-m -mcpu=cortex-m4 -mthumb" which I believe is right for Cortex M4. I made two interesting discoveries:

1) my avr-source program also works on ARM .s file ;-)

2) I learnt a new ARM opcode I hadn't stumbled upon before: BFI which is Bit Field Insert. It has the format:

 BFI Rd, Rn, #, #

And takes the bits in Rn and inserts them into Rd at bit position lsb for a width of "width" bits.

So the code I got was:

main:
//==> int main(void) {
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 0, uses_anonymous_args = 0
        push    {r3, lr}
//==>   join.field.foo = 0xA;
        ldr     r3, .L2
//==>   printf("result = %04X\n", join.val);
        ldr     r0, .L2+4
//==>   join.field.foo = 0xA;
        ldr     r1, [r3, #0]
        mvn     r2, #5
        bfi     r1, r2, #0, #4
//==>   join.field.bar = 0x5;
        movs    r2, #5
        bfi     r1, r2, #4, #4
        str     r1, [r3, #0]
//==>   printf("result = %04X\n", join.val);
        bl      printf
//==> }
        movs    r0, #0
        pop     {r3, pc}
.L3:
        .align  2
.L2:
        .word   join
        .word   .LC0
        .size   main, .-main
        .comm   join,4,4

Some of that is to do with the printf (the bits that refer to LCO and therefore .L2+4) but the bits operating on "join" boil down to:

//==>   join.field.foo = 0xA;
        ldr     r3, .L2 // address of "join" to R3
//==>   join.field.foo = 0xA;
        ldr     r1, [r3, #0] // read "join"
        mvn     r2, #5 // put #5 EOR 0xFFFFFFFF into R2 - effectively A in the bottom 4 bits
        bfi     r1, r2, #0, #4 // insert four bits (A) into join at bit pos 0
//==>   join.field.bar = 0x5;
        movs    r2, #5 // put 5 into R2
        bfi     r1, r2, #4, #4 // insert 5 at bit position 4 in "join"
        str     r1, [r3, #0] // store "join" back to it's location

So once again this is also putting 0x5A into the bottom locations of "join".

I can only assume your copy of arm-gcc is being invoked with build options that cause some re-ordering of this.

Last Edited: Fri. Aug 15, 2014 - 12:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cliff,

FYI I attach the compiler output from a complete rebuild of the project.

Now I notice a lot of warnings looking like this one :

C:\Documents\Atmel Studio\6.2\SPg++\SAMsPlayground++\Devices\SPg_SDCard.h(74,16): info: offset of packed bit-field 'CSD::C_SIZE_MULT' has changed in GCC 4.4

Have no idea what it's all about...

Maybe this is the reason why I had trouble decoding CSD & CID etc structures from SDcards, which are also bitfields spanning multiple bytes. I then postponed the decoding to be solved in the future and hardcoded values...

Attachment(s): 

"As simple as possible, but not simpler"

GUI Framework for Atmel Xplained Pro

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Read about "-Wpacked-bitfield-compat" on this page:

https://gcc.gnu.org/onlinedocs/g...

Also the 4th point down on this page:

https://gcc.gnu.org/gcc-4.4/chan...

So the 4.4 change seems to have been to fix a previous bug and the warning is simply to point out that legacy code from before then may have changed behaviour.

If you can locate it I'd be interested to see the code that was generated for your access to FontToken in the arm-gcc code. I don't see anything obvious in your build options that would make bit fields operate differently to all the compilers I've shown here.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've been using bit fields for 30 years. The purpose of bit fields is to make the code easier to read and program. I would say much easier. It is not used to make code more efficient.

I know of cases programming AVRs where bit fields make the code less efficient. I still use bit fields.

I've programmed PCs using Microsoft's compiler and GCC. I've programmed TI DSPs. I've programmed Motorola 6809 and 68000. I've programmed various AVRs. I've programmed more computers and used more compilers than I can remember. Yes indeed bit fields are portable in all these cases. I challenge you to find one where that isn't so.

I write almost all my code to be portable, and I use bit fields. When I'm porting code between little endian and big endian machines I still use bit fields because it is so much easier to read and program. In this case I make two sets of bit fields where the field order is reversed depending on big or little endian. I even have a feature in my editor to do the flip automatically so I only have to write the code once.

Even if there is some weird situation where bit fields aren't portable, it makes sense to use them where they are portable.

When K&R were inventing C, not all computers used 8 bit bytes. That could cause portability problems, and not just bit field problems.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'll do the reading asap ;)

I *think* the access to the fields in a FontToken is in this code:

      NbrOfPixelsToGo -= (CurrentToken.Bkgnd + CurrentToken.Fgnd);
  40458a:   7c3b         ldrb   r3, [r7, #16]
  40458c:   f3c3 1303    ubfx   r3, r3, #4, #4
  404590:   b2db         uxtb   r3, r3
  404592:   461a         mov   r2, r3
  404594:   7c3b         ldrb   r3, [r7, #16]
  404596:   f3c3 0303    ubfx   r3, r3, #0, #4
  40459a:   b2db         uxtb   r3, r3
  40459c:   4413         add   r3, r2
  40459e:   b29b         uxth   r3, r3
  4045a0:   8c3a         ldrh   r2, [r7, #32]
  4045a2:   1ad3         subs   r3, r2, r3
  4045a4:   843b         strh   r3, [r7, #32]

the complete compiled code :

00404464 <_ZN11SPg_SSD196318DrawCompressedCharERK9SPg_Pointc>:
	uint8_t		Fgnd  : 4;
	uint8_t		Bkgnd : 4;
} __attribute__((__packed__)) FontToken;

uint8_t SPg_SSD1963::DrawCompressedChar(const SPg_Point& location, const char ch)
{
  404464:	b480      	push	{r7}
  404466:	b08b      	sub	sp, #44	; 0x2c
  404468:	af00      	add	r7, sp, #0
  40446a:	60f8      	str	r0, [r7, #12]
  40446c:	60b9      	str	r1, [r7, #8]
  40446e:	4613      	mov	r3, r2
  404470:	71fb      	strb	r3, [r7, #7]
	uint8_t* pFontData = const_cast(Lucida_Console10x16_Compressed);
  404472:	4b79      	ldr	r3, [pc, #484]	; (404658 <_ZN11SPg_SSD196318DrawCompressedCharERK9SPg_Pointc+0x1f4>)
  404474:	627b      	str	r3, [r7, #36]	; 0x24
	uint8_t	 FontWidth = *pFontData++;
  404476:	6a7b      	ldr	r3, [r7, #36]	; 0x24
  404478:	1c5a      	adds	r2, r3, #1
  40447a:	627a      	str	r2, [r7, #36]	; 0x24
  40447c:	781b      	ldrb	r3, [r3, #0]
  40447e:	777b      	strb	r3, [r7, #29]
	uint8_t  Height = *pFontData++;
  404480:	6a7b      	ldr	r3, [r7, #36]	; 0x24
  404482:	1c5a      	adds	r2, r3, #1
  404484:	627a      	str	r2, [r7, #36]	; 0x24
  404486:	781b      	ldrb	r3, [r3, #0]
  404488:	773b      	strb	r3, [r7, #28]
	
	for(char lookup = 32; lookup != ch; lookup++)
  40448a:	2320      	movs	r3, #32
  40448c:	f887 3023 	strb.w	r3, [r7, #35]	; 0x23
  404490:	e00e      	b.n	4044b0 <_ZN11SPg_SSD196318DrawCompressedCharERK9SPg_Pointc+0x4c>
	{
		pFontData++;
  404492:	6a7b      	ldr	r3, [r7, #36]	; 0x24
  404494:	3301      	adds	r3, #1
  404496:	627b      	str	r3, [r7, #36]	; 0x24
		pFontData += *pFontData++;
  404498:	6a7b      	ldr	r3, [r7, #36]	; 0x24
  40449a:	1c5a      	adds	r2, r3, #1
  40449c:	627a      	str	r2, [r7, #36]	; 0x24
  40449e:	781b      	ldrb	r3, [r3, #0]
  4044a0:	6a7a      	ldr	r2, [r7, #36]	; 0x24
  4044a2:	4413      	add	r3, r2
  4044a4:	627b      	str	r3, [r7, #36]	; 0x24
{
	uint8_t* pFontData = const_cast(Lucida_Console10x16_Compressed);
	uint8_t	 FontWidth = *pFontData++;
	uint8_t  Height = *pFontData++;
	
	for(char lookup = 32; lookup != ch; lookup++)
  4044a6:	f897 3023 	ldrb.w	r3, [r7, #35]	; 0x23
  4044aa:	3301      	adds	r3, #1
  4044ac:	f887 3023 	strb.w	r3, [r7, #35]	; 0x23
  4044b0:	f897 2023 	ldrb.w	r2, [r7, #35]	; 0x23
  4044b4:	79fb      	ldrb	r3, [r7, #7]
  4044b6:	429a      	cmp	r2, r3
  4044b8:	d1eb      	bne.n	404492 <_ZN11SPg_SSD196318DrawCompressedCharERK9SPg_Pointc+0x2e>
	{
		pFontData++;
		pFontData += *pFontData++;
	}
	
	uint8_t GlyphWidth = *pFontData++;
  4044ba:	6a7b      	ldr	r3, [r7, #36]	; 0x24
  4044bc:	1c5a      	adds	r2, r3, #1
  4044be:	627a      	str	r2, [r7, #36]	; 0x24
  4044c0:	781b      	ldrb	r3, [r3, #0]
  4044c2:	76fb      	strb	r3, [r7, #27]
	uint8_t NbrOfTokens = *pFontData++;
  4044c4:	6a7b      	ldr	r3, [r7, #36]	; 0x24
  4044c6:	1c5a      	adds	r2, r3, #1
  4044c8:	627a      	str	r2, [r7, #36]	; 0x24
  4044ca:	781b      	ldrb	r3, [r3, #0]
  4044cc:	f887 3022 	strb.w	r3, [r7, #34]	; 0x22
	uint16_t NbrOfPixelsToGo = GlyphWidth * Height;
  4044d0:	7efb      	ldrb	r3, [r7, #27]
  4044d2:	b29b      	uxth	r3, r3
  4044d4:	7f3a      	ldrb	r2, [r7, #28]
  4044d6:	b292      	uxth	r2, r2
  4044d8:	fb02 f303 	mul.w	r3, r2, r3
  4044dc:	843b      	strh	r3, [r7, #32]
	
	uint16_t	StartColumn = location.m_X;
  4044de:	68bb      	ldr	r3, [r7, #8]
  4044e0:	881b      	ldrh	r3, [r3, #0]
  4044e2:	833b      	strh	r3, [r7, #24]
	uint16_t	StartRow	= location.m_Y;
  4044e4:	68bb      	ldr	r3, [r7, #8]
  4044e6:	885b      	ldrh	r3, [r3, #2]
  4044e8:	82fb      	strh	r3, [r7, #22]
	uint16_t	EndColumn	= StartColumn + GlyphWidth -1;
  4044ea:	7efb      	ldrb	r3, [r7, #27]
  4044ec:	b29a      	uxth	r2, r3
  4044ee:	8b3b      	ldrh	r3, [r7, #24]
  4044f0:	4413      	add	r3, r2
  4044f2:	b29b      	uxth	r3, r3
  4044f4:	3b01      	subs	r3, #1
  4044f6:	82bb      	strh	r3, [r7, #20]
	uint16_t	EndRow		= StartRow + Height -1;
  4044f8:	7f3b      	ldrb	r3, [r7, #28]
  4044fa:	b29a      	uxth	r2, r3
  4044fc:	8afb      	ldrh	r3, [r7, #22]
  4044fe:	4413      	add	r3, r2
  404500:	b29b      	uxth	r3, r3
  404502:	3b01      	subs	r3, #1
  404504:	827b      	strh	r3, [r7, #18]
	
	*m_pCmd = SSD1963_CMD_SET_COLUMN_ADDRESS;
  404506:	68fb      	ldr	r3, [r7, #12]
  404508:	691b      	ldr	r3, [r3, #16]
  40450a:	222a      	movs	r2, #42	; 0x2a
  40450c:	701a      	strb	r2, [r3, #0]
	*m_pData = StartColumn / 0x100;
  40450e:	68fb      	ldr	r3, [r7, #12]
  404510:	68db      	ldr	r3, [r3, #12]
  404512:	8b3a      	ldrh	r2, [r7, #24]
  404514:	0a12      	lsrs	r2, r2, #8
  404516:	b292      	uxth	r2, r2
  404518:	b2d2      	uxtb	r2, r2
  40451a:	701a      	strb	r2, [r3, #0]
	*m_pData = StartColumn % 0x100;
  40451c:	68fb      	ldr	r3, [r7, #12]
  40451e:	68db      	ldr	r3, [r3, #12]
  404520:	8b3a      	ldrh	r2, [r7, #24]
  404522:	b2d2      	uxtb	r2, r2
  404524:	701a      	strb	r2, [r3, #0]
	*m_pData = EndColumn / 0x100;
  404526:	68fb      	ldr	r3, [r7, #12]
  404528:	68db      	ldr	r3, [r3, #12]
  40452a:	8aba      	ldrh	r2, [r7, #20]
  40452c:	0a12      	lsrs	r2, r2, #8
  40452e:	b292      	uxth	r2, r2
  404530:	b2d2      	uxtb	r2, r2
  404532:	701a      	strb	r2, [r3, #0]
	*m_pData = EndColumn % 0x100;
  404534:	68fb      	ldr	r3, [r7, #12]
  404536:	68db      	ldr	r3, [r3, #12]
  404538:	8aba      	ldrh	r2, [r7, #20]
  40453a:	b2d2      	uxtb	r2, r2
  40453c:	701a      	strb	r2, [r3, #0]
	
	*m_pCmd = SSD1963_CMD_SET_PAGE_ADDRESS;
  40453e:	68fb      	ldr	r3, [r7, #12]
  404540:	691b      	ldr	r3, [r3, #16]
  404542:	222b      	movs	r2, #43	; 0x2b
  404544:	701a      	strb	r2, [r3, #0]
	*m_pData = StartRow / 0x100;
  404546:	68fb      	ldr	r3, [r7, #12]
  404548:	68db      	ldr	r3, [r3, #12]
  40454a:	8afa      	ldrh	r2, [r7, #22]
  40454c:	0a12      	lsrs	r2, r2, #8
  40454e:	b292      	uxth	r2, r2
  404550:	b2d2      	uxtb	r2, r2
  404552:	701a      	strb	r2, [r3, #0]
	*m_pData = StartRow % 0x100;
  404554:	68fb      	ldr	r3, [r7, #12]
  404556:	68db      	ldr	r3, [r3, #12]
  404558:	8afa      	ldrh	r2, [r7, #22]
  40455a:	b2d2      	uxtb	r2, r2
  40455c:	701a      	strb	r2, [r3, #0]
	*m_pData = EndRow / 0x100;
  40455e:	68fb      	ldr	r3, [r7, #12]
  404560:	68db      	ldr	r3, [r3, #12]
  404562:	8a7a      	ldrh	r2, [r7, #18]
  404564:	0a12      	lsrs	r2, r2, #8
  404566:	b292      	uxth	r2, r2
  404568:	b2d2      	uxtb	r2, r2
  40456a:	701a      	strb	r2, [r3, #0]
	*m_pData = EndRow % 0x100;
  40456c:	68fb      	ldr	r3, [r7, #12]
  40456e:	68db      	ldr	r3, [r3, #12]
  404570:	8a7a      	ldrh	r2, [r7, #18]
  404572:	b2d2      	uxtb	r2, r2
  404574:	701a      	strb	r2, [r3, #0]
	
	*m_pCmd = SSD1963_CMD_WRITE_MEMORY_START;
  404576:	68fb      	ldr	r3, [r7, #12]
  404578:	691b      	ldr	r3, [r3, #16]
  40457a:	222c      	movs	r2, #44	; 0x2c
  40457c:	701a      	strb	r2, [r3, #0]
	
	while(NbrOfTokens)
  40457e:	e049      	b.n	404614 <_ZN11SPg_SSD196318DrawCompressedCharERK9SPg_Pointc+0x1b0>
	{
		FontToken CurrentToken = *(FontToken*)pFontData++;
  404580:	6a7b      	ldr	r3, [r7, #36]	; 0x24
  404582:	1c5a      	adds	r2, r3, #1
  404584:	627a      	str	r2, [r7, #36]	; 0x24
  404586:	781b      	ldrb	r3, [r3, #0]
  404588:	743b      	strb	r3, [r7, #16]
		NbrOfPixelsToGo -= (CurrentToken.Bkgnd + CurrentToken.Fgnd);
  40458a:	7c3b      	ldrb	r3, [r7, #16]
  40458c:	f3c3 1303 	ubfx	r3, r3, #4, #4
  404590:	b2db      	uxtb	r3, r3
  404592:	461a      	mov	r2, r3
  404594:	7c3b      	ldrb	r3, [r7, #16]
  404596:	f3c3 0303 	ubfx	r3, r3, #0, #4
  40459a:	b2db      	uxtb	r3, r3
  40459c:	4413      	add	r3, r2
  40459e:	b29b      	uxth	r3, r3
  4045a0:	8c3a      	ldrh	r2, [r7, #32]
  4045a2:	1ad3      	subs	r3, r2, r3
  4045a4:	843b      	strh	r3, [r7, #32]
		
		for(uint8_t i = 0; i < CurrentToken.Bkgnd; i++)
  4045a6:	2300      	movs	r3, #0
  4045a8:	77fb      	strb	r3, [r7, #31]
  4045aa:	e00e      	b.n	4045ca <_ZN11SPg_SSD196318DrawCompressedCharERK9SPg_Pointc+0x166>
		{
			//	Set bkgnd pixel
			*m_pData = 0x00;	//	BackgroundColor.Red
  4045ac:	68fb      	ldr	r3, [r7, #12]
  4045ae:	68db      	ldr	r3, [r3, #12]
  4045b0:	2200      	movs	r2, #0
  4045b2:	701a      	strb	r2, [r3, #0]
			*m_pData = 0x00;	//	BackgroundColor.Green
  4045b4:	68fb      	ldr	r3, [r7, #12]
  4045b6:	68db      	ldr	r3, [r3, #12]
  4045b8:	2200      	movs	r2, #0
  4045ba:	701a      	strb	r2, [r3, #0]
			*m_pData = 0x00;	//	BackgroundColor.Blue
  4045bc:	68fb      	ldr	r3, [r7, #12]
  4045be:	68db      	ldr	r3, [r3, #12]
  4045c0:	2200      	movs	r2, #0
  4045c2:	701a      	strb	r2, [r3, #0]
	while(NbrOfTokens)
	{
		FontToken CurrentToken = *(FontToken*)pFontData++;
		NbrOfPixelsToGo -= (CurrentToken.Bkgnd + CurrentToken.Fgnd);
		
		for(uint8_t i = 0; i < CurrentToken.Bkgnd; i++)
  4045c4:	7ffb      	ldrb	r3, [r7, #31]
  4045c6:	3301      	adds	r3, #1
  4045c8:	77fb      	strb	r3, [r7, #31]
  4045ca:	7ffa      	ldrb	r2, [r7, #31]
  4045cc:	7c3b      	ldrb	r3, [r7, #16]
  4045ce:	f3c3 1303 	ubfx	r3, r3, #4, #4
  4045d2:	b2db      	uxtb	r3, r3
  4045d4:	429a      	cmp	r2, r3
  4045d6:	dbe9      	blt.n	4045ac <_ZN11SPg_SSD196318DrawCompressedCharERK9SPg_Pointc+0x148>
			*m_pData = 0x00;	//	BackgroundColor.Red
			*m_pData = 0x00;	//	BackgroundColor.Green
			*m_pData = 0x00;	//	BackgroundColor.Blue
		}
		
		for(uint8_t j = 0; j < CurrentToken.Fgnd; j++)
  4045d8:	2300      	movs	r3, #0
  4045da:	77bb      	strb	r3, [r7, #30]
  4045dc:	e00e      	b.n	4045fc <_ZN11SPg_SSD196318DrawCompressedCharERK9SPg_Pointc+0x198>
		{
			//	Set fgnd pixels	
			*m_pData = 0xFF;	//	ForegroundColor.Red
  4045de:	68fb      	ldr	r3, [r7, #12]
  4045e0:	68db      	ldr	r3, [r3, #12]
  4045e2:	22ff      	movs	r2, #255	; 0xff
  4045e4:	701a      	strb	r2, [r3, #0]
			*m_pData = 0xFF;	//	ForegroundColor.Green
  4045e6:	68fb      	ldr	r3, [r7, #12]
  4045e8:	68db      	ldr	r3, [r3, #12]
  4045ea:	22ff      	movs	r2, #255	; 0xff
  4045ec:	701a      	strb	r2, [r3, #0]
			*m_pData = 0xFF;	//	ForegroundColor.Blue
  4045ee:	68fb      	ldr	r3, [r7, #12]
  4045f0:	68db      	ldr	r3, [r3, #12]
  4045f2:	22ff      	movs	r2, #255	; 0xff
  4045f4:	701a      	strb	r2, [r3, #0]
			*m_pData = 0x00;	//	BackgroundColor.Red
			*m_pData = 0x00;	//	BackgroundColor.Green
			*m_pData = 0x00;	//	BackgroundColor.Blue
		}
		
		for(uint8_t j = 0; j < CurrentToken.Fgnd; j++)
  4045f6:	7fbb      	ldrb	r3, [r7, #30]
  4045f8:	3301      	adds	r3, #1
  4045fa:	77bb      	strb	r3, [r7, #30]
  4045fc:	7fba      	ldrb	r2, [r7, #30]
  4045fe:	7c3b      	ldrb	r3, [r7, #16]
  404600:	f3c3 0303 	ubfx	r3, r3, #0, #4
  404604:	b2db      	uxtb	r3, r3
  404606:	429a      	cmp	r2, r3
  404608:	dbe9      	blt.n	4045de <_ZN11SPg_SSD196318DrawCompressedCharERK9SPg_Pointc+0x17a>
			*m_pData = 0xFF;	//	ForegroundColor.Red
			*m_pData = 0xFF;	//	ForegroundColor.Green
			*m_pData = 0xFF;	//	ForegroundColor.Blue
		}
		
		NbrOfTokens--;
  40460a:	f897 3022 	ldrb.w	r3, [r7, #34]	; 0x22
  40460e:	3b01      	subs	r3, #1
  404610:	f887 3022 	strb.w	r3, [r7, #34]	; 0x22
	*m_pData = EndRow / 0x100;
	*m_pData = EndRow % 0x100;
	
	*m_pCmd = SSD1963_CMD_WRITE_MEMORY_START;
	
	while(NbrOfTokens)
  404614:	f897 3022 	ldrb.w	r3, [r7, #34]	; 0x22
  404618:	2b00      	cmp	r3, #0
  40461a:	d1b1      	bne.n	404580 <_ZN11SPg_SSD196318DrawCompressedCharERK9SPg_Pointc+0x11c>
		}
		
		NbrOfTokens--;
	}
	
	while(NbrOfPixelsToGo--)
  40461c:	e00b      	b.n	404636 <_ZN11SPg_SSD196318DrawCompressedCharERK9SPg_Pointc+0x1d2>
	{
		*m_pData = 0x00;	//	BackgroundColor.Red
  40461e:	68fb      	ldr	r3, [r7, #12]
  404620:	68db      	ldr	r3, [r3, #12]
  404622:	2200      	movs	r2, #0
  404624:	701a      	strb	r2, [r3, #0]
		*m_pData = 0x00;	//	BackgroundColor.Green
  404626:	68fb      	ldr	r3, [r7, #12]
  404628:	68db      	ldr	r3, [r3, #12]
  40462a:	2200      	movs	r2, #0
  40462c:	701a      	strb	r2, [r3, #0]
		*m_pData = 0x00;	//	BackgroundColor.Blue
  40462e:	68fb      	ldr	r3, [r7, #12]
  404630:	68db      	ldr	r3, [r3, #12]
  404632:	2200      	movs	r2, #0
  404634:	701a      	strb	r2, [r3, #0]
		}
		
		NbrOfTokens--;
	}
	
	while(NbrOfPixelsToGo--)
  404636:	8c3b      	ldrh	r3, [r7, #32]
  404638:	1e5a      	subs	r2, r3, #1
  40463a:	843a      	strh	r2, [r7, #32]
  40463c:	2b00      	cmp	r3, #0
  40463e:	bf0c      	ite	eq
  404640:	2300      	moveq	r3, #0
  404642:	2301      	movne	r3, #1
  404644:	b2db      	uxtb	r3, r3
  404646:	2b00      	cmp	r3, #0
  404648:	d1e9      	bne.n	40461e <_ZN11SPg_SSD196318DrawCompressedCharERK9SPg_Pointc+0x1ba>
		*m_pData = 0x00;	//	BackgroundColor.Red
		*m_pData = 0x00;	//	BackgroundColor.Green
		*m_pData = 0x00;	//	BackgroundColor.Blue
	}
	
	return GlyphWidth;
  40464a:	7efb      	ldrb	r3, [r7, #27]
}
  40464c:	4618      	mov	r0, r3
  40464e:	372c      	adds	r7, #44	; 0x2c
  404650:	46bd      	mov	sp, r7
  404652:	f85d 7b04 	ldr.w	r7,  , #4
  404656:	4770      	bx	lr
  404658:	0041a620 	.word	0x0041a620

"As simple as possible, but not simpler"

GUI Framework for Atmel Xplained Pro

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oops, html tags inbetween code tags didn't work...

"As simple as possible, but not simpler"

GUI Framework for Atmel Xplained Pro

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I challenge you to find one where that isn't so.
This one?

"As simple as possible, but not simpler"

GUI Framework for Atmel Xplained Pro

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

An interesting day indeed - I've never had to look at ARM bitfield code in detail so earlier I learnt BFI and now I see the unpacking is done with UBFX which the manual has this to say about:

 UBFX Rd, Rn, #, #

Unsigned Bit Field eXtract. It's basically BFI backwards.

      NbrOfPixelsToGo -= (CurrentToken.Bkgnd + CurrentToken.Fgnd);
  40458a:   7c3b         ldrb   r3, [r7, #16]
  40458c:   f3c3 1303    ubfx   r3, r3, #4, #4
  404590:   b2db         uxtb   r3, r3
  404592:   461a         mov   r2, r3
  404594:   7c3b         ldrb   r3, [r7, #16]
  404596:   f3c3 0303    ubfx   r3, r3, #0, #4
  40459a:   b2db         uxtb   r3, r3
  40459c:   4413         add   r3, r2
  40459e:   b29b         uxth   r3, r3
  4045a0:   8c3a         ldrh   r2, [r7, #32]
  4045a2:   1ad3         subs   r3, r2, r3

To me that "looks right". It seems to be accesing #0,#4 and #4,#4 just like the other code I posted doing the BFIs so all this code looks like in a short/int/long it's packing and extracting [7:4] and [3:0]. So what is it that actually lead you to think one was was "wrong" and start this thread?

I can only think that maybe your MSVC was not packing as expected in the first place?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Long explanation...

Let's take a look at the output of the Mikroelektronika's GLCD Font Creator for the '!' character:

	0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char !

If we see this as an immage of zeros and ones, whith the right byte order, we get this image:

00 00    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
00 00    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
00 00    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
00 00    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
FE 1B    0 0 0 * * 0 * * * * * * * * * 0   

This are 4 blank vertical lines followed by the actual exclamation sign.

If we start counting the number of background pixels from the top of the image, going from left to right and then from top to bottom, which means in the picture above trom the right-top downwards to right-bottom, then moving left, this gives

9 bkgnd pixels, 1 fgnd pixel, 4 bkgnd pixels, 1 fgnd pixels ...

resulting in an MSVC FontToken

/* Tokens for '!' */ 	0x05, 0x0b,		0x91,	0x41,	0x41,	0x41,	0x41,	0x41,	0x41,	0x41,	0x41,	0x91,	0x41,

note:
1)the first byte denotes the width (in pixels) of the glyph, the second byte is the number of FontTokens that makes op the glyph.
2)all bkgnd pixels after the last fgnd pixel aren't mentioned in this layout, they are handled in the glyph drawing routine.

Now, if I read these structure in GCC using the exact same FontToken struct, I read the first token as .Fgnd = 9 and .Bkgnd = 1, which is an error.

Hope this helps.

============================================================================================================================================================= 

"As simple as possible, but not simpler"

GUI Framework for Atmel Xplained Pro

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As this is my 100th post on this forum, I don't know to be proud or not. Maybe it's a scale fore my dumbness or unawareness.

I have modified the MSVC program so that it writes the whole shibang to a binary file:

typedef struct FontToken
{
	uint8_t		Bkgnd : 4;
	uint8_t		Fgnd  : 4;
}FontToken;

typedef struct Glyph
{
	uint8_t		Width;
	uint8_t		NbrOfTokens;
	FontToken	Tokens[0x100];
} Glyph;

typedef struct Font
{
	uint8_t		Width;
	uint8_t		Height;
	char		FirstGlyph;
	uint8_t		NbrOfGlyphs;
	uint32_t	GlyphOffsets[0x100];
	Glyph		Glyphs[0x100];
} Font;

bool GetPixelAtOffset(uint8_t* GlyphLine, uint8_t FontHeight, uint16_t pixelPos)
{
	uint8_t BytesPerHorizontalLine = FontHeight / 8;
	if (0 != FontHeight PERCENT_SIGN 8)
		BytesPerHorizontalLine++;
	uint8_t GlyphWidth = GlyphLine[0];
	uint16_t BitVerticalPosition = FontHeight - 1 - (pixelPos / GlyphWidth);
	uint8_t	BitHorizontalPosition = pixelPos PERCENT_SIGN GlyphWidth;
	uint8_t ByteOffset = 1 + (BitHorizontalPosition * BytesPerHorizontalLine) + (BytesPerHorizontalLine - 1 - (BitVerticalPosition / 8));
	uint8_t Mask = (1 << (7 - (BitVerticalPosition PERCENT_SIGN 8)));
	return (Mask == (GlyphLine[ByteOffset] & Mask));
}

int _tmain(int argc, _TCHAR* argv[])
{
	Font font;
	font.Height = 16;
	font.Width = 10;
	font.FirstGlyph = ' ';
	font.NbrOfGlyphs = 96;

	uint8_t BytesPerRow = font.Width / 8;
	if (0 != font.Width PERCENT_SIGN 8)
		BytesPerRow++;

	uint32_t	CurrentGlyphOffset = 0;

	for (int i = 0; i < 96; i++)
	{
		Glyph* pGlyph = &(font.Glyphs[i]);
		pGlyph->NbrOfTokens = 0;
		uint8_t counter = 0;
		uint8_t NbrOfPixels = 0;
		bool	bForeGround = false;
		uint8_t* pLineData = &(Lucida_Console10x16[i * (font.Width * BytesPerRow + 1)]);
		uint8_t	GliphWidth = pGlyph->Width = pLineData[0];
		font.GlyphOffsets[i] = CurrentGlyphOffset;

		uint16_t BitCounter = 0;
		do
		{
			uint8_t BkgndCount = 0;
			uint8_t FgndCount = 0;
			while ((false == GetPixelAtOffset(pLineData, font.Height, BitCounter)) && (BitCounter < (GliphWidth * font.Height)))
			{
				BkgndCount++;
				BitCounter++;
			}

			while ((true == GetPixelAtOffset(pLineData, font.Height, BitCounter)) && (BitCounter < (GliphWidth * font.Height)))
			{
				FgndCount++;
				BitCounter++;
			}
			
			while (BkgndCount > 0x0F)
			{
				pGlyph->Tokens[pGlyph->NbrOfTokens].Bkgnd = 0x0F;
				pGlyph->Tokens[pGlyph->NbrOfTokens].Fgnd = 0x00;
				pGlyph->NbrOfTokens++;
				CurrentGlyphOffset++;
				BkgndCount -= 0x0f;
			}

			while (FgndCount > 0x0F)
			{
				pGlyph->Tokens[pGlyph->NbrOfTokens].Bkgnd = 0x00;
				pGlyph->Tokens[pGlyph->NbrOfTokens].Fgnd = 0x0F;
				pGlyph->NbrOfTokens++;
				CurrentGlyphOffset++;
				FgndCount -= 0x0F;
			}

			pGlyph->Tokens[pGlyph->NbrOfTokens].Bkgnd = BkgndCount;
			pGlyph->Tokens[pGlyph->NbrOfTokens].Fgnd = FgndCount;
			pGlyph->NbrOfTokens++;
			CurrentGlyphOffset++;

		} while (BitCounter < (GliphWidth * font.Height));

		while (pGlyph->NbrOfTokens && (0 == pGlyph->Tokens[pGlyph->NbrOfTokens - 1].Fgnd))
		{
			pGlyph->NbrOfTokens--;
			CurrentGlyphOffset--;
		}

		CurrentGlyphOffset += 2;
	}

	FILE* output;
	FILE* bin;
	fopen_s(&output, "FontOutput.c", "w");
	fopen_s(&bin, "FontOutput.bin", "wb");
	if (output && bin)
	{
		char	szBuffer[1024];
		sprintf_s(szBuffer, 1024, "const uint8_t FontPERCENT_SIGNixPERCENT_SIGNi[] = {\n/* Width */ \t0xPERCENT_SIGN02x,\n/* Height */ \t0xPERCENT_SIGN02x,\n/* FirstChar */ \t0xPERCENT_SIGN02x,\n/* NbrOfChars */ \t0xPERCENT_SIGN02x,", font.Width, font.Height, font.Width, font.Height, ' ', font.NbrOfGlyphs);
		fwrite(szBuffer, sizeof(char), strlen(szBuffer), output);

		fwrite(&font.Width, sizeof(font.Width), 1, bin);
		fwrite(&font.Height, sizeof(font.Height), 1, bin);
		fwrite(&font.FirstGlyph, sizeof(font.FirstGlyph), 1, bin);
		fwrite(&font.NbrOfGlyphs, sizeof(font.NbrOfGlyphs), 1, bin);

		for (uint32_t currentGlyphOffset = 0; currentGlyphOffset < font.NbrOfGlyphs; currentGlyphOffset++)
		{
			sprintf_s(szBuffer, 1024, "\n/* offset to glyph 'PERCENT_SIGNc'*/ \t0xPERCENT_SIGN08x,", 32 + currentGlyphOffset, font.GlyphOffsets[currentGlyphOffset]);
			fwrite(szBuffer, sizeof(char), strlen(szBuffer), output);

			fwrite(&font.GlyphOffsets[currentGlyphOffset], sizeof(font.GlyphOffsets[currentGlyphOffset]), 1, bin);
		}

		for (uint16_t currentGlyph = 0; currentGlyph < font.NbrOfGlyphs; currentGlyph++)
		{
			sprintf_s(szBuffer, 1024, "\n/* Tokens for 'PERCENT_SIGNc' */ \t0xPERCENT_SIGN02x, 0xPERCENT_SIGN02x,\t", 32 + currentGlyph, font.Glyphs[currentGlyph].Width, font.Glyphs[currentGlyph].NbrOfTokens);
			fwrite(szBuffer, sizeof(char), strlen(szBuffer), output);

			fwrite(&font.Glyphs[currentGlyph].Width, sizeof(font.Glyphs[currentGlyph].Width), 1, bin);
			fwrite(&font.Glyphs[currentGlyph].NbrOfTokens, sizeof(font.Glyphs[currentGlyph].NbrOfTokens), 1, bin);

			for (uint8_t currentToken = 0; currentToken < font.Glyphs[currentGlyph].NbrOfTokens; currentToken++)
			{
				uint8_t temp = (font.Glyphs[currentGlyph].Tokens[currentToken].Bkgnd * 0x10) + font.Glyphs[currentGlyph].Tokens[currentToken].Fgnd;
				sprintf_s(szBuffer, 1024, "\t0xPERCENT_SIGN02x,", temp);
				fwrite(szBuffer, sizeof(char), strlen(szBuffer), output);

				fwrite(&font.Glyphs[currentGlyph].Tokens[currentToken], sizeof(FontToken), 1, bin);
			}
		}
		sprintf_s(szBuffer, 1024, "\n}\n");
		fwrite(szBuffer, sizeof(char), strlen(szBuffer), output);
	}

	_fcloseall();
	return 0;
}

This reveils that the order is indeed reversed, for the exclamation sign the output is @0x00000186, showing 0x19 as the first FontToken, where 0x91 was expected.

Attachment(s): 

"As simple as possible, but not simpler"

GUI Framework for Atmel Xplained Pro

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well well, I think my excuses are appropriate...

I changed the MSVC code as follows:

for (uint8_t currentToken = 0; currentToken < font.Glyphs[currentGlyph].NbrOfTokens; currentToken++)
			{
				//uint8_t temp = (font.Glyphs[currentGlyph].Tokens[currentToken].Bkgnd * 0x10) + font.Glyphs[currentGlyph].Tokens[currentToken].Fgnd;
				//sprintf_s(szBuffer, 1024, "\t0x%02x,", temp);
				sprintf_s(szBuffer, 1024, "\t0x%02x,", *(uint8_t*)&font.Glyphs[currentGlyph].Tokens[currentToken]);
				fwrite(szBuffer, sizeof(char), strlen(szBuffer), output);

				fwrite(&font.Glyphs[currentGlyph].Tokens[currentToken], sizeof(FontToken), 1, bin);
			}

And now I can use the same definition in both environments.
I mistakenly was going to move the Bkgnd field to the MSB's in the sprintf function. As this was the first defined bitfield, I thought it was obvious that this field would be in the first bits...

My appollogies to everyone.

Paul

"As simple as possible, but not simpler"

GUI Framework for Atmel Xplained Pro

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Yes indeed bit fields are portable in all these cases.
Bit field code is portable. The bit patterns that the bit fields create are not necessarily the same.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
The bit patterns that the bit fields create are not necessarily the same.

So anything which relies upon them being the same is not going to work.

In that sense, they are not "portable"

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
In that sense, they are not "portable"
But that is a misuse of bit fields. It is using feature for something that was not intended, so there is no need for it to be "portable".

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PaulVdBergh wrote:
Quote:
I challenge you to find one where that isn't so.
This one?
Which one is that?

I've been porting bit fields for 30 years, like I said previously. Peripheral registers are apt to be bit fields. I declare them as such. I've done this with ARM and AVR and TI DSP and with memory mapped peripheral registers in a PC. I have PC programs that send messages to ARMs and AVRs that request the register contents. The messages contain these same register defining structs. They are common code used by the ARM or AVR and by the PC.

I've also programmed a TI DSP and defined the registers with bit fields. I ran this same code on a PC under DOS. Both computers saw the bit fields the same. In this case the DSP and PC were different endianness so I had to turn the bit field structs on their heads.

Here's how I describe the Pin_control register in an Xmega I/O port.

      struct Pin control  {      // little endian
         Register Input_sense     : 3;   // bits 0-2
         Register Output_pull     : 3;
         Register Invert          : 1;
         Register Limit_slew_rate : 1;   // bit 7
         };

The bit called Limit_slew_rate has to be either pin 7 or pin 0, depending on computer endianness. Likewise the field called Input_sense is either bits 5-7 or 0-2. No C compiler I could ever imagine would scramble the bits, arbitrarily assigning say Limit_slew_rate to any bit it felt like. That makes no sense.

You can compile this code with any compiler and target it to any computer and the results will be the same. Again with the understanding that big endian machines will see the bit fields reversed.

Here is how you would define the same fields for the other endianness:

      struct Pin control  {      // big endian
         Register Limit_slew_rate : 1;   // bit 7
         Register Invert          : 1;
         Register Output_pull     : 3;
         Register Input_sense     : 3;   // bits 0-2
         };

Do you really think a compiler would arbitrarily scramble the bits?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
In this case the DSP and PC were different endianness so I had to turn the bit field structs on their heads.
Which some would consider to be a non-portable aspect, so you are arguing against yourself here.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It seems to me the C language could make this bit naming feature be portable. If those camel designing people on the standards committee wanted to do something useful, they could start with this.

You could have a mechanism where you name the bits say starting with the low order bit and working up. The compiler could then generate the correct code depending on the endianness of the target computer. Why couldn't this be done?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
It seems to me the C language could make this bit naming feature be portable. If those camel designing people on the standards committee wanted to do something useful, they could start with this.

You could have a mechanism where you name the bits say starting with the low order bit and working up. The compiler could then generate the correct code depending on the endianness of the target computer. Why couldn't this be done?

+1

"As simple as possible, but not simpler"

GUI Framework for Atmel Xplained Pro