INtime Tech

INtime Top


 RTX 제품으로부터의 이식


1. 처음에

INtime 에서는 WIN32에 포함되는 multi-thread 제어 API와 Ardence사(전 VenturCom사) RTX 제품의 API가 그대로 이용 가능합니다.  이것은 INtime API를 랩 하는 형태로 제공되고 있습니다. 이 iWin32 기능에 의해 종래의 어플리케이션을 INtime 환경에 이행 하는 것이 이전보다 늘어나 스무드하게 되었습니다.

여기에서는 종래의 어플리케이션을 INtime 어플리케이션에 이식(移植)하는 순서를 안내합니다.

  • iWin32/iWin32x의 실장도(実装図)

 

2. INtime 환경의 설정

  • Windows 서비스 애플릿으로부터 "INtime Win32 Service"를 개시합니다. 이 서비스가 iWin32API의 이용을 가능으로 합니다.

3. Source Code 변경

헤더 파일

INtime 이 제공하고 있는 iwin32 기능의 이용에는 "iwin32.h"를 사용합니다.  (Windows.h와 합해<INtime folder)\rt\include에 존재합니다)  INtime 고유의 API를 믹스 하는 일도 가능해, 이 경우에는"iwin32rt.h"도 더해 주세요.  헤더 파일의 기술에는 순서가 있습니다.  windows.h의 뒤로 기술해 주세요.

<변경전의 예>

#include <windows.h>
 #include <stdio.h>
 #include <rtapi.h>
#include <windows.h> #include <stdio.h> # include <rtapi.h>

<변경 후>

#include <windows.h>
 #include <stdio.h>
 #include <iwin32.h>
 #include <iwin32rt.h>
#include <windows.h> #include <stdio.h> #include <iwin32.h> # include <iwin32rt.h>

4. 컴파일 설정의 변경

프리프로세서 정의

<변경전의 예>

프리프로세서 정의:  WIN32, _DEBUG, _CONSOLE, _MBCS

<변경 후>

프리프로세서 정의:  WIN32, _DEBUG, _CONSOLE, _WIN32

인크리드파일패스

헤더 파일의 모든 것은 서드 vender 제공의 것이 아니고, INtime 개발 환경에 포함되어 있는 것을 이용하도록 변경합니다.

<변경 후>

인크리드파일패스:   C: \Program Files\INtime\rt\include 
 "표준 인크리드파일을 무시하는"에 체크합니다

그 외

컴파일러 옵션 ”/GZ” 를 떼어냅니다

이 변경을 하지 않은 경우, 이하의 에러가 나옵니다.
????. obj : error LNK2001: 외부 신호″르"__chkesp"는 미해결입니다

컴파일러 옵션 ”/Op” 를 추가합니다

이 변경을 하지 않은 경우, sin() , cos() 등의 부동 소수점 연산 함수를 사용의 코드를 릴리스 빌드 하면, VC컴파일러에 있어서의 최적화의 사정으로 이하의 에러가 나옵니다.
????. obj : error LNK2001: 외부 신호″르"__CIsin"는 미해결입니다
????. obj : error LNK2001: 외부 신호″르"__CIcos"는 미해결입니다

5. 링크 설정의 변경

출력 파일명

INtime의 어플리케이션은 확장자(extension) "RTA" 이므로,  최종적으로 출력되는 실행 모듈의 확장자(extension)를 변경합니다.

<변경 후>

출력 파일명: Debug/application.rta

추가 라이브러리 패스

라이브러리 파일의 모든 것은 서드 vender 제공의 것이 아니고,  INtime 개발 환경에 포함되어 있는 것을 이용하도록 변경합니다.

<변경 후>

추가 라이브러리 패스:   C: \Program Files\INtime\rt\lib 
 "디폴트 라이브러리를 모두 무시"에 체크합니다

오브젝트 라이브러리 모듈

<변경전의 예>

startupCRT.obj RTXlibcmt.lib oldnames.lib rtapi_rtss.lib rtx_rtss.lib w32_dll.lib

<변경 후>

iwin32.lib rt.lib pcibus.lib netiff3m.lib ciff3mf.lib rmxiff3m.lib
  • C++모듈의 경우에는 라이브러리 모듈 "ecpp.lib" 와 "rtppd.lib" 를 한층 더 더해 주세요. 릴리스 빌드의 경우는, rtppd.lib의 대신에"rtpp.lib"를 사용합니다
ecpp.lib rtppd.lib (또는 rtpp.lib)

엔트리 포인트

  • "엔트리 포인트 심볼"은 INtime의 경우 불필요합니다. main()를 설치해 주시면 거기로부터 개시됩니다. 혹은 임의의 엔트리로 변경해 주시는 일도 가능합니다.

<변경전의 예>

엔트리 포인트 심볼:  _RtapiProcessEntryCRT@8

<변경 후>

엔트리 포인트 심볼:    <지정하지 않는다>

스택 어로케이션

  • "스택 어로케이션" 과" 위탁"은 다음과 같이 변경합니다.

<변경전의 예>

스택 어로케이션: 0 x1000 위탁: 0x1000

<변경 후>

스택 어로케이션: 0 x4000 위탁: 0x1800
  • "버젼 정보"도 다음과 같이 기입해 주세요
메이저: 21076 마이나: 20052

그 외

  • Windows 커넬 모드 드라이버를 구축하기 위한 링커 옵션 "/driver"와 "/align"는 제외합니다. INtime 어플리케이션은 보호된 유저 모드로 동작해 안전성을 보장합니다.

<변경 후>

/driver /align: 0x20…어느쪽이나 삭제
  • 링커 옵션"/subsystem"는 이하와 같이 변경합니다.

<변경전의 예>

/subsystem:native, 4.00

<변경 후>

/subsystem:console

이 변경을 하지 않은 경우, 이하의 에러가 나옵니다.
LINK : error LNK2001: 외부 신호 심볼 "_NtProcessStartup"은 미해결입니다

  • 링커 옵션 "/heap"를 추가해 주세요. 이 값은 4096 x n로 INtime 어플리케이션 프로세스를 취급할 수 있는 물리 메모리 상한을 의미합니다. 이하의 예에서는 1 MB를 상한으로서 설정해 있습니다.

<변경 후>

/HEAP: 1048576

6. 디버그 빌드를 위한 설정 변경

IINtime 어플리케이션은 INtime에 부속되는 Spider 디버거를 사용해, 개발 PC상에서 실행과 셀프테스트가 가능합니다. 이 때 원시 코드 레벨로 열람·싱글스텝 실행·브레이크 포인트등을 사용한 비주얼·디버그가 용이하게 가능합니다.
디버거를 사용한 시험을 실시하기 위해서는 디버그 빌드 구성의 설정을 다음과 같이 조정해 주세요.

  • 컴파일 설정
    <변경 후>
    최적화:  무효 
디버그 정보:  C7호환
 
  • 링크 설정
    <변경 후>
    Microsoft 포맷
    

    7. 그 외 보충 정보

    RtPrintf() 콜

    iiWin32에 대해 이 콜은 준비되어 있지 않습니다. INtime 어플리케이션에서는 ANSI-C함수 printf( )로 대용 가능합니다.

    RtUnmapSharedMemory() 시스템 콜

    iiWin32 및 iWin32x는, RTX 버젼 5.1을 베이스로 작성되고 있습니다. 그 때문에 이전의 RTX 버젼에 대해 존재한 API가 iWin32/iWin32x로 존재하지 않는 경우가 있습니다. RtUnmapSharedMemory()는 RtCreateSharedMemory에 의해 생성된 메모리오브제크트에 대해서 맵을 해제한다고 하는 것입니다만, RTX 버젼 5.1에서는 RtCloseHandle에서 메모리오브제크트의 개방(핸들의 클로우즈, 메모리의 맵 해제)을 실시하도록 개정이 더해지고 있을 것이라고 생각됩니다.

    PCI 라이브러리 콜을 포함한 부분의 이식

    RTX PCI 라이브러리 콜안에는, iWin32내에 존재하지 않는 콜이 있어, 또 RTX INtime에서는 PCI 디바이스 검출 방법이 차이가 납니다. INtime에서는 보다 간략하게 PCI 디바이스의 검출과 자원 취득이 생기도록 설계되고 있습니다. PCI 디바이스 검출부를 RTX 원시 코드로부터 iWin32 원시 코드에 이식할 때는, 이하와 같이 하는 것을 추천합니다:

    PCI 디바이스 검출

    • RTX의 경우
      RTX에서는 RtGetBusDataByOffset() 콜을 사용해 PCI 디바이스 공간의 버스 번호, 디바이스 번호, 펑션 번호를 변경하면서 해당하는 디바이스를 검출합니다:
      【RTX에 의한 디바이스 검출예】 
      	for (bus = 0;  flag;  bus++)  {  
      	  for (i = 0;  i < PCI_MAX_DEVICES && flag;  i++){  
      	  SlotNumber.u.bits.DeviceNumber = i;  
      	    for (f = 0;  f < PCI_MAX_FUNCTION;  f++){  
      	      SlotNumber.u.bits.FunctionNumber = f;  
      	      bytesWritten = RtGetBusDataByOffset (PCIConfiguration,  
      	                            bus,  
      	                            SlotNumber.u.AsULONG,  
      	                            PciData,  
      	                            0, 
      	                            PCI_COMMON_HDR_LENGTH  
      	                           );  
      	      if (bytesWritten == 0)  {  
      	         // out of PCI buses  
      	         flag = FALSE;  
      	         break;  
      	      }  
      	      if (PciData->VendorID == PCI_INVALID_VENDORID){  
      	         // no device at this slot number, skip to next slot 
      	         break;  
      	      }  
      	      // A device is found, if this is our card, then  
      	      // print out all the PCI configuration information  
      	      // and set the variables. 
      	      if ((PciData->VendorID == 0x1093)  &&  
      	         (PciData->DeviceID == 0x0160)) { 
      	          //검출시의 처리 
      	      } 
      	    } 
      	  } 
      	}
    • IINtime의 경우
      INtime 에 대해도 이와 같이 디바이스를 검색하는 것은 가능합니다만, 순간에 디바이스를 검출하기 위한 라이브러리 콜이 준비되어 있습니다(PciFindDevice). 이 라이브러리 콜은 벤더 ID와 디바이스 ID를 키로서 PCI 디바이스의 공간을 검색해, 검출할 수 있었을 경우에 해당 디바이스의 PCIDEV 정보(자원)를 반환합니다:
      PciFindDevice() 
      	<문장구조법> 
      	 BYTE PciFindDevice( 
      	     PCIDEV *pPciDevice 
      	 ); 
      	<파라미터> 
      	 pPciDevice 	PCIDEV 구조체의 포인터  
      	<반환값> 
      	 성공 	TRUE 	지정된 벤더 ID, 디바이스 ID의 디바이스를 검출했을 경우, TRUE를 반환합니다. 
  • 동시에 해당 디바이스의 정보를 PCIDEV 데이터 구조체에 반환합니다. 
    	 실패 	FALSE 	디바이스를 검출할 수 없었던 경우, FALSE를 반환합니다.


    【INtime에 의한 디바이스 검출예】 
    	PCIDEV dev; 
    	dev.wVendorId = 0x1093; 
    	dev.wDeviceId = 0x0160; 
    	dev.wDeviceIndex = 0;         // we want the first matching device 
    	if (! PciFindDevice(&dev))    // PCI 디바이스 검출 콜 
    	 return ;            // no device found 
    	//검출 후 처리 
    	dev.dwBaseAddr[0]  ~dev.dwBaseAddr[5] 
    	   //…꺼낼 수 있었던 I/O, 메모리베이스아드레스가 격납되고 있습니다 
    	dev.byIntLine 
    	   //…꺼낼 수 있었던 IRQ 번호가 격납되고 있습니다

    PCI 디바이스의 물리 주소 맵

    RTX 에서는 RtTranslateBusAddress를 사용해 검출한 디바이스의 주소로부터 논리 주소를 변환 후, 변환된 주소를 맵 할 필요가 있습니다.  동콜에서 변환을 실시하면, 해당 디바이스가 메모리 공간 디바이스일까 I/O공간 디바이스일까를 판단하는 요소도 포함됩니다(0x00: 메모리 공간 0x01: I/O공간). INtime에 대해 디바이스의 물리 주소 맵은 MapRtPhysicalMemory로 실시해, 물리 주소→논리 어드레스 변환을 실시하는 RtTranslateBusAddress에 바뀌는 것은 없습니다.  그 때문에, 디바이스가 I/O공간 디바이스나 메모리 공간 디바이스인가의 판단은 PCIDEV 구조체 베이스 주소(dev. DwBaseAddr[0]) 의 최종 비트를 유저가 판정할 필요가 있습니다.

    • RTX의 경우
      if (RtTranslateBusAddress( BusType, 
      	            BusNumber, 
      	            IoAddress, 
      	            & AddressSpace, 
      	            & cardAddress 
      	            ))  { 
      	  // RtTranslateBusAddress 성공 
      	  if(AddressSpace){ // I/O공간 
      	    address = (PVOID) cardAddress.LowPart; 
      	  }else 	{               //메모리 공간 
      	    address = RtMapMemory(cardAddress, NumberOfBytes, FALSE); 
      	  } 
      	}
    • INtime의 경우
      IoAddress = dev.dwBaseAddr[0]; 
      	if ( (IoAddress && (DWORD) 0x01 )  ){ // I/O공간 	
      	  address = (PVOID)((WORD)( IoAddress & 0xFFFC )); 
      	}else{ 					//메모리 공간 
      	  address = ( PVOID ) MapRtPhysicalMemory(IoAddress, NumberOfBytes); 
      	}

    HOME | INtime