Shop OBEX P1 Docs P2 Docs Learn Events
Prop 'tri-state' I/O possible? — Parallax Forums

Prop 'tri-state' I/O possible?

HarleyHarley Posts: 997
edited 2006-10-27 00:48 in Propeller 1
It seems having a tri-state port should be possible. idea.gif It needs to be as fast as possible, so will have to be in assembly.

Is there a way write to an OUTA register, even though the 'port' is in the Input direction?___ And, once a 'select' occurs, to change directions and have the port Data presented in less than 9 clock cycles (WAITPEQ plus a MOVx maybe)?___ (I've not yet gotten into Prop assembly coding, and am just studying other assembly code to understand what's needed to 'call' assembly from Spin.)

It seems one could have a 'masked' value ready to change direction to Output right after the WAITPEQ.

In assembly this would be 5 + 4 = 9 clock times; at 80 MHz, for 112.5 nsec to output to bus. Would like it much shorter, really. Is there any 'tricks' to do it faster?___

Another question, when actually does a change of direction occur or an output value get output, say for a 4 clock instruction; on the beginning of the 4th, or at the end? (Wish the Prop 'data sheet' were available

Anyone yet needed to work with an effective tri-state bus (say 8-bits)? Any help here would be highly appreciated. yeah.gif

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Harley Shanko
h.a.s. designn

Post Edited (Harley) : 10/23/2006 6:48:04 PM GMT
«1

Comments

  • Paul BakerPaul Baker Posts: 6,351
    edited 2006-10-23 20:12
    Yes OUTA may be written to when the bit is set to input, you will have to scope it to be sure, but there will be 4 to 5 cycles between a WAITxx match state and the completion of the next instruction (this is not including any of the setup time of the WAITxx instruction). The pipeline stages of the propeller are "read source, read destination, read next instruction, write result". So the writing of a result is interleaved with the reading of the next instruction.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
  • Cliff L. BiffleCliff L. Biffle Posts: 206
    edited 2006-10-23 20:49
    Harley,

    I'm working on compiling this sort of information; Paul's description of the pipeline stages here is the closest we've come so far.

    I am scopeless at the moment, unfortunately, so I'm having to be creative (e.g. run two cogs with their pipelines offset by 1-3 clocks, and have one report the actions of the other).
  • Cliff L. BiffleCliff L. Biffle Posts: 206
    edited 2006-10-23 20:53
    Paul Baker said...

    The pipeline stages of the propeller are "read source, read destination, read next instruction, write result". So the writing of a result is interleaved with the reading of the next instruction.

    Oooh, this strikes me as a pretty important detail for self-modifying code. Is the entire instruction fetched and buffered throughout the rest of the stages, or just the I field? In other words, which of the following two code snippets will not work as expected?
          movs foo, dest
    foo  jmp #0
    
    


          movi foo, %010111 ' change to a JMP
    foo  test dest
    
    
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2006-10-23 21:12
    Cliff,

    The modified instruction cannot immediately follow the modifying one. In both your examples, you'll need to add a NOP.

    -Phil
  • Paul BakerPaul Baker Posts: 6,351
    edited 2006-10-23 21:13
    I believe the entire 32 bits is loaded. It is irrelevant about being buffered since the current architecture does not use parallel pipelined execution, hence nothing can alter the remainder of the instruction once it has·begun execution.· Modified code must be separated by 1 instruction from the modifier, this is in the Propeller Tricks and Traps sticky.

    My personal workaround for making the most efficient index based addressing is to do post modification like so:

    :loop  mov  there, here
           add  :loop, SandD           'do mod here so we have 1 instruction between mod and mov
           djnz i, #:loop
     
     
    SandD  long $0000_0201             'lsb of source and destination
    


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.

    Post Edited (Paul Baker (Parallax)) : 10/23/2006 9:25:03 PM GMT
  • HarleyHarley Posts: 997
    edited 2006-10-23 21:24
    Paul,

    The WAITPEQ is listed as 5+ clocks. I suppose if the match doesn't occur, then the 5th state if in effect 'jump back to same instruction' for another match test. Is that true?____

    On a related aspect, if one has several events which need monitoring, I suppose that each one would require separate cogs with each having its own WAITPEQ test. This assumes there is no sequential relationship for the events; else one could chain them, assuming the sequence always occurred. Else, one would get a HANG condition?___

    And, for the 4-clock OUTA instruction, I'm guessing the output state occurs at the beginning of the 'write result' phase?____

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
  • Paul BakerPaul Baker Posts: 6,351
    edited 2006-10-23 21:43
    Yes there is a 4 cycle "setup time" then a minimum 1 cycle match condition, this last stage will extend until the match condition occurs, however many cycles that takes.

    One has to be careful about using WAITPxx because it will hang until the condition becomes true. If you are waiting for multiple possible events, it is best to use the WAITPNE with the mask of the pins you are interested in and the current state of those pins. That way whenever an "other than now" condition occurs, the instruction will exit and you can test to see which event occured.

    Heres a major gotcha: do not set any bit in the state value that isn't set in the mask value otherwise it will hang forever, as a sure thing AND the current state with the mask before sending it to any WAITPxx instruction.

    The outputs wont be affected until the next clock edge, which is after the write stage.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.

    Post Edited (Paul Baker (Parallax)) : 10/23/2006 9:49:29 PM GMT
  • HarleyHarley Posts: 997
    edited 2006-10-23 23:12
    I looked over the 'Assembly Code Examples for the Beginner'. The examples appeared to only control a single I/O pin, or two. What does one do for more sequential bits, say 8 bits?___

    I would like to setup the masks for DIRA and WAITPEQ in Spin. Can these be also referenced in the assembly code?___ Might seem like a dumb question, but haven't run across a good example, and too much newbie here. Is there a demo program which would provide a good example for such?___ yeah.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
  • Paul BakerPaul Baker Posts: 6,351
    edited 2006-10-23 23:29
    Controlling multiple I/O pins depends entirely on what exactly you are controlling.

    There are two handy method for passing masks from Spin to an assembly cog, if the values change during the execution of the cog, you must pass a pointer to thier location when you start the assembly cog via the second argument.

    If they are a "write once" value that is computed prior to starting the assembly cog, you can declare and label a value after your code and before any res in your assembly code such as:

    diraval··· LONG· $0000_0000

    then directly assign thier value in·Spin before starting the cog like this:

    diraval := $0000_0001

    When the assembly cog is launched diraval will contain $0000_0001 instead of $0000_0000, so when you do

    mov·dira, diraval

    in your assembly code, P0 will be set to output.


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
  • HarleyHarley Posts: 997
    edited 2006-10-23 23:45
    Paul,

    Thanks for the advice.

    The assignment of pins will not change for the tri-state bus. I assume, if I wished to use A16..28 for a 8-bit tri-state bus. then I should assign

    diraval := $00FF_0000

    for an output.

    Hopefully this doesn't change other I/O pin assignments.

    I probably will want to set a mask,
    mask := $00FF_0000
    instead, for my application as it has to be for Input and Output port use, some DIRA stuff happening at times.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
  • HarleyHarley Posts: 997
    edited 2006-10-24 22:18
    Help! freaked.gif

    I'm confused. In Ch 5 (Assembly) DIRA, INA, OUTA is described under Registers, but then you can't control individual pins "...unless using the MUXx instructions."

    But in the MUXx instructions they only talk about 9-bit fields. How does that give one control over 32 pins?___

    I browsed the forum on assembly, but didn't recognize anything in particular.

    Does anyone know of a good assembly example(s) for controlling direction, in, out?____ Hopefully one can turn from tri-state to output in less than 200 nsec.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2006-10-24 22:37
    It says that the mask is a register OR a 9-bit literal.

    A literal is when you type it in manually like #20 you will find that the propeller tool will complain if you try to use a literal greater than 9-bits in size.

    You can still control individual pins with OUTA etc by using a mask it is just not as convenient as by using mux instructions.
    
       OR outa, $0000_0003       'would set bits 0 and 1 high but leave the rest as they were (high or low)
    
    
    



    Graham
  • HarleyHarley Posts: 997
    edited 2006-10-24 22:52
    Thanks so much Graham,

    Unfortunately I'm using port pins A16-A24. Maybe I should change my schematic to use pins A0 - A7 to make the setting and masking easier.

    I don't understand the 'register' business with MUXx. Unless they are the '16 special purpose registers'.

    Is there an example of how the 'destination' and 'source' fields are put to use?___ Does the MUX portion correspond to some sort of 'multiplexer'?___ I'm able to figure out most Spin instructions, but am running into 'holes' in the assembly instruction. (Must have missed that lecture!!! Ha, ha>)

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
  • Mike GreenMike Green Posts: 23,101
    edited 2006-10-24 23:05
    The MUXzz instruction may be somewhat misnamed. Think of it just as copying a flag bit into specified bits of a cog memory location. You do have a choice of one of four sources (Carry, not-Carry, Zero, not-Zero). The places where this bit is to be copied is provided by a mask value with one bits indicating that the flag should be copied to the memory location bit and zero bits indicating that nothing should be changed there. The mask value comes from an immediate value or another (source) memory location. Does that help?
  • HarleyHarley Posts: 997
    edited 2006-10-24 23:15
    Thanks Mike,

    I read and 'heard' what you said, but still see no use for these MUX instructions operating on any but the lower 9 pins. Or, can shifting left somehow be useful?___

    I guess it didn't help me much for using, say I/O 16 thru 24, sorry. What I would like to do is set an 8-bit port to tri-state, output or input, depending on the condition. With the output value already ready to be OUTA'd on the port. Too bad the assembly DIR, OUT and IN weren't like the Spin instructions. yeah.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
  • Beau SchwabeBeau Schwabe Posts: 6,560
    edited 2006-10-24 23:36
    Harley,

    This section of the "Assembly Code Examples for the Beginner" might help...
    http://forums.parallax.com/showthread.php?p=603397

    Once you determine a mask for the pin assigned for the job, it does not need to change.


    If you want to switch between making the PIN HIGH or an INPUT

    Use...
    or outa, PinMask ' Make Pin HIGH
    

    And toggle between...
    andn dira, PinMask ' Make Pin an Input
    

    And...
    or dira, PinMask ' Make Pin an Output
    





    If you want to switch between making the PIN LOW or an INPUT

    Use...
    andn outa, PinMask ' Make Pin LOW
    

    And toggle between...
    andn dira, PinMask ' Make Pin an Input
    

    And...
    or dira, PinMask ' Make Pin an Output
    

    EDIT - PinMask can represent one pin or multiple pins

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.

    Post Edited (Beau Schwabe (Parallax)) : 10/24/2006 11:49:26 PM GMT
  • HarleyHarley Posts: 997
    edited 2006-10-24 23:54
    Thanks Beau,

    I've read that one a number of times. But that is dealing with only a 1 bit mask. I need a 8-bit mask to use A16-A24.

    Possibly all the setting and shifting could be done prior to a WAITPEQ. I need to output several bytes on a bus fairly fast. I was planning to use 4 registers set up in the Output registers before calling the assembly code. When external read enables occur, the data needs to be output in much less than 200 nsec. Maybe the Prop cannot handle such! I thought after the WAITPEQ, an DIRA could be issued to place one of the 4 bytes on the bus. Like replacing a TTL -374 tristate latch with a Prop. It's getting the 'output enable' function done quickly that seems to be a huge problem.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
  • Paul BakerPaul Baker Posts: 6,351
    edited 2006-10-25 00:21
    8 pin mask for A16-A23 (I assume you mean through A23 since A16-A24 is 9 bits) is $00FF_0000.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
  • HarleyHarley Posts: 997
    edited 2006-10-25 00:40
    Thanks Paul,

    Looks like I can use more than a 1-bit mask. Good, combining a 8-bit mask with something similar to Beau's suggestion should work, huh?

    Will implement that tomorrow.

    Great, having some assistance on questions that don't yet appear in the Prop manual. I understand it would be impossible to present every possible approach in a manual.

    Thanks, everyone for guidance on this area. yeah.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
  • Mike GreenMike Green Posts: 23,101
    edited 2006-10-25 01:15
    Harley,
    Let's say you have a long word (FOO) that you want to set up for a transfer. This assumes that only the 8 I/O pins used for the transfer (16..23) are set as outputs and that those pins have to remain as inputs until the first of 4 transfers, then have to be set back to inputs. The bus is available for the transfer when the clock is high and the data must be stable by the time the clock goes low. Hold time is minimal (the pins can be made inputs as soon as the clock goes low). The clock (for discussion) is provided on pin 24.
                   rol          FOO,#16            ' Position for first transfer
                   mov       OUTA,FOO          ' Move to output register
                   waitpne  zero,ClkMask      ' Wait for 1st clock
                   mov       DIRA,DirMask     ' Make pins outputs
                   waitpeq  zero,ClkMask      ' Wait for end of clock
                   ror         OUTA,#8            ' Move 2nd byte into position
                   waitpne  zero,ClkMask      ' Wait for 2nd clock
                   waitpeq  zero,ClkMask       ' Wait for end of clock
                   ror         OUTA,#8             ' Move 3rd byte into position
                   waitpne  zero,ClkMask       ' Wait for 3rd clock
                   waitpeq  zero,ClkMask       ' Wait for end of clock
                   ror         OUTA,#8             ' Move 4th byte into position
                   waitpne  zero,ClkMask       ' Wait for 4th clock
                   waitpeq  zero,ClkMask       ' Wait for end of clock
                   mov       DIRA,zero           ' Make pins inputs again
    ' .....
    zero         long       0                        ' Zero value
    ClkMask   long       $01000000        ' Mask for clock pin (24)
    DirMask   long       $00FF0000         ' Mask for data pins (23..16)
    
    


    I think the maximum time to stable data is 4-5 clocks (100-112.5ns) from the low to high clock edge and the data pins are "tri-stated" within 4-5 clocks (100-112.5ns) of the high to low clock edge. Note that this requires that the remainder of the OUTA register is not used (for outputs) by this cog.
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2006-10-25 10:14
    Harley, by register it means any 32bit register you have defined, i.e. a variable. Nearly all of the functions are like this, they take a 32bit register or a 9-bit literal.

    This is the key thing you are missing I think, register means varable. They can be special purpose or user defined.

    
       mov    mask,#1        ' set bit 0 to one
       shl      mask, #23     ' shift bit to pin 23
       or       dira,mask
    
    
    mask      res      1          ' The register you define
    
    or it could be:
    
    mask      long     $00FF0000     ' Set it specifically   
    
    
    
  • HarleyHarley Posts: 997
    edited 2006-10-25 14:46
    Thanks Graham,

    Looking at some assembly code I was totally confused. What that was, was the 'condition' and 'effects' terms on some lines. Looked improperly indented. Wow! what a 32-bit micro provides in the way of neat, yet complex instructions with those one-line instructions with conditions and effects.

    Each person who has tried to answer my questions has helped. Now it is clear WHY it is not easy to write this into a manual. And it didn't help that I'd never worked with other than more limited 8-bit micros. Such 'freedom'.idea.gif

    Thanks, everyone. Hopefully I won't be so stuck with Prop assembly now (= less questions.) yeah.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
  • HarleyHarley Posts: 997
    edited 2006-10-25 23:39
    Mike,

    I have a cog about ready to 'tri-state' some info.

    So I added part of your suggestion. Only the compiler balks at the first FOO!?!?!
                   rol          FOO,#16            ' Position for first transfer
                   mov       OUTA,FOO          ' Move to output register
                   waitpne  zero,ClkMask      ' Wait for 1st clock
    
    


    I think I have FOO properly defined elsewhere.

    I get the error "Expected a constant, a unary operator. or "("." Yet the manual says the value field is a register to rotate. Guess there is loads to learn what to do correctly. Ah, the 'learning curve' effort. I tried a number of things, but the compiler still doesn't like what I do.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2006-10-25 23:45
    please post the whole code as a file so it can be checked properly, the fragment looks OK

    Graham
  • HarleyHarley Posts: 997
    edited 2006-10-26 00:16
    ·Graham,

    Here's the assembly portion.· Hope there's a clue here (it is slightly different than what Mike suggested).· The error flags 'statFOO' of the ROL instruction.
    ''***************************************
    DTbusRd       'test      DTstart, #1 wz          ' test for start condition
    '        if_nz waitpeq   INstate, INmask
                  rol       statFOO,#16             ' position for first transfer
                  mov       OUTA, statFOO                ' move byte to output register
                  waitpeq   zero, IOmask             ' wait for BIORQn low level
                  mov       DIRA, DTbusmask         ' make pins outputs
    ' something else goes in here
                  waitpne   zero,IOmask             ' wait for BIORQn hi level
                  mov       DIRA,zero               ' make pins inputs again
                  cogid    : id
                  cogstop  : id
    statFOO       long  0
    zero          long  0                           ' zero value
    :id           LONG  $0000_0000
    'DTstart       LONG  $0000_0000
    'INstate       LONG  $0000_0000
    'INmask        LONG  $0000_0000
    IOmask        long  $0000_0020  ' mask for only BIORQn pin (A6)
    DTbusmask  LONG  $00FF_0000       
    ''****************************************
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
  • Mike GreenMike Green Posts: 23,101
    edited 2006-10-26 00:29
    The error message is a bit confusing, but I think the problem is that you're referencing a local label (:id) that's "beyond" a global label. Try changing the :id to something else and see what happens.

    Mike
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2006-10-26 09:00
    Unless it is top secret please attach the whole file, then we can get the same bug and try to see why.

    Graham
  • Graham StablerGraham Stabler Posts: 2,510
    edited 2006-10-26 15:47
    After looking at your code (sent via PM) the problem seems to be that you have defined StatF00 in the VAR section as well as in the DAT section.

    The VAR relates to hub ram, you can't access that directly with assembly code, the cog has to load the data in with rlong and then write it back with wrlong.

    Basically if I cut out the declaration in the VAR section it compiled (although I also cut out all other functions so I just had the asm to avoid having to download the required objects.

    So either you need to do that or you need to change the program more drastically if you really do need global access to the variable.

    Graham
  • HarleyHarley Posts: 997
    edited 2006-10-26 16:13
    That was fast, Graham,

    At one time I had commented out StatFOO in VAR, but there probably were other errors at that time and didn't notice it later. Thanks for finding the offending line. Will take a while to get a handle on all the things that have to be proper for the compiler to be 'happy'.

    At least, once one can get past the compile step, then other debugging methods can be applied to verify whether what one intends if really occurring. I'll have to keep in mind these sort of conflicts for future problem solving.

    I owe you one, Graham.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
  • HarleyHarley Posts: 997
    edited 2006-10-26 16:53
    Graham said...
    The VAR relates to hub ram, you can't access that directly with assembly code, the cog has to load the data in with rlong and then write it back with wrlong.
    Ah, so that is how the Spin and assembly communicate with values in HUB memory. Which means I will need to add a 'rdbyte, rdword or rd long' to hand over a set of values to the 'tri-state' cog code, if I understand correctly.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    h.a.s. designn
Sign In or Register to comment.