# printnum

A project log for Suite-16

Suite-16 is a 16-bit cpu built entirely from TTL. It is a personal exploration of how hardware and software interact.

monsonite 10/22/2019 at 21:202 Comments

printnum is essential to any computer system. It takes in a 16 bit integer and prints that as a series of ascii characters to the terminal.

My first attempt was very cumbersome - as I am just starting to learn the assembly language, so I tend to go for the brute force and ignorance approach.

The algorithm works by decimation - we know its a 16-bit number with a maximum value of 65535.

Start by subtracting 10,000 until the number is <0

Count the number of times you subtract 10,000. That will give you the most significant digit. Convert this to ascii and output to the terminal.

Restore the remainder and subtract 1000 until you go below 0, that gives the next digit.

Repeat this for 100, 10 and 1.

The code is flawed - as it bombs out with incorrect ascii characters at 42767 (that's 32767 + 10000 - so clearly a big hint).

The whole routine of inline code including CRLF and incrementing counter is 84 words long.

There are 4 repeated sections of 11 instructions that could be converted to a sub-routine.

R3 is set to a value of 48, four times during the routine. it could be done once at the start saving 6 instructions.

(On the MSP430 I got it down to 33 instructions).  More optimisation is possible, and will be done later - but this is a start and proves that I can print out decimal numbers on Suite-16.

Simulating on Various Dev Boards

I have run this code on the MSP430 version of the simulator (clocked at 16 MHz) It takes about 52 seconds to count from 0 to 32768 and output those 5 digits plus CR LF to the screen.

With the simulator running on the 400MHz STM32H743 Nucleo and at 921600 baud the same code for outputting 0 to 32768 is about 3 seconds!

```        0x1000,     // SET R0, 0x0000
0x0000,
0x1100,     // SET R1, 0x2710    10,000
0x2710,

0xB100,     // SUB R0, R1    :10K  addr = 0x04
0x0208,     // BLT 0x08    END10K
0xE200,     // INC R2
0x0004,     // BRA 0004
0x3400,     // Store R0 in R4       addr = 0x08
0x2200,     // END10K    MOV R2, R0
0x1300,     // SET R3, 0x30
0x0030,
0xA300,     // ADD R0, R3 to make a number
0x0C00,     // putchar R0
0x2400,     // Get R0 back from R4
0xA100,     // ADD R1 adds 10,000 to restore R0
0x1100,
0x03E8,     // R1 = 1000
0x1200,     // SET R2,0    Reset R2
0x0000,

0xB100,     // SUB R0, R1    :1K  address 0x14
0x0218,     // BLT 0x18   END1K
0xE200,     // INC R2
0x0014,     // BRA 0x0014
0x3400,     // Store R0 in R4      addr = 0x18
0x2200,     // END1K   MOV R2, R0
0x1300,     // SET R3, 0x30
0x0030,
0xA300,     // ADD R0, R3 to make a number
0x0C00,     // putchar R0
0x2400,     // Get R0 back from R4
0xA100,     // ADD R1 adds 1000 to restore R0
0x1100,
0x0064,     // R1 = 100
0x1200,     // SET R2,0    Reset R2
0x0000,

0xB100,     // SUB AC, R1    :100 addresss 0x24
0x0228,     // BLT 0x28   END100
0xE200,     // INC R2
0x0024,     // BRA 0x0024
0x3400,     // Store R0 in R4       address = 0x28
0x2200,     // END100   MOV R2, R0
0x1300,     // SET R3, 0x30
0x0030,
0xA300,     // ADD R0, R3 to make a number
0x0C00,     // putchar R0
0x2400,     // Get R0 back from R4
0xA100,     // ADD R1 adds 100 to restore R0
0x1100,
0x000A,     // R1 = 10
0x1200,     // SET R2,0    Reset R2
0x0000,

0xB100,     // SUB AC, R1    :10 addresss 0x34
0x0238,     // BLT 0x38   END10
0xE200,     // INC R2
0x0034,     // BRA 0x0034
0x3400,     // Store R0 in R4     addr = 0x38
0x2200,     // END10  MOV R2, R0
0x1300,     // SET R3, 0x30
0x0030,
0xA300,     // ADD R0, R3 to make a number
0x0C00,     // putchar R0
0x2400,     // Get R0 back from R4
0xA100,     // ADD R1 adds 10 to restore R0
0x1100,
0x0001,     // R1 = 1
0x1200,     // SET R2,0    Reset R2
0x0000,

0x1300,     // SET R3, 0x30  address = 0x44
0x0030,
0xA300,     // ADD R0, R3 to make a number
0x0C00,     // putchar R0
0xB300,     // SUB R3 to restore accumulator

0x1000,     // SET R0, CR
0x000D,
0x0C00,     // putchar R0 CR
0x1000,     // Set R0, LF
0x000A,
0x0C00,     // putchar R0 LF

0x1200,     // SET R2,0
0x0000,
0xE500,     // INC R5
0x2500,     // LD R0, R5
0x0002      // BRA 0002```

## Discussions

Marcel van Kervinck wrote 10/23/2019 at 22:15 point

Our Tiny BASIC has a nice trick to emit unsigned decimal above 32767+10000: first check if the number has the high bit set. If so, initialise the first digit with '3' instead of '0', and subtract 30000. From there on, we're back in unsigned land and can run the normal algorithm.

09b2  59 00                    LDI   0                  Zero
09b4  2b 42                    STW   \$42
09b6  21 3a                    LDW   \$3a
09b8  35 53 c4                 BGE   \$09c6              Branch if high bit clear
09bb  11 d0 8a                 LDWI  \$8ad0              Minus 30,000
09be  99 3a                    ADDW  \$3a
09c0  2b 3a                    STW   \$3a
09c2  59 03                    LDI   3                  Leading zero becomes 3
09c4  2b 42                    STW   \$42
09c6  11 10 27                 LDWI  \$2710             The 10,000 to subtract. etcetera

Are you sure? yes | no

Ken Yap wrote 10/23/2019 at 20:54 point

You might like to see if the double dabble algorithm (https://en.wikipedia.org/wiki/Double_dabble) can be implemented efficiently on suite-16 (does the instruction set have shifts?). Once you have the BCD representation of the integer, it's trivial to convert to printable digits.

Are you sure? yes | no