I think there is some confusion between the speed of machine code and interpreted BASIC.
The native language of a PIC microcontroller and any microprocessor for that matter is machine code.
Some people use the term assembler in lieu of machine code but with assemblers they use mnemonics which are pseudo text codes that are easier for us humans to understand and turns them into binary values for the microprosessor to use. So, assemblers generate machine code for micro-processors to use.
With many micro-processors, yes, it equates roughly to 1 instruction per clock cycle so a 4MHz processor will execute approx 4 million instructions per second.
In the case of the PIC's as used for PICAXE's, one instruction cycle consists of four oscillator periods, so for an oscillator frequency of 4 MHz, this gives a normal instruction execution time of 1 μs. All instructions are executed within a single instruction cycle, unless a conditional test is true, or the program counter is changed as a result of an instruction. When this occurs, the execution takes two instruction cycles.
The PICAXE is programmed in BASIC which is an interpreted language. To save space, the Program editor (as with most BASIC interpreter systems) tokenises you program and instructions are stored by say one 8-bit byte rather than for example the PAUSE command occupying 5 bytes. Rev Ed has further compressed things so some codes and variable space my not require a full byte.
But when we come to execute a BASIC program, the inbuilt interpreter (within the PICAXE chip) must first read the tokenised code, and then execute many machine code instructions to achieve this action.
In a form of pseudo code, if we have the BASIC command:
Code:
FOR b0 = 1 TO 255
B1 = b0 + 1
NEXT b0
Only as a rough guide in machine code as to what we must get the PICAXE processor to:
1. get the token and determine that it is a FOR command
2. make a flag as to which variable (b0) is to be used as the counter
3. take the next value (1) and store that in another location as a starting point
4. take the next value (255) and store than in another location as an end value
5. put the start value into variable b0
6. start a loop
7. load the accumulator with b0
8. add 1 to the accumulator
9. save the accumulator in variable b1
10. load the accumulator from variable b0
11. add 1 (or the STEP value) to the accumulator
12. save the accumulator back into variable b0
13. test is the accumulator value is greater than then end value
14. branch back to start of the loop if accumulator is less than end value – so back to step 7
15. go load the next BASIC command read to interpret.
As you can see, there are many steps here (and this is very rough) to represent a simple FOR…NEXT command. In between times, there are overheads like checking for interrupts, handling PWM signals, etc that all take time as well.
So at the end of the day, one BASIC command can occupy 20, 50 or maybe around 100+ machine code instructions plus the overheads of reading the BASIC code and setting up to action the BASIC so before we know it BASIC commands can occupy anything from 100 to 1000 microseconds each.
Beaniebots has already done some BASIC command timing. Unless you are in need of some critical timing requirement, I suggest you accept that BASIC is slower and just use it.