Close

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.

monsonitemonsonite 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