Shop OBEX P1 Docs P2 Docs Learn Events
Propeller II: Emulation of the P2 on FPGA boards (Prop123-A7/A9, DE0-NANO, DE2-115, etc) - Page 5 — Parallax Forums

Propeller II: Emulation of the P2 on FPGA boards (Prop123-A7/A9, DE0-NANO, DE2-115, etc)

1235724

Comments

  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-01 16:27
    I just tried stripping stuff out of Chip's ROM monitor program to make a simple "Hello, world" program that displays text on the serial terminal. Unfortunately, I guess I've misunderstood something because it doesn't seem to work. I loaded the program then exited PNut.exe and ran putty. I typed a space hoping that would trigger the auto-baud detection and display the "Hello" string but nothing happened. Can anyone (Chip?) tell me where I went wrong?

    Thanks!
    David
    ' mostly stolen from Chip's P2 ROM monitor
    
    DAT
    
                    org
    
                    reps    #$1F6-reserves,#1       'clear reserves
                    setinda reserves
                    mov     inda++,#0
    
                    jmptask #baud_task,#%0010       'enable baud detector task
                    settask #%%0101
    
                    tjz     period,#$               'wait for <space> to set period
    
                    jmptask #rx_task,#%0100         'enable serial receiver task
                    settask #%%0121
    
                    setptra #hello                  'print hello message
    
                    call    #tx_string              'print hello/error message
    
    done		jmp	#done
    
    '
    '
    ' Print string (@ptra)
    '
    tx_string       rdbyte  x,ptra++                'get chr
    tx_string_ret   tjz     x,#0                    'if 0, done
                    call    #tx                     'other?
                    jmp     #tx_string
    
    '
    '
    ' Transmit chr (x)
    '
    tx              shl     x,#1                    'insert start bit
                    setb    x,#9                    'set stop bit
    
                    getcnt  w                       'get initial time
    
    :loop           add     w,period                'add bit period to time
                    passcnt w                       'loop until bit period elapsed
                    shr     x,#1            wc      'get next bit into c
                    setpc   tx_pin                  'write c to tx pin
                    tjnz    x,#:loop                'loop until bits done
    
    tx_ret          ret
    
    '
    '
    ' Receive chr (x)
    '
    rx              call    #rx_check               'wait for rx chr
            if_z    jmp     #rx
    
    rx_ret          ret
    '
    '
    ' Check receiver, z=0 if chr (x)
    '
    rx_check        or      rx_tail,#$80            'if start or rollover, reset tail
    
                    getspb  rx_temp         wz      'if head uninitialized, z=1
            if_nz   cmp     rx_temp,rx_tail wz      'if head-tail mismatch, byte ready, z=0
    
            if_nz   getspa  rx_temp                 'preserve spa
            if_nz   setspa  rx_tail                 'get tail
            if_nz   popar   x                       'get byte at tail
            if_nz   getspa  rx_tail                 'update tail
            if_nz   setspa  rx_temp                 'restore spa
    
    rx_check_ret    ret
    
    
    '************************
    '* Serial Receiver Task *
    '************************
    
    rx_task         chkspb                  wz      'if start or rollover, reset head
            if_z    setspb  #$80
    
                    mov     rx_bits,#9              'ready for 8 data bits + 1 stop bit
    
                    neg     rx_time,period          'get -0.5 period
                    sar     rx_time,#1
    
                    jp      rx_pin,#$               'wait for start bit
    
                    subcnt  rx_time                 'get time + 0.5 period for initial 1.5 period delay
    
    :bit            rcr     rx_data,#1              'rotate c into byte
                    add     rx_time,period          'add 1 period
                    passcnt rx_time                 'wait for center of next bit
                    getp    rx_pin          wc      'read rx pin into c
                    djnz    rx_bits,#:bit           'loop until 8 data bits + 1 stop bit received
    
                    shr     rx_data,#32-8           'align byte
                    pushb   rx_data                 'store byte at head, inc head
    
                    jmp     #rx_task                'wait for next byte
    
    
    '**********************
    '* Baud Detector Task *
    '**********************
    
    baud_task       movd    ctr,rx_pin              'set ctra to time rx pin states
    
    :loop           notb    ctr,#5          wc      'if 1,0 sample set, c=0
                    setctra ctr                     '($20 -> 10000001001 -> 1, 6x 0, 1x 1, 2x 0, 1)
    
            if_nc   mov     limh,buff0              'if 1,0 sample set,
            if_nc   shr     limh,#4                 '..make window from 1st 0 (6x if $20)
            if_nc   neg     liml,limh
            if_nc   add     limh,buff0
            if_nc   add     liml,buff0
    
            if_nc   mov     comp,buff1              'if 1,0 sample set,
            if_nc   mul     comp,#6                 '..normalize 2nd 1 (1x if $20) to 6x
            if_nc   cmpr    comp,limh       wc      '..check if within window
            if_nc   cmp     comp,liml       wc
    
            if_nc   mov     comp,buff2              'if 1,0 sample set,
            if_nc   mul     comp,#3                 '..normalize 2nd 0 (2x if $20) to 6x
            if_nc   cmpr    comp,limh       wc      '..check if within window
            if_nc   cmp     comp,liml       wc
    
            if_nc   add     buff0,buff2             'if $20,
            if_nc   shr     buff0,#3                '..compute period from 6x 0 and 2x 0
            if_nc   mov     period,buff0            '..update period
    
                    mov     buff0,buff1             'scroll sample buffer
                    mov     buff1,buff2
    
    :wait           getcosa buff2                   'wait for next sample
                    tjnz    buff2,#:loop
                    jmp     #:wait
    
    
    '*************
    '* Constants *
    '*************
    
    hello           byte    13, "Hello, Propeller II!", 13, 0
    		long
    
    rx_pin          long	91
    tx_pin          long    90
    
    '*************
    '* Variables *
    '*************
    
    reserves
    
    w               res     1                       'main task
    x               res     1
    y               res     1
    z               res     1
    ctr		res	1
    
    rx_tail         res     1                       'serial receiver task
    rx_temp         res     1
    rx_time         res     1
    rx_data         res     1
    rx_bits         res     1
    
    buff0           res     1                       'baud detector task
    buff1           res     1
    buff2           res     1
    limh            res     1
    liml            res     1
    comp            res     1
    period          res     1
    


    Edit: Removed the code to setup rx_pin and tx_pin and moved rx_pin to 91 and tx_pin to 90.
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-01 18:27
    Another question I have is how the following instruction works:
                    setinda reserves
    
    I assume that this loads the address of "reserves" into inda but I don't understand why it isn't written with an immediate operand like this:
                    setinda #reserves
    
    I tried this and PNut.exe complained.
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-01 19:41
    Well, one problem I've noticed already is that I need to delete this code:
                    getptra rx_pin                  'get rx/tx pins
                    getptra tx_pin
                    shr     tx_pin,#9
                    setp    tx_pin
    
    This is code to fetch the tx and rx pin numbers passed into the COG at startup but I have these values stored as constants. Unfortunately, fixing this didn't really solve the problem.
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-01 20:36
    Okay, maybe this is my problem:
                    setptra #hello                  'print hello message
    
    Here I want to load the hub address of the hello string into ptra but I suspect what I'm actually doing is loading the COG address. How do I get the hub address? Also, I guess this code assumes that the hub address of the hello string is less than 512 which is probably a bad assumption.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2012-12-01 20:53
    David Betz wrote: »
    Okay, maybe this is my problem:
                    setptra #hello                  'print hello message
    
    Here I want to load the hub address of the hello string into ptra but I suspect what I'm actually doing is loading the COG address. How do I get the hub address? Also, I guess this code assumes that the hub address of the hello string is less than 512 which is probably a bad assumption.
    Sorry David, haven't had much time but you need the @ operator with a offset of $0E80 (ROM) (use a pointer)
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-01 20:57
    Sorry David, haven't had much time but you need the @ operator with a offset of $0E80 (ROM) (use a pointer)
    I'm not sure I understand what you mean. Are you saying that if a symbol is assigned a hub address of 0 by the assembler then the actual physical address is really $0E80?
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-01 21:03
    Sorry David, haven't had much time but you need the @ operator with a offset of $0E80 (ROM) (use a pointer)
    Anyway, I guess I have worse problems than the hello string address because I added the following code before the attempt to print the hello string and it doesn't work either:
                    mov	x,#"A"
                    call	#tx
                    mov	x,#"B"
                    call	#tx
                    mov	x,#"C"
                    call	#tx
    		mov	x,#13
    		call	#tx
    
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-01 21:25
    Sorry David, haven't had much time but you need the @ operator with a offset of $0E80 (ROM) (use a pointer)
    Peter, don't you have serial I/O working on the P2? How did you do it?
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-01 22:05
    I just realized that I don't see any code in the monitor that sets pin 90 to an output. Doesn't that require a write to the DIRC register? I guess maybe I need to wait for the detailed instruction set document.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2012-12-02 01:12
    David Betz wrote: »
    I just realized that I don't see any code in the monitor that sets pin 90 to an output. Doesn't that require a write to the DIRC register? I guess maybe I need to wait for the detailed instruction set document.
    I'm back. Did you see one of my earlier posts where I printed out a string?
    My first attempt at working code used the older instructions for setting pins using a mask, so yes, you have to set P90 to an output.
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-02 05:12
    I'm back. Did you see one of my earlier posts where I printed out a string?
    My first attempt at working code used the older instructions for setting pins using a mask, so yes, you have to set P90 to an output.

    Hi Peter,

    Thanks for the pointer to your earlier message. I thought you had gotten this working! I tried setting dirc in my (Chip's) code but it didn't help. Maybe the problem is that I've done something to break Chip's auto-baud code so it isn't even getting to the TX code. Can you post your low-level TX and RX functions including the timing constants and what baud rate you're trying to achieve?

    I don't understand Chip's ROM monitor code. As far as I can tell, it never sets dirc at all so I don't know how it makes P90 an output. I also don't understand his auto-baud code but I couldn't remove it since I don't know what value to give "period" to achieve a 115200 baud rate.

    I assume that "txmask" is initialized something like this:
    txmask  long  1 << (90-64)
    

    Also, I what is the value of "s" in the following code?
            mov    X,nameptr
            call    #PRT_STR
    
            mov    X,#1
            shl    X,#24
            djnz    X,$
            jmp    #TESTLP
    
    nameptr        long    @NAME+s
    

    Thanks for your help! How much of Tachyon Forth do you have working so far?
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-02 06:44
    Okay, I got rid of the auto-baud code and set the period with a constant and Chip's tx function seems to be working. I still don't understand the mapping between the addresses of labels given expressions like @my_string and hub addresses so the tx_string function doesn't work yet. Here is what I did to get the tx function working.
    CON
    
    	CLOCK_FREQ = 60000000
    	BAUD = 115200
    
    DAT
    
    '
    '
    ' Transmit chr (x)
    '
    tx              shl     x,#1                    'insert start bit
                    setb    x,#9                    'set stop bit
    
                    getcnt  w                       'get initial time
    
    :loop           add     w,period                'add bit period to time
                    passcnt w                       'loop until bit period elapsed
                    shr     x,#1            wc      'get next bit into c
                    setpc   tx_pin                  'write c to tx pin
                    tjnz    x,#:loop                'loop until bits done
    
    tx_ret          ret
    
    period          long	CLOCK_FREQ / BAUD
    
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-02 06:55
    I guess I'm on a roll now. The rx code seems to work fine as well. It was just the auto-baud code that I seem to have broken in my version. I have a question about how the ROM monitor code works though. Here is the code that starts the baud_task and and the rx_task. The baud_task setup makes sense to me. We run the main thread and the baud_task thread alternately. What I don't understand is the settask instruction that starts the rx_task. It seems to continue to run the baud_task even though the baud rate has already been determined. Why would you want that running in the background? It even seems to run it twice as often as the other two threads.
                    jmptask #baud_task,#%0010       'enable baud detector task
                    settask #%%0101
    
                    tjz     period,#$               'wait for <space> to set period
    
                    jmptask #rx_task,#%0100         'enable serial receiver task
                    settask #%%0121
    
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-02 07:37
    Okay, this mostly works. The only problem is that the first character of the hello string gets garbled. Any suggestions as to why this might be happening?
    ' mostly stolen from Chip's P2 ROM monitor
    
    CON
    	BASE = $e80
    	CLOCK_FREQ = 60000000
    	BAUD = 115200
    	SERIAL_TX = 90	' must be in the port c
    	SERIAL_RX = 91
    	CR = $0d
    	LF = $0a
    
    DAT
    
                    org
    
    		reps    #$1F6-@reserves,#1	'clear reserves
                    setinda reserves
                    mov     inda++,#0
    
    		mov	dirc,dirc_mask		'make tx pin an output
    
                    jmptask #rx_task,#%0010         'enable serial receiver task
                    settask #%%1010
    
    		' wait for the user to start the terminal emulator
    		mov	x,#5
    :pause          getcnt  w
    		add     w,freq
                    passcnt w
    		djnz	x,#:pause
    
                    setptra hello_addr              'print hello message
                    call    #tx_string              'print hello/error message
    
    idle		call	#rx
    		cmp	x,#CR wz
    	if_nz	jmp	#:next
    		call	#tx
    		mov	x,#LF
    :next           call	#tx
                    jmp	#idle
    
    '
    '
    ' Print string (@ptra)
    '
    tx_string       rdbyte  x,ptra++                'get chr
    tx_string_ret   tjz     x,#0                    'if 0, done
                    call    #tx                     'other?
                    jmp     #tx_string
    
    '
    '
    ' Transmit chr (x)
    '
    tx              shl     x,#1                    'insert start bit
                    setb    x,#9                    'set stop bit
    
                    getcnt  w                       'get initial time
    
    :loop           add     w,period                'add bit period to time
                    passcnt w                       'loop until bit period elapsed
                    shr     x,#1            wc      'get next bit into c
                    setpc   tx_pin                  'write c to tx pin
                    tjnz    x,#:loop                'loop until bits done
    
    tx_ret          ret
    
    '
    '
    ' Receive chr (x)
    '
    rx              call    #rx_check               'wait for rx chr
            if_z    jmp     #rx
    
    rx_ret          ret
    '
    '
    ' Check receiver, z=0 if chr (x)
    '
    rx_check        or      rx_tail,#$80            'if start or rollover, reset tail
    
                    getspb  rx_temp         wz      'if head uninitialized, z=1
            if_nz   cmp     rx_temp,rx_tail wz      'if head-tail mismatch, byte ready, z=0
    
            if_nz   getspa  rx_temp                 'preserve spa
            if_nz   setspa  rx_tail                 'get tail
            if_nz   popar   x                       'get byte at tail
            if_nz   getspa  rx_tail                 'update tail
            if_nz   setspa  rx_temp                 'restore spa
    
    rx_check_ret    ret
    
    
    '************************
    '* Serial Receiver Task *
    '************************
    
    rx_task         chkspb                  wz      'if start or rollover, reset head
            if_z    setspb  #$80
    
                    mov     rx_bits,#9              'ready for 8 data bits + 1 stop bit
    
                    neg     rx_time,period          'get -0.5 period
                    sar     rx_time,#1
    
                    jp      rx_pin,#$               'wait for start bit
    
                    subcnt  rx_time                 'get time + 0.5 period for initial 1.5 period delay
    
    :bit            rcr     rx_data,#1              'rotate c into byte
                    add     rx_time,period          'add 1 period
                    passcnt rx_time                 'wait for center of next bit
                    getp    rx_pin          wc      'read rx pin into c
                    djnz    rx_bits,#:bit           'loop until 8 data bits + 1 stop bit received
    
                    shr     rx_data,#32-8           'align byte
                    pushb   rx_data                 'store byte at head, inc head
    
                    jmp     #rx_task                'wait for next byte
    
    
    '*************
    '* Constants *
    '*************
    
    hello           byte    CR, LF, "Hello, Propeller II!", CR, LF, 0
    		long
    hello_addr      long	BASE + @hello
    rx_pin          long    SERIAL_RX
    tx_pin          long    SERIAL_TX
    dirc_mask	long	1 << (SERIAL_TX - 64)
    period          long	CLOCK_FREQ / BAUD
    freq		long	CLOCK_FREQ
    
    
    '*************
    '* Variables *
    '*************
    
    reserves
    
    w               res     1                       'main task
    x               res     1
    y               res     1
    z               res     1
    
    rx_tail         res     1                       'serial receiver task
    rx_temp         res     1
    rx_time         res     1
    rx_data         res     1
    rx_bits         res     1
    
  • ElectrodudeElectrodude Posts: 1,614
    edited 2012-12-02 07:38
    I'm not really sure if I should ask this here or in the Prop II update - Blog thread, but is there a GETTASK D, S instruction? I realize that it's too late to add it now if there isn't and probably should have asked about a month ago when I came up with the idea. I was hoping there would be because it would make making multitaskers much easier. You could have a program thread that got 15/16 cycles and a kernel that got 1/16. The kernel would do djnz cntr, $ , settask itself to get all of the turns, swap out processes (LMM), and set itself to get 1/16 of the turns and go back to the djnz loop.

    Thanks
  • Bob Lawrence (VE1RLL)Bob Lawrence (VE1RLL) Posts: 1,720
    edited 2012-12-02 09:07
    Looks like a Good turtorial to get started .


    DE0 Nano Introduction

    http://www.pyroelectro.com/tutorials/de0_intro/
  • LeonLeon Posts: 7,620
    edited 2012-12-02 09:19
    Here is a very simple VHDL project:

    http://www.leonheller.com/DE0-Nano

    It turns the first LED on. The LED is turned off when button KEY0 is pressed.
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-02 10:29
    David Betz wrote: »
    Okay, this mostly works. The only problem is that the first character of the hello string gets garbled. Any suggestions as to why this might be happening?
    ' mostly stolen from Chip's P2 ROM monitor
    
    CON
    	BASE = $e80
    	CLOCK_FREQ = 60000000
    	BAUD = 115200
    	SERIAL_TX = 90	' must be in the port c
    	SERIAL_RX = 91
    	CR = $0d
    	LF = $0a
    
    DAT
    
                    org
    
    		reps    #$1F6-@reserves,#1	'clear reserves
                    setinda reserves
                    mov     inda++,#0
    
    		setp	tx_pin		'set the tx pin high
    		mov	dirc,dirc_mask		'make tx pin an output
    
                    jmptask #rx_task,#%0010         'enable serial receiver task
                    settask #%%1010
    
    

    I fixed the problem with the corrupted first character. I had forgotten to set the tx pin high before making it an output. The corrected code is shown above. My test program now works completely thanks mostly to the code I stole from Chip! Next I'd like to make a loader that can handle programs that are larger than 2K...
  • nutsonnutson Posts: 242
    edited 2012-12-02 10:59
    Has somebody figured out a method to start a second COG on the DE2, eg a user COG besides the COG running the monitor?? The only clue I have is post 1766 in the PII thread, where Chip shows a trick to restart the monitor when a COG finishes. Probably I have to wait till a more complete loader becomes available, and Pnut output can be loaded into hub Ram.
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-02 11:03
    nutson wrote: »
    Has somebody figured out a method to start a second COG on the DE2, eg a user COG besides the COG running the monitor?? The only clue I have is post 1766 in the PII thread, where Chip shows a trick to restart the monitor when a COG finishes. Probably I have to wait till a more complete loader becomes available, and Pnut output can be loaded into hub Ram.
    I think the boot ROM starts a separate COG running the crypto stuff. You might look at how that is done.
  • LeonLeon Posts: 7,620
    edited 2012-12-02 11:05
    Thanks for that test program, David.

    I just tried it, and it echoed characters I typed into the terminal program, then went into the P2 monitor. It's doing something, anyway. I seem to have lost the Parallax terminal program, so I'm using RealTerm.
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-02 11:07
    Leon wrote: »
    Thanks for that test program, David.

    I just tried it, and it echo characters I typed into the terminal program, then went into the P2 monitor. It's doing something, anyway. I seem to have lost the Parallax terminal program, so I'm using RealTerm.

    You mean it reset the P2 after you typed a few characters? I haven't noticed that with mine. Are you running on a DE0-Nano or a DE2-115 board?
  • LeonLeon Posts: 7,620
    edited 2012-12-02 11:14
    I'm using the DE0-Nano.

    It didn't reset the P2, it jumped into the monitor. I don't know how it happened, I was typing random characters.

    I've reloaded the program and all it does now is echo whatever I type.
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-02 11:16
    Leon wrote: »
    I'm using the DE0-Nano.

    It didn't reset the P2, it jumped into the monitor. I don't know how it happened, I was typing random characters.

    I've reloaded the program and all it does now is echo whatever I type.
    That's all it's supposed to do. I just wanted to verify that I had working tx and rx functions so I can start trying to get some C code running. I still need details on the loader protocols before I can do that though. I need to be able to load more than 2k.
  • LeonLeon Posts: 7,620
    edited 2012-12-02 11:24
    I just tried using the Parallax Serial Terminal program, and it's a lot better than RealTerm. I got the initial "Hello, Propeller II!" message.

    I should be able to use it to debug P2 code, or could the ROM Monitor be used for that?
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-02 11:27
    Leon wrote: »
    I just tried using the Parallax Serial Terminal program, and it's a lot better than RealTerm. I got the initial "Hello, Propeller II!" message.

    I should be able to use it to debug P2 code, or could the ROM Monitor be used for that?
    I am using putty not PST. I'm not sure what you can do with the ROM monitor once your program is running. I haven't looked at it closely enough to know if it is possible to call it from your code and have a way to return.
  • Bob Lawrence (VE1RLL)Bob Lawrence (VE1RLL) Posts: 1,720
    edited 2012-12-02 11:35
    For anyone that needs the link for Putty:

    http://www.putty.org/
  • LeonLeon Posts: 7,620
    edited 2012-12-02 11:42
    The first thing I used to do with a new chip was to write a simple monitor/debugger for it, hand-assembling the code if I didn't have an assembler. It was a good way to learn all about the architecture and instruction set. Perhaps I should do that for the P2.

    I've modified David's code, so that it waits for a character from the terminal program. It now works a lot better with RealTerm.
                    jmptask #rx_task,#%0010         'enable serial receiver task
                    settask #%%1010
    	
    		call	#rx			'wait for any char to be typed
                    setptra hello_addr              'print hello message
                    call    #tx_string              'print hello/error message
    
    

    Terasic has tweeted this:

    https://twitter.com/Terasic_FPGA/status/275207738731143168
  • David BetzDavid Betz Posts: 14,511
    edited 2012-12-02 13:15
    I've been having trouble with some code I stole from the ROM monitor and I'm wondering if someone can explain how this works:
                    reps    #$1F6-@reserves,#1	'clear reserves
                    setinda reserves
                    mov     inda++,#0
    
    What I don't understand is the expression $1F6-@reserves. Isn't @reserves the byte address of that label? And $1F6 is the long address of the first register in COG memory. I would think the expression would really have to be something like $1F6 - (@reserves / 4) to get the number of longs between the label "reserves" and the first COG register. What am I missing here?

    I think I mentioned this before but I also don't understand why the second line isn't "setinda #reserves".
Sign In or Register to comment.