When Buffalo produces its command prompt “>” we say that Buffalo has control of the development board. In this sense, Buffalo saves the actual CPU register values associated with your program. Buffalo has commands that transfer control to your program. In transferring control, the CPU register values associated with your program are restored. The RM command displays and modifies the stored CPU register values. Enter the following command:
> rm A
The command first lists all the registers and their values, and then gives you the opportunity to change the value. Be sure to remember that Buffalo is case insensitive and only understands hexadecimal numbers.
P-E50A Y-FFFF X-0115 A-00 B-FF C-D0 S-0041 A-00 FF
After you change the A register value, repeat the rm command to see the change. Simply pressing the Enter key makes no change to the affected register. Any CPU register value can be changed in this fashion, the registers are named as: A, B, C, X, Y, and S. It is important to remember, the values reported are safe and are not the current register values being used by Buffalo. Rather, these will be the register values when Buffalo transfers control to your program.
The 68HC11E9 chip in the Axiom board has 512 bytes of RAM starting at address $0000. Buffalo version 3.4 sets aside addresses $0000 to $0041 as the stack for your program. Addresses $0042 to $00FF are reserved by Buffalo, for its own stack, variables, and a jump table that we discuss later. After you've played with the rm command, press the reset button to restore some of the initial register values.
The MD command provides a dump of a range of memory locations, the following is the general format. If the number of bytes is not given then 144 byte values are listed.
The first 256 bytes are generally reserved for use by Buffalo, we will use addresses starting at $100 for a simple example program. Use the following command to look at 16 bytes, starting at $100.MD <address> [bytes]
>md 100 10 0100 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
The following is the format of the MM command
The MM command first lists the memory contents of the given address and then gives you the opportunity to change that value. If you enter a new value and press the enter key, the new value is inserted.> MM <address>
>mm 100 0100 FF AA >md 100 16 0100 AA FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF >mm 100 0100 AA FF >
The MM command allows you to easily change the contents of a range of addresses. Enter the MM command again, but don't press the enter key to accept the value. Rather, press the equal sign key '=', so the same address is repeated. Pressing '+' key ( you may have to press shift and '+') advances to the next address and pressing '-' changes to the preceeding address.
Buffalo provides a very rudimentary assembler/disassembler you can use to enter very short programs, or to examine machine code. The ASM command disassembles and assembles one instruction at a time. The general format is as follows, where <address> is the starting address:
> asm <address>
After you press the Enter key, the instruction at the start address is listed in mnemonic form, along with a new prompt. Pressing the Enter key causes the next instruction to be listed. Entering a new instruction replaces that at the current address and also advances to the next instruction. To exit this assembler/disassembler mode, press the control-A key combination.
At the command prompt enter the following:
> asm 100
Buffalo returns with the following:
0100 STX $FFFF >
Enter text so that you see the following. In the line that begins with 0106 just press the control-A key combination.
0100 STX $FFFF > LDAA #10 86 40 0102 STX $FFFF > STAA 1000 B7 10 00 0105 STX $FFFF > rts 39 0106 STX $FFFF >
Enter the command asm 100 as you did before. This time you the commands that you entered should be disabled from memory. Check to make sure that the code is entered correctly.
The CALL command transfers control to your program by using the assembly language jsr instruction. Because this instruction uses the stack to save the return address, your code must end with a return from interrupt instruction (RTS). With the code that you entered in the previous step still in memory, enter the following command:
> call 100
At this moment the LED that you connected to the development board should be illuminated. To turn off the LED it is only necessary to assign the value zero to the register at $1000. In using the MM command, it's normal that Buffalo cannot change all the bit values of that register.
To make the program more useful, let's design a delay loop that will leave the LED on for approximately one second before turning off. The following is assembly language code for the delay loop. Since the Buffalo assembler is very simple, it will not understand this assembly language code. Buffalo does not understand labels so you will have to substitute in the actual values of N1 and N2 by hand.
* Repeat the outer loop N1 times LDAA #N1 ; 2 cycles * Inner delay loop - ten milliseconds L1: LDX #N2 ; 3 cycles L2: NOP ; 2 cycles DEX ; 3 cycles BNE L2 ; 3 cycles * Rest of the outer loop DECA ; 2 cycles BNE L1 ; 3 cycles
The CPU bus cycle rate in our development board is 2MHz. To execute the inner delay loop in ten milliseconds the CPU must consume approximately 2MHz * 10msec = 20 thousand bus cycles. Thus we write the following equation and solve for N2 and round to the nearest integer.
With this value for N2, the inner loop executes in 20,003 bus cycles. To execute in one second, a total of 2 million bus cycles are required. Here we include the outer loop and solve for N1. In hind-sight, we can produce this number using a simple approximation. Because the delay in the inner loop is much longer than the workings of the outer loop, it's enough to repeat the inner loop one hundred times.3 + N2*(2+3+3) = N2*8 + 3 = 20,000 N2 = 2,500(decimal) or $09C4 (hexadecimal)
We will be using a much better assembler later, but for now write the code in a format Buffalo can understand. Buffalo doesn't 'do' labels; while Buffalo will calculate offset branch values, you must know the target address. If you don't know the target address, temporarily enter an arbitrary address that you know is within range, then use the ASM command again later to insert the correct address value.2 + N1*(20,003 + 5) = 2,000,000 N1 = 100(decimal) = $64 (hexadecimal)
A minor change is made to the program, so that after the delay the LED is turned off. Make special notice that the $ symbol isn't used as Buffalo only knows hexadecimal notation.
0100 LDAA #10 0102 STAA 1000 0105 LDAA #64 0107 LDX #09C4 010A NOP 010B DEX 010C BNE 010A 010E DECA 010F BNE 0107 0111 CLR 1000 0114 RTS
Use the ASM command as you did before to enter the code above, the starting address will be $0100. Use the call command as before, to run the code.
The CALL command is simpler than GO in that the CALL doesn't save a return address on the stack. Ending your program with a JMP $FF7C instruction provides the mechanism to transfer control back to buffalo. Use GO to execute the code. If the LED is on already, it should turn off in a brief moment.>asm 114 0114 RTS >jmp FF7C 7E FF 7C 0117 STX $FFFF > (control-A) >
> go 100
Buffalo version 3.4 initializes the stack pointer register to $41, but you can use the 'RM S' command to manually set the stack pointer register to what you like. In writing your own subroutines, don't initialize the stack pointer register. A subroutine that initializes the stack pointer register will likely remove its own return address and cause the RTS instruction to jump to an unknown address.
However, in writing a complete program you will want to initialize the stack pointer register. The GO command is like a jump instruction in that control is simply passed to your program, hence the return address back to Buffalo is not saved. A jump to the warm-start pseudovector ($FF7C) provides a means to transfer control back to Buffalo.
The BR command is used to set a breakpoint which causes execution to halt just before a specified address. Enter the following to set a breakpoint in the above program.
> BR 10B
Buffalo responds by listing the breakpoint table. Buffalo allows for at most four breakpoints.
010B 0000 0000 0000
Execute the code using the go 100 command, this time the program halts just before the instruction at address $010B. The action of a breakpoint causes the program to halt, report the contents of the CPU registers, and essentially freeze the state of execution.
10B 0000 0000 0000 >go 100 P-010B Y-FFFF X-09C4 A-64 B-FF C-D0 S-0041 >
While your program is halted, you can use the RM, MD, and MM commands as usual to examine the program state. The following table lists variations of the BR command that you will find useful.
BR | : Display the breakpoint table |
BR <address> | : Set a breakpoint |
BR -<address> | : clear a breakpoint |
BR - | : clear all breakpoints |
BR -<address1> <address2> | : change a breakpoint address |
>P P-010B Y-FFFF X-09C3 A-64 B-FF C-90 S-0041 >
The program hit the breakpoint a second time, but the X register now contains the value $09C3, one less than before. A point to make if you use other debuggers is that Buffalo does not have a command named continue. Resist the urge to issue the abbreviated command 'C' as it executes the Buffalo call command.
The trace command is similar to the step command in the THRSim11 tools, but the trace command allows you to specify the number of instructions to execute before returning control to Buffalo.
> T <n>
Here is the trace command in use, remember that pressing the enter key alone repeats the previous command.
>T 1 DEX P-010C Y-FFFF X-09C2 A-64 B-FF C-90 S-0041 > BNE $010A P-010A Y-FFFF X-09C2 A-64 B-FF C-90 S-0041 > NOP P-010B Y-FFFF X-09C2 A-64 B-FF C-90 S-0041 > DEX P-010C Y-FFFF X-09C1 A-64 B-FF C-90 S-0041 >T 3 BNE $010A P-010A Y-FFFF X-09C1 A-64 B-FF C-90 S-0041 NOP P-010B Y-FFFF X-09C1 A-64 B-FF C-90 S-0041 DEX P-010C Y-FFFF X-09C0 A-64 B-FF C-90 S-0041 >
The STOPAT command runs code, stopping execution at an address that you specify. Use the following to clear the existing breakpoint and stop execution at $10B.
>br - 0000 0000 0000 0000 >stop 10b P-010C Y-FFFF X-09C0 A-64 B-FF C-90 S-0041 >
While the trace command discussed earlier is useful, you won't always want to step into every subroutine call. Given that Buffalo doesn't have a command to step over subroutine calls, the STOPAT command provides an alternative. Given the address of a following instruction, STOPAT conveniently executes all the intermediate code.
Unfortunately, the STOPAT command executes code slowly. In the case of slow running code, as in a busy-wait delay loop the wait can seem unbearable. In such cases its better to place a break point and then use the PROCEED command to run the intermediate code at full speed. Take a moment to experiment with the STOPAT, breakpoint, and PROCEED commands.
From here on, you can use the proceed command to run the program to completion. In closing, Buffalo provides commands useful in developing applications. While the built in assembler does provide some use, it is not convenient for processing larger programs. In the next part we examine the Motorola assembler and how to down-load S19 files.
This tutorial page was written for EE332, the Introduction to Microprocessors
course offered by the Electrical Engineering Department in the College of
Engineering at the University of Hartford.
Copyright is dated October 18, 2001 and is reserved by the author,
Jonathan Hill.
Permission is granted to make copies of this document for educational use
as-is, provided that this statement remains attached.
I do strive to improve this document, so please forward constructive
criticism for my review along with suggestions.
Credits will be added as improvements are made to this document.
Original Author: Jonathan Hill (jmhill@mail.hartford.edu)
Last Modified: Wed Jun 5 21:09:02 2002 EST