Hi Dave - sorry to keep throwing these at you, but here's another couple of minor incompatibilities ...
1. p2asm appears to allow "wzc" in place of "wcz" - i.e. the code compiles without error. But actually it silently ignores it, leading to much head scratching!.
2. p2asm accepts the "fit" directive but it seems to do nothing - i.e. it doesn't complain if the code doesn't actually fit.
Anyone looking at the LOC bug?
EDIT: I've just updated it.
Thanks for your test program. LOC and JMP below $400 are certainly difficult cases, and I think you've run into a mixture of assembler bugs, hardware misfeatures, and misunderstandings on all sides.
One potential problem in your code is that you use raw labels rather than asking for hub addresses, so for example the COG code that does:
loc pa, #loctest2
...
orgh $110
loctest2 long $deadbeef
gets compiled as if it read
loc pa, #$110
which of course won't work because as you note in your comments the value $deadbeef is actually located at $44 in COG memory. Should the assemblers catch this mistake? In principle I think they could issue a warning, at least (since the label "loctest2" is after an "orgh" directive we should know it's a hub expression). I think none of them do so now though.
Your program did point out a bug in fastspin, where it needs to divide the relative offset by 4 in COG mode. It looks like the hardware handles LOC and JMP differently in this regard; is that correct @cgracey ?
Actually it rather looks like we always need to divide the LOC value by 4 when running in COG mode, even for HUB addresses. That makes using LOC on byte addresses problematic. Is that intentional? It seems like it may be a hardware restriction that programmers need to be aware of -- it means that we can't use the same LOC code in COG and HUB, and that COG code cannot use LOC to load a HUB byte or word address. Never mind, that was based on a misunderstanding of how Evan's code works.
I think it would be prudent though for "loc" to default to absolute mode rather than relative; it might save trouble in the long run.
Eric,
That example LOC is very much intended to be used as a hub address. There is valid data access hubram below $400. Byte addressing is correct there.
Also, the first LOC is a cog address, 8, which also has the machine code encoded wrongly.
All three assemblers produce the same.
Only the third LOC, above hub $400, is encoded correctly.
It would be nice to retain the relative function. It can be done as Chip intended I think. So even the hubexec encoding needs a little work over for data references below $400.
which of course won't work because as you note in your comments the value $deadbeef is actually located at $44 in COG memory. Should the assemblers catch this mistake? In principle I think they could issue a warning, at least (since the label "loctest2" is after an "orgh" directive we should know it's a hub expression). I think none of them do so now though.
Your program did point out a bug in fastspin, where it needs to divide the relative offset by 4 in COG mode. It looks like the hardware handles LOC and JMP differently in this regard; is that correct @cgracey ?
All of that is related. Yes, there is a distinct difference between data addressing and program addressing. Program address encoding is byte scaled in all domains, but data addressing is longword scaled for cog space while byte scaled for hub space.
A LOC instruction has the encoding features of program addressing but is more likely to be used for data addressing ...
Hi Dave - sorry to keep throwing these at you, but here's another couple of minor incompatibilities ...
1. p2asm appears to allow "wzc" in place of "wcz" - i.e. the code compiles without error. But actually it silently ignores it, leading to much head scratching!.
2. p2asm accepts the "fit" directive but it seems to do nothing - i.e. it doesn't complain if the code doesn't actually fit.
PNUT complains about both of these.
p2asm now prints an error message if an invalid symbol is found when expecting wc, wz or wcz. I also fixed the FIT directive.
I guess I should point out that that would have been a correct answer but the buggy relative address is really $408 for some reason. Producing an absolute address of $416, not the $110 it should be.
I doubt there is any legit reason to want to LOC a cog data address. MOV immediate is just as compact there. If LOC gets assembled as always calculated to a program address (byte scaled) then that would be the easy fix.
It would then get treated same as existing branch long-immediate encoding.
Yes, there is a distinct difference between data addressing and program addressing. Program address encoding is byte scaled in all domains, but data addressing is longword scaled for cog space while byte scaled for hub space.
Oh, that's only true for long-immediate program addressing. Cogexec register direct addressing, for example, doesn't do that. Bit of a brain twister but for hubRAM addressing it's all byte scaled. That's where LOC wants to be used.
I am attempting to tease out your code to the serial terminal. Can you separate it out so I can access it??
Your putch appears to be simple. I was not part of the fpga develpment. I would like to develop a simple subroutine to get to the serial terminal.
thanks
The routines, putch and getch, are simple, yes. The naming was from Dave Hein's bit-bashing routines that I started from.
'===============================================
' input: (none)
' result: pb
'scratch: (none)
'
getch
testp #rx_pin wz 'byte received? (IN high == yes)
if_z rdpin pb, #rx_pin 'get data
if_z shr pb, #32-8 'shift the data to bottom of register
if_z ret wcz 'restore C/Z flags of calling routine
jmp #getch 'wait while Smartpin is idle
'===============================================
' input: pb
' result: (none)
'scratch: (none)
'
putch
rqpin inb, #tx_pin wc 'transmiting? (C high == yes) *Needed to initiate tx
testp #tx_pin wz 'buffer free? (IN high == yes)
if_z_or_nc wypin pb, #tx_pin 'write new byte to Y buffer
if_z_or_nc ret wcz 'restore C/Z flags of calling routine
jmp #putch 'wait while Smartpin is both full (nz) and transmitting (c)
Okay, so the two smartpins first need config'd before they operate as a comport. This is in the _diaginit routine.
'----- Configure diag comport to use smartpins instead of bit-bashing -----
wrpin #%00_11111_0, #rx_pin 'Asynchronous serial receive
wxpin ##ASYNCFG, #rx_pin 'set baurdrate and framing
dirh #rx_pin
wrpin #%01_11110_0, #tx_pin 'Asynchronous serial transmit mode
wxpin ##ASYNCFG, #tx_pin 'set X with baudrate and framing
dirh #tx_pin
' wypin #0, #tx_pin 'trigger first tx ready state (not needed if dual checked)
'single check is buffer full only, dual checking adds in tx flag
ASYNCFG is a preset constant defined at the start of the source. It is dependant on the prop2 system clock frequency, which is also preset in the same group of constants.
Example of 115200 baud and sysclock of 80 MHz from a crystal of 20 MHz.
@evanh
Hello,
I copied your code and have time now to work with it. I am getting an error that I assume is not right. Looking at your loc-cbug code shows similar stuff.
Trying to just print a single character.
Any Ideas?? when you get a chance.
Thanks
Oh, and there is more code in the _diaginit routine that sets the sysclock rate as well. I don't think pnut has any clock setting features.
'Silicon frequencies
hubset clk_mode 'switch to RCFAST using known prior mode
mov clk_mode, ##SETFREQ 'replace old with new
' mov clk_freq, ##CLOCKFREQ 'optional, if clk_freq used
hubset clk_mode 'setup for new mode, still RCFAST
waitx ##20_000_000/100 '~10ms for crystal/PLL to come up to speed
hubset ##ENAFREQ 'engage
And last problem is, because this transmits gapless, the character framing becomes invisible if the first start bit is not observed. Which means the receiving terminal can't work out what the transmitted characters are without some inserted gaps. A long gap at the beginning is enough.
Actually, does anyone have a description of precisely what the "." notation does for symbols - I am assuming it is supposed to be similar to what ":" used to do on the P1?
The ":" notation that was used for the P1 was changed to "." for the P2. I'm not sure why this change was made, but I expressed my concerns about using "." at the time when this was being discussed. When p2asm is in the object mode, it supports some of the GAS directives that happen to start with the "." character. Using "." for local variables complicates things a bit, so I currently don't allow local labels in the object mode. I'll fix this eventually, and just not allow local labels that match the supported GAS directives.
p2asm handles local labels a bit differently than PNut does. In PNut, local labels can exists only between global variables. p2asm allows local labels to be defined without a preceding global label. The scope of the local label does end when a global label is encountered, just like with PNut. Clearly, allowing two local labels with the same name within the same scope is a bug. I'll look into fixing that. At some point I'll also probably adopt the same rules as PNut.
The ":" notation that was used for the P1 was changed to "." for the P2. I'm not sure why this change was made, but I expressed my concerns about using "." at the time when this was being discussed. When p2asm is in the object mode, it supports some of the GAS directives that happen to start with the "." character. Using "." for local variables complicates things a bit, so I currently don't allow local labels in the object mode. I'll fix this eventually, and just not allow local labels that match the supported GAS directives.
p2asm handles local labels a bit differently than PNut does. In PNut, local labels can exists only between global variables. p2asm allows local labels to be defined without a preceding global label. The scope of the local label does end when a global label is encountered, just like with PNut. Clearly, allowing two local labels with the same name within the same scope is a bug. I'll look into fixing that. At some point I'll also probably adopt the same rules as PNut.
It's also common for assemblers to allow define of local labels - maybe that's another, better solution ?
eg this from an Assembler manual
$LOCALPREFIX (_) ; local label prefix is _
; Local labels generated with the previous global label + local label. Local labels must only be unique within the global labels and global label + local label must be unique.
_ThisIsLocalLabel:
; and the associated
$LOCALLIST ; Function: Enable local labels listing in symbol table.
$NOLOCALLIST ; Disable
I just need to change how I handle local labels. Concatenating the last global label with the local label seems to be the way to do it. The local label scope would then be identical to scope implemented by PNut.
EDIT: I ran a few tests with local labels in PNut, and it appears that they are limited to 26 characters instead of 30 characters, which is the limit for global labels. Of course, local labels are typically very short, so a 26-character limit isn't really a problem. I suspect that PNut internally concatenates local labels with a unique 4-character tag.
EDIT2: In my previous post I was wrong about local labels requiring a preceding global label in PNut. A local label can be defined before a global label, and it's scope extends to the following global label.
Thanks for your yelp. I am getting serial terminal data on a rudimentary level.
Now working on decimal numbers.
Attempting to look at Dave Hein's code. Do you have any examples or suggestions.
Martin
Comments
1. p2asm appears to allow "wzc" in place of "wcz" - i.e. the code compiles without error. But actually it silently ignores it, leading to much head scratching!.
2. p2asm accepts the "fit" directive but it seems to do nothing - i.e. it doesn't complain if the code doesn't actually fit.
PNUT complains about both of these.
Thanks for your test program. LOC and JMP below $400 are certainly difficult cases, and I think you've run into a mixture of assembler bugs, hardware misfeatures, and misunderstandings on all sides.
One potential problem in your code is that you use raw labels rather than asking for hub addresses, so for example the COG code that does: gets compiled as if it read which of course won't work because as you note in your comments the value $deadbeef is actually located at $44 in COG memory. Should the assemblers catch this mistake? In principle I think they could issue a warning, at least (since the label "loctest2" is after an "orgh" directive we should know it's a hub expression). I think none of them do so now though.
Your program did point out a bug in fastspin, where it needs to divide the relative offset by 4 in COG mode. It looks like the hardware handles LOC and JMP differently in this regard; is that correct @cgracey ?
Actually it rather looks like we always need to divide the LOC value by 4 when running in COG mode, even for HUB addresses. That makes using LOC on byte addresses problematic. Is that intentional? It seems like it may be a hardware restriction that programmers need to be aware of -- it means that we can't use the same LOC code in COG and HUB, and that COG code cannot use LOC to load a HUB byte or word address. Never mind, that was based on a misunderstanding of how Evan's code works.
I think it would be prudent though for "loc" to default to absolute mode rather than relative; it might save trouble in the long run.
Regards,
Eric
That example LOC is very much intended to be used as a hub address. There is valid data access hubram below $400. Byte addressing is correct there.
Also, the first LOC is a cog address, 8, which also has the machine code encoded wrongly.
All three assemblers produce the same.
Only the third LOC, above hub $400, is encoded correctly.
It would be nice to retain the relative function. It can be done as Chip intended I think. So even the hubexec encoding needs a little work over for data references below $400.
A LOC instruction has the encoding features of program addressing but is more likely to be used for data addressing ...
p2asm now prints an error message if an invalid symbol is found when expecting wc, wz or wcz. I also fixed the FIT directive.
It would then get treated same as existing branch long-immediate encoding.
Much appreciated, Dave!
question?
I am attempting to tease out your code to the serial terminal. Can you separate it out so I can access it??
Your putch appears to be simple. I was not part of the fpga develpment. I would like to develop a simple subroutine to get to the serial terminal.
thanks
Okay, so the two smartpins first need config'd before they operate as a comport. This is in the _diaginit routine.
ASYNCFG is a preset constant defined at the start of the source. It is dependant on the prop2 system clock frequency, which is also preset in the same group of constants.
Example of 115200 baud and sysclock of 80 MHz from a crystal of 20 MHz.
Hello,
I copied your code and have time now to work with it. I am getting an error that I assume is not right. Looking at your loc-cbug code shows similar stuff.
Trying to just print a single character.
Any Ideas?? when you get a chance.
Thanks
Eg:
So, recommend to use this at the start of your testing:
Eg, 1/2 second delay for terminal startup:
Or wait for a keypress before transmitting:
Didn't see that. Changed it and am getting gobbly goop but that is better than nothing. Gonna work on it later.
Thanks.
From the P1 reference manual ...
I can work around this, so it's not a big problem.
Thanks, Dave!
Found another "head scratching" incompatibility. The following code compiles with p2asm, but not with PNUT ...
Here is the output ...
Actually, does anyone have a description of precisely what the "." notation does for symbols - I am assuming it is supposed to be similar to what ":" used to do on the P1?
p2asm handles local labels a bit differently than PNut does. In PNut, local labels can exists only between global variables. p2asm allows local labels to be defined without a preceding global label. The scope of the local label does end when a global label is encountered, just like with PNut. Clearly, allowing two local labels with the same name within the same scope is a bug. I'll look into fixing that. At some point I'll also probably adopt the same rules as PNut.
It's also common for assemblers to allow define of local labels - maybe that's another, better solution ?
eg this from an Assembler manual
EDIT: I ran a few tests with local labels in PNut, and it appears that they are limited to 26 characters instead of 30 characters, which is the limit for global labels. Of course, local labels are typically very short, so a 26-character limit isn't really a problem. I suspect that PNut internally concatenates local labels with a unique 4-character tag.
EDIT2: In my previous post I was wrong about local labels requiring a preceding global label in PNut. A local label can be defined before a global label, and it's scope extends to the following global label.
Thanks for your yelp. I am getting serial terminal data on a rudimentary level.
Now working on decimal numbers.
Attempting to look at Dave Hein's code. Do you have any examples or suggestions.
Martin