Author Topic: PIC12F509 & PIC18F26K20  (Read 13794 times)

0 Members and 3 Guests are viewing this topic.

Online Andy Watson

  • Super Contributor
  • ***
  • Posts: 2104
Re: PIC12F509 & PIC18F26K20
« Reply #25 on: June 07, 2017, 11:38:47 am »
This statement (and the one after it):
Quote
/
   
    while(GPIObits.GP4 = 1);


translates to this assembly code:
Code: [Select]
423:
;Ab.c: 58: }
;Ab.c: 60: while(GPIObits.GP4 = 1);

bsf 6,4 ;volatile
goto l423
line 61
It's stuck in an infinite loop because the "GPIObits.GP4 = 1" always resolves as true. You need to replace the assignment operator (=) with a comparison operator (==), i.e. while(GPIObits.GP4 == 1);
 

Online jpanhalt

  • Super Contributor
  • ***
  • Posts: 3650
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #26 on: June 07, 2017, 12:43:01 pm »
Isn't GP4 an input with a weak pull-up enabled? (TRIS = 0x18, OPTION = 0x00)

That shouldn't toggle unless you have added a switch.  Then what happens to GP2, which was your output, but does not seem to have a function defined for a changed input in the revised code?

Again, my apology for being C-disabled. 

Good luck.

John
 

Offline android

  • Regular Contributor
  • *
  • Posts: 134
  • Country: au
Re: PIC12F509 & PIC18F26K20
« Reply #27 on: June 07, 2017, 01:15:48 pm »
It's stuck in an infinite loop because the "GPIObits.GP4 = 1" always resolves as true. You need to replace the assignment operator (=) with a comparison operator (==), i.e. while(GPIObits.GP4 == 1);
I was wondering when someone would point that out. This has got to be one of the most common C programming errors and I think the blame lies squarely on the inventors of the language.

Better still IMHO is to avoid comparison operators when testing for zero or not-zero...
Code: [Select]
while (GPIObits.GP4);...and to make it even more readable use a DEFINE to name your bits and then code
Code: [Select]
while (SIGNAL_ASSERTED);
Lecturer: "There is no language in which a double positive implies a negative."
Student:  "Yeah...right."
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: PIC12F509 & PIC18F26K20
« Reply #28 on: June 07, 2017, 10:14:29 pm »
Regarding ISR... I should not assume your code could possibly be improved in efficiency in any way regarding latency.. maybe you had to work very had to optimize this aspect.
The core code is very simple - measure servo pulse width by incrementing a counter whenever the pulse is high, which is done with this macro:-
Code: [Select]
DoServoCount    MACRO                         
                btfsc     GPIO, ServoBit
                incf      ServoCount, F
                ENDM
 
This takes 2us to execute. Servo pulse width is measured with a resolution of 7us, so 5 instructions can (must) be inserted between each invocation of the macro. This also creates the step time for the PWM pulse, which requires continuous execution of this code:-   
Code: [Select]
                decf      PwmCount,F           
                skpnz                           ; end of PWM hi pulse?
                bcf       GPIO, RunBit          ; yes, then turn off motor
These two pieces of code are interleaved repetitively so they execute 'simultaneously'. That leaves 2 instructions per 7us to do other things, which I use to check the battery voltage.

I considered using Timer0 to measure the servo pulse width, but it turned out that there was no advantage. Even if the 12C509 did have a timer interrupt it wouldn't help because it would upset the PWM timing.  The 12F675 has a gate on the timer clock which makes it possible to measure pulse time in hardware, however it is active low so you need an external inverter to measure positive pulses!

Quote
I will personally not touch a macro, ever, under any circumstance.

You can be a masochist if you want, but there's no doubt that macros make asm coding easier. Here's one of the macros I used in my 12F617 ESC, which needed 16 bit math to get 1us resolution:-

Code: [Select]
lsl16   MACRO   aa
        clrc
        rlf     aa
        rlf     aa+1
        ENDM 

This generates 3 words which effectively create a single 16 bit instruction. Why bother having to type in that repetitive stuff by hand when a macro can do it for you? And it makes the code a lot easier to read and understand.

Here's the macro in use:-
Code: [Select]
; multiply by 10
lsl16 ServoCount ; *2
mov16 ServoCount,AARGB0       ; temp = * 2
lsl16 ServoCount ; *4
lsl16 ServoCount ; *8
add16 AARGB0,ServoCount ; *8 + *2 = *10

Quote
I'll take the extra 4 cycles wherever possible to make my code more manageable by using subroutine over a macro.

Often I will create a subroutine to do a small job, then when the algorithms are sorted I will go back and inline it. I will also break a large block of code into simpler subroutines that can be reused - but always bearing in mind the speed penalty. This is the sort of stuff you have to do in asm that a compiler generally does for you automatically. But I prefer doing it manually because then I know what code will be produced.
 
 
 

Offline KL27x

  • Super Contributor
  • ***
  • Posts: 4108
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #29 on: June 08, 2017, 01:10:37 am »
Wow, cool beans. I have to admit I may be shortsighted on the macros thing. Been a long time since I removed all macros from my code and finished cursing their very existence. The lsl16 macro don't really excite me. But the interesting thing for me are the ones with multiple literals. Is this what they look like?

mov16   macro    aa,bb
      movf    aa,w
      movwf   bb
      movf           aa+1,w
      movwf   bb+1
      ENDM

add16       macro    aa,bb
      clrc
      movf           aa,w
      addwf   bb,f
      btfsc           STATUS,C
      incf            aa+1,w
      addwf   bb+1,f
      endm

Once tested and verified, I am generally not looking too close at the code again, other than my comments. But the multiple literal ones are hard to bury from sight, and my method of doing that would have been horrible, in comparison.
« Last Edit: June 08, 2017, 01:14:12 am by KL27x »
 

Online jpanhalt

  • Super Contributor
  • ***
  • Posts: 3650
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #30 on: June 08, 2017, 10:10:58 am »
Since this discussio is way OT, here's another couple of bits:

Bit0:  For someone who swore off ever using a macro, what is the difference between a macro and pseudo-instruction, such as CLRC?

BIT1:  For someone who doesn't find the enhanced mid-range instruction set useful, it would help you from using the CLRC in the
"lsl16" macro (as just one example):
Code: (asm) [Select]
p=12F1840

lsl16   MACRO   aa
        lslf    aa
        rlf     aa+1
        ENDM
;D

John

Edit: changed pseudo code to pseudo-instruction
« Last Edit: June 08, 2017, 12:04:55 pm by jpanhalt »
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: PIC12F509 & PIC18F26K20
« Reply #31 on: June 08, 2017, 03:06:09 pm »
it would help you from using the CLRC in the
"lsl16" macro (as just one example):
Thanks for that. I have a couple of 'enhanced' midrange PICs, but haven't done much with them yet because I still have a bunch of older chips to use up.





 
 

Offline KL27x

  • Super Contributor
  • ***
  • Posts: 4108
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #32 on: June 08, 2017, 10:25:48 pm »
Quote
For someone who swore off ever using a macro, what is the difference between a macro and pseudo-instruction, such as CLRC?

Pseudo instructions are treated by the IDE exactly like instructions. Macros are not. To not use banksel, I can't even imagine.

#define xxxx is fine, too. Rock solid.
equ, no problem
assembler/IDE directives... awesome.

There are probably a lot of other differences for macros I am not even aware of. But the one that has the biggest suck IME is that there are instances where the assembler will decide that an error is located in a macro. The code in the macro can be 100% perfect. But due to some change to other parts of the code, the error will show up in the macro.

The IDE gives you link and line number..... of a line of code in your macro. I think I explained this in detail, already. One of the big reasons to use a macro is so you don't have to write the same thing over and over, so chances are you used it a lot more than once. :) When your code is 100 pages spread across 5 different *.asm files, this results in a hideous waste of time. If your code is only 10 or 20 pages and/or you use the macro only once or twice, macro may not make an enormous difference, at all. I think in general, I tend to adopt whatever is going to work if and when the code becomes long and complicated. I appreciate the speed you can get with assembly, but I am quick to give up SOME of it to adopt code style that will not fall apart when you find you need to add more straw to the camel's back.

Other reason (that may be useless to others) is that every other "line" in midrange/baseline assembly with a few exceptions equals one instruction. Which makes it useful for managing branches/jumps with relative changes to the program counter. Using relative changes to PC allows easier cut and paste of code that you may reuse, with less editing. This is maybe an additional reason I find use of subroutines so useful... not for the ultimate execution speed, but for writing and managing the code.

There are many ways to skin a cat, esp in assembly. :)
« Last Edit: June 08, 2017, 11:19:06 pm by KL27x »
 

Online jpanhalt

  • Super Contributor
  • ***
  • Posts: 3650
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #33 on: June 08, 2017, 11:42:36 pm »
Quote
For someone who swore off ever using a macro, what is the difference between a macro and pseudo-instruction, such as CLRC?
Pseudo instructions are treated by the IDE exactly like instructions. Macros are not. To not use banksel, I can't even imagine.

Glad you feel banksel is a useful for you.   It is an Assembler directive and is somewhat different than the pseudo-instruction CLRC in that it has no ad hoc translation to opcode(s) without knowing the MCU.  That is, it is like other directives, e.g., RADIX, __Config, etc. I tend to use MOVLB <x> as I like to know and track what bank I am in.  I almost never use banksel unless I am very tired.  I then disassemble and change to MOVLB at my first opportunity.


Every PIC microcontroller has a defined instruction set that maps directly to machine code.  CLRC (i.e., BCF 3,0) is a macro that the compiler/Assembler interprets as an allowed instruction or, for other pseudo-instructions, a sequence of allowed instructions.  Consider for example, SKPNZ, SKPC, BNZ, LCALL and so forth.  That is, not all are single instructions.  Many are two instructions, and LCALL is three instructions.  The MPASM Assembler User's Guide shows the macro definitions for pseudo-instructions and disassembly of code using them shows the same translations.  Disassembly of Assembler directives does not usually show specific opcodes; although, Banksel does.

 I don't believe the distinction between a macro you define and one defined in the Assembler is a significance difference.  They both work the same way, take the same program space, and disassemble to inline code.

John
 

Offline KL27x

  • Super Contributor
  • ***
  • Posts: 4108
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #34 on: June 08, 2017, 11:54:48 pm »
If it is the same thing, i will concede to your superior knowledge. But I have never had assembly error point to the actual expanded code for a pseudo instruction or assembly directive, in the linker file or whatnot. Leaving me no clue where my implementation of said macro is causing a problem in my own code.
 
Perhaps it boils down to understanding exactly what u can put in a macro where this is not possible. I have no clue what that is, admittedly.

I struggled with banksel, myself. I ultimately decided it is better for me to use it. By default i try to write my code with the assumption it may end up multiple pages and banks and that i may have to do some shuffling. And if changing device. And who knwos what else. I know what bank are most things anyhow and banksel 0h, banksel portx, for instance i know is bank 0. If I don't want to look up bank of cmcon1 or whatnot, I banksel, then banksel back.... if I learn this was redundant, later, I can remove it, later.

Im fully aware of many instructions/exceptions which expand to multiple instructions, yeah. Why you get lcall as 3, though? I may be making an incorrect assumption. I always treat it like 2, pagesel x, call x, and my code works this way. Does pagesel expand to 2 instructions (on certain but not all devices, perhaps? That is a lot of pages, lol). Or are you counting instruction cycles? Yeah, call, goto, return, et al, they take 2 to execute, but they are one instruction as far as the program counter and code space are concerned.
« Last Edit: June 09, 2017, 02:26:30 am by KL27x »
 

Offline KL27x

  • Super Contributor
  • ***
  • Posts: 4108
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #35 on: June 08, 2017, 11:57:16 pm »
Im dumbing it down here: One visual difference is that banksel and clrc and say movfw (on midrange) all show up blue, not purple like a macro. Purple also for label or an address, literal, constant, etc. I dont know why that is the case if the IDE handles them identically.

Maybe i should be asking why u can use macros and not have this problem? Of macros hiding source of error? I mean i used pseudo instructions and assembler directives hundreds of times in my code and never have error pointing to hundreds of locations for one misuse of said.

Im not linguistic expert and i didnt rtfm all the way. I'm pretty sure I wouldn't understand all of it if I did. My guess is that the pseudo instruction is blue and treated like a single instruction, even if it expands to 2 or 3. When there is an error, it points to this specific implementation of said (pseudo) instruction. Conversely, the ide treats a "user" macro like the expanded code that it represents, and it will point, unfortunately, to the actual line of code where it determines the fault.... the line of code in the friggin macro.... which means it points nowhere/everywhere.

Is there an way to make the IDE treat a macro like a single instruction as far as error reporting goes? To get the error point to the unique implementation of the macro? THIS is my problem with macros. AFAIK, the IDE is never going to tell you "hey, one of your clrc's is fucked, but I'm not going to tell you which one. Here's a hint: it's a bad implementation of BCF STATUS,C." (Which in this case would be obvious.) AFAIK, the IDE will do that with a macro. Maybe I'm missing something. Does the link jump you to the macro, but maybe there's a line number for you to figure out which one?
« Last Edit: June 09, 2017, 02:52:02 am by KL27x »
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: PIC12F509 & PIC18F26K20
« Reply #36 on: June 09, 2017, 03:01:38 am »
I tend to use MOVLB <x> as I like to know and track what bank I am in.  I almost never use banksel unless I am very tired.
The advantage of BANKSEL is that the assembler automatically chooses the correct bank for the register. The disadvantage is you don't know which bank that is so you have to put it before every new file register reference to make sure the correct bank is always selected.

If you know what banks the registers are in then you can use BANKSEL (or MOVLB, BSF RP0 etc.) only when necessary. However you then have to avoid jumping into code that assumes one bank is selected when you are in another. It is easy to introduce bugs this way, and it doesn't help that the registers for a single peripheral may be spread over several banks. 

So you either have to bloat the code, or optimize bank selects but end up with brittle code. Coding in assembler is hard enough already without having to deal with this issue, which is why I hate banked registers! Unfortunately this is the price you pay for having lots of RAM and peripherals and an instruction set that can only address 64 registers.
   
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: PIC12F509 & PIC18F26K20
« Reply #37 on: June 09, 2017, 03:30:20 am »
Is there an way to make the IDE treat a macro like a single instruction as far as error reporting goes?
The problem occurs when you have an error that gets past the macro invocation line but breaks inside the macro itself. Since the parser is already in the macro at this point it cannot tell which line was the original cause.

However it's not that much of an issue because most coding errors (syntax errors, undefined symbols...) will be reported on the line where they occurred. Also it is unlikely for a macro to throw up errors in several places unless there are errors in all those places or in the macro itself, so you generally only have to look at the last bit of code you wrote to find the error.

But hey, it's no worse than a C compiler throwing up cryptic error messages 50 lines below where you missed out a bracket or semicolon! (or worse, buried several directories deep in an include file so full of #ifdefines that you can't figure out which bits of the code are active...).

 

Offline KL27x

  • Super Contributor
  • ***
  • Posts: 4108
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #38 on: June 09, 2017, 08:22:30 am »
Quote
However it's not that much of an issue because most coding errors (syntax errors, undefined symbols...) will be reported on the line where they occurred.
Maybe something to do with how I code. But I was able to do this many times even with macros which have no syntax... beyond simple macros that should always be valid and have no additional modifier/literals. No clue as to the origin, short of ripping them all out and replacing with actual code. I wish I had an example, because it never made any sense to me and I can't recreate one, intentionally.

Quote
Also it is unlikely for a macro to throw up errors in several places unless there are errors in all those places or in the macro itself
Yes, I never got this. What I meant was when the error (super rarely for everyone but me) "parces in the macro" and that is your only clue, you have to assume it is any one of the instances where you used it. The IDE only shows you one source of error, but you have to look at them all.

Quote
so you generally only have to look at the last bit of code you wrote to find the error.
Any time you write/add new code, you're temporarily breaking it, and you might have to alter several parts before it (hopefully) assembles and works, again. Writing new code is hard enough in assembly... backtracking even my own code to find a ghost error is quite annoying, I have to say, lol. Analogy is where I had 2 shorts on a pcb between power and ground, recently. It's just a 6 square inch board, and the power rail is plainly in view in its entirety, more or less, from one side. And for the life of me I couldn't find a short under the microscope. Making some cuts in the power rail to narrow it down and suddenly it becomes obvious. Even if "the last thing I altered" is the problem, that could be 4 or 5 different areas of the code. 

I am going to definitely give it another go. Maybe I can start to understand how it is an error ends up "parcing in the macro," better ways to prevent or minimize the damage, and better ways to unravel a solution after the fact. But suffice to say when this happens, it is bigtime problem. If/when I get another bad apple, at least maybe I can share it and hopefully learn something from someone with more experience. It has also been many years since I ditched the macros, and my coding and coding practices have evolved, with code integrity and revision history and documentation being more meticulous than ever. So maybe I brought the problems on myself... Dunno. I don't really remember too well, all of the details. But the pain is hard to forget. :)

Quote
The advantage of BANKSEL is that the assembler automatically chooses the correct bank for the register. The disadvantage is you don't know which bank that is so you have to put it before every new file register reference to make sure the correct bank is always selected.
This is a logical fallacy. If you use banksel you do not HAVE to know which bank you are selecting. This is not the same as not knowing. Even when I know exactly the bank in which said register resides, I still use banksel. Even when I optimize and remove redundant bank changes, I am using banksel command. I personally have no real issue with banks. It is easily second nature. The first time I spilled over into page 1, OTOH.... them were some long nights. That, too, is second nature, now, but the learning curve was much steeper.

Even if you prefer to have direct control, you can do it with banksel, after defining your banks:
banksel bank0
banksel bank1
etc.

This is probably more sensical than movlb when you have 16 banks. And going back to device with 2 banks... why change the format when this works for them all.  I #define my banks according to the memory map for each device, based on the start address of the user memory, if available on that bank. Or the first register if no user memory is present. Even though I never actually use the "bankx", myself, except maybe bank0. I mostly banksel [register name] and learn what bank that is, but I may refer to this "map" in case I need to arrange user memory for direct access. Easy access by clinking on an inc file, rather than opening the datasheet.

Example for 16F1938
#define   bank0    0x020         ;;;;;;;;;;;;;;;;;;;;;
#define   bank1   0x0A0
#define   bank2   0x120
#define     bank3   0x1A0
#define     bank4   0x220
#define     bank5   0x2A0
#define   bank6   0x320   ; thru 0x32F, just 16 register on this page
...etc, etc.

So you see, I'm not against the principle of macros making code harder for other people to read. I would use them extensively, if it were not for the error reporting.

(Why not #define bank0 banksel 0x020, so's you don't have to type out "banksel" ? I can't stand this looking like a label.)
« Last Edit: June 10, 2017, 10:39:32 am by KL27x »
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: PIC12F509 & PIC18F26K20
« Reply #39 on: June 10, 2017, 11:46:25 pm »
Maybe I can start to understand how it is an error ends up "parcing in the macro,"
It ends up in the macro when a parameter seems to be OK where it was used, but fails when the macro looks at it. For example a symbol which is supposed to represent a register, but resolves to an invalid address, won't fail until the macro tries to reference it.

You can find the line with the mistake on it by examining the listing file. Search for the error message and you should see the macro expansion immediately after the line with the bad code.     

Quote
This is a logical fallacy. If you use banksel you do not HAVE to know which bank you are selecting. This is not the same as not knowing.
When I said "don't know" I meant that the code doesn't tell you. Of course you can look it up in the datasheet or include file, but BANKSEL is not intended to be used that way.

Quote
Even when I know exactly the bank in which said register resides, I still use banksel.
Me too. Different PICs have different ways of selecting banks. BANKSEL automatically produces the correct code for your PIC, so it makes sense to use it.
 
 

Offline KL27x

  • Super Contributor
  • ***
  • Posts: 4108
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #40 on: June 11, 2017, 01:30:58 am »
Quote
You can find the line with the mistake on it by examining the listing file. Search for the error message and you should see the macro expansion immediately after the line with the bad code.
:-+ :-+
Listing file. Cool beans. I will have to check this out. If this means what I hope it does, this just changed the way I code! If it means what I think it does... i.e. macro is expanded in every instance (seems like this is a given in order to produce a list file... the whole point is to show every line number and instruction) and there is still no way to distinguish (I am convinced you do not get a line number in this type of error... maybe I'm wrong; I hope), let alone automatically jump to, the problem area, then... well, thanks, anyway!  :-// Having to scroll through the entire list file is not very convenient, even if there were a visual distinction. In short... if there is a line number showing where the error is, I will feel pretty dumb but also glad to find this out. This is the main reason I removed macros from my code... though there are some others.
Quote
It ends up in the macro when a parameter seems to be OK where it was used, but fails when the macro looks at it. For example a symbol which is supposed to represent a register, but resolves to an invalid address, won't fail until the macro tries to reference it.
This could be the answer, I suppose. But I am afraid it isn't an answer. Errors happen because I make errors. But if I can manage to get an error to manifest in the macro (and only in the macro), again, I'll be sure to post it. I'll be sure to examine the error report for a line number. (And examine the list file to see if it left any clue.) I'm sure it will likely be a boneheaded error. But I am even more sure I will continue to make even more boneheaded errors.

Regarding banksel, I thought of another advantage. Even though I can't tell you what bank LATA is in (other than is it not 0, and it is not the same bank as TRISx), I know without looking that LATB and LATC are in the same bank, and I can manipulate those registers without adding redundant banking instructions. I can think of no real drawback to using banksel. There are quite a lot of times the actual bank doesn't matter. I'm gonna check a flag or change a bit, then go back to bank0. Another place is in the initial configuration: swapping from INTCON to CMCON to TMRx to whatnot. I don't really give a rats ass what banks those are. I am back to bank0 in the end. If you use direct bank bit write, you need to look these up. If you use banksel, you can often gain the same benefit without knowing. And you can still look them up, if you want.

I don't really care to really know by memory all the special registers in a bank unless my code is frequently using these registers and/or spending a lot of time in bank other than 0. This is a need-to-learn basis kinda thing. And learning the registers in a given bank is all you need, in this case. You don't need to remember the actual bank numbers.

« Last Edit: June 11, 2017, 03:17:10 am by KL27x »
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: PIC12F509 & PIC18F26K20
« Reply #41 on: June 11, 2017, 07:21:51 am »
there is still no way to distinguish (I am convinced you do not get a line number in this type of error...  maybe I'm wrong; I hope), let alone automatically jump to, the problem area, then... well, thanks, anyway!
You don't need a line number. Just search for the error message and the editor will jump to the line where the macro was expanded, which is right below the line where it was invoked.

Here's an example.

Source code with mistake (invalid address):-
Code: [Select]
#define myvar 4000
.
  rr16    myvar

Output message:-
Code: [Select]
Executing: "C:\Program Files\Microchip\MPASM Suite\MPASMWIN.exe" /q /p12F617 "Speed617.asm" /l"Speed617.lst" /e"Speed617.err"
Warning[219] C:\CODE\PIC\ESC\SPEED617.ASM 292 : Invalid RAM location specified.

Listing file:-
Code: [Select]
LOC  OBJECT CODE     LINE      SOURCE TEXT


                      00764                 rr16    myvar
Warning[219]: Invalid RAM location specified.
0117   0CA1               M         rrf     4000+1
00764 is the line in the source code with the mistake. Or perhaps the real culprit is the #define? (can't always expect the compiler to find the actual error).

If you keep the listing listing file open then it is updated automatically. It doesn't automatically jump to the error for you, but do you  need that much hand-holding?

Quote
Regarding banksel, I thought of another advantage. Even though I can't tell you what bank LATA is in (other than is it not 0, and it is not the same bank as TRISx), I know without looking that LATB and LATC are in the same bank, and I can manipulate those registers without adding redundant banking instructions.
That's how I do it. Most of the PICs I use only have a few banks so it's fairly easy to remember which SFRs are in the same bank.

My complaint isn't with BANKSEL, but the fact that you have to switch banks at all. Some newer chips have dozens of banks (most of which are half empty).
 
   

 

Offline KL27x

  • Super Contributor
  • ***
  • Posts: 4108
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #42 on: June 12, 2017, 03:08:39 am »
@Bruce Abbot: 

Yeah, seems like we agree on banksel. I think japanhalt is the nonbeliever.

Your last post has me all kinds of confused, though.

First off, I could not reproduce that error. Your code assembles fine on my version of MPLAB.
I assume "40000" represents SOME number to the IDE. I dont' even know what the default actually is, tbh. I always use "0x" or "." or "b'" etc. In my MPLAB (I suppose there could be options or differences between versions), there is no invalid number. If you exceed the max for the device's bank, it just wraps around. It doesn't even give me a warning when I turn off all warning suppression, even. The only warning I get is to make sure the proper bankbits are selected, because 4000 doesn't happen to wrap all the way back to bank0, apparently.

You say you don't need a line number because it jumps you to the line.
Here's is an example macro error that I just generated on my version of MPLAB:

Code: [Select]
#define myvar 4000

lsl16 macro aa
clrc
rrl aa,f
rrl aa+1,f
endm


;test code

lsl16 20h

nop
goto $-1

If I assemble that, it's fine. Now I add:
Code: [Select]
lsl16   myvar.TYPO.OOPS

And I get an error when I assemble it. Because I misspelled "myvar," in case you did not catch that.

Now, here's the rub.
In my error report, I get
Error[113]   Z:\...\testcode.ASM 33 : Symbol not previously defined (MYVAR.OOPS.TYPO)
Error[113]   Z:\...\testcode.ASM 34 : Symbol not previously defined (MYVAR.OOPS.TYPO)

Those are the only two errors generated. If I click on them, they shoot me over to where I wrote the macro. This tells me I used the macro wrong somewhere...... BUT WHERE?

If I go into the .lst file, number 33 and 34 don't immediately mean anything to me. I finally find this:

                      00031 LSL16   MACRO   AA
                      00032         CLRC
                      00033         RLF     AA,F
                      00034         RLF     AA+1,F
                      00035         ENDM

This was much work, because it seems all I have is 2 digits from the error list which match up to ONE of many sets of said numbers in the "line source code" column. Maybe it's cuz I dont know how to read the lst file and need to looks for something else... but don't worry, it gets much worse! Because even after finding it... it is MY definition of the macro. Which it just another kick in the nads.

I have to scan the entire lst file to finally find the error. And list files are huge. And finally after finding the needle in the haystack with zero help from the IDE, here it is, as shown in the lst file.

Error[113]  : Symbol not previously defined (MYVAR.OOPS.TYPO)
0087   0D80               M         RLF     MYVAR.OOPS.TYPO,F
Error[113]  : Symbol not previously defined (MYVAR.OOPS.TYPO)
0088   0D81               M         RLF     MYVAR.OOPS.TYPO+1,F
Even if the list is ONLY a few pages, this is still a PITA, to me. On a big project, the list file can be hundreds of pages. I don't call this hand-holding to want a bone, here, which there is so far absolutely none. The address given on the error report has NOTHING to do with where the error is. It only points to where I wrote the actual macro, itself.

Now, once I have found the actual error by physically scanning the entire LST file, it shows line number 87 in the code. So I go back to my code and enter this line number... and it takes me... somewhere in the vicinity but not even to the correct line. I have to scan about 10 lines back to find it (depending on how many macros you used, it could be a lot more dead space to scroll back... pages and pages.)  This is AFTER scanning the entire lst file just to find this line number.


If I wrote:

rrl     typoooooooo,f

or maybe..

call subroutine.typooooooooooo

or even if I have to go through all the trouble to write this:

lcall subroutine.typooooooo
pagesel $
banksel xyz


and I try to assemble it, the error will link me right to the spot. It takes 5 seconds to recognize and fix my typo and hit "build." Clicky, typy, f10. Compare that to the game of "where's Waldo?" Now that I am going thru these motions, again, I recall doing these same tests, back when, after finally having enough and ripping out all my macros and wondering if perhaps I was just doing something wrong. I remember specifically being annoyed with this aspect of turning a minor typo into a major hassle. This why I have to wonder if there are settings on the IDE which you have used. I can't imagine never running into this exact thing and exercising the vocal cords with familiar 4 letter words. Now IF the error was in the last file you edited, you can cntrl + Z till something clicks.. make a mental note... cnrl+Y to put everything back. Then go back and fix the error. Or you can look thru the entire list file. You can dump all the work you just did and go back to an earlier revision. Or you can just take the macro out of the code in every instance where you used it, and never go thru this, again.

Also, now that I am thinking about it, again, the problem with macros using no parameters is that if you misspell the macro, you will create a label. There is no error. No color change in the text. Just an invisible error that your assembler can't find. You can use the indented label warning, I would think. Or you could use the IDE's jump to [label] and scan for your typo, assuming you didn't mess up the first couple of letters... But again, it's been years since I investigated this stuff, so whatever solutions I found, they were not satisfactory to me. I really rather have error than to have to keep my code free of all such warnings to even have a chance to notice this --- in fact indented labels are a tool I use, frequently, to make bookmarks. This is why peudoinstructions and assembler directives are fine to me but macros are to be avoided, wherever possible. (I concede there are instances where macros are worth the trouble; but you always have to be careful.)

Blue is good. Purple is bad. :)

I have come up with some truly inelegant subroutines to replace nice macros. Thinking more about it, it should be possible to use macros IN subroutines. Once that tests good, you are fairly solid as long as you are calling the subroutine in your future code. The assembler/IDE is the smart one in my partnership. With my bestest thinking cap on, all I do is create and fix errors. I'm not gonna go off the reservation, alone, unless I have to. I can see how macros are the best thing since sliced bread when your code is fairly short and legible. Short and legible do not describe assembly for long. Even modestly complex code will soon turn into a strand of DNA which is navigable only with the help of the IDE.
« Last Edit: June 12, 2017, 06:33:19 am by KL27x »
 

Offline KL27x

  • Super Contributor
  • ***
  • Posts: 4108
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #43 on: June 12, 2017, 04:08:51 am »
Ok, I thought to try something.

Config>settings>project>
uncheck the "halt on first failure" box.

No dice. The only two errors point to where I wrote the macro, still.
Quote
My complaint isn't with BANKSEL, but the fact that you have to switch banks at all. Some newer chips have dozens of banks (most of which are half empty).
Once you give up on neat and legible, these enhanced midrange are great for assembly. Yes, you give up a lot in terms of elegance. This is the point where if you want to use fancy peripherals and super low power and more memory and EEPROM and PLL with 48MHz and multiple interrupts, you will start letting go of neat and elegant and legible, and you will focus more on making sure the IDE has your back. Cuz it IS going to get fairly messy no matter what you do. I hide whatever I can in subroutines so that the main code loop is manageable. These are my messy suitcases that once closed and tested and verified, I don't have to be too careful when using them, and I don't need to look, again, at what's inside. This is what the huge stack is for. So your subroutines can call other subroutines and branch to other subroutines ad infinitum. Now all you have to do is follow the bank and page protocol when using your subroutines and keep your memory from co-mingling. That sounds easier than it is (cuz I spend 99% of my time writing and modifying subroutines. :))
« Last Edit: June 12, 2017, 07:36:57 am by KL27x »
 

Offline KL27x

  • Super Contributor
  • ***
  • Posts: 4108
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #44 on: June 12, 2017, 08:22:25 am »
Some basic obvious subroutines, I'm sure everyone has copied right out of the datasheet, for example:
Code: [Select]
read
;    loads W with EEPROM @ address loaded into addypointer
;    global memory: addypointer
;     returns in bank0
;;;;;;;;;;;;;;;;;;;;;;;;;;;
BANKSEL EEADRL
movf addypointer,w
movwf EEADRL
BANKSEL EECON1
BCF EECON1,CFGS
BCF EECON1,EEPGD
BSF EECON1,RD
BANKSEL EEDAT
movf EEDAT,0
BANKSEL 20h
incf addypointer,f
return
save
;  saves W to EEPROM at address indicated in addypointer
;  global memory: addypointer, temp
;   returns in bank0
;   turns GIE off and BACK ON
movwf temp
BANKSEL EEADRL
movf addypointer,w
movwf EEADRL
movf temp,w
movwf EEDATL
BCF EECON1,CFGS
BCF EECON1,EEPGD
BSF EECON1,WREN
BCF INTCON,GIE
movlw 55h
movwf EECON2
movlw 0AAh
movwf EECON2
bsf EECON1,WR
BSF INTCON,GIE
bcf EECON1,WREN
btfsc EECON1,WR
goto $-2
banksel 0h
incf addypointer,f
movf temp,w
return
Now in code, I can write new subroutines like so
Code: [Select]
save_stuff
;memory: register1, register2
;  save subroutine
;constant: desired.address is EEPROM starting address, 2 bytes
;returns in bank0
movlw  desired.address
        movwf    addypointer   ;global nonlinear register
        banksel register1
        movf    register1,w
lcall    save
        banksel register2
        movf    register2,w
        call save
pagesel $
return
load_stuff
;memory: register1, register2
;   read subroutine
;   constant: desired.address
;return in register1 bank
  movlw desired.address
  movwf addypointer
lcall read
banksel register1
movwf register1
call read
banksel register2
movwf register2
pagesel $
return

This is not elegant. But in my code, I am just calling and using any of these subroutines from the main code loop with just their name. I can keep "load_stuff" on the local page where it is used, and "read" and "save" can be anywhere.

Here is a part of a delay module with several selectable software interrupts:
Code: [Select]
Delay.Module.Subroutines
clearflags
clrf DM.INTFLAG.REG
bcf DM.STATUS,1 ;Delay.IF.Master
DM.return
RETURN
Wx100mS
call clearflags
movwf DM.tempreg2
Wx100mS.1
btfss Delay.IE.Master
goto Wx100mS.2
btfsc Delay.IF.Master
return
Wx100mS.2
movlw .39
movwf DM.tempreg1
movlw .16
movwf DM.tempreg0
call Delay_10uS_PL
decfsz DM.tempreg2,f
goto Wx100mS.1
return
Wx10mS
call clearflags
movwf DM.tempreg2
Wx10mS.1
btfss Delay.IE.Master
goto Wx10mS.2
btfsc Delay.IF.Master
return
Wx10mS.2
movlw .3
movwf DM.tempreg1
movlw .232
movwf DM.tempreg0
call Delay_10uS_PL
decfsz DM.tempreg2,f
goto Wx10mS.1
return
Wx1mS
call clearflags
MOVWF DM.tempreg2
Wx1mS.1
btfss Delay.IE.Master
goto Wx1mS.2
btfsc Delay.IF.Master
return
Wx1mS.2
movlw .100
movwf DM.tempreg0
clrf DM.tempreg1
call Delay_10uS_PL
decfsz DM.tempreg2,f
goto Wx1mS.1
return
; if REV!=0xF1
Wx10uS
call clearflags
movwf DM.tempreg0
clrf DM.tempreg1
goto Delay_10uS_PL

To use it, I would first have to set the IE bits I want active, then clear the flags, then
movlw .6
call Wx100mS
movlw .4
call Wx10mS
This is 640mS delay with whatever software interrupts I enabled. Not as elegant as a macro, but this the price I pay. If a flag is set, the delays exit immediately, and a master IF is set. If this bit is set, I can further check which individual flags were set, if it matters. Basically same way an IOC interrupt works.

Here is a snippet of an I2C subroutine "man in the middle" thing I made, which for to hack a device using an I2C port extender and to intercept and modify the data, bouncing between slave and master.
Code: [Select]
I2C.ISR.Subroutine ;called at end of TMR4 interrupt... there is also an i2c isr called after ioc
banksel bank4
btfsc Slave.Busy.Bit
return
lCALL CHANGE_TO_MASTER
lCALL Read.inputs
lCALL Convert.P.to.Output.F
lCALL CHANGE_TO_SLAVE
pagesel $
return

There's like no code there, at all. The subroutine just calls other subroutine. Each bit forged with pain until it frigging worked. What does the code look like? Well, it's greek even to me, and I wrote it. It don't make any sense unless I have the datasheet and I2C protocol in front of me. The labels are detailed, and there is tons of comment. And I have a specific format I generally use (some of my indentations/tabs are messed up in my snippets, which sucks - example I always put lcalls/pagesels with 1 fewer indent than the other instructions to make them stand out, but that didn't show up in my copy/paste). But even so, it's long, it's cryptic, and suffice to say, it gets its own page of code and bank of memory for itself. Funny, looking at it, I used Lcall so many times. I am pretty sure I ended up putting everything on one page, but I prolly wrote it like that just in case. Well, the memory was consolidated to one bank, except I put the virtual TRIS and LAT registers on the same bank as the other PIC ports'. But once one part is working, pack it up, tape it over, and don't mess with it. Eat the elephant one bite at a time.

Here's a little tidbit. This part is so I can read the port extender and write to the spoofed master exactly the way I can to any port of the PIC, using virtual ports P0 and P1 and F0, F1, with their own virtual PORT, LAT and TRIS registers. This how I really came to appreciate what the LAT register does, lol. This was more fun than a root canal. Slightly.
Code: [Select]
banksel PORTP0
movf PORTP0,w
banksel bank4
movwf F00
movwf P0.tru.input.state

banksel TRISP0
;movlw 0xFF
;movwf TRISP0
movf TRISP0,w
banksel LATP0
iorwf LATP0,w
banksel bank4
movwf Mask.L
banksel TRISP0
comf TRISP0,w
banksel LATP0
andwf LATP0,w

banksel bank4
;hi mask is in w
iorwf F00,f
movf Mask.L,w
andwf F00,f

8 bit math:
Wx5
;global memory: temp, temp1
;does not alter bank
movwf temp
movwf temp1
clrc
rlf       temp,f
rlf       temp,w
addwf temp1,w
return

load w reg with value, call Wx5 or call Wx3, or whatnot. Saves a lot of codespace if you call it a lot. Often I need some low value multiplication before a BRW instruction where I need 2 or 3 or 4 lines per each branch, or whatnot. (4 lines for a pagesel X, call X, pagesel $, return, for instance. Seeing a pattern here?)
« Last Edit: June 12, 2017, 10:01:44 am by KL27x »
 

Online jpanhalt

  • Super Contributor
  • ***
  • Posts: 3650
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #45 on: June 12, 2017, 10:09:29 am »
Some basic obvious subroutines, I'm sure everyone has copied right out of the datasheet, for example:
Code: (asm) [Select]

8 bit math:
Wx5
;global memory: temp, temp1
;does not alter bank
movwf temp
movwf temp1
clrc
rlf       temp,f
rlf       temp,w
addwf temp1,w
return
Using the less elegant, less neat, and less legible enhanced mid-range  instructions becomes:

Code: (asm) [Select]
X5enhanced
     movf      temp,w
     lslf      temp,f
     lslf      temp,f
     addwf     temp,w   
     return

;NB: If for whatever reason you want to preserve "temp" it is trivial
;to rewrite the above doing the rotates on w instead of temp. 
;Second, should the seed value not give a x5 value that is 8-bit, the
;second method will still give the correct lower byte, but your
;method will not.  Try d.140 as the seed.

BTW, just what is less elegant, less neat, and less legible about the enhanced mid-range chips?  For example, I find being able directly manipulate wreg and address the stack as (e.g., use it as a memory stack) quite useful and code saving.  The enhanced instruction set is also useful as illustrated above.

John



« Last Edit: June 12, 2017, 10:12:13 am by jpanhalt »
 

Offline KL27x

  • Super Contributor
  • ***
  • Posts: 4108
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #46 on: June 12, 2017, 11:22:51 am »
^I thought there was an instruction that did the whole shift without the carry. I guess I didn't warm up to the spelling of that. Took me long enough to remember rlf rrf.

The initial reason I ever made this subroutine is that after returning from another subroutine (hehe, there's the theme) which loads a value into w, I can call Wx5 and BRW from there in 5 line spacing. I know my subroutine doesn't work for numbers that exceed 256. But in either case you're clipping the higher order bit. So what if your example if off by 256 and mine is off by only 255, sometimes. Mine is more accurate, lol. And since mine loads W you saved only 1 instruction (and the one register, which I could also save, if I had thought about it. In fact, I couldn't find my actual code and just wrote this on the spot, which is why this isn't copypasta'd. I wonder when I do find it if I used two temporary registers or just one? I felt like it was too bulky when I wrote it...)

Quote
BTW, just what is less elegant, less neat, and less legible about the enhanced mid-range chips?
As Bruce Abbott has stated his dislike for the banks. I see his point of view. The fact enhance chip might have 4x the code space, you might end up getting only twice as much actual processing done in that space, and also going thru a lot of teething pains managing the extra pages you end up with due to all the bank management, let alone the extra banks. But this is offset somewhat when you make use of that stack. Subroutines don't have to be pretty. And once you get over that, the bank management doesn't need to be hard. You can write your actual code loop with very little of it when you let the subroutines handle it.

This bulky subroutine kinda illustrates my point. I'm not trying to squeeze out every instruction unless it matters. Take my tris/lat/port emulator code for instance... speed mattered, there. I think that if you understand what it is doing, it might actually be very miserly on the instruction cycles, maybe even perfect (highly doubtful, but I did wrack my brain on it). But unless it matters, I am not much caring. When it works, I'm moving on.







« Last Edit: June 12, 2017, 11:55:59 am by KL27x »
 

Online jpanhalt

  • Super Contributor
  • ***
  • Posts: 3650
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #47 on: June 12, 2017, 11:57:53 am »
As Bruce Abbott has stated his dislike for the banks. I see his point of view. The fact enhance chip might have 4x the code space, you might end up getting only twice as much actual processing done in that space, and also going thru a lot of teething pains managing the extra pages you end up with due to all the bank management, let alone the extra banks. But this is offset somewhat when you make use of that stack. Subroutines don't have to be pretty.

So somehow, you perceive using the many useful peripherals, which require bank changes, as being less elegant and less legible than doing everything in code.

I disagree and except for code I wrote years ago, I go to the enhanced chips as my first choice.   I do keep two "cheat" sheets available when I write code -- the instruction set and the memory pages showing banks for what I am doing.  Neither is inconvenient nor reflected in the code, except I may be reminded of an instruction such as subwfb and addwfc that I might have forgotten since my last exercise in coding. NB: I code mostly just during Winter when I am not tending to the farm and do it only as a hobby.

One thing I try to do religiously is keep track of the bank using columns 76-80 on the page, e.g.,
Code: (asm) [Select]
;*******************************************************************************
;Setup SPI serial port
;*******************************************************************************
     movlb     4              ;                                            |B4 
     clrf      WPUC           ;disable WPU(default is enabled)             |B4                           
     clrf      SSPSTAT        ;CKE=0, SMP=0 (sample at middle)             |B4
;NB: CKE (bit6) set opposite CPHA, i.e., 10 = mode 11(mode 3)
     movlw     b'00110001'    ;enable SSPEN, set SPI CLK to Fosc/16        |B4           
     movwf     SSPCON1        ;CKP=1(idle high),master clk =Fosc/x         |B4
     movlb     2              ;                                            |B2
     bsf       CSn            ;set chip select high                        |B2
     movlb     0              ;                                            |B0     
;*******************************************************************************


John
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: PIC12F509 & PIC18F26K20
« Reply #48 on: June 12, 2017, 01:53:37 pm »
First off, I could not reproduce that error. Your code assembles fine on my version of MPLAB. I assume "40000" represents SOME number to the IDE.
It was 4000 not 40000, and I have the default number base set to decimal so that is address 0x0FA0. On my PIC (12F617) that is an invalid address.

Quote
If you exceed the max for the device's bank, it just wraps around. It doesn't even give me a warning when I turn off all warning suppression, even.
This is somewhat disturbing, as it allows you to make serious errors that won't be picked up. But being able to do stuff like that is one of the charms of assembler (actually you can do it in C too, but it's harder to do accidentally). With great power comes great responsibility, and assembler gives you more power than any HLL.

Quote
If I go into the .lst file, number 33 and 34 don't immediately mean anything to me. I finally find this:

                      00031 LSL16   MACRO   AA
                      00032         CLRC
                      00033         RLF     AA,F
                      00034         RLF     AA+1,F
                      00035         ENDM

Here's what I got after searching for "Symbol not previously defined (myvar.TYPO.OOPS)" in the listing file:-
Code: [Select]
                      00016  lsl16   myvar.TYPO.OOPS
0003   1003               M  clrc
Error[113]  : Symbol not previously defined (myvar.TYPO.OOPS)
0004   0D80               M  rlf myvar.TYPO.OOPS,f
Error[113]  : Symbol not previously defined (myvar.TYPO.OOPS)
0005   0D81               M  rlf myvar.TYPO.OOPS+1,f
Lines with "M" are the macro expansion. Directly above them you see  "00016  lsl16   myvar.TYPO.OOPS". 

Click-drag mouse over error message in output window, right-click/copy or type CTRL-C, click in listing file window, type CTRL-F, paste error message, click 'find next'. Not that hard.  ;)

Of course in this case you didn't need to do that. Just search for "myvar.TYPO.OOPS" in the source code.

Quote
If I wrote:... and I try to assemble it, the error will link me right to the spot. It takes 5 seconds to recognize and fix my typo and hit "build."
People today have it so easy! And patience to match.

I do most of my coding with a text editor, and having the error message link back to the source line is a novelty. The project I am currently working on has over 10,000 lines of Z80 asm code spread over a dozen files. You make one little typo and the assembler throws hundreds of unrelated error messages. Searching the listing file is often the only practical way to find stuff.   

Quote
Also, now that I am thinking about it, again, the problem with macros using no parameters is that if you misspell the macro, you will create a label. There is no error. No color change in the text. Just an invisible error that your assembler can't find.
As far as the assembler is concerned it's not an error, and why should it be? Perhaps you wanted a label with that name, and the assembler can't be expected  to know otherwise.

Quote
You can use the indented label warning, I would think.
Yes, that's a good idea. I always put labels at column 0 and terminate them with a ':', but sadly the assembler does not require this.

Quote
indented labels are a tool I use, frequently, to make bookmarks.
Yuk. How does that work?

Quote
I can see how macros are the best thing since sliced bread when your code is fairly short and legible. Short and legible do not describe assembly for long.
Assembly code gets long fast, but it doesn't have to be illegible.

I use macros not just to reduce typing but also to make the code more readable. A well designed macro hides all the messy implementation details and stops you making silly errors (and the less typing you have to do, the fewer typos you make!). I also use macros to create data structures. On other platforms I create GUI elements with them (no crappy form designers for me!).
« Last Edit: June 12, 2017, 01:56:53 pm by Bruce Abbott »
 

Offline KL27x

  • Super Contributor
  • ***
  • Posts: 4108
  • Country: us
Re: PIC12F509 & PIC18F26K20
« Reply #49 on: June 12, 2017, 08:40:28 pm »
Quote
Lines with "M" are the macro expansion. Directly above them you see  "00016  lsl16   myvar.TYPO.OOPS". 

Click-drag mouse over error message in output window, right-click/copy or type CTRL-C, click in listing file window, type CTRL-F, paste error message, click 'find next'. Not that hard.  ;)

Of course in this case you didn't need to do that. Just search for "myvar.TYPO.OOPS" in the source code.

Wow, thanks. Cntrl-F. I did not know this existed. And yes, I am able to find error both ways. (But in the latter method, you must know in which asm file to look.) Thanks a bunch... I get it, now. I have never seen "find file" in the gui, and I didn't know it existed.  :palm: Now I am seeing it is a thing in basically any text editor..  :palm: :palm: Yes, we have it good when we RTFM.
Quote
People today have it so easy! And patience to match.

I do most of my coding with a text editor, and having the error message link back to the source line is a novelty. The project I am currently working on has over 10,000 lines of Z80 asm code spread over a dozen files. You make one little typo and the assembler throws hundreds of unrelated error messages. Searching the listing file is often the only practical way to find stuff.   
The only time I have ever had to look at the lst file is when I first started managing pages and using BRW incorrectly, to debug. You may not believe this, but even on project with multiple files and hundred plus pages, when I have errors, I look at the error report, I click, I find. It's not a guessing game, no matter how big the project is. The error report will link me there. The first error is essentially always going to take me to the source of an error, because I wrote my code in a way where it works this way. I've clung to this like a lifeline, lol. (Maybe I can start letting go, now that I am learning new tricks :)).


Quote
Quote

Also, now that I am thinking about it, again, the problem with macros using no parameters is that if you misspell the macro, you will create a label. There is no error. No color change in the text. Just an invisible error that your assembler can't find.

As far as the assembler is concerned it's not an error, and why should it be? Perhaps you wanted a label with that name, and the assembler can't be expected  to know otherwise.
Yes, it's not an "error," it's technically a bug. Perhaps I wanted a label? No, I am not going to make a label almost exactly same as a macro name. Perhaps I made a typo, and now we wait until I finally realize I even made this error mistake.  This is something I do not want to introduce to my code, because I see the grey hairs in advance.



Quote
Quote

indented labels are a tool I use, frequently, to make bookmarks.


Yuk. How does that work?
It works by writing
[indent] yourlabel

And now, I get a warning everytime I assemble. Which shows "yourlabel" in the warning.
Unlike the bookmark system you can select which bookmark by title, rather than next/previous. And more importantly, unlike the goto [label] (or find, thank you) in IDE, this works across all of your asm files. You don't have to click on the right file. just click on it in the error report and it opens the correct asm file and brings you to your bookmark. When you're done with it, click on it to jump there, and erase it. This is very useful when modifying multiple asm files. It's also impossible to accidentally erase or lose all your bookmarks, as with the IDE's bookmark function. Even going back to earlier revisions, your bookmarks from that time are preserved, which more the clues to what I was doing and thinking, the better.

Quote
So somehow, you perceive using the many useful peripherals, which require bank changes, as being less elegant and less legible than doing everything in code.
I think we are both in the same camp, here. I also would also prefer to use enhanced before any midrange or baseline, in general. The bank management is just part of the deal which becomes second nature. Going back to baseline, it's actually more work for me to streamline my code to take advantage of tris instruction and ability to do so much on one bank. Writing good code on baseline feels like making bad habits for midrange.

Quote
I use macros not just to reduce typing but also to make the code more readable. A well designed macro hides all the messy implementation details and stops you making silly errors (and the less typing you have to do, the fewer typos you make!). I also use macros to create data structures. On other platforms I create GUI elements with them (no crappy form designers for me!).
I'm learning a lot, fellas. Keep it coming. I'd love to see some examples of this data structure macro.

« Last Edit: June 12, 2017, 10:12:34 pm by KL27x »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf