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.
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.
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.
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)
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?
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:
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 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.
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?
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
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
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
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.
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...
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.
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.
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.
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?
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.
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.
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
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".
Comments
Thanks!
David
Edit: Removed the code to setup rx_pin and tx_pin and moved rx_pin to 91 and tx_pin to 90.
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:
Also, I what is the value of "s" in the following code?
Thanks for your help! How much of Tachyon Forth do you have working so far?
Thanks
http://www.digikey.ca/scripts/DkSearch/dksus.dll?WT.z_header=search_go&lang=en&keywords=P0082-ND&x=14&y=12&cur=USD
DE0 Nano Introduction
http://www.pyroelectro.com/tutorials/de0_intro/
http://www.leonheller.com/DE0-Nano
It turns the first LED on. The LED is turned off when button KEY0 is pressed.
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...
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.
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?
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.
I should be able to use it to debug P2 code, or could the ROM Monitor be used for that?
http://www.putty.org/
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.
Terasic has tweeted this:
https://twitter.com/Terasic_FPGA/status/275207738731143168
I think I mentioned this before but I also don't understand why the second line isn't "setinda #reserves".