Shop OBEX P1 Docs P2 Docs Learn Events
PASM2 noob issue — Parallax Forums

PASM2 noob issue

It's been a while since I wetted my toes in PASM2 and I wanted to create a seemingly simple program just to go over some concepts of PASM2. So, I created this small program to calculate the length of a zero terminating string in hub memory.

I expected STRSIZE to give the same result as the counter value in the PASM program running on the other cog, but they are not. If anyone could point out what's wrong I would appreciate it (I'm 99% sure it's a misconception on my part)

CON
    _CLKFREQ = 160_000_000
    MAX_CHARACTERS = 10

VAR
  byte size
  byte text[MAX_CHARACTERS+1]


PUB main()

  set_text(String("Hello"))
  coginit(COGEXEC_NEW, @sizeof, @size)
  waitms(1)

  debug(ZSTR(@text))
  debug(udec(STRSIZE(@text)))
  debug(UDEC(size))


PUB set_text(addr)|c,i
  'Clear text
  repeat i from 0 to MAX_CHARACTERS
    text[i] := 0

  'Set new text
  repeat i from 0 to MAX_CHARACTERS-1                   'Reserve last character place for the terminating 0
    c := BYTE[addr][i]
    debug(udec(c))
    if c <> 0
      text[i] := c
    else
      quit
  text[i] := 0


DAT
  ORG

sizeof
  'get the address of size
  MOV retpointer, PTRA

  'get the address of text[0]
  MOV pointer, PTRA
  ADD pointer, #1

.loop
  'checks if text[pointer] is 0, if it is jumps to .return
  RDBYTE charvalue, pointer  '<--- Read the value of the hub memory location pointer and copy it to charvalue
  TJZ charvalue, #.return
  ADD pointer, #1
  ADD counter, #1
  JMP #.loop

.return
  'copy the value of counter to the address of the return value variable
  WRBYTE counter, retpointer

' local variables
  counter byte 0
  ALIGNL
  charvalue byte 0
  pointer res 1
  retpointer res 1
  FIT 496

Comments

  • Your program is missing an ending, so it's running off and executing garbage. Put a JMP #$ at the end to trap it in an infinite loop.

    Also, all cog ram variables must be long, since that's how the CPU addresses them (unless you use the special GETBYTE/SETBYTE instructions)

  • @Wuerfel_21 said:
    Your program is missing an ending, so it's running off and executing garbage. Put a JMP #$ at the end to trap it in an infinite loop.

    Also, all cog ram variables must be long, since that's how the CPU addresses them (unless you use the special GETBYTE/SETBYTE instructions)

    Thank you @Wuerfel_21 !
    Added the JMP #$ at the end of the program and it worked as expected.

    I'll get into the GETBYTE/SETBYTE instructions next.

  • Wuerfel_21Wuerfel_21 Posts: 5,105
    edited 2024-04-22 15:47

    Also, you if you wanted to do this same thing but better:

    DAT
                  ORG
    
    sizeof
                  'get the address of size
                  MOV retpointer, PTRA
    
                  'get the address of text[0]
                  MOV pointer, PTRA
                  ADD pointer, #1
    
                  RDFAST #0,pointer ' subsequent RFxxxx will read from pointer
    
    .loop
                  RFBYTE charvalue wz '<--- Read the value of the hub memory location pointer, copy it to charvalue and set zero flag
            if_nz IJNZ counter,#.loop ' increment counter and jump if result not zero (never happens)
    
    .return
                  'copy the value of counter to the address of the return value variable
                  WRBYTE counter, retpointer
    
                  COGID PA
                  COGSTOP PA
    
    ' local variables
    counter       long 0
    charvalue     res 1
    pointer       res 1
    retpointer    res 1
    
                  FIT 496
    

    When reading memory at incrementing addresses, use the RDFAST mechanism where possible, it saves you from having to increment the pointer and is also significantly faster. You can also combine the increment of the counter with the branch.

  • Actually, there's a really cracked way to do a count like this that's even more fasterer (4 cycles per byte instead of 6).

    DAT
                  ORG
    
    sizeof
                  'get the address of size
                  MOV retpointer, PTRA
    
                  'get the address of text[0]
                  MOV pointer, PTRA
                  ADD pointer, #1
    
                  RDFAST #0,pointer ' subsequent RFxxxx will read from pointer
    
                  REP #2,#0 ' loop next two instructions forever until a jump breaks out of it
                  RFBYTE charvalue wz '<--- Read the value of the hub memory location pointer, copy it to charvalue and set zero flag
            if_z  IJNZ pointer,#$+1 ' if zero, increment pointer by 1 (to compensate for the zero we just read) and break out of loop
    
                  GETPTR counter ' get current FIFO pointer
                  SUB counter,pointer ' subtract start pointer + 1 to get length
    
    .return
                  'copy the value of counter to the address of the return value variable
                  WRBYTE counter, retpointer
    
                  COGID PA
                  COGSTOP PA
    
    ' local variables
    counter       long 0
    charvalue     res 1
    pointer       res 1
    retpointer    res 1
    
                  FIT 496
    
  • @Wuerfel_21 said:
    Actually, there's a really cracked way to do a count like this that's even more fasterer (4 cycles per byte instead of 6).

    DAT
                  ORG
    
    sizeof
                  'get the address of size
                  MOV retpointer, PTRA
    
                  'get the address of text[0]
                  MOV pointer, PTRA
                  ADD pointer, #1
      
                  RDFAST #0,pointer ' subsequent RFxxxx will read from pointer
    
                  REP #2,#0 ' loop next two instructions forever until a jump breaks out of it
                  RFBYTE charvalue wz '<--- Read the value of the hub memory location pointer, copy it to charvalue and set zero flag
            if_z  IJNZ pointer,#$+1 ' if zero, increment pointer by 1 (to compensate for the zero we just read) and break out of loop
    
                  GETPTR counter ' get current FIFO pointer
                  SUB counter,pointer ' subtract start pointer + 1 to get length
    
    .return
                  'copy the value of counter to the address of the return value variable
                  WRBYTE counter, retpointer
    
                  COGID PA
                  COGSTOP PA
    
    ' local variables
    counter       long 0
    charvalue     res 1
    pointer       res 1
    retpointer    res 1
    
                  FIT 496
    

    Nice, thanks!

  • I got another noob question.

    I don't understand why this wont work:

    My assumption was that once I have the hub address of the variable send_value, if I add 4 to it I would get the address of the next long which is return_value.

    However, if I just refer to PTRA[0] and PTRA[1] in the RDLONG and WRLONG instructions respectively it does work as expected:

    If someone knows what I'm doing wrong, please let me know. Thanks.

  • evanhevanh Posts: 16,023
    edited 2024-04-24 03:16

    It acts like an array index. It's built into the RDLONG/WRLONG instructions themselves. PTRA holds the base address, the index is then multiplied by 4 before being added to the base. RDWORD/WRWORD are x2. RDBYTE/WRBYTE are x1.

    However, this feature is limited to PTRA/PTRB special registers, and also max index of +31 -32 I think.
    Further reading under HubRAM Interface sub-section RANDOM ACCESS INTERFACE in the Silicon Doc.

    EDIT: Oh, I see. You already know that. You're right, the first approach should also work. Dunno why it doesn't.

    EDIT2: Found it after typing each line in and getting a compile error because I'd renamed "services" to "loop". The coginit(COGEXEC_NEW, @services, @send_value) call is not correct as is. You need a label for starting the cog at the ORG point. It didn't matter for the second example since that part of the code was redundant then.

  • @evanh said:
    It acts like an array index. It's built into the RDLONG/WRLONG instructions themselves. PTRA holds the base address, the index is then multiplied by 4 before being added to the base. RDWORD/WRWORD are x2. RDBYTE/WRBYTE are x1.

    However, this feature is limited to PTRA/PTRB special registers, and also max index of +31 -32 I think.
    Further reading under HubRAM Interface sub-section RANDOM ACCESS INTERFACE in the Silicon Doc.

    EDIT: Oh, I see. You already know that. You're right, the first approach should also work. Dunno why it doesn't.

    EDIT2: Found it after typing each line in and getting a compile error because I'd renamed "services" to "loop". The coginit(COGEXEC_NEW, @services, @send_value) call is not correct as is. You need a label for starting the cog at the ORG point. It didn't matter for the second example since that part of the code was redundant then.

    Oh right! I suspected it was something trivial!! Thanks @evanh !!

Sign In or Register to comment.