Sunday, June 17, 2018

iar stm8에서 재미있는 트릭.

stm8은 register만 봤을 때, 8086과 같은 CISC구조를 채용하고 있다.
그래서 적은 수의 register(A, X, Y, SP, PC, CC)를 제공하고 있다.

하지만, C기준으로 보다면, 함수 내에서 수개의 variable을 유지하면서 기능을 수행하는 것이 일반적이며 현대의 많은 compiler들은 이러한 부분에 대해서 최적화되어 있다.

이 말은, compiler는 더 나은 성능을 위해서 stm8이 제공하는 register보다 많은 수의 register를 사용하기를 원한다.

이런 간극을 해결하기 위해서 (IAR에 한정된 이야기일 수 있지만) stm8 compiler는 virtual register라는 가상의 register를 채용하고 있다.
이 register는 실제로 register가 아니라 memory상의 영역이다.

IAR stm8의 경우 모두 1byte 16개, 혹은 2 bytes 8개, 4 bytes 4개의 virtual register를 제공하며,
이 virtual register의 위치는 0x0부터 0x10 번지에 위치한다.

그 이름은 ?b0 ~ ?b15 혹은 ?w0 ~ ?w8,  ?i0 ~ ?i4..

이 레지스터는 ARM에서와 같이 용도가 정해져있다.

b0~b7의 경우 scratch register로 caller가 필요시 저장(push)되기 때문에 function내에서는 버려도 상관없다.
b8~b15의 경우, callee가 책임을 지고 유지해야하는 register이며, RTOS에서는 context에 포함되어 저장되어야 한다.

implement system call in stm8 via trap instruction.

There is 'trap' instruction in stm8 mcu.
This instruction has (maybe) same purpose with svc instruction in ARM.

The purpose is perform some function without awareness of the function pointer.
(Anyway, in the APU level, the svc instruction has more mission (ie. protect the process memory space), this article is only for low level mcu)


Below is the code.
======================
#include ...
#include ...

#define BIT(x)  (1<<(x))
#define ON      (0x11)
#define OFF     (0x22)

//INTERRUPT_HANDLER_TRAP(TRAP_IRQHandler)
#pragma vector = 1
 __interrupt void (trap_handler) (void)
{
  /* In order to detect unexpected events during development,
     it is recommended to set a breakpoint on the following instruction.
  */
  char param = 0x11;

  asm("ld a, xl");
  
  switch(param)
  {
  case ON:
    PB_ODR |= BIT(5);
    break;
  case OFF:
    PB_ODR &= ~BIT(5);
    break;
  default:
    break;
  }
}

void delay(unsigned int n)
{
    while (n-- > 0);
}

void sys_call(char id)
{
  asm("ld xl, a");
  __trap();
}

//main entry point
int main( void )
{
  PB_ODR = 0; //Turn off all pins
  PB_DDR = BIT(5);
  PB_CR1 = BIT(5);

//  __enable_interrupt();
  while (1)
  {
    delay(30000);
    sys_call(ON);
    delay(30000);
    sys_call(OFF);
  }
}
 ===========================

the code enters system call via trap instruction.
and to pass the operation code, it uses XL register.

This code is checked in IAR, but has some special configurations.
the configuration is 'optimize off(none)'.

Because if optimizing is on, the compiler remove some code include that needed system call.

Finally,
To perfect implementation, we need to known 'C & assembly mixing'
And next time, I will introduce it if possible.

stm8 에서 trap으로 system call 구현하는 방법(1)

stm8 mcu에는 trap이라는 instruction이 있다.
이 command는 ARM에서 svc instruction과 (아마도) 같은 목적을 위해 제공되는 것이다.

그 목적은 main task 상에서 단순 function call이 아닌 방법으로 (즉, function의 위치를 몰라도..) 특정 기능을 수행하는 것이다.

(Process space를 보호해주는 OS상에서의 svc는 좀 더 다른 목적(?)이 있지만, 이 글은 MMU가 없는 mcu level에 국한한다.)


아래는 관련 code이다.
======================
#include
#include

#define BIT(x)  (1<<(x))
#define ON      (0x11)
#define OFF     (0x22)

//INTERRUPT_HANDLER_TRAP(TRAP_IRQHandler)
#pragma vector = 1
 __interrupt void (trap_handler) (void)
{
  /* In order to detect unexpected events during development,
     it is recommended to set a breakpoint on the following instruction.
  */
  char param = 0x11;

  asm("ld a, xl");
  
  switch(param)
  {
  case ON:
    PB_ODR |= BIT(5);
    break;
  case OFF:
    PB_ODR &= ~BIT(5);
    break;
  default:
    break;
  }
}

void delay(unsigned int n)
{
    while (n-- > 0);
}

void sys_call(char id)
{
  asm("ld xl, a");
  __trap();
}

//main entry point
int main( void )
{
  PB_ODR = 0; //Turn off all pins
  PB_DDR = BIT(5);
  PB_CR1 = BIT(5);

//  __enable_interrupt();
  while (1)
  {
    delay(30000);
    sys_call(ON);
    delay(30000);
    sys_call(OFF);
  }
}

/**

*/
===========================

trap instruction을 사용하여 system call로 진입을 하였고,
system call에서 해야할 일을 전달하기 위해서 xl register를 이용하였다.

이 코드는 iar에서 확인되었으나, 조금 특이한 설정이 필요하다.
optimize는 off(none)으로 해야 정상동작이 되는 코드이다.

optimize에 의해서 필요없다고 보여지는 code들이 모두 제거되기 때문인데,
이는 C compiler가 asm으로 실행될 내용에 대해 이해하지 못하기 때문에 일어나는 일이다.

그래서,
정확한 구현을 하기 위해서는 C와 assembly의 mixing방법에 대한 표준을 알 필요가 있고, 이 부분은 (가능하다면...) 다음 글에 소개할 예정이다.
(아직 필자도 모름니다. ㅡ.ㅡ;;)