self-modifying code
Hi Guys,
I have tried to read everything about self-modifying code... and I just don't get it.
I have used self-modifying code in higher level languages... So, I grasp the basic concept... but I have read Graham's questions and the responses, and I have done searches from several different directions. It seems like there is somethng missing. I feel so ignorant I don't even know how to ask the right question. The best issue seems to be table indexing in assembly.
Could someone post a complete example that does nothing but index through a dat table and pass the values back to a Spin array... ?
I'll be running around too much to respond for a few days... (a teenage daughter[noparse]:)[/noparse]
Rich
I have tried to read everything about self-modifying code... and I just don't get it.
I have used self-modifying code in higher level languages... So, I grasp the basic concept... but I have read Graham's questions and the responses, and I have done searches from several different directions. It seems like there is somethng missing. I feel so ignorant I don't even know how to ask the right question. The best issue seems to be table indexing in assembly.
Could someone post a complete example that does nothing but index through a dat table and pass the values back to a Spin array... ?
I'll be running around too much to respond for a few days... (a teenage daughter[noparse]:)[/noparse]
Rich
Comments
If you want to take a look at some self modifying code in a real application, take a look at the code for the logic analyser I wrote: http://forums.parallax.com/showthread.php?p=606048
If you scroll down to the the assembly code, GetFast's storeloop is about as straightforward as it goes for a real world example. It·also shows you can modify code without using the movd or movs instructions.·The constant d_inc is the value 1<<9 or the least significant bit of the destination register, so by adding this value to the previous mov instruction, each successive mov is writing the contents of ina to the next location in memory.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Paul Baker
Propeller Applications Engineer
Parallax, Inc.
Thanks. My search skills seem to be deficient as well[noparse]:)[/noparse]
Rich
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Paul Baker
Propeller Applications Engineer
Parallax, Inc.
{Assembler Data Table read} CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 VAR long cog long Array[noparse][[/noparse]10] OBJ tv : "TV_Text" 'or VGA_Text or PC_Text PUB Start | n tv.start(12) cog := cognew(@asm_entry, @Array) 'start Assembly routine repeat until Array[noparse][[/noparse]9] > 0 'wait until finished cogstop(cog) 'free cog repeat n from 0 to 9 'show Array tv.dec(Array[noparse][[/noparse]n]) tv.out(13) repeat DAT org asm_entry mov ArrayPntr,par 'address of Spin Array mov ReadCnt,#10 'number of longs to read movs ReadPntr,#Table 'replace 0-0 with table address nop 'wait 4 cycles before read ReadPntr mov temp,0-0 'read Table value wrlong temp,ArrayPntr 'write in Spin Array add ArrayPntr,#4 '#2 for words, #1 for bytes add ReadPntr,#1 'next long in table djnz ReadCnt,#ReadPntr 'repeat until all done Halt jmp #Halt Table long 1,2,4,8,16,32,64,128,256,512 ArrayPntr res 1 ReadCnt res 1 temp res 1
Andy
If the forum was periodically offered on a $CD... I· could have found your post on my Mac[noparse]:)[/noparse]!!!
Andy,
Exactly!!!· I am in the Blue Grass State, without my Prop.· Won't be home til Sunday... try it then,
Thanks.
Rich
Your example was perfect... and as usual, you gave me something to think about...
BTW... you have gauged me correctly... if you hadn't explained the d_inc... (1<<9 ) ... I would have thought you were joking[noparse]:)[/noparse]
Rich
I realise this is a long dead thread, and there are probably numerous others referring to the same thing, but I am having serious difficulty with self modifying code. I have looked for keywords on the forums and google (movd, self modifying, etc) for the answers, but all the code examples seem to be similar, and no one seems to have had the troubles I see.
I'm attempting to write an audio tuning application for the demoboard using an audio sampler, a number of FFTs, VGA and serial. Trying to pass hub ram FFT input array pointers to the sampler cog.
The following example, taken from various forum posts and web pages, attempts to add 1 into the destination field of the rdlong instruction, labelled :patch.
d0 being a long defined as 1 << 9, and param_count declared as a CONstant
I understand the need to have an instruction in between the instruction to modify and the modified instruction because of the interleaved fetch execute cycles.
mov in_ptr,PAR movd :patch,#asm_flag_ptr mov t2,#param_count 'load number of parameters, giving time to modify :patch instruction :rdloop :patch rdlong 0,in_ptr add :patch,d0 'increment destination operand by 1 / point at next cog long add in_ptr,#4 'set to read next long from hub ram, giving plenty of time for fetch/execute of updated :patch long djnz t2,#:rdloop
I get some seriously strange behaviour, my serial cog starts flooding me with lots of #, ? and $ symbols, with the occasional sporadic other character in there too...
The screen starts making some seriously funky fast flashing colourful patterns too. Obviously the "add :patch,d0" instruction isn't having the intended effect.
The only way I've found I can get the behaviour I want, within a loop, is to use an intermediate pointer and re-hit :patch with the movd instruction:
mov in_ptr,PAR mov out_ptr,#asm_flag_ptr movd :patch,out_ptr mov t2,#param_count :rdloop rdlong t1,in_ptr :patch mov 0,t1 add out_ptr,#1 add in_ptr,#4 movd :patch,out_ptr ' add :patch,d0 'can try commenting out the line above and uncommenting this one for quick switching between methods djnz t2,#:rdloop
Can any propeller gurus tell me what I'm doing wrong? Why won't adding d0 to :patch increment the destination operand in the expected way?
I'm glad I've got it working to some degree, after a day of forehead vs keyboard interaction and epilepsy inducing visions on the screen, but it seems more round-about and less elegant than the method advertised.
Thanks all,
Pete
Page 23 of this PDF is where I got some ideas:
http://www.cp.eng.chula.ac.th/~piak/project/propeller/machinelanguage.pdf
In your app, do you have d0 set as follows?
d0 long 512
or to something else that evaluates the same?
Also, just as an FYI, it's become customary for PASM arguments that are the target of self-modifying code to be expressed as 0-0.
-Phil
I modified the version of Beau's fixed point FFT to accept pointers of hub ram instead of constant memory locations. (Out of interest, is there a way of telling the compiler to allocate a 1024 word buffer at a certain hub location, e.g. $5000... It allocates it at compiler time right? So can you tell it you want it to be explicitly in a certain location?)
Got it from here:
http://propeller.wikispaces.com/FFT
I modified the microphone to VGA demo to write to FFT buffers. Since the audio sampler seemed to be about 2 1/2 times quicker than the FFTs (to the best of my ability to tell using serial to print out clock values) I had four running and used the flag pointers to communicate when their buffers were full or finished. Each FFT plots to the screen by XORing pixels, so it seems to work nicely at 19.5 KHz and 38 KHz, but any higher and the sampler starts over writing the input buffer before the FFT completes and it shows on the screen..
In my main object I have declared these:
VAR 'buffers for FFT cogs word real_buffer1[fft#NN] word imag_buffer1[fft#NN] word real_buffer2[fft#NN] word imag_buffer2[fft#NN] word real_buffer3[fft#NN] word imag_buffer3[fft#NN] word real_buffer4[fft#NN] word imag_buffer4[fft#NN] 'flags used to measure run time and tops used to show detected frequency spikes long fft1_flag long fft1_top[peaks] long fft2_flag long fft2_top[peaks] long fft3_flag long fft3_top[peaks] long fft4_flag long fft4_top[peaks] long aud_flag 'pointers for audio sampler cog long audio_flag_ptr long array_size long buffer1_ptr long buffer2_ptr long buffer3_ptr long buffer4_ptr long fft1_flag_ptr long fft2_flag_ptr long fft3_flag_ptr long fft4_flag_ptr OBJ vga : "vga_320x240_bitmap" fft : "fft" pst : "Parallax Serial Terminal" ' Serial communication object aud = "sampler" PUB launch 'start vga vga_cog := vga.start(16, @colors, @pixels, @sync) 'init colors to gold on blue repeat i from 0 to tiles - 1 colors[i] := %%3300_0020 long[@audio_flag_ptr] := @aud_flag long[@array_size] := fft#NN long[@buffer1_ptr] := @real_buffer1 .. long[@fft1_flag_ptr] := @fft1_flag ......... pst_cog := pst.Start(115200) ' Start the Parallax Serial Terminal cog ......... fft1_val := fft.start(@fft1_flag,@real_buffer1,@imag_buffer1,@pixels) ......... audio_cog := aud.start(@audio_flag_ptr)
here's the sampler code in its entirety..
{Sampler - This object takes samples from the microphone and stores them in Main RAM} CON _clkmode = xtal1 + pll16x 'Standard clock mode * crystal frequency = 80 MHz _xinfreq = 5_000_000 ' At 80MHz the ADC/DAC sample resolutions and rates are as follows: ' ' sample sample ' bits rate ' ---------------- ' 5 2.5 MHz ' 6 1.25 MHz ' 7 625 KHz ' 8 313 KHz ' 9 156 KHz ' 10 78 KHz ' 11 39 KHz ' 12 19.5 KHz ' 13 9.77 KHz ' 14 4.88 KHz bits = 12 'try different values from table here param_count = 10 VAR long cog 'Cog flag/id PUB start (flagptr): okay ' longmove(@asm_flag_ptr,flagptr,10) stop okay := cog := cognew(@asm_entry, flagptr) + 1 'launch assembly program into a COG PUB stop '' stop sampler and release the cog if cog cogstop(cog~ - 1) DAT org 0 asm_entry mov dira,asm_dira 'make pin 8 (ADC) output movs ctra,#8 'POS W/FEEDBACK mode for CTRA movd ctra,#9 movi ctra,#%01001_000 mov frqa,#1 'microphone now setup cogid cog_id mov in_ptr,PAR 'get the address of the first hub ram pointer mov out_ptr,#asm_flag_ptr 'copy the address of the cog ram movd :patch,out_ptr 'patch the mov instruction mov t2,#param_count 'setup loop counter :rdloop rdlong t1,in_ptr 'get the pointer address :patch mov 0,t1 'move to relevant cog ram location add out_ptr,#1 'point at next cog cell add in_ptr,#4 'point at next hub ram long movd :patch,out_ptr 'patch the mov instruction again djnz t2,#:rdloop 'go round until all parameters are retrieved mov buffer_number,#0 mov in_ptr,asm_buffer1_ptr 'use in_ptr as input to the array sub asm_array_size,#1 'more convenient for checking for end of array mov asm_cnt,cnt 'prepare for WAITCNT loop add asm_cnt,asm_cycles loop waitcnt asm_cnt,asm_cycles 'wait for next CNT value (timing is determinant after WAITCNT) mov asm_sample,phsa 'capture PHSA and get difference sub asm_sample,asm_old add asm_old,asm_sample wrword asm_sample,in_ptr 'write sample to fft array add in_ptr,#2 add array_offset,#1 'keep count of how far into array we are test array_offset,asm_array_size wz if_nz jmp #loop 'wait for next sample period mov array_offset,#0 add buffer_number,#1 'change fft buffer testn buffer_number,#1 wz if_z mov in_ptr,asm_buffer2_ptr if_z wrlong zero,asm_fft1_ptr testn buffer_number,#2 wz if_z mov in_ptr,asm_buffer3_ptr if_z wrlong zero,asm_fft2_ptr testn buffer_number,#3 wz if_z mov in_ptr,asm_buffer4_ptr if_z wrlong zero,asm_fft3_ptr testn buffer_number,#4 wz 'counting 0-3 if_z mov buffer_number,#0 if_z mov in_ptr,asm_buffer1_ptr 'reset input to the relevant array if_z wrlong zero,asm_fft4_ptr 'trigger fft cog mov asm_cnt,cnt 'prepare for WAITCNT loop add asm_cnt,asm_cycles wrlong asm_cnt,asm_flag_ptr 'tell caller how long I took ' wrlong buffer_number,asm_flag_ptr 'let outside object know buffer in use via the flag jmp #loop ' ' ' Data ' asm_cycles long |< bits - 1 'sample time asm_dira long $00000200 'output mask asm_cnt res 1 asm_old res 1 asm_sample res 1 asm_data res 1 asm_flag_ptr long 0 asm_array_size long 0 asm_buffer1_ptr long 0 asm_buffer2_ptr long 0 asm_buffer3_ptr long 0 asm_buffer4_ptr long 0 asm_fft1_ptr long 0 asm_fft2_ptr long 0 asm_fft3_ptr long 0 asm_fft4_ptr long 0 array_offset long 0 array_end long 0 cog_id long 0 in_ptr long 0 out_ptr long 0 t1 long 0 t2 long 0 buffer_number long 0 'Numbering 0-3 zero long 0 d0 long 1 << 9
I realise this gets a bit messy without comments, and the last bit of my code could use some work.. Anyone got good methods of switching between 4 different buffers?
-Phil
Cheers for explaining that! Not more tears ^_^