Mês: março 2016

Ponteiros em 7 arquiteturas – de z80 a ARM

Eu admito que somente entendi ponteiros quando fiz a ponte entre código em C e Assembly. Ponteiros são complicados mesmo. É um disfarce de alto nível para o baixo nível da máquina. Ponteiros devem ser usados com cuidado em muitos aspectos; como no problema de alocação dinâmica e liberação da memória alocada, múltiplas instâncias do mesmo endereço, problemas de endianess, acessos não autorizados ou em áreas indesejadas …

Por curiosidade gerei o código assembly  do código em C abaixo para 7 processadores ou microcontroladores sendo eles: HCS08, STM8, Z80, X86-64,  ARM, ColdFire e AVR.

 int *a,*b;
 char *c;
 int i = 10;

void main(void)
 {

a = &i;
 b = a;
 *b = *b + 5;
 c = (char *) &i;
 *c = *c + 5;
 c = c + 5;

while (1);

}

E vamos aos códigos. É bom lembrar que diferenças irão ocorrer não somente pela arquitetura mas pelos compiladores usados. Um exemplo é o SDCC que para somar 5 não utilizou instrução de soma mas cinco incrementos para o Z80, provavelmente pela contagem de ciclos.

ColdFire – O mais limpo dos códigos

_main:
; main:
lea _i(a5),a0
move.l a0,_a(a5)
;
; 13: b = a;
;
move.l _a(a5),d0
move.l d0,_b(a5)
;
; 14: *b = *b + 5;
;
movea.l d0,a0
addq.l #5,(a0)
;
; 15: c = (char *) &i;
;
lea _i(a5),a0
move.l a0,_c(a5)
;
; 16: *c = *c + 5;
;
movea.l _c(a5),a0
mvs.b (a0),d0
addq.l #5,d0
move.b d0,(a0)
;
; 17: c = c + 5;
; 18:
; 19: while (1);
;
addq.l #5,_c(a5)
;
; 19: 1);
;
bra.l *+0</pre>

Z80 – Se aproveita de seus registradores de 16 Bits e acesso indireto

_main::
 61 ;ponteiros.c:9: a = &i;
ld de,#_i+0
ld (_a),de
 64 ;ponteiros.c:10: b = a;
ld hl,(_a)
ld (_b),hl
 67 ;ponteiros.c:11: *b = *b + 5;
ld hl,(_b)
push hl
ld c,(hl)
inc hl
ld b,(hl)
pop hl
inc bc
inc bc
inc bc
inc bc
inc bc
ld (hl),c
inc hl
ld (hl),b
 82 ;ponteiros.c:12: c = (char *) &i;
ld (_c),de
 84 ;ponteiros.c:13: *c = *c + 5;
ld hl,(_c)
ld a,(hl)
add a, #0x05
ld (hl),a
 89 ;ponteiros.c:14: c = c + 5;
ld hl,#_c
ld a,(hl)
add a, #0x05
ld (hl),a
inc hl
ld a,(hl)
adc a, #0x00
ld (hl),a
 98 ;ponteiros.c:16: while (1);
00102$:
jr 00102$

STM8 – O registrador x de 16 bits e as instruções de carga 16 bits ajudam muito


1 ; C Compiler for STM8 (COSMIC Software)
 2 ; Parser V4.10.2 - 02 Nov 2011
 3 ; Generator (Limited) V4.3.7 - 29 Nov 2011
 15 bsct
 16 0000 _i:
 17 0000 000a dc.w 10
 50 ; 7 main()
 50 ; 8 {
 52 switch .text
 53 0000 _main:
 57 ; 10 a = &i;
 59 ldw x,#_i
 60 ldw _a,x
 61 ; 11 b = a;
 63 ldw x,#_i
 64 ldw _b,x
 65 ; 12 *b = *b + 5;
 67 ldw x,_i
 68 addw x,#5
 69 ldw _i,x
 70 ; 13 c = (char *) &i;
 72 ldw x,#_i
 73 ldw _c,x
 74 ; 14 *c = *c + 5;
 76 ld a,_i
 77 add a,#5
 78 ld _i,a
 79 ; 15 c = c + 5;
 81 ldw x,#_i+5
 82 ldw _c,x
 83 L12:
 84 ; 17 while (1);
 86 jra L12
 140 xdef _main
 141 xdef _i
 142 switch .ubsct
 143 0000 _c:
 144 0000 0000 ds.b 2
 145 xdef _c
 146 0002 _b:
 147 0002 0000 ds.b 2
 148 xdef _b
 149 0004 _a:
 150 0004 0000 ds.b 2
 151 xdef _a
 171 end

HCS08 – Surpreso? Esse processador só tem um registrador index e um acumulador!


11: 
 12: a = &i;
 LDHX @i
 STHX a
 13: b = a;
 STHX b
 14: *b = *b + 5;
 LDHX ,X
 AIX #5
 TXA 
 PSHH 
 LDHX @i
 STA 1,X
 PULA 
 STA ,X
 15: c = (char *) &i;
 16: *c = *c + 5;
 ADD #5
 STA ,X
 17: c = c + 5;
 AIX #5
 STHX c
 L1E:
 19: while (1);
 BRA L1E
 21: }

X86-64 –

{
 push %rbp
 mov %rsp,%rbp

 a = &i;
 movq $0x0,0x0(%rip)  
 b = a;
 mov 0x0(%rip),%rax 
 mov %rax,0x0(%rip) 
 *b = *b + 5;
 mov 0x0(%rip),%rax 
  mov 0x0(%rip),%rdx 
 mov (%rdx),%edx
 add $0x5,%edx
 mov %edx,(%rax)
 c = (char *) &i;
 movq $0x0,0x0(%rip) 

 *c = *c + 5;
 mov 0x0(%rip),%rax 
 mov 0x0(%rip),%rdx 
 movzbl (%rdx),%edx
 add $0x5,%edx
 mov %dl,(%rax)
 c = c + 5;
 mov 0x0(%rip),%rax 
 add $0x5,%rax
 mov %rax,0x0(%rip) 

 while (1);
 jmp 65

ARM – É um RISC …


push {fp} ; (str fp, [sp, #-4]!)
add fp, sp, #0 
//a = &i;
ldr r3, [pc, #116] 
ldr r2, [pc, #116] 
str r2, [r3]
//b = a;
ldr r3, [pc, #104] 
ldr r3, [r3]
ldr r2, [pc, #104] 
str r3, [r2]
//*b = *b + 5;
ldr r3, [pc, #96] 
ldr r3, [r3]
ldr r2, [pc, #88] 
ldr r2, [r2]
ldr r2, [r2]
add r2, r2, #5
str r2, [r3]
//c = (char *) &i;
ldr r3, [pc, #72] 
ldr r2, [pc, #60] 
str r2, [r3]
//*c = *c + 5;
ldr r3, [pc, #60] 
ldr r3, [r3]
ldr r2, [pc, #52] 
ldr r2, [r2]
ldrb r2, [r2]
add r2, r2, #5
and r2, r2, #255 
strb r2, [r3]
//c = c + 5;
ldr r3, [pc, #28] 
ldr r3, [r3]
add r3, r3, #5
ldr r2, [pc, #16] 
str r3, [r2] 
//while (1);
b 80 

AVR – Infelizmente o processamento ficou todo em registradores


push r28
push r29
in r28, 0x3d ; 61
in r29, 0x3e ; 62 
// a = &i;
ldi r24, 0x00 ; 0
ldi r25, 0x00 ; 0
sts 0x0000, r25
sts 0x0000, r24
// b = a;
lds r24, 0x0000
lds r25, 0x0000
sts 0x0000, r25
sts 0x0000, r24
// *b = *b + 5;
lds r24, 0x0000
lds r25, 0x0000
lds r18, 0x0000
lds r19, 0x0000
mov r30, r18
mov r31, r19
ld r18, Z
ldd r19, Z+1 ; 0x01
subi r18, 0xFB ; 251
sbci r19, 0xFF ; 255
mov r30, r24
mov r31, r25
std Z+1, r19 ; 0x01
st Z, r18
// c = (char *) &i;
ldi r24, 0x00 ; 0
ldi r25, 0x00 ; 0
sts 0x0000, r25
sts 0x0000, r24
// *c = *c + 5;
lds r24, 0x0000
lds r25, 0x0000
lds r18, 0x0000
lds r19, 0x0000
mov r30, r18
mov r31, r19
ld r18, Z
subi r18, 0xFB ; 251
mov r30, r24
mov r31, r25
st Z, r18
// c = c + 5;
lds r24, 0x0000
lds r25, 0x0000
adiw r24, 0x05 ; 5
sts 0x0000, r25
sts 0x0000, r24

// while (1);
rjmp .+0

Afinal o que é um ponteiro? É simplesmente uma posição de memória que guarda um endereço que contém algum dado.

São dois endereços: Um é a variável que contém o dado, o outro contém o endereço desta variável.

Assim b = &i diz ao processador para guardar no endereço b o endereço de i. Logo b e i estão apontando para o mesmo dado. Mas b não é igual a i. A variável i é um endereço que contém um dado e o ponteiro b é um endereço que contém um endereço que contém um dado.

Veja em HCS08

// a = &i
LDHX @i
STHX a
Carrega o endereço de i em HX e posteriormente guarda o valor de HX em a

Veja que em STM8

// *b = *b + 5
67 ldw x,_i
68 addw x,#5
69 ldw _i,x

O compilador decidiu por não usar o ponteiro b para acessar i pois ele percebeu que b ainda contém o endereço de i e usou diretamente o endereço de i. Normalmente o correto seria carregar o valor de b em x e então indiretamente ‘(x)’ carregar o valor endereçado por x no acumulador e finalmente efetuar a soma.

Foi exatamente o que o Z80 iria fazer

ld hl,(_b)
push hl
ld c,(hl)
inc hl
ld b,(hl)
pop hl
inc bc
inc bc
inc bc
inc bc
inc bc
ld (hl),c
inc hl
ld (hl),b

Espero ter ajudado a compreender o que de fato é um ponteiro. Entretanto este post foi útil e agradável ao demonstrar as diferentes formas de acesso a memória em diferentes arquiteturas e principalmente as otimizações que compiladores diferentes fazem.

 

Sistemas Operacionais Modernos – [ Livros que você deveria ler ]

Inauguro esta série com este livro que qualquer programador de baixo nível (nível máquina) deveria ler. Sendo honesto é uma livro chato de se ler porém de grande valor. O autor Tanenbaum é aquele que Linus Torvalds no passado mandou aquela famosa mensagem sobre desenvolver um sistema livre e acabou por criar o Linux.

Já no começo do livro há uma narrativa bem humorada sobre a história do desenvolvimento de sistemas operacionais e suas definições. Um livro comum sobre a área apenas joga o assunto e nos trás a noção que tudo surgiu por mágica. Porém Tanenbaum de fato desenvolveu e acompanhou o desenvolvimento de sistemas operacionais e é honesto em nos mostrar que alguns algorítimos não surgiram do nada mas vieram para resolver um problema de usuários ‘espertinhos’ ou melhorar o desempenho de velhos leitores de fita por exemplo.

Em seguida cada parte de um sistema operacional é revelado com seus algorítimos, deficiências e vantagens. As vezes tanta honestidade te deixa confuso como por exemplo qual método de gerenciamento de processos é o melhor? Ou o que fazer com DeadLocks? E esse é o valor do Livro: Ao lê-lo todo você tem uma noção completa de um sistema operacional.

Eu li na biblioteca da faculdade um antigo que tinha como sistema de estudo o MS-DOS. Pulei este capitulo. Mas li o Amoeba e o Unix. Os atuais tem Windows, Linux e outros.

Ler este livro te elevará a níveis de conhecimentos preciosos como programador. Se você gosta de algorítimos, a história da informática, gosta de conhecer outras plataformas e desenvolve para sistemas embarcados este livro será de grande utilidade.

Ah! Esqueça PDF. Ele é um livro grande para ser lido inteiro. Compre o livro físico e leia com calma.

 

A era de ouro das revistas de eletrônica

Quando era adolescente juntava todo mês algumas moedas para comprar revistas de eletrônica. Minhas preferidas eram a Aprendendo e Praticando Eletrônica e a incomparável e didática Bê a Bá da Eletrônica e as temáticas da editora Fittipaldi.

Se tenho alguma? Poucas. Muitas amarelaram. Quando veio a internet ficaram esquecidas e depois de muitas mudanças algumas se foram, porém os ensinamentos ficaram.

E aqui fica a dica deste post: Neste site o sujeito publica scans das revistas de 80 e 90 e faz um ótimo trabalho. Recomendo!

http://www.blogdopicco.blogspot.co.id/2014/11/revistas-be-ba-da-eletronica.html

 

Android Box reiniciando ou desligando sozinho

Comprei um desses Android Box da China. São versáteis para jogar, assistir Youtube, Netflix e outras atividades tipicas do Android.
Entretanto o que comprei veio com um problema: Ele desligava sozinho quando o WiFi era muito exigido ou a GPU era usada.

Usando de analogia com o Raspberry Pi que tem um problema de performance quando a tensão caia abaixo de 4.97V imaginei que era problema de alimentação.Testei várias fontes e as fontes fracas faziam o aparelho se comportar muito mal. Mas nunca tive uma boa resposta mesmo com uma fonte de 2A.

Eis a solução:

IMG_20160320_095131514

Sim! Um capacitor eletrolítico de 1000uF que achei em sucatas ligado ao positivo e negativo. O capacitor menor eu tirei porque não fechava a caixa. Não sugiro ligar nos fios da fonte pois a impedância (mesmo que pequena) dos fios talvez atrapalhe.

E funciona que é uma beleza!

Outras causas

Porém alguns já relataram que não funcionou. Outro motivo relatado por Tiel (Abaixo nos comentários) é o excessivo aquecimento. Então neste caso um cooler ou dissipador mini para Raspberry PI colado no chip principal deverá ajudar.

Outro motivo comum de qualquer aparelho Android é aplicativos ruins instalados que corrompem o sistema. Neste caso forçar um ‘reset’ as configurações de fábrica deve ajudar. Saiba que tudo será apagado e o aparelho voltará a ficar como veio de fábrica. Normalmente este comando fica em Settings->Personal->Backup&Reset.

Onde adquirir?

As vezes as pessoas param aqui porque querem comprar um. Eu comprei o meu no famoso DX.com mas isso foi a alguns anos. Hoje o Aliexpress é a melhor opção pois tem preços melhores e aceita pagamento por boleto para quem não tem cartão de crédito (e da tempo de se arrepender!).

Veja os exemplos abaixo. O primeiro tem preço muito bom.

AliExpress.com Product – 2GB RAM+16GB ROM NEXBOX A95X Smart TV Box Amlogic S905X Quad core 64 Bit Android 6.0 4Kx2K 2.4GHz WiFi Media Player Set Top Box
AliExpress.com Product – GOTiT S805 TVBox+Royal IPTV 1950 Arabic African French Europe IPTV Channels Quad Core Smart 1G/8G Android KODI TV Set Top Box
AliExpress.com Product – KII Pro DVB-T2 + DVB-S2 Android 5.1 TV Box 2GB/16GB Amlogic S905 Quad-core Kodi 17.0 4K*2K 2.4G&5G Dual Wifi Bluetooth KIIpro

Este ai que comprei tem WiFi, Ethernet, GPU, entrada de MicroSD e saída HDMI e Video Composto e é esta saída que uso atualmente em uma TV analógica de tubo antiga. Outra boa aplicação é quando se viaja para algum lugar e você quer levar o Netflix junto.

sku_426763_6