HC9S12DG128
From Arctic Core - the open source AUTOSAR embedded platform
Contents |
Arctic Studio Setup
Compiler
To build for the HCS12 you will need a cross-compiler.
- It can be downloaded from here: m6811-elf.zip
- Unzip it into cygwin/opt/ in your Arctic Studio install directory.
- The structure should end up looking like this:
opt
'--- m6811-elf
|--- bin
|--- include
|--- info
|--- lib
|--- m6811-elf
|--- man
|--- share
Examples
The tiny example (examples/tiny) is compatible with the HCS12 port. If running another project or example, make sure to edit the linkscript (arch/hc1x/hcs12d/scripts/linkscript_gcc.ldf) to map the code in memory.
Settings
To configure the toolchain in Studio:
- Go to Properties on the project you want to build
- Under C/C++ Build --> Environment, set
- BOARDDIR = hcs12_elmicro_card12
- CROSS_COMPILE = /opt/m6811-elf/bin/m6811-elf-
Memory
16 bit -> 64k address space, combined for regs, ram, eeprom, flash. 128k flash available as 8 * 16k banks. Two banks are permanently mapped in address space, and the others are available through a bank window.
Map
0x0000
registers, RAM, EEPROM (mapped at runtime)
0x4000
fixed flash 1, 16k
0x8000
bank window, 8*16k
0xc000
fixed flash 2, 16k
0xffff
Flash module banks
The theoretical maximum of memory banks on the 68HC12 is 256 * 16k = 4MB. The MC9S12DG128 uses banks 8-15 of the 256.
name id mapping ----------------------------- bank 8 38 - bank 9 39 - bank 10 3a - bank 11 3b - bank 12 3c - bank 13 3d - bank 14 3e fixed flash 1 bank 15 3f fixed flash 2
Runtime
At runtime a cpu register called PPAGE selects which bank is shown in the bank window. The register is located at 0x0030 and is writable in bits 5:0. The banking scheme presents some challenges:
- branching to/calling code in banked memory
- reading data from banked memory
GNU compiler
The 68HC1x port of GCC supports compiling code that uses banked memory.
On the 68HC11, jumps that require bank switching are implemented by generation of so called trampoline functions. These functions are atomic and reside in un-banked memory. They are linked in between the caller and the callee and contain code that writes to PPAGE and then jumps to the originally called address.
On the 68HC12, specific atomic operations for performing this task have been added to the instruction set. The operations are CALL and RTC and are the banked memory equivalents of JSR and RTS respectively.
GCC can be told to compile to either one of these operations locally in code by adding the attributes near and far to functions.
extern void __attribute__((near)) f (void); extern void __attribute__((far)) f (void);
A function with the attribute far is called with CALL (or through a trampoline if using 68HC11) and returns with RTC.
To make all calls far, give the following option to GCC
-mlong-calls
GNU linker script
The linker needs to fill in bank numbers as well as addresses in the compiled code. This is done by a convention where all of the memory is unfolded in a large virtual space.
There are two separate concepts concerning memory addresses:
- VMA (Virtual Memory Address)
- Addresses that are used in the code
- LMA (Load Memory Address)
- Addresses that specify where in memory that things are loaded
These addresses are often equal, but as we will see, they will differ when dealing with banked memory.
A common example of differing VMA and LMA is for initialized data placed in RAM. To make RAM data persistent in the sense that it is initialized with the same values on each reset, the data is placed in a section of flash and copied to RAM at boot time by program code. Still, references to this data from other parts of program code must point to the RAM. Thus in this example the data section will have a VMA -> some RAM address, and a LMA -> some flash address.
On top of this, on 68HC1x, both memory address specifications run in an expanded range that is larger than 64k (16bit)
VMA
For VMA:s the linker uses these formulas to make HW addresses and bank numbers from specified addresses:
if sym_addr >= sym_bank_base then hw_addr = ((sym_addr - sym_bank_base) % hw_bank_size) + hw_bank_window_base hw_bank = ((sym_addr - sym_bank_base) / hw_bank_size) else hw_addr = sym_addr hw_bank = 0 end if;
where
- hw_addr
- is the actual address used on the hw,
- hw_bank
- is the bank number used for PPAGE,
- hw_bank_window_base = 0x8000
- is the start address of the bank window,
- hw_bank_size = 0x4000 (16k)
- is the size of the banks,
- sym_addr
- is the address specified in the linker script,
- sym_bank_base = 0x0d0000
- is the base address for the banks in the virtual expansion
This means that to specify VMA:s for our banks 8-15 we put the following in our link script:
MEMORY
{
bank8 (rx) : ORIGIN = 0x0f0000, LENGTH = 16k /* hw_addr: 0x8000, hw_bank: 8 */
bank9 (rx) : ORIGIN = 0x0f4000, LENGTH = 16k /* hw_addr: 0x8000, hw_bank: 9 */
bank10 (rx) : ORIGIN = 0x0f8000, LENGTH = 16k /* hw_addr: 0x8000, hw_bank: a */
bank11 (rx) : ORIGIN = 0x0fc000, LENGTH = 16k /* hw_addr: 0x8000, hw_bank: b */
bank12 (rx) : ORIGIN = 0x100000, LENGTH = 16k /* hw_addr: 0x8000, hw_bank: c */
bank13 (rx) : ORIGIN = 0x104000, LENGTH = 16k /* hw_addr: 0x8000, hw_bank: d */
bank14 (rx) : ORIGIN = 0x108000, LENGTH = 16k /* hw_addr: 0x8000, hw_bank: e */
bank15 (rx) : ORIGIN = 0x10c000, LENGTH = 16k-0x100 /* hw_addr: 0x8000, hw_bank: f */
/* leaving space for vector table here */
}
LMA
For LMA:s, the addressing scheme is used by the downloader to put the data in the correct banks in the flash (therefore I assume that this scheme could differ between different downloaders, but I'm not sure. I got it working with s19 format downloaded using Code Warrior debugger over TBDML)
LMA:s for the banks are specified like this:
0x<bank id>8000
We add this to the MEMORY section in the link script
bank8_lma (rx) : ORIGIN = 0x388000, LENGTH = 16k bank9_lma (rx) : ORIGIN = 0x398000, LENGTH = 16k bank10_lma (rx) : ORIGIN = 0x3a8000, LENGTH = 16k bank11_lma (rx) : ORIGIN = 0x3b8000, LENGTH = 16k bank12_lma (rx) : ORIGIN = 0x3c8000, LENGTH = 16k bank13_lma (rx) : ORIGIN = 0x3d8000, LENGTH = 16k bank14_lma (rx) : ORIGIN = 0x3e8000, LENGTH = 16k bank15_lma (rx) : ORIGIN = 0x3f8000, LENGTH = 16k-0x100 vectors_lma (rx) : ORIGIN = 0x3fff80, LENGTH = 0x80
Placing code and data
- NOTE
- The GNU linker can't place code into the banks automatically, so things that are added will end up in the default section (.text) which is loaded into the fixed area at 0x4000 - 0x8000. Since this space is limited, manual placement by editing the linker script is probably needed whenever adding code. Removing code that is already mapped in the linker script will generate a link-time error.
Strategy
Memory layout strategy:
0x0000
Registers
0x2000
RAM:
data (loaded into 0xc000+ and copied at init), uninitialized data (cleared at init)
0x4000
Code (that needs to be un-banked):
init, interrupts, some library code
0x8000
Code (into banks):
platform, drivers, application
0xc000
Read-only data:
ram image, configuration etc.
0xffff
Link script
There are many ways to put the appropriate addresses into your binary and I will show a way that worked for me
I define a section for each bank, and put stuff marked with the bank name in the code in to it. I also manually place object code into the sections.
.bank8 :
{
*(.bank8)
my_obj.o(.text)
. = ALIGN(2);
} > bank8 AT>bank8_lma =0xff
.bank9 :
{
*(.bank9)
. = ALIGN(2);
} > bank9 AT>bank9_lma =0xff
...
The > name operator tells ld to set the section VMA to be the memory area name. The AT> name operator tells ld to set the section LMA to be the memory area name.
Mapping RAM, registers and EEPROM
These memory sections are mapped into the memory range at runtime.
Setting INITRM, INITRG, INITEE
.section ".install1" movb #0x39,0x0010 ;INITRM movb #0x00,0x0011 ;INITRG movb #0x09,0x0012 ;INITEE
TODO: What exactly does this do?
If memory sections overlap in the on-chip system memory space, the precedence is defined as follows:
- — Highest —
- On-chip registers (usually $0000 or $1000)
- BDM ROM (only when BDM active)
- On-chip RAM
- On-chip EEPROM
- On-chip program memory (FLASH or ROM)
- Expansion windows (on MCUs with expanded memory)
- Other external memory
- — Lowest —
Debuggers
winIDEA
Settings:
- Emulation Options
- iCARD : 68HC12
- CPU : MC9S12DG128
- CPU Setup
- Operating mode : Special (important)
- Breakpoints : Software
- Use this clock after RESET : 16000
- FLASH Programming Setup
- Through FLASH monitor
- Download Files (.elf)
- Load Code from : Program Header / Physical
- Files for download (.elf)
- Load Code from : Program Header / Physical
- Load Code : no
- Load Symbols : yes
- Debug Options
- Directories
- Convert source file paths : \cygdrive\c=c:
- Directories