MOV W0, [W8++] ; move value W0 to address pointed by W8, move W8 pointer 1 further
SUB W0, #10h, [W8++] ; subtract 10h from W0, store result in address pointed by W8, move W8 pointer 1 further
MOV W0, [W8+1FAh]
These operations are 1 instruction word (which is actually 24-bits, or 3 bytes) and take 1 cycle.MOV #24h, W0
MOV W0, 0xCAFE ; CAFE = your RAM address
The free XC8 is obviously bloating NOP's and BRA's all over the place to make the commercial version look worthwhile.
comparing GCC's -O0
The only significant issue I see in the asm was writing to port instead of latch...
void main(void)
!{
! char pwm1, pwm2, pwm3, pwm4, pwm5, level_delay, pwm_delay;
! init();
0x2FE: CALL 0x2F0
! bright1 = 50; // "random" initialization
0x2FF: MOVLW 0x32
0x300: BCF STATUS, 0x5 ;; unnecessary setting of status.
0x301: MOVWF 0x23 ;; unnecessary (and soon overwritten) save to mem 23.
0x302: MOVF 0x23, W ;; unnecessary move back to W.
0x303: MOVWF bright1
! bright2 = 20;
0x304: MOVLW 0x14
0x305: MOVWF 0x23 ;; status already set, so only the mysterious loc 23 code!
0x306: MOVF 0x23, W
0x307: MOVWF bright2
! bright3 = 10;
So that's 4 or 5 instructions where there should be 2. Presumably the code generator has nice rules about keeping the status register up-to-date, along with some internally-used temporary register?! if (--pwm3 == 0) {
0x350: MOVLW 0x1
0x351: SUBWF pwm3, F
0x352: BTFSS STATUS, 0x2
0x353: GOTO 0x355
0x354: GOTO 0x356
0x355: GOTO 0x358
! led3_off;
0x356: BCF GPIO, 0x3
0x357: GOTO 0x358
! }
Isn't that a swell chain of three GOTOs? I think one would do... Presumably these implement a generic conditional branch if/else setup, using the skip instructions. But, yuck!0049 2001 0247 CALL init
0248 ; bright1 = 50; // "random" initialization
004A 3032 0249 MOVLW .50
004B 00A8 0250 MOVWF bright1
0251 ; bright2 = 20;
004C 3014 0252 MOVLW .20
004D 00A9 0253 MOVWF bright2
0254 ; bright3 = 10;
:
0317 ; if (--pwm3 == 0) {
0073 0BA2 0318 m010 DECFSZ pwm3,1
0074 2877 0319 GOTO m011
0320 ; led3_off;
0075 1283 0321 BCF 0x03,RP0
0076 1505 0322 BSF 0x05,GPIO2
;; The initialization code is much nicer
bright1 = 50; // "random" initialization
178: 82 e3 ldi r24, 0x32 ; 50
17a: 80 93 61 00 sts 0x0061, r24
bright2 = 20;
17e: 84 e1 ldi r24, 0x14 ; 20
180: 80 93 64 00 sts 0x0064, r24
bright3 = 10;
184: 8a e0 ldi r24, 0x0A ; 10
186: 80 93 60 00 sts 0x0060, r24
:
;; But the conditional code is considerably worse.
if (--pwm3 == 0) {
1fe: 8d 81 ldd r24, Y+5 ; 0x05 ;; local variables come from the stack
200: 81 50 subi r24, 0x01 ; 1 ;; decrement
202: 8d 83 std Y+5, r24 ; 0x05 ;; and go back to the stack.
204: 8d 81 ldd r24, Y+5 ; 0x05 ;; and are gotten from the stack again
206: 88 23 and r24, r24 ;; separate test for zero.
208: 39 f4 brne .+14 ; 0x218 <main+0xb6>
led3_off;
20a: a8 e3 ldi r26, 0x38 ; 56 ;; and then we have this awful code for led3_off, which
20c: b0 e0 ldi r27, 0x00 ; 0 ;; isn't quite fair because avr uses portb &= ~mask;
;; while the PIC has "bit variables" gpio3 = 0;
20e: e8 e3 ldi r30, 0x38 ; 56
210: f0 e0 ldi r31, 0x00 ; 0
212: 80 81 ld r24, Z
214: 8b 7f andi r24, 0xFB ; 251
216: 8c 93 st X, r24 ;; and separate pointers for reading and writing??
}
I rather like this "bad code" better than the PIC's bad code, because it's more obvious what it's doing and what it hasn't done. The AVR code is a sort of naive translation of the C into AVR assembler. The unoptimized PIC code is (probably) more of straightforward translation of an "intermediate abstraction" of a compiler target (one short sequence of PIC code for each abstracted operation), and is much less obvious (thus leading to the rumors of intentionally bad code.) (because you can think in C, or you can think in assembler, but somehow compiler writers' usual abstraction isn't very close to either one. Sigh.);; (The initialization code is the same)
if (--pwm3 == 0) {
11a: 91 50 subi r25, 0x01 ; 1 ;; local variables now optimized to registers.
11c: 09 f4 brne .+2 ; 0x120 <main+0x5c>
led3_off;
11e: c2 98 cbi 0x18, 2 ; 24 ;; The special io bit set ins is used!
}
37: void main(void)
38: {
39: // 8 bit number (1 byte)
40: unsigned char cnt = 0;
07E7 01F2 CLRF cnt
41:
42: // set internal oscillator to 500kHZ
43: OSCCON = 0b00111000;
07E8 3038 MOVLW 0x38
07E9 0021 MOVLB 0x1
07EA 0099 MOVWF T1GCON
44:
45: // make all of PORTC (RC0 - RC7) and output
46: TRISC = 0;
07EB 018E CLRF PORTC ;; NO! You should be clearing TRISC (Surprised this line is not causing issues)
07EC 2FED GOTO 0x7ED
47:
48: while (1) {
07FD 2FED GOTO 0x7ED ;; Why? totally not needed 7ED is the next instruction!
49: LATC = cnt;
07ED 0872 MOVF cnt, W
07EE 0022 MOVLB 0x2
07EF 008E MOVWF PORTC ;; NO! You write to LATC not PORTC
50:
51: // 1 second delay
52: __delay_ms(1000);
07F0 30A3 MOVLW 0xA3
07F1 00F1 MOVWF 0x71
07F2 3055 MOVLW 0x55
07F3 00F0 MOVWF 0x70
07F4 0BF0 DECFSZ 0x70, F
07F5 2FF4 GOTO 0x7F4
07F6 0BF1 DECFSZ 0x71, F
07F7 2FF4 GOTO 0x7F4
53:
54: // increment count by 1
55: // when it overflows passed 255 it will reset to 0
56: cnt++;
07F8 3001 MOVLW 0x1
07F9 00F0 MOVWF 0x70
07FA 0870 MOVF 0x70, W
07FB 07F2 ADDWF cnt, F
07FC 2FED GOTO 0x7ED
57: }
58: }
07FE 3180 MOVLP 0x0
45: // make all of PORTC (RC0 - RC7) and output
46: TRISC = 0;
07EB 018E CLRF PORTC ;; NO! You should be clearing TRISC (Surprised this line is not causing issues)
[...]
49: LATC = cnt;
07ED 0872 MOVF cnt, W
07EE 0022 MOVLB 0x2
07EF 008E MOVWF PORTC ;; NO! You write to LATC not PORTC
I think this is just a failure of the listing pretty-printer -- remember the PIC banks its registers, so only the bottom part of the register address is present in the MOVWF instruction. The other half is in the bank select bits, which in your excerpts are set by the MOVLB calls prior to the MOVWFs; the pretty-printer is obviously just looking up the operand and translating to a bank 0 address, rather than trying to keep track of which bank will be selected for each instruction. I would imagine the register summary will show PORTC, TRISC and LATC are all at the same address but in banks 0, 1 and 2 respectively.
(Not that I've actually checked, of course, but that's certainly how PORTx and TRISx are laid out on chips that don't have the LATx registers...)
movlw b'00111000' ; We want a clock of 500kHZ giving us (1/(500k/4)) per instruction
movwf OSCCON ; Move W register into OSCCON
The first major difference I noticed was that with developing PIC you need to set the chips fuses in code. This is rather crappy in my opinion as it is rather tedious to do and easy to make a slip up, however this can be negated by creating a standardized header file to handle this for us.
The first major difference I noticed was that with developing PIC you need to set the chips fuses in code. This is rather crappy in my opinion as it is rather tedious to do and easy to make a slip up, however this can be negated by creating a standardized header file to handle this for us.MPLAB X does have a built-in editor for fuses. If you open up the Configuration Bits memory view you can edit the bits as you see fit, and when you click the "Generate Source Code to Output" button it generates code which you can copy into your source files.
Having the different compiler for every chip is just bad
as a whole MPLABX is very buggy and a lot of the issues arise directly from the core netbeans backend.
but in the long run [avr-gcc] would gradually equate to or be smaller then the PIC code.
All the extra working registers on the AVR take up some space.