2015-02-19 16 views
6

Tôi đang tìm cách chuyển thanh ghi thiết bị nhúng vào mẫu C++, sử dụng gcc 4.8.4. Trong các bảng dữ liệu mô tả các thiết bị nhúng, các địa chỉ của thanh ghi thường được cho là các vị trí bộ nhớ thô (ví dụ 0x40008000).Đăng ký làm thông số mẫu

Khi tôi kiểm tra phần mềm, tôi muốn sử dụng số nguyên tĩnh làm thanh ghi để xem liệu giá trị đăng ký có được đặt chính xác hay không.

Vì vậy, về cơ bản một wrapper xung quanh một số thiết bị ngoại vi nắm để một lớp học với nó địa chỉ đăng ký được cho là mẫu tham số:

template < volatile std::uint32_t* Reg > 
struct peripheral {}; 

Kiểm tra hoạt động tốt:

std::uint32_t reg; 
peripheral< &reg > mocked; 

Nhưng khi tôi muốn nhanh chóng mẫu có địa chỉ cố định, bảng dữ liệu được cung cấp:

peripheral< reinterpret_cast< std::uint32_t* >(0x40008000) > mocked; 

gcc than phiền: could not convert template argument '1073774592u' to 'volatile uint32_t* {aka volatile long unsigned int*}. clang không phàn nàn về điều này.

Nếu tôi sử dụng địa chỉ đưa ra là số nguyên như mẫu tham số, tôi có vấn đề để nhanh chóng các mẫu trong thử nghiệm của tôi với địa chỉ của thanh ghi chế giễu:

template < std::intptr_t Reg > 
struct peripheral {}; 

std::uint32_t reg; 
peripheral< reinterpret_cast<std::intptr_t>(&reg) > mocked; 

kết quả này trong error: conversion from pointer type 'uint32_t* {aka long unsigned int*}' to arithmetic type 'intptr_t {aka int}' in a constant-expression.

tôi có thể nghĩ đến hai giải pháp này:

1) Sử dụng con trỏ như tham số mẫu, sử dụng các biến toàn cầu như đăng ký và sửa chữa các địa chỉ của các thanh ghi với một số mối liên kết kịch bản kỳ diệu.

2) Sử dụng các loại đăng ký đặc biệt có giao diện chung cho mẫu ngoại vi nhưng có hai cách triển khai rất khác nhau để thử nghiệm và cho ứng dụng thực.

Nhưng tôi đang tìm cách dễ dàng hơn để thực hiện việc này. Bất kỳ ý tưởng, con trỏ hoặc ý kiến?

+1

Hãy nhớ rằng loại con trỏ phải luôn biến động. Điều này có thể là nguyên nhân của một số vấn đề. – Lundin

+0

Cảm ơn bạn đã chỉ ra điều này. –

+0

Nhưng đó không phải là vấn đề gây ra lỗi biên dịch. Mỗi Pointer to T sẽ được chuyển đổi thành 'volatile T'. –

Trả lời

0

Giải pháp của tôi trông như thế này:

template < class Name = int, typename T = std::uint32_t, T* Value = nullptr > 
class mocked_register 
{ 
public: 
    static void set(T v) 
    { 
     *address() = v; 
    } 

    static T get() 
    { 
     return *address(); 
    } 

    static volatile T* address() 
    { 
     static T internal_; 
     return Value ? Value : &internal_; 
    } 
}; 

đâu Tên nên có bất kỳ loại mà làm instantiation khác nhau từ sự khởi tạo khác. Khi xác định nhiều loại, một loại có thể sử dụng các loại được xác định trước đó làm tên:

typedef mocked_register<>    START; 
typedef mocked_register<START>  STOP; 
typedef mocked_register<STOP>  COUNT; 

Để thử nghiệm, loại sẽ giữ biến 'bán' tĩnh để giữ giá trị sổ đăng ký. Đối với kiến ​​trúc cánh tay, tôi có một số trường hợp, ở đó hữu ích, sử dụng một mảng các thanh ghi.Trong trường hợp này, tham số Value có thể được sử dụng để cung cấp một mảng bên ngoài:

std::uint32_t capture_regs[ 4 ]; 
typedef mocked_register< SHUTDOWN, std::uint32_t, capture_regs > CAPTURE; 

Đối với phần sản xuất, mẫu là dễ dàng hơn nhiều:

template < std::uint32_t Register > 
struct addressed_register 
{ 
    static void set(std::uint32_t value) 
    { 
     *reinterpret_cast< volatile std::uint32_t* >(Register) = value; 
    } 

    static std::uint32_t get() 
    { 
     return *reinterpret_cast< volatile std::uint32_t* >(Register); 
    } 
}; 

Trong cả hai trường hợp (thử nghiệm và sản xuất) một thiết bị trừu tượng mất một tập hợp các thông số mẫu và sử dụng chúng như thanh ghi:

template < 
    class OUTSET, 
    class OUTCLEAR, 
    class DIRSET, 
    class DIRCLR, 
    class PIN_CNF, 
    std::uint8_t Nr > 
struct pin 
{ 
    static void init_as_input() 
    { 
     DIRCLR::set(1 << Nr); 
    } 
}; 

More đăng ký như cú pháp, có thể được thêm vào nếu chuyển nhượng và chuyển đổi ngầm đến T sẽ được triển khai (nhưng tôi không phải là người hâm mộ lớn của ý tưởng đó):

START start; 
COUNT count; 
start = 1; 
std::uint32_t c = count; 
2

Thực hiện reinterpret_cast<> không được phép trong biểu thức không đổi (đó là những gì trình biên dịch cũng cho bạn biết); xem thêm Constant expressions .

tôi xin đề nghị như sau (xem thêm C++11 constexpr function's argument passed in template argument):

#include <cstdint> 
#include <cassert> 

template<typename PtrT, PtrT Ptr> 
struct peripheral 
{ 
    static void* const value; 

    template<typename T> 
    static T* as() noexcept 
    { return static_cast<T*>(value); } 
}; 

#define PERIPHERAL(addr) peripheral<decltype((addr)), (addr)> 

std::uint32_t reg = 0; 

int main() { 
    peripheral<std::uintptr_t, 0x42> mocked1; 
    peripheral<volatile std::uint32_t*, &reg> mocked2; 
    PERIPHERAL(0x42) mocked3; 
    PERIPHERAL(&reg) mocked4; 
    assert((mocked3.value == PERIPHERAL(0x42)::as<void*>())); 
    return 0; 
} 
+0

Một thậm chí có thể thêm một số hàm thành viên 'std :: uint32_t volatile operator()() const {return reinterpret_cast (Ptr); } 'tới' ngoại vi', để cung cấp một giao diện chung (có thể cộng với một số 'static_assert' trên kiểu' PtrT'). – dyp

+0

@ipadadop Cảm ơn bạn đã đề xuất. Làm thế nào tôi có thể truy cập vào sổ đăng ký (trong sản xuất) và làm cách nào để truy cập vào sổ đăng ký giả thử nghiệm? TIA –

+1

@TorstenRobitzki Tôi đã thêm một vài người trợ giúp cho điều đó: ':: value' sẽ cung cấp cho bạn con trỏ như một' void * 'và' :: as() 'hàm tĩnh cho phép bạn có một dàn diễn viên tiện dụng thông qua một hàm. Tôi nghĩ rằng bằng cách cũng buộc bất cứ điều gì con trỏ để đi qua void * Tôi nên chăm sóc của bất kỳ vấn đề răng cưa (nếu không xin vui lòng sửa tôi). – ipapadop

Các vấn đề liên quan