
Nossa licença Open Hardware e sugestões para endianness na OSS 2020
Falamos sobre a licença CERN para Open Hardware e endianness na cimeira Open Source + Linux Embedded na Europa, no dia 27 de outubro de 2020.
Licença CERN para Open Hardware
Por que não usar uma licença para software como a GPL?
Licenças para hardware são específicas, portanto são escritas com a nomenclatura apropriada: fabricante, dispositivos, CAD, etc..
Por que escolhemos a licença CERN para Open Hardware v1.2?
Achamos que oferece uma proteção melhor para quem recebe uma licença quando comparada com outras licenças para hardware como a TAPR.
Quem recebe e quem fornece a licença?
No nosso projeto, nós (comunidade Power Progress) recebemos a licença e o licenciador é o fabricante do hardware.
O licenciador pode fabricar e distribuir produtos?
O licenciador pode modificar nosso trabalho, mas essas modificações precisam ser disponibilizadas sob a mesma licença, ou licença equivalente.
Como somos protegidos?
O licenciador é responsável pelo hardware e sua qualidade.
Outras notas importantes
– Firmware, drivers e outro software precisam de suas próprias licenças.
– A propriedade intelectual é nossa.
– A documentação precisa ser fornecida no formato correto para que possa ser livremente modificada (usando uma ferramenta CAD).
Endianness
O que é endianness?
É a maneira com que dados são ordenados na memória de um computador.
Afeta números inteiros que sejam maiores que 1 byte.
Pode ser um problema quando arquiteturas diferentes compartilham informação.
É um dos problemas principais que um desenvolvedor de software precisa ter em mente quando escreve software portátil.
Endianness na memória: Big Endian
Os dados são lidos da esquerda para a direita.
O byte mais significante fica na esquerda.
A palavra no endereço 0x101 é:
0x0203 = 515
A palavra dupla no endereço 0x100 é:
0x01020304 = 16909060
Endianness na memória: Little Endian
Os dados são lidos da direita para a esquerda.
O byte mais importante fica na direita.
A palavra no endereço 0x101 é:
0x0302 = 770
A palavra dupla no endereço 0x100 é:
0x04030201 = 67305985
Conversão de endianness
Existem dois metódos para trocar endianness: manual e automático.
Troca manual
16 bit unsigned swap:
swapped = (num>>8) | (num<<8);
32 bit unsigned swap:
swapped = ((num>>24)&0xff) | // move byte 3 to byte 0
((num<<8)&0xff0000) | // move byte 1 to byte 2 ((num>>8)&0xff00) | // move byte 2 to byte 1
((num<<24)&0xff000000); // byte 0 to byte 3
There are ready-to-use functions that have the same behaviour:
bswap_16(x);
bswap_32(x);
bswap_64(x);
Detecção de arquitetura
Trocas manuais devem ser evitadas. Conhecimento da arquitetura em questão é importante. A arquitetura deve ser detectada e casos específicos implementados, senão o código não será independente de plataformas.
#if __BYTE_ORDER == __LITTLE_ENDIAN
<LITTLE ENDIAN SWAP DEFINITION>
#elif __BYTE_ORDER == __BIG_ENDIAN
<BIG ENDIAN SWAP DEFINITION>
#end
Por exemplo, se o programa requisita uma função little endian em uma plataforma little endian, a função retornará os dados como estão. Em caso contrário, um procedimento de troca será executado.
Conversão de funções
POSIX tem ferramentas úteis para a conversão de endianness chamadas de host-to-network e de network-to-host:
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
Estas funções são executadas sempre que você precisa lidar com um problema de endianness. Tenha em mente que network order é “byte mais significante primeiro”, ou seja, Big Endian.
Existem outras funções para conversão little/big endian. Elas não são padrão, mas são muito úteis:
#include <endian.h>
uint16_t htobe16(uint16_t host_16bits);
uint16_t htole16(uint16_t host_16bits);
uint16_t be16toh(uint16_t big_endian_16bits);
uint16_t le16toh(uint16_t little_endian_16bits);
uint32_t htobe32(uint32_t host_32bits);
uint32_t htole32(uint32_t host_32bits);
uint32_t be32toh(uint32_t big_endian_32bits);
uint32_t le32toh(uint32_t little_endian_32bits);
uint64_t htobe64(uint64_t host_64bits);
uint64_t htole64(uint64_t host_64bits);
uint64_t be64toh(uint64_t big_endian_64bits);
uint64_t le64toh(uint64_t little_endian_64bits);