Menu

Help please decoding Assembler.

mkstevo
2019-10-03
2019-10-07
  • mkstevo

    mkstevo - 2019-10-03

    I am trying to replicate a white noise source project from September's Practical Electronics Magazine that used a Linear Shift Feedback register on a PIC12F675 to generate random white noise at one of the output pins.

    The source code was provided, in .asm format. As I don't understand assembler, I'm struggling to convert the LSF function in BASIC (which I only partly understand anyway).

    ';generate random output (note: Using bit labelling 1-31 (rather than 0 to 30 for software), take 1 from Q value if counter labelling required
        rlf     NOISE0,w        '; move Q31 to ms bit
        movwf   STORE           '; store value for xoring with Q28
    '; place bit 31 to GPIO,0
        rlf     STORE,w     '; get carry (bit 31)
        rlf     GPIO,f          '; carry to bit 0 GPIO
    '; get Q28
        swapf   NOISE0,w        '; Q28 to ms bit
    '; both store and w have required Q31 and Q28 in ms bit
        xorwf   STORE,f         '; xor Q31 and Q28
        rlf     STORE,w     '; move xored value to carry
    '; move shift register values along 1
        rlf     NOISE3,f        '; carry to ls byte
        rlf     NOISE2,f        '; carry to next byte
        rlf     NOISE1,f        '; carry to next byte
        rlf     NOISE0,f        '; carry to ms byte
    

    I am assuming that rlf is a rotate left command.
    The first rlf seems to my eye to be rotating NOISE0 left, and storing the result in 'w'.
    'w' then seems to be being copied to STORE.
    STORE itself seems to be rotated left, with the value being stored in 'w'.

    Then I get lost.
    The output register GPIO appears to be being rotated left, with the result of it being sored in 'f'.
    What would the equivalent of that be in GCB please? The port I was intending to use in my 12F1840 is PortA.2, could I achieve the same thing with:

        rlf     PORTA,f          '; carry to bit 0 PORTA
    

    The swapf command comment (Q28 to ms bit) implies that it is a bitwise command, again I don't see how that might be done. Similarly, the xorwf command implies that it is bitwise only. Are the locations of 'w' and 'f' bit values only?

    Any guidance would be appreciated.

     
  • Anobium

    Anobium - 2019-10-03

    Post the article. Some genius will sort.

     
  • mkstevo

    mkstevo - 2019-10-03

    The article simply deals with the 'electronics', with no mention of the code at all. I have the full Assembler:

    ; Noise source
    ; 31 bit shift register random generator XOR Q31 and Q28
    
    ; Quoted from XILINX application  XAPP 052 July 7,1996 (Version 1.1)
    
    ;"An n-bit LFSR counter can have a maximum sequence
    ;length of 2n-1. In that case, it goes through all possible
    ;code permutations except one, which would be a lock-up
    ;state. A maximum length n-bit LFSR counter consists of an
    ;n-bit shift register with an XNOR in the feedback path from
    ;the last output Qn to the first input D1. The XNOR makes
    ;the lock-up state the all-ones state; an XOR would make it
    ;the all-zeros state. For normal Xilinx applications, all-ones
    ;is more easily avoided, since ìby defaultî the flip-flops wake
    ;up in the all-zeros state. Table 3 describes the outputs that
    ;must be used as inputs of the XNOR. LFSR outputs are traditionally
    ;labeled 1 through n, with 1 being the first stage of
    ;the shift register, and n being the last stage. This is different
    ;from the conventional 0 to (n-1) notation for binary
    ;counters."
    
    
        ERRORLEVEL -302
        ERRORLEVEL -306
    
            list      p=12F617            ; list directive to define processor
         #include <p12F617.inc>        ; processor specific variable definitions
    
    
         __CONFIG   _CP_OFF & _BOR_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _IOSCFS_8MHZ & _WRT_OFF
    
    ; RAM 
    NOISE0      equ H'20'       ; ms byte of shift register
    NOISE1      equ H'21'       ; next byte of shift register
    NOISE2      equ H'22'       ; next byte of shift register
    NOISE3      equ H'23'       ; ls byte of shift register
    STORE       equ H'24'       ; storage value
    
    ; ******************************************************************
    
    ; start at memory 0
    
        org     0           ; reset vector
    
    MAIN
    ; set oscillator calibration
        bsf     STATUS,RP0  ; bank 1
            movlw   0x00                 ; set oscillator to factory calibrated frequency 
            movwf   OSCTUNE
        bcf     STATUS,RP0
    ; set inputs/outputs
        movlw   B'00000000'
        movwf   GPIO            ; ports low
        movlw   B'00000111'     ; comparators off
        movwf   CMCON0
        bsf     STATUS,RP0  ; select memory bank 1
        movlw   B'00000000'     ;  WPU
        movwf   WPU
        movlw   B'00000000'     ; outputs/inputs set 
        movwf   TRISIO          ; port data direction register
        movlw   B'01000101'     ; settings 
        movwf   OPTION_REG
    
        bcf     STATUS,RP0  ; select memory bank 0
    
    ;  initial states
    ; preload shift registers
        movlw   H'11'
        movwf   NOISE0
        movlw   H'8A'
        movwf   NOISE1
        movlw   H'9F'
        movwf   NOISE2
        movlw   H'01'
        movwf   NOISE3
    
    RND ; Output at GPIO,0 only; 
    ;generate random output (note: Using bit labelling 1-31 (rather than 0 to 30 for software), take 1 from Q value if counter labelling required
        rlf     NOISE0,w        ; move Q31 to ms bit 
        movwf   STORE           ; store value for xoring with Q28
    ; place bit 31 to GPIO,0
        rlf     STORE,w     ; get carry (bit 31)
        rlf     GPIO,f          ; carry to bit 0 GPIO
    ; get Q28
        swapf   NOISE0,w        ; Q28 to ms bit
    ; both store and w have required Q31 and Q28 in ms bit
        xorwf   STORE,f         ; xor Q31 and Q28
        rlf     STORE,w     ; move xored value to carry
    ; move shift register values along 1
        rlf     NOISE3,f        ; carry to ls byte  
        rlf     NOISE2,f        ; carry to next byte
        rlf     NOISE1,f        ; carry to next byte
        rlf     NOISE0,f        ; carry to ms byte
    
        goto    RND         ; total 13 clock cycles (6.5us) per half frequency generation
    
    ; 2 to the power of 31 -1 results = 2,147,483,647
    ; clock is 2MHz so 13 cycles is 153.8451kHz generating max frequency of 76.923kHz 
    ; minimum frequency is 76.923kHz/ 2,147,483,647 = 35.83uHz
    ; sequence repeats after 13us x 2,147,483,647 = 27,917,280s or 7.75hours
    
    
        end
    
     
  • mkstevo

    mkstevo - 2019-10-03

    I have something working but I can't be certain I have it close to the original, never mind right!

    #Chip 12F1840, 2
    
    Dim NOISE0      As Byte
    Dim NOISE1      As Byte
    Dim NOISE2      As Byte
    Dim NOISE3      As Byte
    Dim STORE       As Byte
    
    Dim WF          As Bit
    Dim FF          As Bit
    
    Let   NOISE0 = 0x11
    Let   NOISE1 = 0x8A
    Let   NOISE2 = 0x9F
    Let   NOISE3 = 0x01
    
    Do
    
        Let PortA.2 = WF
    
        Let WF = Noise3.3 XOR Noise3.6 'Bits 31 and 28
    
        Let FF = Noise3.0
        Rotate Noise3 Left
        Let Noise3.7 = WF
    
        Let WF = Noise2.0
        Rotate Noise2 Left
        Let Noise2.7 = FF
    
        Let FF = Noise1.0
        Rotate Noise1 Left
        Let Noise1.7 = WF
    
        Let WF = Noise0.0
        Rotate Noise0 Left
        Let Noise0.7 = FF
    
    Loop
    
     

    Last edit: mkstevo 2019-10-03
  • Chris Roper

    Chris Roper - 2019-10-04

    This should do it:

    ; PE-Sep19-Noise.gcb
    ; Noise source
    ; 31 bit shift register random generator XOR Q31 and Q28
    
    #chip 12f675,8
    
    Dim Noise as Long ' Create a 32bit shift register
    Noise = Random    ' Randomise inital state (anything but zero)
    
    do
      C = Noise.27 XOR Noise.30 ' Test and set Carry flag
      Rotate Noise Left         ' Rotate all 32 bits
      GPIO.0 = Noise.30         ' Output bit 31
    loop
    

    It compiles and the ASM generated looks good but I have not yet built the hardware.
    Give it a try on your device.

    Cheers
    Chris

    EDIT: With a speaker attached it is generating White Noise :>)

     

    Last edit: Chris Roper 2019-10-04
  • mkstevo

    mkstevo - 2019-10-04

    Oh wow!
    That is so elegant and simple.

    I hadn't realised you could rotate a Long variable.

    Many thanks. Yours is far superior to what I was attempting to do.

     
    • Chris Roper

      Chris Roper - 2019-10-04

      Thanks.

      I have just updated the code having read the original article.

      I see he has indexed from 1 not zero and the final stage is 7 bit not 8 bit.
      As a result we need to XOR Noise.27 and Noise.30 wich in the article are referred to as Q28 and Q31.

      I am not sure if there are any long term implications for 32 bits over 31 bits but the new code now fits his original algorithm.

      Cheers
      Chris

       
  • Anobium

    Anobium - 2019-10-04

    And, it works on an 18f45k80.

    Portable code rules!!

     
  • mkstevo

    mkstevo - 2019-10-04

    Here is the complete program, should anyone be interested:

    #Chip 12F1840, 2
    
    'Inspired by the Practical Electronics White Noise project, September 2019
    'White Noise source
    'Using a 31 bit shift register random generator XOR Q31 and Q28
    
    'Most of this work was done by Chris Roper
    'of the GCB forum for which I am most grateful.
    
    Dim Noise      As Long  ' Create a 32bit shift register
    Let Noise    = Random   ' Seed the LSFR
    
    Dim LS         As Bit
    'This allows us to the port on, or off. Without it the port goes
    'momentarily low in each cycle, even if it is intended to stay high
    
    'You end up with this:
    
    '____|‾|‾|‾|____|‾|‾|____
    
    'Instead of this:
    
    '____|‾‾‾‾‾|____|‾‾‾|____
    
    Do
    
    'This line causes an error:
    'Error: GCASM: Symbol 3.0 has not been defined
      'Let C = Noise.27 XOR Noise.30 ' Test and set Carry flag
    
    'Replaced with this If...Then
      If Noise.27 <> Noise.30 Then
        Let C = 1
      Else
        Let C = 0
      End If
    
      Rotate Noise Left             ' Rotate all 32 bits
      If Noise.31 <> LS Then
        Let LS = Noise.31
        Let PortA.2 = LS            ' Output bit 31
      End If
    
    Loop
    

    I found that the line:

    Let C = Noise.28 XOR Noise.31 ' Test and set Carry flag
    

    Caused an error when compiling for the 12F1840:
    Error: GCASM: Symbol 3.0 has not been defined

    I also found that direct XOR comparisons on Noise.28 and Noise.31 always equated to 0 (zero).
    Using the If...Then statement cured that error.

    Another anomaly was seen on the oscilloscope when observing the output. Directly setting the output port to the value of a variable seemed to cause it to momentarily dip to zero even if it was 'changing' from 1 (one) to 1 (one). This is why PortA.2 is only 'changed' when the value actually changes.

     

    Last edit: mkstevo 2019-10-04
    • Anobium

      Anobium - 2019-10-04

      @Steve. What error? I just tried this code... Send me your code that fails, alone with the ASM.

      Thank you.

      #Chip 12F1840, 2
      
      'Inspired by the Practical Electronics White Noise project, September 2019
      'White Noise source
      'Using a 31 bit shift register random generator XOR Q31 and Q28
      
      'Most of this work was done by Chris Roper
      'of the GCB forum for which I am most grateful.
      
      Dim Noise      As Long  ' Create a 32bit shift register
      Let Noise    = Random   ' Seed the LSFR
      
      Dim LS         As Bit
      'This allows us to the port on, or off. Without it the port goes
      'momentarily low in each cycle, even if it is intended to stay high
      
      'You end up with this:
      
      '____|‾|‾|‾|____|‾|‾|____
      
      'Instead of this:
      
      '____|‾‾‾‾‾|____|‾‾‾|____
      
      Do
      
        Let C = Noise.27 XOR Noise.30 ' Test and set Carry flag
      
        Rotate Noise Left             ' Rotate all 32 bits
        If Noise.31 <> LS Then
          Let LS = Noise.31
          Let PortA.2 = LS            ' Output bit 31
        End If
      
      Loop
      
       
      • mkstevo

        mkstevo - 2019-10-05

        The code failed to compile at all.

        Let C = Noise.28 XOR Noise.31 ' Test and set Carry flag
        Caused an error when compiling for the 12F1840:
        Error: GCASM: Symbol 3.0 has not been defined

         
        • Chris Roper

          Chris Roper - 2019-10-05

          You are the only one getting that error, nether Even nor I can reproduce it.
          here is my compiler output:

          10:15:21    G+Stool started with parameter 'hex'   ->   processing   C:\GCB@Syn\G+Stools\makeHEX.bat
          Source-File  =  C:\GCB@Syn\GreatCowBasic\Working\test.gcb
          Target-File  =  C:\GCB@Syn\GreatCowBasic\Working\test.hex
          Compiler Version (YYYY-MM-DD): 0.98.<<>> 2019-05-14 (Windows 32 bit)   Program Memory: 108/4096 words (2.64%)   RAM: 15/256 bytes (5.86%)   Chip: 12F1840
          Duration:   3.6  Seconds.
          

          What version are you running?

           
          • mkstevo

            mkstevo - 2019-10-05

            I was at work. I'll have to check the version, I had assumed it was a fairly recent version. I will check if I get this error at home.

            My compiler here and at work will be one of the macOS versions which could be the reason you are not seeing the error? I'm certain mine here is the very latest, the one at work could be one version back from the latest, I can't be certain.

             
            • Anobium

              Anobium - 2019-10-05

              I cannot reproduce the error. So, have a check.

               
  • Chris Roper

    Chris Roper - 2019-10-04

    The dip you were seeing is caused by this in the compiler output:

    ;GPIO.0 = Noise.30         ' Output bit 31
        bcf GPIO,0
        btfsc   NOISE_E,6
        bsf GPIO,0
    

    I did wonder if that would be an issue.
    Your workaround is good but it introduces two XOR’s over one and additional branching code.
    It does eliminate the glitch though at the cost of output frequency.

    I don't know why you are seeing a compiler error, however.
    I am unable to reproduce your error even on the 12F1840 device.

    Your Code is looking good though and should be useful to others too.

     
  • Anobium

    Anobium - 2019-10-04

    I think you can stop the glitch. See if this works.

    #option volatile bit

    So, it would be

    #option volatile GPIO.0

     
  • Chris Roper

    Chris Roper - 2019-10-04

    This version uses the above to solve the output Glitch and improve portability:

    ; PE-Sep19-Noise.gcb
    ; Noise source
    ; 31 bit shift register random generator XOR Q31 and Q28
    
    #chip 12f675,8
    
    #define NoisePin GPIO.0
    #option volatile NoisePin
    
    Dim Noise as Long ' Create a 32bit shift register
    Noise = Random    ' Randomise inital state (anything but zero)
    
    do
      C = Noise.27 XOR Noise.30 ' Test and set Carry flag
       Rotate Noise Left         ' Rotate all 32 bits
        NoisePin = Noise.30       ' Output 31st bit
    loop
    

    It now gives a main loop of 20 Instructions at 8Mhz, slightly more than the original, for a sampling rate of 100kHz, vs the original 153.846kHz, that is a frequency distribution of 50kHz which still covers the entire audio spectrum of 20Hz to 20kHz and the repeat sequence remains approximately 8 hours.

     
    • mkstevo

      mkstevo - 2019-10-05

      I'll give the "volatile" option a try when I'm next at the oscilloscope which may not be until next week now.

      Any combination I tried using XOR always gave a result of 0 (zero) into the C (carry) register, filling the shift register with zeros. My <> comparison always worked? It could be being altered at a lower level by the serial LCD code I had which was outputting the 32 bits onto the LCD to see if it was working, which it wasn't. Perhaps as I passed "noise.30" and "noise.27" to the HSerPrint routine, they became corrupted, although they don't seem to have been when I use my If <> Then comparison. Odd.

       
  • mkstevo

    mkstevo - 2019-10-05

    The aded compiler directive:

    #Option Volatile NoisePin
    

    has cured the apparent glitches at least as far as my super cheap Chinese USB 'scope shows. Thanks for that suggestion.

    Here at home, the line:

    Let C = Noise.28 XOR Noise.31 ' Test and set Carry flag
    

    compiles normally, and the XOR does not seem to be filling the shift register with zeros.

    I have the compiler version:
    Great Cow BASIC (0.98.05 2019-04-20 (Darwin 64 bit))
    I will have to see what version I have at work next week.

     

    Last edit: mkstevo 2019-10-06
    • Anobium

      Anobium - 2019-10-05

      Oh my. Please update Great Cow BASIC. We are many releases greater than that version.

      My guess. Old version in use.

       
      • Trev

        Trev - 2019-10-05

        Perhaps just one release behind ... the current version is 0.98.06 (vs 0.98.05) unless I'm missing something?

         
        • Anobium

          Anobium - 2019-10-06

          I am the dim one. I read the version as 0.95.05!!!! Silly

           
          • mkstevo

            mkstevo - 2019-10-07

            I was correct, I am one version behind at work.
            Great Cow BASIC (0.98.04 2018-10-20 (Darwin 64 bit))
            I will update now.

            Updated to:
            Great Cow BASIC (0.98.06 2019-06-12 (Darwin 64 bit))
            Program now compiles without errors at work.

            I think I had updated previously, but had selected the 'All Users' install directory whilst my programs and scripts were located in my '~User' directory. I'll get that changed.

             

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.