Re: Memory mapped hardware registers

From: Simon Paradis (see.end.of.message_at_globetotter.net)
Date: 01/24/05


Date: Mon, 24 Jan 2005 01:53:38 GMT

I got it after messing around. I defined all 8 or 16 bit registers as
bitfields like that:

/* CSPAR1 (0xYFFA46): Chip Select Pin Assignement Register 1 */
typedef struct _CSPAR1 {
    WORD _UNUSED_1 : 6;
    WORD cspa14 : 2;
    WORD cspa13 : 2;
    WORD cspa12 : 2;
    WORD cspa11 : 2;
    WORD cspa10 : 2;
} CSPAR1;

Then I built a monster struct having the *exact* layout as written in
Motorola documentation. The struct has attribute packed: it's a gcc
extension that disable all struct member alignement. The _uXX bytes are
unused bytes in the SIM area. They exist to make sure registers are properly
placed in memory.

typedef struct _SIM_REGISTERS
{
    /* 15..............8 7...............0 */
    /* ------------------------------------------------- */
    /* YFFA00 */ SIMCR simcr;
    /* YFFA02 */ WORD simtr;
    /* YFFA04 */ SYNCR syncr;
    /* YFFA06 */ BYTE _u1; RSR rsr;
    /* YFFA08 */ WORD simtre;
    /* YFFA0A */ BYTE _u2; BYTE _u3;
    /* YFFA0C */ BYTE _u4; BYTE _u5;
    /* YFFA0E */ BYTE _u6; BYTE _u7;
    /* YFFA10 */ BYTE _u8; PORTE0 porte0;
    /* YFFA12 */ BYTE _u9; PORTE1 porte1;
    /* YFFA14 */ BYTE _u10; DDRE ddre;

    ... many more registers snipped ..

} __attribute__ ((__packed__)) SIM_REGISTERS;

extern volatile SIM_REGISTERS sim;

Then in sim_registers.c, you allocate a single global SIM_REGISTER:

    volatile SIM_REGISTERS sim;

The variable is volatile because those registers can change anytime abd some
bits always reads as 0 even if set them to 1. This 'sim' thing results in a
so-called COMMON symbol (ie uninitialized symbol).

In the sections statement of the linker script, you add:

    /* SIM (System Integration Module) Registers. This maps the
     * sim variable from bsp/registers/sim_registers.c at the
     * MCU SIM memory area.
     */
    .sim_registers 0xFFFA00 :
    {
        sim_registers.o(COMMON);
    }

That section must be before bss in the linker script because otherwise, the
sim variable could end up in .bss because typically .bss includes all COMMON
symbols.

And there you go. The global sim structure match Motorola's doc. The C code
can access
registers directly with no pointers like that.

#include <sim_registers.h>

int main(void)
{
    return sim.simcr.iarb;
}

If you look at the resulting S-Record (code begins at 0x3000)

S00700006D61696E53
S11330004E560000103900FFFA01720FC0814E5E67
S10530104E75F7
S10530120000B8
S113301441F900003044B1FC000030486406421811
S1133024528860F261FFFFFFFFD64E4F00634E7576
S1133034000000010000000200000003000030480A
S10C3048466F6F6F6F6F6F21007A
S9033014B8

you see no data/code loaded at FFFA00 which is what you want: registers do
not get overwritten. This is similar to .bss sections: the data there takes
no space in the executable but gets zeroed-out in RAM by startup code. Here,
I just don't zero out the register area. If you see lots of
S10FFFA00xxxxxxx, you didn't get it right, the CPU will crash when loading
the code.

To verify you didn't screw up, you can run 'nm --size' on sim_registers.o or
look at the linker produced map file. The sim variable should be the same
size as the SIM area (128 bytes). The map file will show the placement:

.sim_registers 0x00fffa00 0x80
 sim_registers.o(COMMON)
 COMMON 0x00fffa00 0x80
/home/Simon/kit331/bsp/registers/sim_registers.o
                                  0x0 (size before relaxing)
                0x00fffa00 sim

Looking at asm code generated by the compiler from the test C code above,
you see the direct access (the sim.simcr.iarb field is in the 4 low order
bits of the second byte of the sim area). So the asm code does what's
expected. Apparently, m68k gcc aligns bit fields from MSB to LSB.

main:
 link.w %a6,#0
 move.b sim+1,%d0
 moveq #15,%d1
 and.l %d1,%d0
 unlk %a6
 rts

Now that's quite non-portable code :-) You can do these tricks for stuff
like interrupt vectors and every memory mapped registers.

Simon Paradis
simon _dot_ paradis _at_ usherbrooke _dot_ ca

"Michael Schnell" <mschnell_at_bschnell_dot_de@aol.com> wrote in message
news:ct11ka$ks3$02$1@news.t-online.com...
> I suppose you are using µCLinux. As there is no memory management unit,
> you can access the hardware as well in Kernel as in user mode.
>
> Why not just load a pointer with the appropriate address:
>
> struct _SIMCR *psimcr
>
> psimcr = (struct _SIMCR *) 0xYFFA00;
> psimcr -> exoff = 0x11;
> etc.
>
>
>
> BTW.: You are the first person I meet using the GNU compiler with an
> 68K. I might be intending to do that (for a non-Linux project). So I
> have some questions. What debugger are you using ? Does this work OK ?



Relevant Pages

  • device driver for the SGI system clock, mmtimer
    ... The driver has been widely used for applications on the Altix platform. ... +static int mmtimer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); ... * of the page where the registers are mapped) for the counter in question. ...
    (Linux-Kernel)
  • Re: [RFC] full suspend/resume support for i915 DRM driver
    ... Greg, DRM desperately needs review of its device model usage, can you ... struct drm_sysfs_class; ... * This is the number of cycles out of the backlight modulation cycle for which ... * 855 scratch registers. ...
    (Linux-Kernel)
  • Re: CPU simulator written in C
    ... struct WORDREGS { ... These structures allow C programs on PCs to access the CPU registers. ... In protected mode the segment registers become selector registers. ... struct DWORDREGS {unsigned int eax; ...
    (comp.lang.c)
  • [RFC] Changing SysRq - show registers handling
    ... Currently SysRq "show registers" command dumps registers and the call ... trace from keyboard interrupt context when SysRq-P. ... For that struct pt_regs * ...
    (Linux-Kernel)