Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 11:13 19 Apr 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : PicoMite - thinking about PIO - and a request

     Page 2 of 3    
Author Message
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 3490
Posted: 09:10am 28 Jun 2021
Copy link to clipboard 
Print this post

Please treat below text as thoughts about the PIO compiler. Just thoughts...

After doing some reading on the actual implementation in micropython, and reading the RP2040 datasheet, I am not clear on why they split up the code the way they do now.

if you look at the PIO sequencer code you need to define upfront how the 5 delay/side bits are to be interpreted. But the definition of this, and the actual assigned PIO pins are not in the sequencer source code, but in the associated python code.

This makes going back and forth between PIO code and python code needed to understand what is actually going on. Yeah...I know...old guy, used to looking at a single file program, trying to understand what is going on.

How would this work in our MMBasic environment, we would have to put the GPIO assignments in the basic program, and the PIO code in data statements (or separate file) compiled as binaries.

Items like SIDESET_COUNT, PINCTRL_SIDESET_COUNT, EXECCTRL_SIDE_EN, PINCTRL_SIDESET_BASE. Since the compiler has to know how to fill the 5 bits delay field, some of these parameters must be known to the compiler before. But some of it must be known/set to the basic program (i.e. the PINCTRL_SIDESET_BASE) because this info is not in the compiled code.

Maybe that is because ".side_set 1" is in the compiled code, and (similar/overlapping) the "SIDE_COUNT" in the python code.

Anyway, it looks like the compiled sequencer code (the hex file) contains a block of functionality that can be mapped by the python(MMBasic) program towards IO pins/timers. Like a relocatable function block. But there are some setting that must be set the same in PIO code and MMBasic. How do we do that ..?

End of thoughts... have to get to work now...
PicomiteVGA PETSCII ROBOTS
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8566
Posted: 09:27am 28 Jun 2021
Copy link to clipboard 
Print this post

More thoughts:

Obviously the use of PIO will not be for the "beginner" so I'm going to expose some of the actual PIO registers to the user as the most powerful way of providing access. So the proposed user I/F is now as follows:

SETPIN n,PIO0
SETPIN n,PIO1

configures a pin to allow write access by a PIO program. NB: any pin can be read by a PIO program without specific configuration. The firmware cannot tell if a PIO program tries to read a pin set for another function

PIO PROGRAM pionumber, program_array%()

Programs one of the two PIO with a specific program. The program_array%() will always be 8 elements long (32x16bit instructions) and unneeded instructions should be filled with MOV y,y (NOP)

PIO INIT MACHINE pionumber, clockspeed, EXECCTRL register, SHIFTCTRL register, PINCTRL register, statemachine%

This says to set up a statemachine for the specified PIO with a given clock speed. The user is then required to specify the three registers which control how the PIO will operate. See the manual for details. The statemachine% parameter will return the number of the state machine that has been created (1 to 4). It is anticipated that eventually the assembler will be able to generate the register values for the user along with the program array based on the defined assembler directives.

NB: I have extensively reviewed both the source of PIOASM and the source of the limited assembler implementation in MicroPython and in both cases trying to integrate the code would be harder than coding from scratch in C and much harder than coding something in Basic

PIO START pionumber, statemachine%

Starts or restarts a specific state machine

PIO STOP pionumber, statemachine%

Stops a specific state machine

PIO WRITE pionumber, statemachine%, nbr_of_data_elements, data

Write data to a specific statemachine. The data format will be the same as the SPI WRITE command i.e. flexible

PIO READ pionumber, statemachine%, nbr_of_data_elements, data%(), timeout

Read data from a specific statemachine. The data format will be the same as the SPI READ command i.e. a single integer array. The timeout specifies the time to wait in milliseconds for data to be available

Thoughts?
Edited 2021-06-28 19:40 by matherp
 
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 3490
Posted: 10:50am 28 Jun 2021
Copy link to clipboard 
Print this post

Hi Peter,

Please explain the format of program_array%. Do you expect the PIO code to be formatted as 64 bit integers in this array (8 x 64 bit = 32 x 16 bit). Which 16 bit value goes where (endianness).

Please explain the reason to fill the rest of the array with MON y,y. Since the machine never get's there, why not JMP 0 (= &h0). No problem, just curious...

I like the idea of the "basic compiler" since (Mixtel90 showed) it is do-able, maintainable, and this step could also be replaced by using external compilers. As long as they generate a hex file.

Do you see an option for the compiler (basic) to become an integral part of the picomite ? In the MX170 we have a "library" where we can store basic functions that we use often, and these where available from the running program. If that where the case  the library could contain the compiler, and we could have the PIO source code in our basic program (i.e. as data statements), could compile "on the fly", and plunge the resulting hex into the programming array%.

You could even imagine using slot #0 in flash for that (for the library), or would you need the library to be in RAM also ?

Regards,

Volhout
PicomiteVGA PETSCII ROBOTS
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8566
Posted: 10:59am 28 Jun 2021
Copy link to clipboard 
Print this post

  Quote  Do you expect the PIO code to be formatted as 64 bit integers in this array (8 x 64 bit = 32 x 16 bit


Yes, normal endidness

  Quote  Please explain the reason to fill the rest of the array with MON y,y.


Could be either - just needs to be a valid instruction

  Quote  Do you see an option for the compiler (basic) to become an integral part of the picomite ?


TBD

  Quote  In the MX170 we have a "library" where we can store basic functions that we use often, and these where available from the running program. If that where the case  the library could contain the compiler, and we could have the PIO source code in our basic program (i.e. as data statements), could compile "on the fly", and plunge the resulting hex into the programming array%.


The concept of a library doesn't make much sense since we are running from RAM. You could though store the Basic assembler in a flash slot and chain to and from it to load up the PIO programs. This is functionality that should work now.
 
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 3490
Posted: 01:04pm 28 Jun 2021
Copy link to clipboard 
Print this post

Hi Peter,

You made the request about PIO in this thread, and added the new code in the LCD display thread. Kind of confusing.

  Quote  The concept of a library doesn't make much sense since we are running from RAM. You could though store the Basic assembler in a flash slot and chain to and from it to load up the PIO programs. This is functionality that should work now.


I only played a bit with CHAIN, but AFAIK the chain does not return to the program it was called from. So invoking the compiler from a chain, need you to edit the compiler itself to make it return to the program you called it from. Or split up your program in 2 parts (to avoid re-dimensioning variables if you return from the chain). Part 1 does the DIM's , and inits for PIO, then chain the compiler, then chain the execution part of your program.

The hard reference to a flash slot can help in that effect. If you always have your execution part of the program in slot 1, then the compiler can be hard coded to execute slot 1 after compilation.
PicomiteVGA PETSCII ROBOTS
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8566
Posted: 01:15pm 28 Jun 2021
Copy link to clipboard 
Print this post

  Quote  and added the new code in the LCD display thread. Kind of confusing.


I put the code in the code thread

  Quote  but AFAIK the chain does not return to the program it was called from. S


I'll add a system variable that tells the program which flash slot it was loaded from. That way a program can set a variable to tell a chained program where to next chain
 
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 3490
Posted: 01:24pm 28 Jun 2021
Copy link to clipboard 
Print this post

Hi Peter,

Maybe an idea to add the system variable that shows the previous flash slot.
I.e. MM.chain

-1 : it is an initial run
0-10 : the slot that called the current program.

That way you can skip de DIM statements


'code in any flash slot
if MM.chain < 0 then
 DIM a%(100)
 flash chain 1
end if
print a%(1)



'in flash slot #1
a%(1)=23
flash chain MM.chain

Edited 2021-06-28 23:26 by Volhout
PicomiteVGA PETSCII ROBOTS
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 5705
Posted: 06:58pm 28 Jun 2021
Copy link to clipboard 
Print this post

Latest version
PIO assembler wip015.zip
A lot has changed. At the expense of clarity, I'm pretty sure that it's smaller (and maybe slightly slower) than previously. The assembler is now a proper Sub to make it easier to use. Will now save to the required array format.

I'm currently working on having 2 sets of data statements and two output arrays, allowing it to assemble the code for both PIO progs in the same program.
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8566
Posted: 07:37am 29 Jun 2021
Copy link to clipboard 
Print this post

Mick

Great work but another request - sorry. The PIO have a facility where you can force a specific instruction on to them which executes immediately. The various supplied examples use this to change the way execution is happening. I'm incorporating a new sub-command to support this

PIO EXECUTE pionumber,statemachinenumber, instruction


To be fully integrated we will need a instruction function that returns a single integer

e.g.

? PIOinstruction("PULL ifempty,block")


Then we can execute a Basic statement like

CODE]PIO EXECUTE pionumber,statemachinenumber, PIOinstruction("PULL ifempty,block")

Later today I'll post a bunch of the example PIO programs and the correct machine code for you to help testing
Edited 2021-06-29 17:39 by matherp
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 5705
Posted: 08:09am 29 Jun 2021
Copy link to clipboard 
Print this post

Thanks. It'll help a lot. :)

The assembler should recognise now. (p346 of the RP2040 dada sheet)
Load a 32-bit word from the TX FIFO into the OSR.

pull <ifempty> block
where <ifempty> defaults to 0 and block defaults to 1
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8566
Posted: 09:10am 29 Jun 2021
Copy link to clipboard 
Print this post

Sample 1
   0x9080, //  0: pull   noblock         side 0    
   0xa027, //  1: mov    x, osr                    
   0xa046, //  2: mov    y, isr                    
   0x00a5, //  3: jmp    x != y, 5                  
   0x1806, //  4: jmp    6               side 1    
   0xa042, //  5: nop                              
   0x0083, //  6: jmp    y--, 3    

Sample 2
   0xf780, //  0: set    pindirs, 0      side 0 [7]
   0xf781, //  1: set    pindirs, 1      side 0 [7]
   0xff80, //  2: set    pindirs, 0      side 1 [7]
   0xff81, //  3: set    pindirs, 1      side 1 [7]

Sample 3

   0x008c, //  0: jmp    y--, 12                    
   0xc030, //  1: irq    wait 0 rel                
   0xe027, //  2: set    x, 7                      
   0x6781, //  3: out    pindirs, 1             [7]
   0xba42, //  4: nop                    side 1 [2]
   0x24a1, //  5: wait   1 pin, 1               [4]
   0x4701, //  6: in     pins, 1                [7]
   0x1743, //  7: jmp    x--, 3          side 0 [7]
   0x6781, //  8: out    pindirs, 1             [7]
   0xbf42, //  9: nop                    side 1 [7]
   0x27a1, // 10: wait   1 pin, 1               [7]
   0x12c0, // 11: jmp    pin, 0          side 0 [2]
           //     .wrap_target
   0x6026, // 12: out    x, 6                      
   0x6041, // 13: out    y, 1                      
   0x0022, // 14: jmp    !x, 2                      
   0x6060, // 15: out    null, 32                  
   0x60f0, // 16: out    exec, 16                  
   0x0050, // 17: jmp    x--, 16                    
            //     .wrap

Sample 4
   0x7821, //  0: out    x, 1            side 1    
   0x0623, //  1: jmp    !x, 3                  [6]
   0x1700, //  2: jmp    0               side 0 [7]
   0x0704, //  3: jmp    4                      [7]
   0x7021, //  4: out    x, 1            side 0    
   0x0627, //  5: jmp    !x, 7                  [6]
   0x1f04, //  6: jmp    4               side 1 [7]
   0x0700, //  7: jmp    0                      [7]

Sample 5
   0x2ba0, //  0: wait   1 pin, 0               [11]
   0x00c4, //  1: jmp    pin, 4                    
   0x4021, //  2: in     x, 1                      
   0x0000, //  3: jmp    0                          
   0x4141, //  4: in     y, 1                   [1]
           //     .wrap_target
   0x2b20, //  5: wait   0 pin, 0               [11]
   0x00c9, //  6: jmp    pin, 9                    
   0x4041, //  7: in     y, 1                      
   0x0000, //  8: jmp    0                          
   0x4121, //  9: in     x, 1                   [1]
           //     .wrap

Sample 6            //     .wrap_target
   0x80a0, //  0: pull   block           side 0    
   0x40e1, //  1: in     osr, 1          side 0    
   0x6068, //  2: out    null, 8         side 0    
   0x40e1, //  3: in     osr, 1          side 0    
   0x6068, //  4: out    null, 8         side 0    
   0x40e1, //  5: in     osr, 1          side 0    
   0x6060, //  6: out    null, 32        side 0    
   0x80a0, //  7: pull   block           side 0    
   0x50e1, //  8: in     osr, 1          side 1    
   0x7068, //  9: out    null, 8         side 1    
   0x50e1, // 10: in     osr, 1          side 1    
   0x7068, // 11: out    null, 8         side 1    
   0x50e1, // 12: in     osr, 1          side 1    
   0x7060, // 13: out    null, 32        side 1    
   0x507a, // 14: in     null, 26        side 1    
   0xb016, // 15: mov    pins, ::isr     side 1    
           //     .wrap

Sample 7
           //     .wrap_target
   0x80e0, //  0: pull   ifempty block              
   0xe022, //  1: set    x, 2                      
   0x40e5, //  2: in     osr, 5                    
   0x6065, //  3: out    null, 5                    
   0x4063, //  4: in     null, 3                    
   0x0042, //  5: jmp    x--, 2                    
   0x4048, //  6: in     y, 8                      
   0xa0d6, //  7: mov    isr, ::isr                
   0x6061, //  8: out    null, 1                    
   0xe03f, //  9: set    x, 31                      
   0xe000, // 10: set    pins, 0                    
   0xa606, // 11: mov    pins, isr              [6]
   0xe001, // 12: set    pins, 1                    
   0x46c1, // 13: in     isr, 1                 [6]
   0x004a, // 14: jmp    x--, 10                    
           //     .wrap

Sample 8
           //     .wrap_target
   0x80a0, //  0: pull   block                      
   0xa02f, //  1: mov    x, !osr                    
   0x80a0, //  2: pull   block                      
   0xa047, //  3: mov    y, osr                    
   0x0006, //  4: jmp    6                          
   0x0046, //  5: jmp    x--, 6                    
   0x0085, //  6: jmp    y--, 5                    
   0xa0c9, //  7: mov    isr, !x                    
   0x8020, //  8: push   block                      
           //     .wrap

Sample 9
   0x2ba0, //  0: wait   1 pin, 0               [11]
   0x00c4, //  1: jmp    pin, 4                    
   0x4021, //  2: in     x, 1                      
   0x0000, //  3: jmp    0                          
   0x4141, //  4: in     y, 1                   [1]
           //     .wrap_target
   0x2b20, //  5: wait   0 pin, 0               [11]
   0x00c9, //  6: jmp    pin, 9                    
   0x4041, //  7: in     y, 1                      
   0x0000, //  8: jmp    0                          
   0x4121, //  9: in     x, 1                   [1]
           //     .wrap

Sample 10
           //     .wrap_target
   0x7821, //  0: out    x, 1            side 1    
   0x0623, //  1: jmp    !x, 3                  [6]
   0x1700, //  2: jmp    0               side 0 [7]
   0x0704, //  3: jmp    4                      [7]
   0x7021, //  4: out    x, 1            side 0    
   0x0627, //  5: jmp    !x, 7                  [6]
   0x1f04, //  6: jmp    4               side 1 [7]
   0x0700, //  7: jmp    0                      [7]
           //     .wrap
}

 
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 3490
Posted: 10:20am 29 Jun 2021
Copy link to clipboard 
Print this post

@Mixtel: interesting concept using the Instr function that returns the pointer to the found match, then divide by the element size .... as a "decoder". Replaces the search in a linked list or structure.
PicomiteVGA PETSCII ROBOTS
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 5705
Posted: 09:53pm 29 Jun 2021
Copy link to clipboard 
Print this post

side & [ ] now working.
It now passes Sample 1, Sample 2 and most of Sample 3.
irq and .wrap not implemented at all yet. irq coming soon, it shouldn't be so impatient!
out null,32 won't assemble as there are only 5 data bits.
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 3490
Posted: 06:34am 30 Jun 2021
Copy link to clipboard 
Print this post

Hi Mixtel90,

I am impressed, you took up the glove, and are really making the whole compiler !! Great work, and thank you !!!

About out null,32:



So you shift out 32 bits from the OSR, basically clearing the OSR.





Volhout

P.S. While reading though the sequencer instruction set, I get scared. You can write really confusing code using this set. You can interpret data in the shift registers as instruction, or as direct jump address. So you can write a sequence that reads serial data in the ISR, passes it to the OSR, and executes it..... scary...

I guess next years programming challenge will be to write the most obfuscated program for the PIO sequencer on the picomite....
Edited 2021-06-30 16:48 by Volhout
PicomiteVGA PETSCII ROBOTS
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 5705
Posted: 07:13am 30 Jun 2021
Copy link to clipboard 
Print this post

At the moment I'm simply taking strings from the data statements and converting them into 16-bit words for the RP2040 to process. Unless it's something that I can do that with I'm a bit stuck. That's why I've been thinking of it as an assembler. A compiler would probably be the high level PIO commands that Peter's doing.

I should have seen that - probably got too bog-eyed. lol In this case It's easy enough, I can encode 32 as &b00000 easily enough, but I can't (at the moment) handle stuff like .wrap as that's a directive that does something that isn't a command as such (it's a backward jump, but you can't assemble it as that because it's much faster). I've no directives at the moment and no idea how to implement them. I couldn't activate autopull if it had a big on-off switch on it. :)

Yep - this thing is seriously scary. :)  Even the concept of 4 state machines independently working from the same 32-byte memory is a little bit scary...
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8566
Posted: 07:19am 30 Jun 2021
Copy link to clipboard 
Print this post

  Quote   I've no directives at the moment and no idea how to implement them.


All the directives translate into bit settings in the PINCTRL, EXECCTRL, and SHIFTCTRL registers. If your assembler could return values for these (could be in like named Global variables) then this would complete the loop. The user would then just include these in the PIO INIT MACHINE command
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 5705
Posted: 04:42pm 30 Jun 2021
Copy link to clipboard 
Print this post

Is there a map of those registers somewhere, Peter? I couldn't see them by those names in the datasheet. If I'm correct, each status machine has it's own register set.

The IRQ is *still* waiting to be processed...  :)
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8566
Posted: 05:50pm 30 Jun 2021
Copy link to clipboard 
Print this post

rp2040-datasheet.pdf

Section 3.7
Edited 2021-07-01 03:51 by matherp
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 5705
Posted: 08:29pm 30 Jun 2021
Copy link to clipboard 
Print this post

I looked there...
I assume the ones I want are:
SM0_EXECCTRL
SM0_SHIFTCTRL
SM0_PINCTRL

where SM0, SM1, SM2 and SM3 are the state machines. I was looking for some sort of "general" rather than SM-specific ones.


IRQ assembles.
.wrap target and .wrap now store their discovered addresses (next and previous respectively) in variables
test printout much improved!
Edited 2021-07-01 07:22 by Mixtel90
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8566
Posted: 10:01pm 30 Jun 2021
Copy link to clipboard 
Print this post

  Quote  where SM0, SM1, SM2 and SM3 are the state machines


Correct, the state machines run the same code but they can differ in clock speed and pin usage and even which bit of the code they run. So effectively there could be 4 different (but very short) programs for each PIO with each state-machine running a different program by using different entry points to the code for their pio
 
     Page 2 of 3    
Print this page
© JAQ Software 2024