Dexter Posted June 17, 2015 Author Share Posted June 17, 2015 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? Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3259340 Share on other sites More sharing options...
Asmusr Posted June 18, 2015 Share Posted June 18, 2015 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. Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3259597 Share on other sites More sharing options...
Dexter Posted June 27, 2015 Author Share Posted June 27, 2015 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 4 Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3266030 Share on other sites More sharing options...
Asmusr Posted June 29, 2015 Share Posted June 29, 2015 Well done. Great to see more assembly games being developed. Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3267362 Share on other sites More sharing options...
Dexter Posted June 29, 2015 Author Share Posted June 29, 2015 (edited) 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. runme.dsk Edited June 29, 2015 by Dexter 2 Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3267435 Share on other sites More sharing options...
Opry99er Posted June 29, 2015 Share Posted June 29, 2015 Hey man, good solid work here... Thank you for your contribution. 3 Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3267467 Share on other sites More sharing options...
Dexter Posted July 6, 2015 Author Share Posted July 6, 2015 The battle goes on: I’m trying to display the score on the screen by two digits. Which pretty much looks like this: 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. 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 1 Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3272089 Share on other sites More sharing options...
+InsaneMultitasker Posted July 6, 2015 Share Posted July 6, 2015 Look at The battle goes on: I’m trying to display the score on the screen by two digits. Which pretty much looks like this: Look at the DIV command and where it stuffs the remainder and the quotient. Then review which values you are trying to display. 1 Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3272102 Share on other sites More sharing options...
Dexter Posted July 6, 2015 Author Share Posted July 6, 2015 OK. Quotient in r4 and remainder in r5, so 10's in r4 and 1's in r5. I'll try it out emmediately! Now I regret that I asked. Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3272120 Share on other sites More sharing options...
RickyDean Posted July 6, 2015 Share Posted July 6, 2015 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. Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3272154 Share on other sites More sharing options...
Dexter Posted July 6, 2015 Author Share Posted July 6, 2015 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! 1 Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3272167 Share on other sites More sharing options...
Willsy Posted July 7, 2015 Share Posted July 7, 2015 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 1 Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3272544 Share on other sites More sharing options...
Dexter Posted July 7, 2015 Author Share Posted July 7, 2015 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. Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3272573 Share on other sites More sharing options...
Tursi Posted July 7, 2015 Share Posted July 7, 2015 You divide by 10 each time in a loop and display the remainder. hah! Somehow, I've never thought of going that way... makes looping a lot easier! Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3272589 Share on other sites More sharing options...
Asmusr Posted July 7, 2015 Share Posted July 7, 2015 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 1 Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3272749 Share on other sites More sharing options...
Dexter Posted July 7, 2015 Author Share Posted July 7, 2015 That's what I hoped for, some different approaches and solutions. 1 Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3272951 Share on other sites More sharing options...
+mizapf Posted July 7, 2015 Share Posted July 7, 2015 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. 1 Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3272977 Share on other sites More sharing options...
Tursi Posted July 8, 2015 Share Posted July 8, 2015 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. Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3273319 Share on other sites More sharing options...
Willsy Posted July 8, 2015 Share Posted July 8, 2015 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' Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3273366 Share on other sites More sharing options...
Willsy Posted July 8, 2015 Share Posted July 8, 2015 By the way, this source is published online here: http://turboforth.net/source/ This particular routine is in 1-10-Strings Mark Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3273370 Share on other sites More sharing options...
Dexter Posted July 8, 2015 Author Share Posted July 8, 2015 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? Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3273424 Share on other sites More sharing options...
Dexter Posted July 8, 2015 Author Share Posted July 8, 2015 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? Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3273429 Share on other sites More sharing options...
Willsy Posted July 8, 2015 Share Posted July 8, 2015 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. Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3273437 Share on other sites More sharing options...
+Lee Stewart Posted July 8, 2015 Share Posted July 8, 2015 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 Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3273473 Share on other sites More sharing options...
Willsy Posted July 8, 2015 Share Posted July 8, 2015 ^^^^ What he said 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 Quote Link to comment https://forums.atariage.com/topic/237815-simon-game-in-assembly-language/page/3/#findComment-3273490 Share on other sites More sharing options...
Recommended Posts
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.