w Sitcom: Projects: Lesson 2
         
One of the SITCOM training computer prototypes
 SITCOM 85 Training Computer
 
 

Lesson 2

Before we continue with lesson 2 I would like to introduce a nifty little feature of most assemblers to you. From now on I'm going to use an include file to initialize Sitcom.
Remember the first couple of lines of practically all programs we've seen so far. They all start by telling the assembler we used an 8085 processor, and we want to send the generated code directly to Comm port 1. Then we continue by declaring some constants regarding the I/O addresses of the 8255 we've used. And finally we used 2 instructions to initialize the 8255 itself.
All these instructions will be present in all the programs that use our basic I/O board with 16 LEDs and 8 push buttons. So why repeating this code in every program over and over again if we have a clever assembler to hand?

 
   

;------------------------------------------------------------------------
;
; INIT01.ASM
;
; Initialise experiments with the basic I/O board
;
;------------------------------------------------------------------------

            .CR   8085            The processor we're using
            .CP   1,9600,N,8,1    SITCOM is connected to COM1
            .TF   COM1:,INT       Send generated code to COM1

;------------------------------------------------------------------------
;
; Constants declarations
;
;------------------------------------------------------------------------

PORTA       .EQ   000H            Port A on the 8255
PORTB       .EQ   001H            Port B on the 8255
PORTC       .EQ   002H            Port C on the 8255
CONTROL     .EQ   003H            Control register of the 8255

;------------------------------------------------------------------------
;
; Initialize the 8255
;
;------------------------------------------------------------------------

START       MVI   A,10001001B      Select outputs for Ports A and B
            OUT   CONTROL          of the 8255, Port C are inputs
 
 

Enter the program above in a separate file and call it INIT01.ASM. From now on we can enter all the code of this program by adding just one single line to our programs using the .IN directive.
The .IN directive stalls the interpretation of the present source file, opens a new file (INIT01.ASM in our case), and starts interpreting that file from top to bottom. Once the included file is completely interpreted, the assembler will return to the original source file and continue to interpret the rest of it.

 
   

            .IN   INIT01          Initialize the assembler
 
 

That is all we need to do from now on to get started with a new program. This serves some interesting purposes:

  • We are lazy, and this saves us some typing.
  • Those of you who use a different Comm port must change the Comm parameters only once.
  • The listings on these pages will be shorter.

But remember: The processor never will know the difference between this approach, and the previous ones. The generated code will be exactly the same in both ways.

It goes without saying that the INIT01.ASM should reside in the same directory as the main source file, otherwise you'll have to specify the include file's path too.

 
 

Chasing LEDs

Try to catch them Let's make a program that shows 2 LEDs chasing each other, from left to right. This is easy enough, and it only involves just one new instruction, which is called RRC.

Here is what the RRC instruction does: It rotates all bits in the Accu from left (MSB) to right (LSB), hence the name Rotate Right. Thus bit 7 is copied to bit 6, bit 6 is copied to bit 5, ...... bit 1 is copied to bit 0, and finally bit 0 is copied to bit 7 again. At the same time bit 0 (the one that falls out of the byte) is copied to the Carry flag. We'll discuss the Carry flag later in this lesson. RRC

Here is the program that does the trick:

 
   

;------------------------------------------------------------------------
;
; LESSON2A.ASM
;
; Chasing LEDs
;
;------------------------------------------------------------------------

            .IN   INIT01           Initialize the assembler

;------------------------------------------------------------------------
;
; Running around in circles
;
;------------------------------------------------------------------------
	
            MVI   A,11111110B      Load the accumulator with bit pattern

CHASE       OUT   PORTA            Output the bit pattern to port A
            OUT   PORTB            Output the bit pattern to port B

            MVI   B,50             Load outer loop counter

DELAY1      MVI   C,250            Load inner loop counter

DELAY2      NOP                    Begin of inner loop
            NOP
            NOP
            NOP
            DCR   C                Decrement inner loop counter
            JNZ   DELAY2           Repeat until loop counter = 0

            DCR   B                Decrement outer loop counter
            JNZ   DELAY1           Repeat until loop counter = 0

            RRC                    Rotate Accu right
            JMP   CHASE            Repeat for ever
 
 

Now, if I tell you that the opposite instruction of RRC is called RLC (Rotate Left), you may figure out yourself how to make the LEDs run the other way. You may even add some more LEDs chasing each other by changing only one value in the program above.

 
 

A lonely LED

So, making the LEDs chase each other is easy enough. Making one LED wander from left to right past all 16 LEDs is a bit more difficult. Let me explain why:

  • Until now the output pattern has always stayed inside the Accu, which was alright in our examples because there was only one pattern to output. Showing only one LED on two different ports involves showing two different patterns, which requires a different approach.
  • The light must walk across all LEDs of port B, while all LEDs of port A remain dark. When the light drops out of port B, it must be handed over to port A. From then on port B must remain dark.
  • When the light eventually falls out of port B the whole process must be repeated.
 
   

;------------------------------------------------------------------------
;
; LESSON2B.ASM
;
; A lonely light walking from left to right across all 16 LEDs
;
;------------------------------------------------------------------------

            .IN   INIT01           Initialize the assembler

;------------------------------------------------------------------------
	
RELOAD      MVI   D,01111111B      Load pattern for port B (left half)
            MVI   E,11111111B      Load pattern for port A (right half)

WALK        MOV   A,E              Output the bit pattern to port A
            OUT   PORTA
            MOV   A,D              Output the bit pattern to port B
            OUT   PORTB

            MVI   B,50             Load outer loop counter

DELAY1      MVI   C,250            Load inner loop counter

DELAY2      NOP                    Begin of inner loop
            NOP
            NOP
            NOP
            DCR   C                Decrement inner loop counter
            JNZ   DELAY2           Repeat until loop counter = 0

            DCR   B                Decrement outer loop counter
            JNZ   DELAY1           Repeat until loop counter = 0

            STC                    Set the carry
            MOV   A,D              Rotate pattern for port B first
            RAR
            MOV   D,A
            MOV   A,E              Then rotate pattern for port A
            RAR
            MOV   E,A

            JC    WALK             Jump if it didn't fall out of port A
            JMP   RELOAD           Otherwise reload the bit patterns
 
 

We start at label RELOAD, where we load the two initial patterns for ports B and A into the registers D and E. There are several ways to store intermediate results, but to avoid too many new things to happen in one program I decided to use two extra internal registers of the 8085. We are going to use the registers B and C again for our delay loop, so we can't use those. Registers D and E will serve our purpose well.

On the line with label WALK we see a new instruction. The MOV instruction moves a value from one register to another. In fact it doesn't move the value, it simply makes a copy of it in the other register. The first register in the operand field is the destination register, while the second operand is the source register.
In this case the contents of register E are copied to register A. We have to make this copy, because we cannot directly send the E register to an output port. Only the Accu can be copied to the output port, which is done in the next line.
Similarly the contents of register D is first copied to register A, and then sent to port B. This solves the problem of the two different values for port A and B.

Then we see our familiar delay loop, creating a delay of about 125 milli seconds.

Before I'm going to explain the next 7 instructions I'm going to introduce the Carry flag to you. We have seen, without knowing it, one of the flags in the flag register in action. It was the Zero flag (have a glance at the software dashboard of lesson 1 if you forgot about the flag register). The Zero flag will be set when the result of the previous math instruction was 0, and the Zero flag will be cleared if the result was not zero. We used the instruction JNZ in the delay loops to test whether the Zero flag was set or not. In this case we only jump if the Zero flag was NOT set. BTW: The JZ instruction would jump if the Zero flag IS set, which means the result of the previous math instruction was 0.
The Carry flag is an other bit in the flag register, and serves as a carry or borrow bit, effectively being a ninth bit of a math instruction. Some math instructions set or clear the Carry flag, depending on the resulting values. Two conditional jump instructions use the status of the Carry flag to decide whether the jump is made or not. The JC instruction will only jump if the Carry was set, while the JNC instruction will only jump if the Carry is cleared.

And now for the instructions that actually make the LEDs walk. First of all the Carry is set with the STC instruction (SeT Carry). I will explain why in a moment.
Then the contents of register D are copied to the Accu again because the Accu is the only register that can be used rotate bytes. After that follows the RAR instruction, which Rotates the contents of the Accu to the right. Here's what the RAR instruction does:

RAR

It differs only a little with the RRC instruction. The bit that falls out of the byte is only copied to the Carry flag, while the Carry flag is copied to bit 7. As a matter fact with the RAR instruction the bits roll "through" the Carry, whereas the RRC instruction lets the bits roll inside the byte. You may consider RAR to be a 9-bit roll, while RRC is an 8-bit roll.
This immediately shows why we had to set the Carry flag two lines ago. That value is copied to bit 7 of the port B pattern, which ensures that it will remain dark as soon as the light falls out of the byte eventually.
Then we have to save the byte back to register D to free the Accu for the next rotate instruction.
The next 3 lines do exactly the same for the pattern of port A, which is retrieved from register E first. Though this time the Carry will not always be set, like in the previous roll. It will be set most of the time, but when the light fell out of the pattern for port B it will be clear. This effectively transfers the light from bit 0 of port B to bit 7 of port A.

Now the light can walk all across the LEDs of port A too. But what if it falls out of port A eventually?
Here's where the JC comes in. As long as the light didn't fall out of port A, the Carry flag will be set at this point, causing the JC instruction to jump back to label WALK. But if the light did fall out of port A, the Carry will be clear, in which case the next JMP instruction will jump back to label RELOAD.
BTW: It is good programming practice to use the most often occuring condition in a program branch like this. Most of the time the Carry will be set, thus we used the JC instruction. We could have used the JNC RELOAD instruction instead, followed by a JMP WALK instruction. That would have worked equally well, but would take longer to execute (not that it matters much in our example).

 
 

Experiment tip:
If I tell you that the opposite instruction of RAR is RAL, you should be able to make the LED walk the other way.
Believe me, it is not just a matter of replacing the two RAR instructions by RAL instructions! Try to make it work the first time, which means you'll have to think things over carefully to avoid all pitfalls.

 
  Continue Lesson 2 - Moving up and down
 
  [Home] [Latest News] [Essentials] [Hardware] [The Build] [Programs] [Projects] [Downloads]
 
  Made in the UK