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
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
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
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