<< Previous | Index | Next >>

> ## Appendix B. Wait State Bug

> ### B.1 Overview of the Bug

> A bug associated with the use of memory wait states was discovered in the Rabbit 2000 processor approximately 13 months after the product was introduced. This bug was not discovered previously because the use of wait states in situations that evoke the problem is unusual. A number of modifications to Dynamic C starting with version 7.05 have been made to make it easy, or in some cases automatic, to avoid problems created by the bug. The bug manifests when memory wait states are used during certain instruction fetches or during certain read operations. The data read instructions are the simpler case and we will describe them first.

> Wait states for I/O devices work normally and are not associated with this problem.

> ### B.2 Wait States In Data Memory

> The two instructions `LDDR` and `LDIR` are repeating instructions that move a block of data in memory. If wait states are enabled, then one wait state less than specified is used on every data read except the first one in the block. This can be corrected in either of two ways.

> An additional wait state can be specified, which will cause there to still be sufficient wait states when one is lost, or a directive can be issued to the Dynamic C compiler to automatically substitute different instructions for `LDDR` or `LDIR` which accomplish the same operation.

> The directive is:

>     #pragma DATAWAITSUSED on
>     #pragma DATAWAITSUSED off

> This will cause Dynamic C to substitute code as follows:

>     ldir

> becomes

>     call ldir_func

> and

>     lddr

> becomes

>     call lddr_func

> This change causes the block move to proceed at 11 clock cycles per byte (on average) rather than 7 clock cycles per byte.

> For small memory blocks (<45 bytes), it is more efficient to write the following code:

>     start_ldi: ldi
>     jp nov, start_ldi

>     start_ldr: ldr
>     jp nov, start_ldr

> ### B.3 Wait States in Code Memory

> There are two manifestations of the wait state bug in code memory. If wait states are enabled, there are certain instructions that will execute incorrectly and there are certain other instructions whose use will reduce the length of the output enable signal.

> #### B.3.1 Instructions Affected by the Wait State Bug

> If wait states in code memory are enabled, the 20 instructions in the table below execute incorrectly and should not be used:

> set b, (ix+d) | set b, (iy+d)
> res b, (ix+d) | res b, (iy+d)
> bit b, (ix+d) | bit b, (iy+d)
> rl (ix+d) | rl (iy+d)
> rlc (ix+d | rlc (iy+d)
> rr (ix+d) | rr (iy+d)
> rrc (ix+d) | rrc (iy+d)
> sla (ix+d) | sla (iy+d)
> sra (ix+d) | sra (iy+d)
> srl (ix+d) | srl (iy+d)
> Table B-1. Rabbit 2000 Instructions

> These instructions work correctly if there are zero wait states. If wait states are desired, equivalent instructions work without any problem. For example:

>     SRA (IX+8)    ; 13 clocks

> can be replaced by:

>     LD B,(IX+8)  ; 9 clocks
>     SRA B        ; 4 clocks
>     LD(IX+8),B    ; 10 clocks

> Any of the registers A, H, L, D, E, B, C can be used to hold the intermediate value, so you should be able to find a free register.

> For:

>     BIT  3,(IX+4)  ; 10 clocks

> use:

>     LD B,(IX+4)   ; 9 clocks
>     BIT 3,B        ; 4 clocks

> If the atomic nature of the operation is important then the operation can be shifted to the hl index register. For example:

>     SET 3,(IX+4)

> Use instead:

>     PUSH HL
>     PUSH DE
>     LD HL,IX
>     LD DE,4
>     ADD HL,DE
>     SET 3,(HL)
>     POP DE
>     POP HL

> ##### B.3.1.1 Dynamic C version 7.05

> Starting with version 7.05, Dynamic C does not generate any of the instructions in Table B-1, and they are not used in the library routines. If any of these instructions are used in an application program, a warning will be generated by the compiler.

> ##### B.3.1.2 Prior versions of Dynamic C

> In versions of Dynamic C prior to 7.05, the library, `SLICE.LIB`, contains one of these instructions: `bit b,(iy+d)`. Do not use wait states with slice statements in these earlier versions of Dynamic C. If any of the instructions in the table above are used in an application program, no warning is generated and you are on your own.

> #### B.3.2 Output Enable Signal and Conditional Jumps

> If wait states are enabled for code memory, the memory output enable signal is shortened by one clock cycle for the first byte read after any conditional jump instruction that does not jump. This is not the same as losing a wait state, and in some cases the shortened output enable signal will not cause a problem. The conditional jump instructions are:

>     jp cc, mn

>             cc (condition code) is one of the following:
>     	 NZ, Zero flag not set;
>     	 Z, Zero flag set;
>     	 NC, Carry flag not set;
>     	 C, Carry flag set;
>     	 LZ, Logical/Overflow flag is not set;
>     	 LO, Logical/Overflow flag is set;
>     	 P, Sign flag not set;
>     	 M, Sign flag set

>     jr cc, e

>             cc (condition code) is one of the following:
>     	 NZ, Zero flag not set;
>     	 Z, Zero flag set;
>     	 NC, Carry flag not set;
>     	 C, Carry flag set;

>     djnz e

> ##### B.3.2.1 Workaround for Wait State Bug with Conditional Jumps

> One way to compensate for the shortened output enable signal is to add one more wait state than would otherwise be needed. An example of the memory access with the shortened output enable signal is shown in the figure below.

> #### B.3.3 Output Enable Signal and Mul Instruction

> If wait states are enabled for code memory, the length of the output enable signal is reduced to a single clock cycle for the first instruction byte fetch after a multiply (`mul`) instruction. This is the length the output enable signal would be if there were zero wait states. The read of this byte is always a long read cycle (the same as 10 wait states) since it is shared with the execution of `mul`.This effectively precludes the use of `mul` with wait states unless the following condition is met: the length of time from the start of the output enable signal to when the data becomes ready to sample is less than 1 clock cycle - 9 nanoseconds.

> If the clock doubler is used alternate clocks may have slightly different lengths and a slightly stricter standard may need to be applied.

> #### B.3.4 Alternatives to Wait States in Code Memory

> If the code memory is slow and requires wait states at a certain clock speed, the simplest alternative is to lower the clock speed so that no wait states will be required. Lowering the clock speed to 2/3 of its previous value has the same effect as adding one wait state. Lowering the clock speed to 1/2 is the same as 2 wait states. Lowering the clock speed to 1/3 is the same as 4 wait states.The clock speed can be cut in half by turning of the clock doubler. The clock speed can be divided by 8 by enabling the clock divider.

> Another way to avoid wait states is to run normally with the clock doubler enabled, and when you need to execute code from the slower memory turn off the clock doubler. This doubles the length of the memory cycle, which is equivalent to adding 2 wait states.

> ### B.4 Enabling Wait States

> Memory wait states can be specified independently for each of 4 different addressing zones in the memory space. The four memory bank control registers (`MBxCR`) control the wait states inserted for memory accesses in each zone. The number of wait states can be programmed as 0, 1, 2 or 4. The principle reasons for enabling memory wait states are:

> 1. During startup of the Rabbit 2000, wait states are automatically set to 4 wait states. Unless it has been modified, the BIOS promptly sets the processor to zero wait states.

> 2. Enabling wait states can be used as a strategy for reducing power consumption. This can still be done if the restrictions and work-arounds detailed in this chapter are adhered to. For example, you don't use the 20 instructions that execute incorrectly.

> 3. A slow flash memory used for data storage may be interfaced to the processor as a memory device and it may require wait states. This will still work as long as only data accesses are made to the memory. If instructions are to be executed from the memory, then the restrictions and work-arounds detailed in this chapter must be adhered to.

> ### B.5 Summary

> In a typical design implementation, wait states are not used for access to the main instruction memory. Normally the processor clock speed is selected so that with zero wait states the processor memory cycle is matched with the instruction memory access time. Hence, the wait state bug will not be encountered by most users.

> If the memory used is fast enough to run at zero wait states and the 20 failing instructions are not used, then inserting wait states will not cause problems. Thus, when the Rabbit starts up after a reset and maximum wait states are enabled there will not be a problem. Nor will there be a problem if wait states are inserted to conserve power. Controller boards produced by Rabbit Semiconductor will not experience the wait state bug unless the default setup in the BIOS is overridden.

> Rabbit Semiconductor flash write routines may move code into RAM memory and execute it there in order to perform a write on the flash code memory. These routines automatically avoid any wait state bug problems.

> Wait states in memory used for data are not a problem because of the compiler directive that can be used to avoid the bug. There is no reason to avoid wait states for data memory.

Rabbit 2000 Designer's Handbook | << Previous | Index | Next >> | rabbit.com