Shop OBEX P1 Docs P2 Docs Learn Events
LMM — Parallax Forums

LMM

Jay KickliterJay Kickliter Posts: 446
edited 2009-04-16 16:43 in Propeller 1
Ale said...

Hei Jay,

I do the following for LMM code:

lmm_pc is the PC in the LMM kernel. Manipulating it directly allows for jumps to +64/-63 instructions.


lmm_jump
rdlong lmm_pc, lmm_pc ' access long just after call to lmm_jump
add lmm_pc, #16 ' adjust for real address
jmp #lmm_fetch


lmm_fetch
rdlong lmm_i, lmm_pc
add lmm_pc, #4 ' next inst
lmm_i
nop
jmp #lmm_fetch

...


somewhere your LMM code:

mov somevar, #500
jmp #lmm_jump
long @some_label

...

somelabel
mov somevar, #200

mov var_1, #500
...
sub lmm_pc, #($-somelabel-1)*4 ' This is a jump backwards to somelabel


someloop:
add lmm_pc, #(someotherlabel - 1 - $)*4 ' jump forwards





That kind of LMM does not need anything extra from the compiler and works very well!
The rest of the code that access variables and subroutines in COG do not need any change, because it will be run from COG RAM as any other instruction. Only jumps or calls to LMM code need to work around different address range. Two small routines can take care of that (lmm_jump, lmm_call).

I didn't want to continue this on the other thread, since it turns out I don't need any special compiler support. Ale, do you happen to have any working examples of this that you'd be willing to share?

Comments

  • AleAle Posts: 2,363
    edited 2009-03-29 21:15
    I have them in my other machine wink.gif. I'll post them tomorrow if it is ok with you. But be warned... it is exactly like that one smile.gif, but with other names. I have some menu system for LCDs running on LMM basically a User interface. All supporting and drawing routines are in COG.
  • AleAle Posts: 2,363
    edited 2009-03-30 07:09
    Here is my actual code. I just added some documentation. If you have questions please do not hesitate to ask. The drawing routines and so on (used in the LMM code) are not included nor necessary.
    All calls to LMM related routines... start with krnl_. Registers are krnl_r0 to krnl_r15. Another set of registers exist (k4_a to k4_g mapped to the other set).

    DAT   ' C4
    ' ***************************************************************
    ' ***************************************************************
    ' ***************************************************************
    '
    '        display refresh, oscilloscopes, fft, other data
    '
    '
    '        This is a lmm kernel with some drawing routines
    '
    ' kernel routines like krnl_jmp/call etc do not need to be calls
    ' because return address is discarded and changed by krnl_fetch
    ' at the end of routine
    '
    ' ***************************************************************
    ' ***************************************************************
    ' ***************************************************************
    
                    org
    
    c4_start
    krnl_init       mov     krnl_pc,PAR
                    sub     krnl_pc,#4
                    mov     krnl_sp,krnl_pc       ' stack starts before program
    krnl_inc_pc     add     krnl_pc,#4
    krnl_fetch      rdlong  krnl_inst,krnl_pc
                    add     krnl_pc,#4
    krnl_inst       nop
                    jmp     #krnl_fetch
    
    krnl_r0         long 0
    krnl_r1         long 0
    krnl_r2         long 0
    krnl_r3         long 0
    krnl_r4         long 0
    krnl_r5         long 0
    k4_a
    krnl_r6         long 0
    k4_b
    krnl_r7         long 0
    k4_c
    krnl_r8         long 0
    k4_d
    krnl_r9         long 0
    k4_e
    krnl_r10        long 0
    k4_f
    krnl_r11        long 0
    k4_g
    krnl_r12        long 0
    k4_h
    krnl_r13        long 0
    k4_i
    krnl_r14        long 0
    krnl_lr         long 0
    krnl_sp         long 0
    krnl_pc         long 0
    krnl_cnt_ofsmsk long $7fff
    krnl_cnt_cntmsk long $3ffff
    krnl_t1         long 0
    krnl_t2         long 0
    ' Scratch for call
    krnl_call_ret
    krnl_jmp_ret
    krnl_rts_ret
    krnl_push_lr_ret
    krnl_pop_lr_ret
    krnl_get_arg_ret
    krnl_push_arg_ret
    krnl_load_cnt_ret
    krnl_load_adr_ret
    krnl_exit_ret
                    long   0
    
    
    ' performs a call, return address is
    ' saved in the link register, dest address follows
    ' This can be combined with flags
    '
    '      if_z     jmp     #krnl_call
    '               long    @address
    
    krnl_call       mov     krnl_lr,krnl_pc ' save PC in link register
                    add     krnl_lr,#4
                    rdlong  krnl_pc,krnl_pc ' address of destination
                    add     krnl_pc,#16     ' adjust for real address
                    jmp     #krnl_fetch
    ' Performs a jump, address follows
    ' This can be combined with
    ' flags
    '
    '      if_z     jmp     #krnl_jmp
    '               long    @address
    '
    krnl_jmp        rdlong  krnl_pc,krnl_pc ' reads address of destination
                    add     krnl_pc,#16     ' adjust for real address
                    jmp     #krnl_fetch
    
    ' returns from a call using the value in the link register
    ' this could be avoided later on using just a mov
    krnl_rts        mov     krnl_pc,krnl_lr
                    jmp     #krnl_fetch
    
    ' pushes the link register to the stack
    krnl_push_lr    sub     krnl_sp,#4
                    wrlong  krnl_lr,krnl_sp
                    jmp     #krnl_fetch
    
    ' pops the link register from the stack
    krnl_pop_lr     rdlong  krnl_lr,krnl_sp
                    add     krnl_sp,#4
                    jmp     #krnl_fetch     ' stack underflow shoud be checked here
    
    ' gets an argument from stack
    ' the long that follows has 2 arguments
    '
    ' 31       23 22 18 17     0
    ' +----------+-----+--------+
    ' | Addr_reg |  0  | offset |
    ' +----------+-----+--------+
    
    krnl_get_arg    rdlong  krnl_t1,krnl_pc
                    mov     krnl_t2,krnl_t1
                    shr     krnl_t1,#23             ' address of destination register!
                    movd    krnl_get_arg_g,krnl_t1  ' sets dest address
                    and     krnl_t2,krnl_cnt_ofsmsk
                    add     krnl_t2,krnl_sp
    krnl_get_arg_g  rdlong  0,krnl_t2
                    jmp     #krnl_inc_pc            ' next instruction
    
    ' puts an argument back to the stack
    ' the long that follows has 2 arguments
    '
    ' 31       23 22 18 17     0
    ' +----------+-----+--------+
    ' | Addr_reg |  0  | offset |
    ' +----------+-----+--------+
    
    krnl_put_arg    rdlong  krnl_t1,krnl_pc
                    mov     krnl_t2,krnl_t1
                    shr     krnl_t1,#23             ' address of destination register!
                    movd    krnl_put_arg_g,krnl_t1  ' sets dest address
                    and     krnl_t2,krnl_cnt_ofsmsk
                    add     krnl_t2,krnl_sp
    krnl_put_arg_g  wrlong  0,krnl_t2
                    jmp     #krnl_inc_pc            ' next instruction
    
    ' loads a constant into a register
    ' the long that follows has 2 arguments
    '
    ' 31       23 22 18 17     0
    ' +----------+-----+--------+
    ' | Addr_reg |  0  |   cnt  |
    ' +----------+-----+--------+
    krnl_load_cnt   rdlong  krnl_t1,krnl_pc
                    mov     krnl_t2,krnl_t1
                    shr     krnl_t1,#23             ' address of destination register!
                    movd    krnl_load_cnt_g,krnl_t1 ' sets dest address
                    and     krnl_t2,krnl_cnt_cntmsk
    krnl_load_cnt_g mov     0,krnl_t2
                    jmp     #krnl_inc_pc            ' next instruction
    
    ' loads an address into a register
    ' the long that follows has 2 arguments
    '
    ' 31       23 22 16 15     0
    ' +----------+-----+--------+
    ' | Addr_reg |  0  |   cnt  |
    ' +----------+-----+--------+
    krnl_load_adr   rdlong  krnl_t1,krnl_pc
                    mov     krnl_t2,krnl_t1
                    shr     krnl_t1,#23             ' address of destination register!
                    movd    krnl_load_adr_g,krnl_t1 ' sets dest address
                    and     krnl_t2,krnl_cnt_ofsmsk
                    add     krnl_t2, #16            ' adjusts for real address
    krnl_load_adr_g mov     0,krnl_t2
                    jmp     #krnl_inc_pc            ' next instruction
    
                    fit
    
    ' stack space for LMM program
    c4_lmm_stack  long      0, 0, 0, 0, 0, 0, 0, 0
    ' LMM program, it is executed from the lmm kernel in c4
    ' No more than a depth of 8 levels in the stack is allowed
    ' two sets of registers are available, krnl_r0..krnl_r13
    ' and k4_a..k4_i
    ' the use of r0..r13 is encouraged
    
    c4_lmm_start  mov       k4_d,#72
                  mov       k4_e,#16
                  mov       k4_i,#13
                  call      #c4_wkstrxyn
                  mov       k4_d,#0
                  mov       k4_e,#32
                  mov       k4_i,#14
                  call      #c4_wkstrxyn
                  mov       k4_d,#12*8
                  mov       k4_e,#48
                  mov       k4_i,#15
                  call      #c4_wkstrxyn
                  mov       k4_a,#1
                  shl       k4_a,#28
                  add       k4_a,CNT
                  waitcnt   k4_a,#0     ' lets wait showing the copyright
    c4_lmm_mainscreen
                  call      #c4_clrscr
    ' Fixed messages
                  mov       k4_d,#136
                  mov       k4_e,#0
                  mov       k4_i,#1      ' Freq
                  call      #c4_wkstrxyn
                  mov       k4_d,#196
                  mov       k4_e,#8
                  mov       k4_i,#12      ' Hz
                  call      #c4_wkstrxyn
                  mov       k4_d,#136
                  mov       k4_e,#16
                  mov       k4_i,#2       ' Timer
                  call      #c4_wkstrxyn
                  call      #c4_wkstrxyn
                  call      #c4_drawrect4
    c4_lmm_mainnc call      #c4_ddotoscis
    
    ' displays frequency
                  or        k4_flags, #k_4_INVTEXT
                  call      #krnl_load_adr
                  long      @m_L_cfg_fbase+(k4_i<<23)
                  mov       k4_d, #148
                  mov       k4_e, #8
                  call      #c4_wint5
    ' Timer
    
    ' Mode
                  call      #krnl_load_adr
                  long      @m_B_cfg_mode+(k4_a<<23)
                  rdbyte    k4_a, k4_a
                  cmp       k4_a, #k_CTRL_RBUTTON1   wz
            if_z  mov       k4_i, #6  ' Continuos mode
                  cmp       k4_a, #k_CTRL_RBUTTON2   wz
            if_z  mov       k4_i, #7  ' Continuos mode
                  cmp       k4_a, #k_CTRL_RBUTTON3   wz
            if_z  mov       k4_i, #8  ' Continuos mode
    
                  mov       k4_d,#148
                  mov       k4_e,#32
                  call      #c4_wkstrxyn
    ' Display Mode
                  call      #krnl_load_adr
                  long      @m_B_cfg_dmode+(k4_a<<23)
                  rdbyte    k4_a, k4_a
                  cmp       k4_a, #k_CTRL_RBUTTON1   wz
            if_z  mov       k4_i, #9  ' Osci
                  cmp       k4_a, #k_CTRL_RBUTTON2   wz
            if_z  mov       k4_i, #10  ' FFT
                  cmp       k4_a, #k_CTRL_RBUTTON3   wz
            if_z  mov       k4_i, #11  ' FFT  4096
    
                  mov       k4_d,#148
                  mov       k4_e,#40
                  call      #c4_wkstrxyn
    ' Display Activity, If Active
                  andn      k4_flags, #k_4_INVTEXT   ' Normal text
    
                  call      #krnl_load_adr
                  long      @m_L_ACT+(k4_a<<23)
    
                  call      #krnl_load_cnt
                  long      k_ACTMAGIC+(k4_b<<23)
    
                  cmp       k4_a, k4_b  wz
            if_z  mov       k4_i, #16          ' active
            if_z  mov       krnl_r4, #17       ' active
            if_nz mov       k4_i, #18          ' not active
            if_nz mov       krnl_r4, #18       ' not active
                  mov       k4_d,#140
                  mov       k4_e,#48
                  call      #c4_wkstrxyn
                  mov       k4_i, krnl_r4
                  mov       k4_d,#140
                  mov       k4_e,#56
                  call      #c4_wkstrxyn    ' displays ACTIVE MESSAGE
    
    
                  mov       k4_a, CNT
                  add       k4_a, cnt_k4_25fps
                  waitcnt   k4_a, #0
    
                  rdbyte    k4_a,cnt_k4_key
                  cmp       k4_a,#0 wz
           if_z   jmp       #krnl_jmp
                  long      @c4_lmm_mainnc
    
                  test      k4_a,#k_KMNEXT wc
            if_c  jmp       #krnl_jmp
                  long      @c4_lmm_config
    
                  test      k4_a,#k_KMPREV wc
            if_c  jmp       #krnl_jmp
                  long      @c4_lmm_config
    ' Verify for STOP and RUN keys
                  call      #c4_getkey           ' consumes key
                  jmp       #krnl_jmp
                  long      @c4_lmm_mainnc
    
    { Config management
      Displays config and allows to change values
      Changed values cannot be cancelled !!
    
    }
    c4_lmm_config call      #c4_getkey           ' consumes key
                  mov       k4_a,#0
                  call      #krnl_load_adr
                  long      @m_B_cfg_curr+(k4_b<<23)
                  wrbyte    k4_a,k4_b                   ' sets current config panel to 0, initial
    ' loads pointer to panel table
                  call      #krnl_load_adr
                  long      @cnt_w_cfgtbl+(krnl_r4<<23)
    c4_lmm_cfg_clr
                  call      #c4_clrscr
    c4_lmm_cfg_loop
                  rdword    krnl_r0, krnl_r4           ' loads pointer to panel
                  call      #krnl_load_cnt
                  long      (krnl_r1<<23)+$ffff
                  cmp       krnl_r0, krnl_r1   wz
            if_z  sub       krnl_pc, #($-c4_lmm_mainscreen+1)*4         ' returns to main screen if end of menu reached
    
                  call      #c4_w_show                 ' shows control form
    ' waits for key
                  call      #c4_getkey
                  rdword    krnl_r0, krnl_r4           ' loads pointer to panel
    
    ' key was pressed, process key
                  test      k4_a,#k_KMNEXT wc
            if_c  add       krnl_r4, #2                ' increments pointer to next entry in panel table
            if_c  jmp       #krnl_jmp
                  long      @c4_lmm_cfg_clr
    
                  test      k4_a,#k_KMPREV wc
            if_c  sub       krnl_r4, #2                ' decrements pointer to prev entry in panel table
            if_c  jmp       #krnl_jmp
                  long      @c4_lmm_cfg_clr
    
                  test      k4_a,#k_KMDOWN wc
            if_c  call      #c4_w_incwptr              ' increments pointer to next entry in panel table
            if_c  sub       krnl_pc, #($-c4_lmm_cfg_loop+1)*4
    
                  test      k4_a,#k_KMUP wc
            if_c  call      #c4_w_decwptr              ' increments pointer to next entry in panel table
            if_c  sub       krnl_pc, #($-c4_lmm_cfg_loop+1)*4
    
                  test      k4_a, #k_KUP   wc
            if_nc add       krnl_pc, #(c4_lmm_cfg_k5-1-$)*4  ' cheap jump
    
                  call      #c4_w_getselptr            ' gets pointer of selected widget
                  rdword    k4_a,krnl_r0
                  and       k4_a, #$f0
                  cmp       k4_a, #k_CTRL_INT5   wz    ' if it is a number
            if_z  call      #c4_w_addtovar
                  cmp       k4_a, #k_CTRL_RBUTTON  wz  ' if it is a radio
            if_z  call      #c4_w_setradio
    
    c4_lmm_cfg_k5 test      k4_a, #k_KDOWN   wc
            if_nc add       krnl_pc, #(c4_lmm_cfg_k6-1-$)*4  ' cheap jump
    
                  call      #c4_w_getselptr
                  rdword    k4_a,krnl_r0
                  and       k4_a, #$f0
                  cmp       k4_a, #k_CTRL_INT5   wz
            if_z  call      #c4_w_subtovar
                  cmp       k4_a, #k_CTRL_RBUTTON wz
            if_z  call      #c4_w_setradio
    
    c4_lmm_cfg_k6
                  jmp       #krnl_jmp
                  long      @c4_lmm_cfg_loop
    
    



    Enjoy.
  • AleAle Posts: 2,363
    edited 2009-04-14 15:08
    He Jay I was wondering if you saw this ? (And what do you think of it smile.gif ? )

    Ale
  • AleAle Posts: 2,363
    edited 2009-04-15 11:50
    Cluso: But you did not see it work! because it does wink.gif. I'm so proud of that code (the whole thing) that I forgot to make the real piece of electronic work :-(. Anybody knows why those Amidon toroidal cores are not good to make a transformer ? :-( :-(
  • nutsonnutson Posts: 242
    edited 2009-04-15 13:17
    Ale, could you elaborate on the the project this code is taken from? Reason; the comments suggest it is from·a·test and measurement application, ref "oscilloscope display" etc. FFT is very interesting, basic for any type of spectrum analyzer.

    For quite some time I·have wanted to build·a test and measurement system with multiple props each generating /·measuring certain signals (DC, LF analog, HF analog, digital, protocol,·TV). Comparable to this·project ·http://www.heise.de/ct/projekte/machmit/ctlab/wiki. But being a propeller user with props of course. I can handle all the hardware detail, but as I am·less of a software person·I cannot decide on two important·software aspects:
    - the GUI: how to control·generated·signals and control measurement result display? (Try to) use a PC application like in the mentioned project "NI Labview"? There is some·good software around (like Virtins Multi-instrument 3.1) that uses a PC soundcard as a measurement device. Use a prop with VGA and mouse·to display and alter parameters?·Use Viewport?·Use Femtobasic (text oriented, but with good automation possibilities)?
    - how to display oscilloscope type·signals. I have·a number of FPGA4FUN Flashy modules available (100Mhz, 8 bit sampling) but how to display the results? Could a prop (or multiple props) handle 4 traces of (graphics) oscilloscope display? I can·use the·FPGA needed for·the Flashy modules to generate a VGA signal (have done some experiments already), but that is quite inflexible. Transport the data to a PC and display it there (viewport again?). · Hanno had a T&M application in the pipeline "dreamkit",·hoped this would come with general purpose·GUI software, but this seems to evolve into the "propscope".

    Would appreciate any thoughts on·this.

    Nico Hattink·
  • AleAle Posts: 2,363
    edited 2009-04-15 19:52
    nutson: It all depends on how many MPS you want, which are you tolerable dead times and what do you want to do with the signals.

    Just to display them at 60 Hz is not a problem, even 4 of them (some 200 or so samples). If you want something fancy like what real DSO do (aka digital phosphor or similar) forget it because you do not even have more than3 shades of the same color available!. The point here is the dead time you can tolerate.

    FFT is not a problem, just see the article I wrote on propeller.wikispaces.com/FFT. I tested it with a real propeller too smile.gif. It works.

    My simple (very) GUI does not allow more than some simple widgets (numbers and radio buttons and text) with max/min values and increment prefixed (to be used with a rotary encoder). I can post the code of a simple oszi with FFT for VGA ready-to-use if you are still interested.
  • nutsonnutson Posts: 242
    edited 2009-04-15 20:22
    I would me delighted if you would post your code for a basic VGA oscilloscope. My coding skills are such that I can understand and modify a example, but not good enough to do it all from scratch. You may remember I am working with FPGA's, my goal would be to have the FPGA acquire preprocess the ADC data, and have the prop display them.
  • AleAle Posts: 2,363
    edited 2009-04-16 08:23
    Here is the FFT example.

    You will need an ADC (any will do) just modify the hardware accordingly to accept the data nd you are done.

    If I find a picture of this I'll post it.

    Have fun.
  • nutsonnutson Posts: 242
    edited 2009-04-16 16:43
    Jay, sorry for hijacking your post, will not post here more.

    Ale, many thanks, just got it working (without a DAC). Just inserted the CNT value where you do the INA in the ADC routine.
Sign In or Register to comment.