# Computer Architecture Lab/Winter2007/SHWH/Assembler description

## Tante Emma Assembler

Version 1.3

### Assembler Usage

First of all, include your .asm file in TanteEmmaAsmProject.h (For example #include "myFirstAsmFile.asm"). Then you should compile the assembler project with "make all". This is already successfully tested under Windows XP and Linux. If you have already written your assembler file, for example named "myFirstAsmFile.asm", call TanteEmmaAsm myFirstAsmFile to get the binary input file for the processor.

### Assembler Syntax

Our assembler does instructionword generation very simple. We use simple C Makros to define our Instruction set. So the assembler syntax is different to other ones:

```//a Comment
```
• Redifining Registers
```#define EXAMPLE_REG	R0
```
• defining integer constants
```#define MY_CONSTANT	100
```
• defining hex constants
```#define MY_CONSTANT 0xAA
```
• load immedate low and high

when loading immedaite low, the processor does sign extention, so a signed immediate can be loaded in one cycle

```LDIL(R1,-100) //load a signed immedate within one cycle

LDIL(R2,0xAA) //load unsigned immedate as hex value
LDIH(R2,0x01) //load the upper byte into the register
```
• Add two Registers
```ADD(Rx,Ry)	//Rx = Rx + Ry
```
• Add with carry
```ADC(Rx,Ry)	//Rx = Rx + Ry + C
```
• Sub
```SUB(Rx,Ry)	//Rx = Rx - Ry
```
• Sub with carry
```SBC(Rx,Ry)	//Rx = Rx - Ry - C
```
• And
```AND(Rx,Ry)	//Rx = Rx and Ry
```
• or
```OR(Rx,Ry)	//Rx = Rx or Ry
```
• xor
```XOR(Rx,Ry)	//Rx = Rx xor Ry
```
• shift left
```SHL(Rx)
```
• shift right
```SHR(Rx)
```
• arithmic shift right
```ASR(Rx)
```
• Rotate left through carry
```ROL(Rx)
```
• Rotate right through carry
```ROR(Rx)
```
• 2th Complement
```NEG(Rx)
```
• Increment Register x
```INC(Rx)
```
• Decrement Register x
```DEC(Rx)
```
• Clear Register x
```CLR(Rx)
```
• Set Register x
```SET(Rx)
```
• Call procedure at ProgrammCounter(PC) x

Before we can call the prozedure, we have to load the PC value into a Regiser

```LDIL(R1,0xF0)
LDIH(R1,0x00)
...
CALL(R1)
```
• Jump
```Jump to the Programm address which is saved in Register x
```
```JUMP(Rx)
```
• Return from Procedure Call
```RET()
```
• Compare two registers

the operation will manipulate the zero, less and greater flag. You can use this instruction in combination with the branch instructions.

```CMP(Rx,Ry)
BR..(..)
```
• Compare two registers

if the two registers are equal than skip the next instruction

```CMPSKIP(Rx,Ry)
...	//jump here if false
...	//jump here if true

```
• Branch if zero
```BRZ(6)		//Branch PC + 6
BRZ(-4)		//Branch PC - 4
BRZ(0x04)	//Branch with hex value
```
• Branch if not zero
```BRNZ(-6)
```
• Branch if less
```BRL(-6)
```
• Branch if not less
```BRNL(-6)
```
• Branch if greater
```BRG(-6)
```
• Branch if not greater
```BRNG(-6)
```
• Move Reg y to Reg x
```MOV(Rx,Ry) Rx = Ry
```
• Load from Memory
```the load is Register Direct, so the memory address is saved in Register z
```
```LDIL(Rz,0x0F)
LD(Rx,Rz) //Rx = (Rz)
```
• Store to Memory
```ST(Rz,Rx)	//(Rz) = Rx, in Rz the memory address is saved
```
• In from I/O
```IN(Rx,Rz)	//Rx = [Rz], in Rz the pin number is saved
```
• OUT to I/O
```OUT(Rx,Rz)	//[Rz] = Rx, in Rz the pin number is saved
```
• No operation
```NOP()
```

### Example Assembler Code

• Fast Blinking Led
```#define LED_PIN_NR	166

LDIL( R4, LED_PIN_NR)
LDIH( R4, 0)
LDIL( R5, 0xFF)

LDIL( R2, 0xFF)
LDIL( R1, 0xFF)
DEC( R1)
BRNZ( -2)
DEC( R2)
BRNZ( -2)
XOR( R3, R5)
OUT( R3, R4)
AND( R0, R0)
BRZ( -10)

NOP()
NOP()
NOP()
```

• Hello World

This program sends Hello World to the console.

```//DemoProgramm für CA
//Hello World
//Write Hallo World to the console

#define REG_UART_TX_RX_NR		R2
#define UART_TX_NR				178
#define UART_RX_NR				153

#define A_H	0x48
#define A_e	0x65
#define A_l	0x6C
#define A_o	0x6F
#define A_W	0x57
#define A_r	0x72
#define A_d	0x64
#define SPACE	0x20
#define LF	0x0A

LDIL(REG_UART_TX_RX_NR,UART_TX_NR)
LDIH(REG_UART_TX_RX_NR,0)

LDIL(R1,A_H)
LDIH(R1,0)
NOP()
OUT(R1,REG_UART_TX_RX_NR)

LDIL(R1,A_e)
LDIH(R1,0)
NOP()
OUT(R1,REG_UART_TX_RX_NR)

LDIL(R1,A_l)
LDIH(R1,0)
NOP()
OUT(R1,REG_UART_TX_RX_NR)

LDIL(R1,A_l)
LDIH(R1,0)
NOP()
OUT(R1,REG_UART_TX_RX_NR)

LDIL(R1,A_o)
LDIH(R1,0)
NOP()
OUT(R1,REG_UART_TX_RX_NR)

LDIL(R1,SPACE)
LDIH(R1,0)
NOP()
OUT(R1,REG_UART_TX_RX_NR)

LDIL(R1,A_W)
LDIH(R1,0)
NOP()
OUT(R1,REG_UART_TX_RX_NR)

LDIL(R1,A_o)
LDIH(R1,0)
NOP()
OUT(R1,REG_UART_TX_RX_NR)

LDIL(R1,A_r)
LDIH(R1,0)
NOP()
OUT(R1,REG_UART_TX_RX_NR)

LDIL(R1,A_l)
LDIH(R1,0)
NOP()
OUT(R1,REG_UART_TX_RX_NR)

LDIL(R1,A_d)
LDIH(R1,0)
NOP()
OUT(R1,REG_UART_TX_RX_NR)

NOP()
BRNZ(-1) //endless loop
NOP()

```

• Reverse Text

Here is an example code which is receiving x bytes from UART. When the Programm receives a LF then the programm returns the received String in reverse Order.

```//DemoProgramm für CA
//Reverse Text

#define REG_UART_TX_RX_NR		R1
#define UART_TX_NR				178
#define UART_RX_NR				153

#define LED_PIN_NR	166

#define REG_IN_ALPHA			R2
#define REG_LF					R4

#define A_W	0x57
#define LF	0x0A

LDIL(REG_LF,LF)
LDIH(REG_LF,0)

LDIL(REG_UART_TX_RX_NR, UART_RX_NR)
LDIH(REG_UART_TX_RX_NR,0)

//label RX
NOP()
IN(REG_IN_ALPHA,REG_UART_TX_RX_NR)
NOP()
CMP(REG_IN_ALPHA,REG_LF) //when we receive a LF Rx is over
BRNZ(-7)

//switch led on begin
LDIL(R13,LED_PIN_NR)
LDIH(R13,0)
LDIL(R14,1)
OUT(R14,R13)
//switch led on end

//switch UART to Send
LDIL(REG_UART_TX_RX_NR, UART_TX_NR)
LDIH(REG_UART_TX_RX_NR,0)

//switch to the last alpha unequl to \n

//label TX

NOP()
NOP()
NOP()
OUT(REG_IN_ALPHA,REG_UART_TX_RX_NR)
BRNZ(-7)

//send last alpha
NOP()
OUT(REG_IN_ALPHA,REG_UART_TX_RX_NR)

CMP(R0,R0)
NOP()

```
• Add two 16 bit Numbers
```//DemoProgramm für CA
//Multipliation of 2 16 bit values

#define REG_UART_TX_RX_NR		R8
#define UART_TX_NR				178
#define UART_RX_NR				153

#define REG_UART_TX_NR  R8

#define LED_PIN_NR      166

#define REG_PRODUCT_H   R1
#define REG_PRODUCT_L   R2

#define REG_FACTOR1     R3
#define FACTOR1_H       0xFF
#define FACTOR1_L       0xFF

#define REG_FACTOR2     R4
#define FACTOR2_H       0xFF
#define FACTOR2_L       0xFF

#define REG_COUNTER     R9

#define REG_SHIFT       R10
#define CNT_SHIFT       8

#define REG_SEND        R11
#define HELP			R12
#define STOP 			R13
#define COUNT1			R14
#define COUNT2			R14

LDIL(REG_SHIFT,CNT_SHIFT)

LDIL(REG_UART_TX_NR,UART_TX_NR)
LDIH(REG_UART_TX_NR,0)

LDIL(REG_PRODUCT_H,0)
LDIH(REG_PRODUCT_H,0)
LDIL(REG_PRODUCT_L,0)
LDIH(REG_PRODUCT_L,0)

LDIL(REG_COUNTER,0x00)
LDIH(REG_COUNTER,0x00)

LDIL(REG_FACTOR1,FACTOR1_L)
LDIH(REG_FACTOR1,FACTOR1_H)

LDIL(REG_FACTOR2,FACTOR2_L)
LDIH(REG_FACTOR2,FACTOR2_H)

// ************************** main ***********************
LDIL(STOP,0x0A)
LDIH(STOP,0)
CLR(COUNT1)

LDIL(REG_UART_TX_RX_NR,153)
LDIH(REG_UART_TX_RX_NR,0)

IN(HELP, REG_UART_TX_RX_NR)
LDIH(HELP,0)
NOP()
ST(COUNT1, HELP)
NOP()
INC(COUNT1)
CMP(HELP, STOP)
BRNZ(-8)//39

DEC(COUNT1) //remove Line feed
MOV(COUNT2,COUNT1)
IN(HELP, REG_UART_TX_RX_NR)
LDIH(HELP,0)
NOP()
ST(COUNT2, HELP)
NOP()
INC(COUNT2)
CMP(HELP, STOP)
BRNZ(-8)//39

LDIL(REG_SHIFT,CNT_SHIFT)
CLR(COUNT1)
LD(HELP,COUNT1)
NOP()

DEC(REG_SHIFT)
SHL(HELP)
CMP(REG_SHIFT,R0)
BRNZ(-4)
NOP()
INC(COUNT1)
LD(REG_FACTOR1,COUNT1)
NOP()

LDIL(REG_SHIFT,CNT_SHIFT)
INC(COUNT1)
LD(HELP,COUNT1)
CMP(0,0)
NOP()

DEC(REG_SHIFT)
SHL(HELP)
CMP(REG_SHIFT,R0)
BRNZ(-4)
NOP()
INC(COUNT1)
LD(REG_FACTOR2,COUNT1)
CMP(0,0)
NOP()

LDIL(REG_UART_TX_RX_NR,178)
LDIH(REG_UART_TX_RX_NR,0)

/*
MOV(REG_SEND,REG_FACTOR1)
OUT(REG_SEND,REG_UART_TX_NR)
NOP()
MOV(REG_SEND,REG_FACTOR2)
NOP()
OUT(REG_SEND,REG_UART_TX_NR)
NOP()*/

MOV(REG_PRODUCT_L,REG_FACTOR1)
//carry auf Produkt High übertragen

CLR(REG_FACTOR2)
CLR(REG_FACTOR1)

//send high byte high but before shift right 8 times
NOP()
MOV(REG_SEND,REG_PRODUCT_H)
LDIL(REG_SHIFT,CNT_SHIFT)

DEC(REG_SHIFT)
SHR(REG_SEND)
CMP(REG_SHIFT,R0)
BRNZ(-4)
NOP()
OUT(REG_SEND,REG_UART_TX_NR)

NOP()
MOV(REG_SEND,REG_PRODUCT_H)
//send high byte low
NOP()
OUT(REG_SEND,REG_UART_TX_NR)
NOP()

//send low byte high but before shift right 8 times
NOP()
MOV(REG_SEND,REG_PRODUCT_L)
LDIL(REG_SHIFT,CNT_SHIFT)

DEC(REG_SHIFT)
SHR(REG_SEND)
CMP(REG_SHIFT,R0)
BRNZ(-4)
NOP()
OUT(REG_SEND,REG_UART_TX_NR)

NOP()
MOV(REG_SEND,REG_PRODUCT_L)
//send low byte low
NOP()
OUT(REG_SEND,REG_UART_TX_NR)

//label endless loop
CMP(0,0)
NOP()
NOP()
NOP()
JUMP(0)
NOP()
NOP()
//CMP(R0,R0)
//BRZ(-2)

```
• Mulitply two 16 bit Numbers
```//DemoProgramm für CA
//Multipliation of 2 16 bit values

#define REG_UART_TX_NR	R8
#define UART_TX_NR	178
#define UART_RX_NR	153
#define LED_PIN_NR	166

#define REG_PRODUCT_H	R1
#define REG_PRODUCT_L	R2

#define REG_FACTOR1	R3
#define FACTOR1_H	0xAA
#define FACTOR1_L	0xAA

#define REG_FACTOR2	R4
#define FACTOR2_H	0x00
#define FACTOR2_L	0x02

#define REG_COUNTER	R9

#define REG_SHIFT	R10
#define CNT_SHIFT	8

#define REG_SEND	R11

// begin of Program

LDIL(REG_PRODUCT_H,0)
LDIH(REG_PRODUCT_H,0)
LDIL(REG_PRODUCT_L,0)
LDIH(REG_PRODUCT_L,0)

LDIL(REG_COUNTER,0x00)
LDIH(REG_COUNTER,0x00)

LDIL(REG_UART_TX_NR,UART_RX_NR)
LDIH(REG_UART_TX_NR,0)

//receive Factor1, high Byte
LDIL(REG_SHIFT,CNT_SHIFT)
NOP()
DEC(REG_SHIFT)
CMP(REG_SHIFT,R0)
BRNZ(-4)

//receive Factor1, low Byte
NOP()
IN(REG_FACTOR1,REG_UART_TX_NR)
NOP()

//receive Factor2, high Byte
LDIL(REG_SHIFT,CNT_SHIFT)
NOP()
DEC(REG_SHIFT)
CMP(REG_SHIFT,R0)
BRNZ(-4)

//receive Factor2, low Byte
NOP()
IN(REG_FACTOR2,REG_UART_TX_NR)
NOP()

// ************************** multiplication *************

//label: mul loop
INC(REG_COUNTER)

//carry auf Produkt High übertragen

CMP(REG_COUNTER,REG_FACTOR2)
BRNZ(-5)

LDIL(REG_UART_TX_NR,UART_TX_NR)
LDIH(REG_UART_TX_NR,0)

//send high byte high but before shift right 8 times
NOP()
MOV(REG_SEND,REG_PRODUCT_H)
LDIL(REG_SHIFT,CNT_SHIFT)

DEC(REG_SHIFT)
SHR(REG_SEND)
CMP(REG_SHIFT,R0)
BRNZ(-4)
NOP()
OUT(REG_SEND,REG_UART_TX_NR)

NOP()
MOV(REG_SEND,REG_PRODUCT_H)
//send high byte low
NOP()
OUT(REG_SEND,REG_UART_TX_NR)

//send low byte high but before shift right 8 times
NOP()
MOV(REG_SEND,REG_PRODUCT_L)
LDIL(REG_SHIFT,CNT_SHIFT)

DEC(REG_SHIFT)
SHR(REG_SEND)
CMP(REG_SHIFT,R0)
BRNZ(-4)
NOP()
NOP()
OUT(REG_SEND,REG_UART_TX_NR)

NOP()
MOV(REG_SEND,REG_PRODUCT_L)
//send low byte low
NOP()
OUT(REG_SEND,REG_UART_TX_NR)

//label endless loop
CMP(R0,R0)
BRZ(-66)
```
• Bubble Sort

You can send 8bit numbers to the processor via Uart, finish your input with LF (line feed ). The processor will return the these numbers in ascending order. (UART Settings: 115200 8N1)

```//Bubblesort
//Bubblesort

#define REG_UART_TX_RX_NR		R2
#define UART_TX_NR				178
#define UART_RX_NR				153

#define STOP R10
#define SORT1 R11
#define SORT2 R12
#define SORT3 R13
#define SORT4 R14
#define SORT5 R15
#define LENGTH R6
#define COUNT1 R10
#define COUNT2 R9
#define HELP R8
#define SPRUNG1 R7
#define BOOLV R5
#define NULLV R4

CLR(NULLV)
CLR(BOOLV)
LDIL(LENGTH,5)
LDIL(SORT1,43)
LDIL(SORT2,7)
LDIL(SORT3,41)
LDIL(SORT4,12)
LDIL(SORT5,42)
CLR(COUNT1)
ST(COUNT1,SORT1)
INC(COUNT1)
ST(COUNT1,SORT2)
INC(COUNT1)
ST(COUNT1,SORT3)
INC(COUNT1)
ST(COUNT1,SORT4)
INC(COUNT1)
ST(COUNT1,SORT5)
CLR(COUNT1)
CLR(COUNT2)
INC(COUNT2)
LDIL(SPRUNG1,22)

//Label: 22
CLR(BOOLV)
LD(SORT1,COUNT1)
LD(SORT2,COUNT2)
CMP(SORT1,SORT2)
BRL(3) //wenn gleich überspringe Vertauschen
ST(COUNT1,SORT2)
ST(COUNT2,SORT1)
SET(BOOLV)
//Label 30 BRL Sprung
INC(COUNT1)
INC(COUNT2)
CMPSKIP(COUNT2,LENGTH) //Schleifenende erreich??
JUMP(SPRUNG1) //SchleifenEnde innerste
CLR(COUNT1)
CLR(COUNT2)
INC(COUNT2)
DEC(LENGTH)
CMPSKIP(NULLV,BOOLV)
JUMP(SPRUNG1)

LDIL(REG_UART_TX_RX_NR,178)
LDIH(REG_UART_TX_RX_NR,0)
CLR(COUNT1)
INC(COUNT1)
//LDIL(SORT1,0x0F) //Debug
LD(SORT1,COUNT1)
OUT(SORT1,REG_UART_TX_RX_NR)
INC(COUNT1)
//LDIL(SORT1,0x1F) //Debug
LD(SORT1,COUNT1)
OUT(SORT1,REG_UART_TX_RX_NR)
INC(COUNT1)
//LDIL(SORT1,0x2F) //Debug
LD(SORT1,COUNT1)
OUT(SORT1,REG_UART_TX_RX_NR)
INC(COUNT1)
//LDIL(SORT1,0x3F) //Debug
LD(SORT1,COUNT1)
OUT(SORT1,REG_UART_TX_RX_NR)
INC(COUNT1)
//LDIL(SORT1,0x4F) //Debug
LD(SORT1,COUNT1)
OUT(SORT1,REG_UART_TX_RX_NR)

/*
LDIL(REG_UART_TX_RX_NR,153)
LDIH(REG_UART_TX_RX_NR,0)
LDIL(STOP,0x20)
LDIH(STOP,0)
CLR(COUNT1)*/

/*IN(SORT1, REG_UART_TX_RX_NR)
ST(COUNT1, SORT1)
NOP()
INC(POINTER)