Jump to content
IGNORED

Simon (game) in assembly language


Dexter

Recommended Posts

Setting R1 to 0xe100 may be what you need i.e., "LI R1,>E100"

I hope that I keep remembering now, everything works out OK when working with words. I have to get used to the byte commands.
This part of the problem is solved now.

 

You have to set 8 bytes of the color table for every character.

Of course, you’re right.

 

After correcting that, it almost works out fine. Thanks to both of you!

 

The graphics are converted with Magellan, a fantastic tool, but on some bytes it pick background color and pixel color reversed. Mostly I have two colors in one character. While importing, Magellan doesn’t know which color of the two is background or pixels, so it probably picks them randomly.
To get that right, I have to correct each “reversed” character by hand. Or is there an easier way?
Link to comment
Share on other sites

 

The graphics are converted with Magellan, a fantastic tool, but on some bytes it pick background color and pixel color reversed. Mostly I have two colors in one character. While importing, Magellan doesn’t know which color of the two is background or pixels, so it probably picks them randomly.
To get that right, I have to correct each “reversed” character by hand. Or is there an easier way?

 

 

Try setting the screen background color before you import as a hint to indicate the desired background color.

 

If the above doesn't work try holding shift when you press the invert button for individual characters. This when swap background and foreground but not change the colors.

Link to comment
Share on other sites

  • 2 weeks later...

 

Try setting the screen background color before you import as a hint to indicate the desired background color.

 

 

Of course that worked out fine! Now I have the values as they should be.

 

Finally I have sort of a playable version!

After starting the game “S”, respond with the keys 1, 2, 3 or 4.

A wrong key press responds with altering 2 and 3 continuously.

Waiting longer than 5 seconds, responds with the sequence 4, 3, 2, 1.

The game auto starts with the XB Cartridge.

 

Of course it comes with a free bug. :)

 

runme.dsk

simon.a99

tiplayer.a99

simon3.vgm.a99

  • Like 4
Link to comment
Share on other sites

Well done. Great to see more assembly games being developed.

Hmm, not well enough. The input routines were pretty messed up. But this version should play fine, without bugs.

 

This time, a wrong key press actually DOES responds with altering 2 and 3 continuously.
Waiting longer than 5 seconds, responds with the sequence 4, 3, 2, 1.
Gameplay is also slightly faster.
The game auto starts with the XB Cartridge.
Edited by Dexter
  • Like 2
Link to comment
Share on other sites

The battle goes on:

 

I’m trying to display the score on the screen by two digits. Which pretty much looks like this:

post-41771-0-52030700-1436210818_thumb.png

 

I’m not proud of the code, but by trial and error I got it half working. Up and till 09 the score is displayed as it should. At 10 it goes wrong.

post-41771-0-69248000-1436210819_thumb.png

The code is really horrible, I know, and there has to be a much simpler solution. I’m not looking to fix this code, but for an entire different solution.

 

 

 

rndnum DATA >0000             * round number

*      Routine to display a score at >3910 and >3911
*      Score is 2 decimal digits from 00 to 99.
*      @rndnum will hold the round number i.e. the score.
*      Character number for '0' begins at 212 (>D4) and ends with '9' at 221

*                             * round number 10 digit
       mov @rndnum,r5         * move round number into r5
       ai r5,-1
       clr r4                 * r4 and r5 contains >000000xx round number in hex
       li r6,10               * r6 contains decimal 10
       div r6,r4              * left most digit of round number in r4

       ai r4,>d4              * add >d3 to show the result as ascii char
       li r0,>3910            * at the desired location
       mov r4,r1              * 
       swpb r1                * 
       bl @vsbw               * print on screen

*                             * round number 1 digit
       mov @rndnum,r5
       ai r5,>d3
       li r0,>3911
       mov r5,r1
       swpb r1
       bl @vsbw

 

 

  • Like 1
Link to comment
Share on other sites

Don't worry about regrets, you are learning and all will work out in the end as your understanding grows. I am just getting into software development with C# and SQL and I just got called in today for filling out paperwork for a job offer if my background check and drug test support it. I don't know near what I would like to know but I to am learning, just glad I had a little bit of TI basic and assembler programming under my belt, even though it was almost 20 years ago.

Link to comment
Share on other sites

Look at

 

Look at the DIV command and where it stuffs the remainder and the quotient. Then review which values you are trying to display. ;)

 

Thanks, beautiful, that works great. I obviously forgot about the remainder. Even the code doesn’t look bad now.

If it were 3 digits, I’d have to divide through 100. I’d have the 100’s in r4. The other two digits should be done with what's in r5, and used in my current routine:


*********************************************************************
*
*      Routine to display a score at >3910 and >3911
*      Score is 2 decimal digits from 00 to 99.
*      @rndnum will hold the round number i.e. the score.
*      Character number for '0' begins at 212 (>D4) and ends with '9' at 221
*

shwrn

       MOV  R11,*R10+         * Push return address onto the stack
       mov @rndnum,r5         * move round number into r5

       ai r5,-1               * Start from 0 instead of 1
       clr r4                 * r4 and r5 contains >000000xx round number in hex
       li r6,10               * r6 contains decimal 10
       div r6,r4              * Quotient in r4 and Remainder in r5

       ai r4,>d4              * add >d4 to show the result as ascii character
       li r0,>3910            * line 8 position 15
       mov r4,r1              * move the 10's digit to r1
       swpb r1                * prepare for vsbw
       bl @vsbw               * print on screen

       ai r5,>d4              * add >d4 to show the result as ascii character
       li r0,>3911            * line 8 position 16
       mov r5,r1              * move the 1's digit to r1
       swpb r1                * prepare for vsbw
       bl @vsbw               * print on screen

Don't worry about regrets, you are learning and all will work out in the end as your understanding grows. I am just getting into software development with C# and SQL and I just got called in today for filling out paperwork for a job offer if my background check and drug test support it. I don't know near what I would like to know but I to am learning, just glad I had a little bit of TI basic and assembler programming under my belt, even though it was almost 20 years ago.

 

That’s true, no regrets, the code is now good enough to show. :)

Indeed, it’s good to have a little bit of programming “background” when you start learning a new language.

In general, coding for the TI is pretty intuitive and rewarding. I’m enjoying it!

  • Like 1
Link to comment
Share on other sites

No. For three digits you don't divide by 100. You divide by 10 each time in a loop and display the remainder. So for 123:

 

123 / 10 = 12 remainder 3. Display the 3

12 / 10 = 1 remainder 2. Display the 2

1 / 10 = 0 remainder 1. Display the 1

 

So you are displaying digits from the right and moving left.

 

HTH

  • Like 1
Link to comment
Share on other sites

No. For three digits you don't divide by 100. You divide by 10 each time in a loop and display the remainder. So for 123:

 

123 / 10 = 12 remainder 3. Display the 3

12 / 10 = 1 remainder 2. Display the 2

1 / 10 = 0 remainder 1. Display the 1

 

So you are displaying digits from the right and moving left.

 

HTH

Thanks for the idea, makes perfectly sense! Tried it with some different and bigger numbers too.

Link to comment
Share on other sites

The only thing, with this method you have to set up a new VDP address for each digit, or store the result in a buffer first. It's quite easy to set up a list of divisors: 10000, 1000, 100, 10, keep a pointer to the list in a register, say R3, and divide the remainder from last time by *R3+.

 

Edit: This is just an example copied from one of my demos and is not meant to be a generic routine. To send directly to VDP R0 should contain VDPWD and *R4+ should be replaced by *R4.

*********************************************************************
*
* Display decimal number
*
* R0 contains the write address
* R1 contains the number to display
*
DSPNUM MOV    R11,*R10+            * Push return address onto the stack
       MOV    R0,R4
       LI     R2,4                 * Counter
       LI     R3,DIVS              * Pointer to list of divisors
*      Leading zeros loop
DSPNU0 CLR    R0                   * Clear high word of dividend
       DIV    *R3+,R0              * Divide to get digit
       MOV    R0,R0                * Check quotient
       JNE    DSPNU2               * Display digit if not zero
       DEC    R2                   * Count down
       JNE    DSPNU0               * Leading zeros loop
       JMP    DSPNU3
*      Digit loop
DSPNU1 CLR    R0                   * Clear high word of dividend
       DIV    *R3+,R0              * Divide to get digit
DSPNU2 AI     R0,48                * Add ASCII code for zero
       SWPB   R0                   * Swap to high byte
       MOVB   R0,*R4+              * Display digit
       DEC    R2                   * Count down
       JNE    DSPNU1               * Digit loop
*      Last digit
DSPNU3 AI     R1,48                * Add ASCII code for zero to remainder
       SWPB   R1                   * Swap to high byte
       MOVB   R1,*R4+              * Display last digit
*      Return
       DECT R10                    * Pop return address off the stack
       MOV   *R10,R11
       B     *R11
DIVS   DATA 10000,1000,100,10
*// DSPNUM
  • Like 1
Link to comment
Share on other sites

For some reason, in programming we are all trained to save space, but rarely to waste space in order to save time. One interesting example where I noticed this is CRC calculation, which can be pretty fast when it uses a prepared table of values.

  • Like 1
Link to comment
Share on other sites

You're right too, Rasmus. I've always (always!) just done each division separately and explicitly (or in a few cases, just used BCD so I could shift and mask instead). I'd certainly use a buffer for the backwards counting loop, you'll make up the 5 bytes needed for buffer many times over when you write to the VDP sequentially. ;)

Link to comment
Share on other sites

The only thing, with this method you have to set up a new VDP address for each digit, or store the result in a buffer first. It's quite easy to set up a list of divisors: 10000, 1000, 100, 10, keep a pointer to the list in a register, say R3, and divide the remainder from last time by *R3+.

 

Edit: This is just an example copied from one of my demos and is not meant to be a generic routine. To send directly to VDP R0 should contain VDPWD and *R4+ should be replaced by *R4.

 

Indeed. I was just keeping it simple ;)

 

TurboForth uses a nice routine that I wrote that uses that technique. The code below can convert a number to a string in any number base from 2 to 36, signed or unsigned, with leading zeros or without. As you mentioned, it computes the divisors. However, it's a little clever. If, when calling the routine, you are converting a number in the same base as you did in the previous call, then it doesn't re-compute the divisors. That saves quite a lot of cycles.

 

This could easily be converted to general use. If anyone is interested in a general use subroutine then let me know and I'll convert it into a stand-alone BL routine or something similar.

 

 

; NUMBER TO STRING ( num -- addr len )
; Takes a number off the stack and converts it to a signed string equivalent,
; with respect to the current number base. Number base may be between
; 2 and 36. The routine checks location DOSIGN, and if 0, the
; number is treated as signed, else its unsigned. The routine also checks
; location LZI, and, if zero, leading zero's will be supressed.
; This is quite a bitch of a routine. Since any number base (between 2 and 36)
; can be employed this routine is rather complex. The routine must first
; determine the appropriate powers of the number base so we can divide the
; target number later. Obviously this is expensive, so the routine remembers
; what the active number base was the last time it was called, and ONLY
; re-computes the exponents if the base has changed since the last time it was
; called.
; This first part computes the column values.
; So, if the base is 10, you end up with 1,10,100,1000,10000
_nts    mov rstack,r14              ; save rstack 'cos we're using it
        mov *stack,r9               ; get number off stack 
        li r7,2                     ; exponent counter (base^0 and base^1 are
                                    ; easy to compute 
                                    ; used as a word offset into workbuffer so
                                    ; counts in multiples of 2.
        c @base,@lbase              ; check if base has chaged since the last
                                    ; time we were called
        jeq dodiv                   ; base hasn't changed, no need to compute
                                    ; powers of the base.
        mov @base,@lbase            ; base has changed, store it in 'last base'
        li r0,1                     ; base^0 is always 1 - easy 
        li r1,wrkbuf                ; place to store the powers of our base
    ; determine base^x until result > 65535
        mov r0,*r1+                 ; store base^0 and move forward in buffer
        mov @base,*r1               ; base^1 is always base  store it
pwr     mov *r1+,r5                 ; get previous exponent
        mpy @base,r5                ; multiply it by base - lower 16 bit result
                                    ; in r6
        mov r5,r5                   ; see if the result overflowed into upper
                                    ; 16 bits
        jne pwrout                  ; there was an overflow, exit loop
        mov r6,*r1                  ; otherwise store result
        inct r7                     ; and increment exponent counter
        jmp pwr                     ; and repeat
    ; Ok we have computed the 'column values' (powers) for our base. Now we
    ; sucessively divide the number down until nothing is left, building
    ; the string equivalent as we compute each digit. Just to make life
    ; harder for ourselves, we will optionally allow leading zero's to be
    ; supressed. If the word at LZI<>0 then leading zero's are suppressed.
pwrout  mov r7,@expcnt              ; save exponent count for next time routine
                                    ; is run
dodiv   mov @expcnt,r7              ; entry point when exponents arent computed.
                                    ; restore exponent count
        li r0,strbuf                ; address of string buffer where we build
                                    ; the string
        clr r1                      ; buffer length counter
        mov @dosign,r8              ; check if producing an unsigned number
        jne ninn                    ; skip if we are
        mov r9,r8                   ; else, check if number is negative and if
                                    ; so, add "-" character
        andi r8,>8000               ; is it negative
        jeq ninn                    ; its not negative, jump
        li r8,'-'*256               ; the number is negative, add a minus sign
                                    ; to the string buffer
        movb r8,*r0+                ; place it in the buffer
        inc r1                      ; increment length counter
        neg r9                      ; change the number to positive
ninn    clr r8                      ; div instruction uses 32 bit dividend, our
                                    ; 16 bit argument is in r9
        mov @lzi,r10                ; leading zero indicator 0=suppress
nxtdig  div @wrkbuf(r7),r8          ; divide our number by exponent value.
                                    ; result=r8, remainder=r9
        mov r8,r8                   ; was the result 0?
        jeq testlz                  ; if yes then check if ignoring leading
                                    ; zeros
        seto r10                    ; not zero, so reset leading zero indicator
dodig   movb @tlut(r8),*r0+         ; lookup digit value, move it to string
                                    ; buffer and advance buffer address
        clr r8                      ; clear result for next interation
        inc r1                      ; increment length counter
iglz    dect r7                     ; done all our columns/exponents?
        jne nxtdig                  ; loop if not
        movb @tlut(r9),*r0+         ; lookup digit value, move it to string
                                    ; buffer and advance buffer address
    ; we've done our division, push address & length to the stack and exit
        li r0,strbuf                ; address of string buffer
        mov r0,*stack               ; move address to stack
        dect stack                  ; new stack entry
        inc r1                      ; adjust length for remainder
        mov r1,*stack               ; move length to stack
        mov r14,rstack              ; restore return stack pointer
        b @retB0
    ; we're looking for leading zero's and ignoring them
testlz  mov r10,r10                 ; are we ignoring leading zero's?
        jeq iglz                    ; 0=ignore leading digit
        jmp dodig                   ; else do digit normally
    ; character lookup table for printing numbers between bases 2 to 36
tlut    text '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
Link to comment
Share on other sites

For some reason, in programming we are all trained to save space, but rarely to waste space in order to save time. One interesting example where I noticed this is CRC calculation, which can be pretty fast when it uses a prepared table of values.

 

If displaying the score was time critical, I could set it up with a look up table.

*********************************************************************
*
* Routine to display a score at >3910 and >3911
* Score is 2 decimal digits from 00 to 99.
* @rndnum will hold the round number i.e. the score.
* Character number for '0' begins at 212 (>D4) and ends with '9' at 221
*
* VMBW VDP Multiple Byte Write
* R0   Starting write address in VDP RAM
* R1   Starting read address in CPU RAM
* R2   Number of bytes to send to the VDP RAM
*
shwrn
       MOV  R11,*R10+         * Push return address onto the stack

       mov  @rndnum,r5        * move round number into r5
       ai   r5,-1             * Start from 0 instead of 1
       sla  r5,1              * index for bytes to look up
       li   r0,>3910          * line 8 position 15
       li   r2,2              * 2 bytes to transfer

*      part of VMBW
       MOVB @R0LB,@VDPWA      * Send low byte of VDP RAM write address
       ORI  R0,>4000          * Set read/write bits 14 and 15 to write (01)
       MOVB R0,@VDPWA         * Send high byte of VDP RAM write address

shwrn1 MOVB @scco(r5),@VDPWD  * Write byte to VDP RAM
       DEC  R2                * Byte counter
       JNE  shwrn1            * Check if done

       DECT R10               * Pop return address off the stack
       MOV  *R10,R11
       B    *R11

scco   byte 212,212,212,213,212,214,212,215,212,216,212,217,212,218,212,219,212,220,212,221
       byte 213,212,213,213,213,214,213,215,213,216,213,217,213,218,213,219,213,220,213,221

I've tried this routing, but it doesn't display anything except "00". Did I mis a byte / word conversion, again?

Link to comment
Share on other sites

 

 

Indeed. I was just keeping it simple ;)

 

TurboForth uses a nice routine that I wrote that uses that technique. The code below can convert a number to a string in any number base from 2 to 36, signed or unsigned, with leading zeros or without. As you mentioned, it computes the divisors. However, it's a little clever. If, when calling the routine, you are converting a number in the same base as you did in the previous call, then it doesn't re-compute the divisors. That saves quite a lot of cycles.

 

This could easily be converted to general use. If anyone is interested in a general use subroutine then let me know and I'll convert it into a stand-alone BL routine or something similar.

; NUMBER TO STRING ( num -- addr len )
; Takes a number off the stack and converts it to a signed string equivalent,
; with respect to the current number base. Number base may be between
; 2 and 36. The routine checks location DOSIGN, and if 0, the
; number is treated as signed, else its unsigned. The routine also checks
; location LZI, and, if zero, leading zero's will be supressed.
; This is quite a bitch of a routine. Since any number base (between 2 and 36)
; can be employed this routine is rather complex. The routine must first
; determine the appropriate powers of the number base so we can divide the
; target number later. Obviously this is expensive, so the routine remembers
; what the active number base was the last time it was called, and ONLY
; re-computes the exponents if the base has changed since the last time it was
; called.
; This first part computes the column values.
; So, if the base is 10, you end up with 1,10,100,1000,10000
_nts    mov rstack,r14              ; save rstack 'cos we're using it
        mov *stack,r9               ; get number off stack 
        li r7,2                     ; exponent counter (base^0 and base^1 are
                                    ; easy to compute 
                                    ; used as a word offset into workbuffer so
                                    ; counts in multiples of 2.
        c @base,@lbase              ; check if base has chaged since the last
                                    ; time we were called
        jeq dodiv                   ; base hasn't changed, no need to compute
                                    ; powers of the base.
        mov @base,@lbase            ; base has changed, store it in 'last base'
        li r0,1                     ; base^0 is always 1 - easy 
        li r1,wrkbuf                ; place to store the powers of our base
    ; determine base^x until result > 65535
        mov r0,*r1+                 ; store base^0 and move forward in buffer
        mov @base,*r1               ; base^1 is always base  store it
pwr     mov *r1+,r5                 ; get previous exponent
        mpy @base,r5                ; multiply it by base - lower 16 bit result
                                    ; in r6
        mov r5,r5                   ; see if the result overflowed into upper
                                    ; 16 bits
        jne pwrout                  ; there was an overflow, exit loop
        mov r6,*r1                  ; otherwise store result
        inct r7                     ; and increment exponent counter
        jmp pwr                     ; and repeat
    ; Ok we have computed the 'column values' (powers) for our base. Now we
    ; sucessively divide the number down until nothing is left, building
    ; the string equivalent as we compute each digit. Just to make life
    ; harder for ourselves, we will optionally allow leading zero's to be
    ; supressed. If the word at LZI<>0 then leading zero's are suppressed.
pwrout  mov r7,@expcnt              ; save exponent count for next time routine
                                    ; is run
dodiv   mov @expcnt,r7              ; entry point when exponents arent computed.
                                    ; restore exponent count
        li r0,strbuf                ; address of string buffer where we build
                                    ; the string
        clr r1                      ; buffer length counter
        mov @dosign,r8              ; check if producing an unsigned number
        jne ninn                    ; skip if we are
        mov r9,r8                   ; else, check if number is negative and if
                                    ; so, add "-" character
        andi r8,>8000               ; is it negative
        jeq ninn                    ; its not negative, jump
        li r8,'-'*256               ; the number is negative, add a minus sign
                                    ; to the string buffer
        movb r8,*r0+                ; place it in the buffer
        inc r1                      ; increment length counter
        neg r9                      ; change the number to positive
ninn    clr r8                      ; div instruction uses 32 bit dividend, our
                                    ; 16 bit argument is in r9
        mov @lzi,r10                ; leading zero indicator 0=suppress
nxtdig  div @wrkbuf(r7),r8          ; divide our number by exponent value.
                                    ; result=r8, remainder=r9
        mov r8,r8                   ; was the result 0?
        jeq testlz                  ; if yes then check if ignoring leading
                                    ; zeros
        seto r10                    ; not zero, so reset leading zero indicator
dodig   movb @tlut(r8),*r0+         ; lookup digit value, move it to string
                                    ; buffer and advance buffer address
        clr r8                      ; clear result for next interation
        inc r1                      ; increment length counter
iglz    dect r7                     ; done all our columns/exponents?
        jne nxtdig                  ; loop if not
        movb @tlut(r9),*r0+         ; lookup digit value, move it to string
                                    ; buffer and advance buffer address
    ; we've done our division, push address & length to the stack and exit
        li r0,strbuf                ; address of string buffer
        mov r0,*stack               ; move address to stack
        dect stack                  ; new stack entry
        inc r1                      ; adjust length for remainder
        mov r1,*stack               ; move length to stack
        mov r14,rstack              ; restore return stack pointer
        b @retB0
    ; we're looking for leading zero's and ignoring them
testlz  mov r10,r10                 ; are we ignoring leading zero's?
        jeq iglz                    ; 0=ignore leading digit
        jmp dodig                   ; else do digit normally
    ; character lookup table for printing numbers between bases 2 to 36
tlut    text '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'

 

 

Although it's far more than I need ATM., I'd like to have a general subroutine, just for references.

I suppose the maximum that can be displayed is a full word, i.e. less than 65536?

Link to comment
Share on other sites

 

Although it's far more than I need ATM., I'd like to have a general subroutine, just for references.

I suppose the maximum that can be displayed is a full word, i.e. less than 65536?

Correct. I'll try and get it together over the next day or so.

Link to comment
Share on other sites

Forth, including TurboForth, TI Forth and fbForth, has a mechanism for this, using a picture format, for any radix (number base) you can use in Forth. It is based on 32-bit integers and is capable of fixed-radix-point representation. It uses a buffer that grows the ASCII string for the number from right to left. Leading zeros are managed with a fixed format, <# # # # # #> for a field width of 4, whereas, leading zeros are suppressed with <# #S #> . Though these words are written in high-level Forth, which results in a list of execution addresses that get processed by the Forth address interpreter, they could be cobbled together into just such an ALC routine. Such a routine would continuously divide by the current radix until the dividend = 0—pretty much what @Willsy suggested in post #62.

 

...lee

Link to comment
Share on other sites

^^^^ What he said :grin:

 

Those new to Forth will find <# # #> stuff totally perplexing. I spell it out in the 32-bit library documentation:

 

9.1 <#

Stack signature: --

Begins Pictured Numeric Output (PNO) conversion. PNO is a method of formatting numbers for display on the screen, using # symbols to represent digits. PNO actually converts the number to be displayed to a string, allowing the opportunity to insert characters into the character stream as conversion progresses (for example, commas, to separate hundreds and thousands, etc.). See # and #> for more information.

<# begins the PNO conversion process, it initialises the PNO buffer (referred to as _PNOB in the code), the PNO buffer pointer (_PNOBP) and the PNO length indicator (_PNOLEN). Therefore, if importing the PNO words into your own system you must observe the above dependencies.

_PNOB _PNOBP and _PNOLEN are declared as follows: CREATE _PNOB 34 CHARS ALLOT  \ pno buffer 0 VALUE _PNOLEN              \ pno length _PNOB 33 + VALUE _PNOBP      \ pno current position pointer 

To begin PNO conversion, an unsigned-double value must be on the stack (note, however, that <# does not affect the value on the stack, hence its stack signature is empty).

For example:

	12345678. <#

At this point, the double value 12,345,678 is on the stack, and the PNO buffers and pointers etc. are initialised to commence PNO conversion. The actual conversion is performed using the words # and #S. Please see the following sections for more information.

9.2 #

Stack Signature: ud:x – ud:y

The word # takes a single digit from the unsigned-double number on the stack (it divides the number by the current number base, as determined by BASE) and places this digit into the PNO buffer for display later.

For example:

	DECIMAL 123. <# # # # #> TYPE

Taking the above example one 'word' at a time:

  • First, the double value 123 is placed on the stack.

  • <# is executed, which prepares the PNO buffer to receive data.
  • # is executed. This divides the number on the stack (123) by BASE, which has been set to 10 in the above example by means of DECIMAL. The division of 123 by 10 yields a quotient of 12 and a remainder of 3. The remainder (3) is placed in the PNO buffer in ASCII form, and the quotient (12) replaces the value on the stack (123).
  • # is again executed. This divides the number on the stack (12) by BASE. The division of 12 by 10 yields a quotient of 1 and a remainder of 2. The remainder (2) is placed in the PNO buffer in ASCII form, and the quotient (1) replaces the value on the stack.
  • # is again executed. This divides the number on the stack (1) by BASE. The division of 1 by 10 yields a quotient of 0 and a remainder of 1. The remainder (1) is placed in the PNO buffer in ASCII form, and the quotient (0) replaces the value on the stack.
  • #> is then executed. #> removes the value from the stack, and replaces it with the address and length of the string that has been constructed in the PNO buffer. This address/length pair can be fed directly to TYPE to display the number. At this point, PNO conversion is complete.
  • TYPE is executed, which simply uses the data left on the stack by #> to display the string inside the PNO buffer.

Upon completion of PNO conversion the PNO buffer contains the ASCII characters:

1 2 3

And _PNOLEN contains the length.

Since # performs division, taking the remainder and adding it to the PNO buffer, the order of the conversion proceeds from least significant digit to most significant digit. However, to make things simple for the user, the PNO buffer is populated 'backwards' meaning that the string is actually stored 'forwards' in the PNO buffer, which is why words such as TYPE can be used to display it.

Additional features exist to add characters to the PNO string in order to format the number as desired. See HOLD and INS: for more information.

 

See http://turboforth.net/32-bit.html#9

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...