LMM
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
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_loopEnjoy.
Ale
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Links to other interesting threads:
· Home of the MultiBladeProps: TriBladeProp, SixBladeProp, website (Multiple propeller pcbs)
· Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
· Prop Tools under Development or Completed (Index)
· Emulators: Micros eg Altair, and Terminals eg VT100 (Index)
· Search the Propeller forums (via Google)
My cruising website is: ·www.bluemagic.biz·· MultiBladeProp is: www.bluemagic.biz/cluso.htm
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·
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
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.
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.
Ale, many thanks, just got it working (without a DAC). Just inserted the CNT value where you do the INA in the ADC routine.