Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 06:51 02 Aug 2025 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 : uM2(+): CFunctions

     Page 1 of 2    
Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 03:48am 06 Sep 2015
Copy link to clipboard 
Print this post

Unfortunately the support site for CFunctions is no longer online so I have programmed a clunky but workable replacement for CFuncGen

This is written in MMBasic V4.5 for DOS. Unfortunately this doesn't support OPTION EXPLICIT or INTEGER datatypes so some of the variable usage may be a bit unclear. However, I was impressed how reliable MMBasic for DOS is doing some quite complex logic.

The program reads the .ELF file created by MPLabX and outputs the CFunctions in Basic format.

There are simple instructions for use in the file header. If you can write CFunctions you should be able to work out how to use it, but any questions do ask.

I used this document as my source of information on the .ELF file

The program is tested on a selection of my CFunctions including display drivers and works properly on the tested examples but please let me know if you find any bugs. The program includes a fairly primitve mechanism for replacing Jump and Link instructions which are not position independent with Branch and link which are. This has only been tested with backwards references, e.g. calling the first function in a merged file from the second.

2015-09-06_134007_cfgen.zip


'
' CFGEN.BAS V1.0
'
' Program to convert a .ELF file to Basic statements formatted for use as CFunctions
' Runs under MMBasic for DOS V4.5
'
' It is recommended that the .ELF file is copied to the same directory as this file
' and that the filename is shortened to make life easier
'
' To run open a DOS box on the computer
' navigate to the directory containing the MMBasic.exe file and this program
' run MMBasic and you will get the normal ">" prompt
' Load this program
' Type run
'
' Then give the filename of the .elf file including the extension
' Choose "join" or "merge" to define the output format
' "join" is typically used for individual CFunctions, each function in the .ELF file is given
' its own header, all the CFunctions are output to a single file but can then be copied and
' pasted as required. When "join is chosen the "main" function is a dummy and is not included in the output
' "merge" is used for CFunctions such as drivers where one C function can be called from another
'
' Choose the name of the file for the Basic output. Do not include ".BAS", this will be appended automatically
'
' You can run MMBasic for DOS from MMEDIT, but in this case you will need to specify the correct directory information for the .ELF file
'
dim program_header,section_header,program_header_size, program_header_num, section_header_size, section_header_num
dim string_table_sector, string_table, text_section, text_position, text_size, text_link, symtab_section, strtab_section
dim symtab_offset, symtab_num, symstr_offset, first
dim text_add$ length 31
dim symbols$(100,2) length 31
line input ".ELF filename ? ",inname$
do
line input "mode(join, merge) ? ",m$
loop while (m$<>"join") and (m$<>"merge")
mode =0
if m$="merge" then mode=1
line input "CFunction name ? ",cname$
print "Created "+cname$+".bas"
open cname$+".bas" for output as #2
first=1 'first time into the various loops
print "processing ",inname$
open inname$ for random as #1
SEEK #1, 0
'
dat$ = INPUT$(16, #1) ' Get the .elf identification
dat$=input$(12,#1) 'Get unused header
dat$=input$(4,#1)
program_header=getnum4(dat$)
dat$=input$(4,#1)
section_header=getnum4(dat$)
dat$=input$(6,#1) 'step past the flags and header size
dat$=input$(2,#1)
program_header_size=getnum2(dat$)
dat$=input$(2,#1)
program_header_num=getnum2(dat$)
dat$=input$(2,#1)
section_header_size=getnum2(dat$)
dat$=input$(2,#1)
section_header_num=getnum2(dat$)
dim sections$(section_header_num+2)
dat$=input$(2,#1)
string_table_sector=getnum2(dat$)
'
i=section_header+ (Section_header_size*string_table_sector) + 16 'get to the offset in the string table sector
seek #1,i
dat$=input$(4,#1)
string_table= getnum4(dat$) 'get the offset to the string table
Print "Functions found:"
print "Address",chr$(9)+"Function"
for j=0 to section_header_num-1
i=section_header+ (Section_header_size*j) 'get to the next sector header
seek #1,i 'point to the .text section header
dat$=input$(4,#1) 'get the pointer to the sector name string
k=getnum4(dat$)
seek #1,k+string_table 'point to the name string for this sector
s$=""
d$=input$(1,#1)
do while asc(d$)<>0 'read in the zero terminated string
S$=S$+D$
d$=input$(1,#1)
loop
if s$=".text" and text_section=0 then 'store text sector number
text_section=j
endif
if s$=".symtab" and symtab_section=0 then 'store symbol table sector number
symtab_section=j
endif
if s$=".strtab" and strtab_section=0 then 'store symbol table strings sector number
strtab_section=j
endif
next j
'
i=section_header+ (Section_header_size*text_section) 'get to the .text offset
seek #1,i 'point to the .text section header
dat$=input$(12,#1)
dat$=input$(4,#1)
text_add$=getadd$(dat$)
dat$=input$(4,#1)
text_position=getnum4(dat$)
dat$=input$(4,#1)
text_size= getnum4(dat$)
dat$=input$(4,#1)
text_link= getnum4(dat$)
dat$=input$(4,#1)
text_info= getnum4(dat$)
dat$=input$(4,#1)
text_addralign= getnum4(dat$)
dat$=input$(4,#1)
text_entsize= getnum4(dat$)
'
i=section_header+ 16+ (Section_header_size*(symtab_section))
seek #1,i 'point to the .text section header
dat$=input$(4,#1) 'get the offset to the symbol table
symtab_offset=getnum4(dat$)
dat$=input$(4,#1)
symtab_num=getnum4(dat$)/16
'
i=section_header+ 16+ (Section_header_size*(strtab_section))
seek #1,i 'point to the .text section header
dat$=input$(4,#1) 'get the offset to the symbol table
symstr_offset=getnum4(dat$)
'
m=0 'counter for the stored symbols array
for i=1 to symtab_num 'loop through all the symbols
seek #1,symtab_offset+(16*i) 'point to the next symbol in the .symtab section
dat$=input$(4,#1)
k=getnum4(dat$)
dat$=input$(4,#1)
a$=getadd$(dat$)
dat$=input$(4,#1)
dat$=input$(1,#1)
l=asc(dat$)
seek #1,k+symstr_offset 'point to the symbol name
s$=""
d$=input$(1,#1)
do while asc(d$)<>0
S$=S$+D$
d$=input$(1,#1)
loop
if l=18 and left$(s$,1)<>"_" then 'Only store function names
symbols$(m,1)=a$
symbols$(m,2)=s$
print symbols$(m,1),symbols$(m,2)
m=m+1
if s$="main" then main_offset$=a$
endif
next i
'
s$= hex$(subtract(right$(main_offset$,5),right$(text_add$,5))) 'calculate the offset of the main function
if len(s$)=1 then s$="0000000"+S$
if len(s$)=2 then s$="000000"+S$
if len(s$)=3 then s$="00000"+S$
if len(s$)=4 then s$="0000"+S$
if len(s$)=5 then s$="000"+S$
if len(s$)=6 then s$="00"+S$
if len(s$)=7 then s$="0"+S$
main$=s$
'
seek #1,text_position
k=0
currentfunction=0
s$=text_add$
for i=1 to text_size step 4
for j=0 to m-1
if s$=symbols$(j,1) then 'address matches the start of a function
currentfunction=j
if k<>0 and mode then print #2,"" 'The last function didn't end with a newline so output one
if k<>0 and (not mode) and symbols$(j,2)<>"main" then print #2,""
k=0
if first and mode then ' First time in for a merged file output the Cfunction name
print #2,"CFunction "+cname$
print #2,chr$(9)+main$
endif
if mode then print #2,chr$(9)+"'"+symbols$(j,2)
if not mode and symbols$(j,2)<>"main" then
if not first then
print #2,"End CFunction"
print #2,"'"
endif
print #2,"CFunction "+symbols$(j,2)
print #2,chr$(9)+"00000000"
endif
first=0
endif
next j
if k=0 then print #2,chr$(9);
dat$=getadd$(input$(4,#1))
if left$(dat$,3)="0F4" then 'Jump instruction found convert to a branch
a$=getjumpaddress$(right$(dat$,5)) 'this the address for the jump
branchoffset=subtract(right$(s$,5),right$(a$,5))
branch$="0411FFFF"
do
decrement(branch$)
branchoffset=branchoffset-1
loop while branchoffset
if not mode and symbols$(currentfunction,2)<>"main" then print #2, branch$+" ";
if mode then print #2, branch$+" ";
else
if not mode and symbols$(currentfunction,2)<>"main" then print #2, dat$+" ";
if mode then print #2, dat$+" ";
endif
k=k+1
if k=8 then 'deal with line feed every eight words
if not mode and symbols$(currentfunction,2)<>"main" then print #2,""
if mode then print #2,""
k=0
endif
increment4(s$) 'step on the program counter
next i
if k<>0 then print #2,""
print #2,"End CFunction"
close #1
close #2
'
end

function subtract(b$,c$)
local a,b,c,d,e,f,g,a$
a=asc(mid$(b$,5,1)) : a=a-48 : if a> 9 then a=a-7
b=asc(mid$(b$,4,1)) : b=b-48 : if b> 9 then b=b-7
c=asc(mid$(b$,3,1)) : c=c-48 : if c> 9 then c=c-7
d=asc(mid$(b$,2,1)) : d=d-48 : if d> 9 then d=d-7
e=asc(mid$(b$,1,1)) : e=e-48 : if e> 9 then e=e-7
f=((((((((e * 16) + d) * 16 ) + c ) * 16 ) + b ) * 16 ) + a)
a=asc(mid$(c$,5,1)) : a=a-48 : if a> 9 then a=a-7
b=asc(mid$(c$,4,1)) : b=b-48 : if b> 9 then b=b-7
c=asc(mid$(c$,3,1)) : c=c-48 : if c> 9 then c=c-7
d=asc(mid$(c$,2,1)) : d=d-48 : if d> 9 then d=d-7
e=asc(mid$(c$,1,1)) : e=e-48 : if e> 9 then e=e-7
g=((((((((e * 16) + d) * 16 ) + c ) * 16 ) + b ) * 16 ) + a)
subtract=(f-g)/4
end function

function getjumpaddress$(a$)
local a,b,c,d,e,f
a=asc(mid$(a$,5,1)) : a=a-48 : if a> 9 then a=a-7
b=asc(mid$(a$,4,1)) : b=b-48 : if b> 9 then b=b-7
c=asc(mid$(a$,3,1)) : c=c-48 : if c> 9 then c=c-7
d=asc(mid$(a$,2,1)) : d=d-48 : if d> 9 then d=d-7
e=asc(mid$(a$,1,1)) : e=e-48 : if e> 9 then e=e-7
f=((((((((e * 16) + d) * 16 ) + c ) * 16 ) + b ) * 16 ) + a)*4 + 1048576
getjumpaddress$=left$(text_add$,3)+right$(hex$(f),5)

end function

function getadd$(d$)
local a,b,c,d
a=asc(left$(d$,1))+256
b=asc(mid$(d$,2,1))+256
c=asc(mid$(d$,3,1))+256
d=asc(right$(d$,1))+256
getadd$=right$(hex$(d),2)+right$(hex$(c),2)+right$(hex$(b),2)+right$(hex$(a),2)
end function

function getnum4(d$)
local a,b,c,d
a=asc(left$(d$,1))
b=asc(mid$(d$,2,1))
c=asc(mid$(d$,3,1))
d=asc(right$(d$,1))
getnum4=((((d*256)+c)*256)+b)*256+a
end function

function getnum2(d$)
local a,b
a=asc(left$(d$,1))
b=asc(right$(d$,1))
getnum2=b*256+a
end function

sub increment4(p$)
local a,b,c,d,e,f,g,h,v
a=asc(mid$(p$,8,1)) : a=a-48 : if a> 9 then a=a-7
b=asc(mid$(p$,7,1)) : b=b-48 : if b> 9 then b=b-7
c=asc(mid$(p$,6,1)) : c=c-48 : if c> 9 then c=c-7
d=asc(mid$(p$,5,1)) : d=d-48 : if d> 9 then d=d-7
e=asc(mid$(p$,4,1)) : e=e-48 : if e> 9 then e=e-7
f=asc(mid$(p$,3,1)) : f=f-48 : if f> 9 then f=f-7
g=asc(mid$(p$,2,1)) : g=g-48 : if g> 9 then g=g-7
h=asc(mid$(p$,1,1)) : h=h-48 : if h> 9 then h=h-7
a=a+4 : if a=16 then
b=b+1 : a=0
if b=16 then
c=c+1 : b=0: if c=16 then
d=d+1 : c=0: if d=16 then
e=e+1 : d=0 : if e=16 then
f=f+1 : e=0 : if f=16 then
g=g+1: f=0 : if g=16 then
g=0: h=h+1
endif
endif
endif
endif
endif
endif
endif
endif
a=a+48: if a> 57 then a=a+ 7
b=b+48: if b> 57 then b=b+ 7
c=c+48: if c> 57 then c=c+ 7
d=d+48: if d> 57 then d=d+ 7
e=e+48: if e> 57 then e=e+ 7
f=f+48: if f> 57 then f=f+ 7
g=g+48: if g> 57 then g=g+ 7
h=h+48: if h> 57 then h=h+ 7
p$=chr$(h)+chr$(g)+chr$(f)+chr$(e)+chr$(d)+chr$(c)+chr$(b)+chr$(a)
end sub

sub decrement(p$)
local a,b,c,d,e,f,g,h
a=asc(mid$(p$,8,1)) : a=a-48 : if a> 9 then a=a-7
b=asc(mid$(p$,7,1)) : b=b-48 : if b> 9 then b=b-7
c=asc(mid$(p$,6,1)) : c=c-48 : if c> 9 then c=c-7
d=asc(mid$(p$,5,1)) : d=d-48 : if d> 9 then d=d-7

if a<>0 then
a=a-1
else
a=15
if b<>0 then
b=b-1
else
b=15
if c<>0 then
c=c-1
else
c=15
if d<>0 then
d=d-1
else
d=15
endif
endif
endif
endif
a=a+48: if a> 57 then a=a+ 7
b=b+48: if b> 57 then b=b+ 7
c=c+48: if c> 57 then c=c+ 7
d=d+48: if d> 57 then d=d+ 7
p$=left$(p$,4)+chr$(d)+chr$(c)+chr$(b)+chr$(a)
end sub
Edited by matherp 2015-09-07
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9610
Posted: 03:52am 06 Sep 2015
Copy link to clipboard 
Print this post

I've never played with MMBASIC for DOS. Does it compile it's code to an exe or something like that you can run from the DOS command prompt?Edited by Grogster 2015-09-07
Smoke makes things work. When the smoke gets out, it stops!
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 05:02am 06 Sep 2015
Copy link to clipboard 
Print this post

  Quote  I've never played with MMBASIC for DOS. Does it compile it's code to an exe or something like that you can run from the DOS command prompt?


It just runs the interpreter in a DOS box. The language is basically the same as Maximite less the various PIC specific hardware support. What makes it very useful for me is that the file handling is really easy just like on the Maximite. Because you can't do 32-bit integer arithmetic when you only have floats I've had to do some very inefficient coding with addresses maintained as 8 character hex strings but despite this the code runs perfectly acceptably quickly.

If you need to do any sort of simple file format conversion and, like me, don't know things like python then MMBasic for Dos is a great solution.

MMBasic for DOS is available here Edited by matherp 2015-09-07
 
paceman
Guru

Joined: 07/10/2011
Location: Australia
Posts: 1329
Posted: 07:25pm 06 Sep 2015
Copy link to clipboard 
Print this post


One of the very handy things that MMBasic for DOS has is the SYSTEM command.

Format: SYSTEM command$

Useage:
Submit 'command$' to the operating system. It can be any command recognised by the command window in Windows XP/Vista/7. The available commands are listed here:
http://ss64.com/nt
For example, this will set the window to blue lettering on a yellow background: SYSTEM "COLOR 1E"
Note that the command is executed in a different instance of the command processor to MMBasic so some commands (like "CD ..") will have no effect.

SYSTEM allows you to use Windows system commends for a range of things - it's particularly useful for multiple file handling. You can do things like:

ProcessFolder:
'Create a DOS "DIR" command to list .txt files from the folder and re-direct
'the output .txt file list (filenames only) to a temporary data file "songlist.dat".

SYSTEM "DIR *.txt /B/O:N >songlist.dat" 'MS Windows comand
Songlist$ = Source$ + "songlist.dat" 'Build full filePath for songlist.dat
'Request file no. to process. Add folder path, process, then request next file.
.
.
.


Also you can build batch files to be executed, like:

'Read lyrics.txt file via lyricline$ variable into lyric$ array & count lines
FileLines = 0
Open FileName$ for input as #2

Do
Line Input #2, lyricLine$
FileLines = FileLines + 1
lyric$(FileLines) = LyricLine$
Print "Line" filelines,lyric$(filelines)
Loop Until filelines = 12 'EOF(#2) shortened for testing********
Close #2

'Identify music codec file type via batch file & read music file name from Filename.txt
' *** add other music file types (aac, org etc) later ***

NameNoExt$ = left$(Filename$,len(Filename$)-4)
Open "FileName.bat" for Output as #2
Print #2, "If Exist "+chr$(34)+NameNoExt$+".mp3"+chr$(34)+" echo "+NameNoExt$+".mp3> Filename.txt"
Print #2, "If Exist "+chr$(34)+NameNoExt$+".m4a"+chr$(34)+" echo "+NameNoExt$+".m4a> Filename.txt"
Close #2

SYSTEM "FileName.bat > nul" 'Batch command file creates Filename.txt which
Open "FileName.txt" for Input as #2 'contains the music codec filename; if one exists.
Line Input #2, MusicFile$ 'Now can read music codec filename with extension.
Close #2
KILL "FileName.bat"
KILL "FileName.txt"

'Setup batch file to start iTunes playing
'OutputString$ command format: ...START "" "MusicFile$"...
'The "" is apparently necessary & normally encloses the window title.

Open "StartItunes.bat" for OUTPUT as #2
OutputString$ = "START "+chr$(34)+chr$(34)+" "+chr$(34)+MusicFile$+chr$(34)
Print #2, OutputString$
Print #2, "Exit"
Close #2
SYSTEM "StartItunes.bat > nul" 'Start the song playing
Kill "StartItunes.bat" 'Delete temporary file

'Note: We have to "mouse-click" back into the MMBasic DOS window after the song is started, before 'timestamping can commence.
.
.
.

Greg
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 09:26pm 06 Sep 2015
Copy link to clipboard 
Print this post

Greg

Very useful - thanks.

Is there a way of getting MMBasic to accept parameters on the command line?

e.g.

MMBASIC cfgen.bas /f=test.elf /merge /o=myfile.basEdited by matherp 2015-09-08
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 09:40pm 06 Sep 2015
Copy link to clipboard 
Print this post

I have optimized the increment4 subroutine a bit.
[code]
sub increment4(value$)
Local V$(7) LENGTH 1, i, NewValue$ LENGTH 8
for i= 0 to 7: V$(i) = mid$(value$, i+1, 1): next
V$(7) = Chr$(Asc(V$(7)) + 4)
for i = 7 to 1 step -1
v = Asc(V$(i))
if v > 70 then ' "F"
V$(i) = Chr$(v - 23): V$(i-1) = Chr$(Asc(V$(i-1)) + 1)
else
if v >57 and v < 65 then V$(i) = Chr$(v + 7) ' "9" "A"
endif
NewValue$ = V$(i)+ NewValue$
next
value$ = V$(0) + NewValue$
end sub
[/code]

Also you can use the VAL function to get the value of a HEX character
so instead of doing:
[code]
a=asc(mid$(a$,5,1)) : a=a-48 : if a> 9 then a=a-7
[/code]
you can do:
[code]
a = val("&H" + mid$(a$,5,1))
[/code]

Alternatieve for:
[code]
s$= hex$(subtract(right$(main_offset$,5),right$(text_add$,5))) 'calculate the offset of the main function
if len(s$)=1 then s$="0000000"+S$
if len(s$)=2 then s$="000000"+S$
if len(s$)=3 then s$="00000"+S$
if len(s$)=4 then s$="0000"+S$
if len(s$)=5 then s$="000"+S$
if len(s$)=6 then s$="00"+S$
if len(s$)=7 then s$="0"+S$
main$=s$
[/code]
is
[code]
main$= right$("00000000"+hex$(subtract(right$(main_offset$,5),right$(text_add$,5))),8) 'calculate the offset
[/code]

Still working on the decrement sub.:)

Microblocks. Build with logic.
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 09:51pm 06 Sep 2015
Copy link to clipboard 
Print this post

TZ

Great stuff

You will see the decrement routine is actually used in a loop to subtract two addresses so what is really needed is a routine that subtracts "12AB34CD" from "34CD12AB"

Thanks Peter
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 10:03pm 06 Sep 2015
Copy link to clipboard 
Print this post

  matherp said  
Is there a way of getting MMBasic to accept parameters on the command line?

e.g.

MMBASIC cfgen.bas /f=test.elf /merge /o=myfile.bas


Sort of...
MMBasic.ex will take a BAS file name on the commandline but that's all

I used this cludge to get a command line string to a BAS program

All it does is get your BAS program to read a known configuration/command line file.

Batch file:
echo. "more command line stuff" > temp.txt
"C:\Users\Jim\Documents\apps\maximite\DOS MMBasic\MMBasic.exe" test.bas


TEST.BAS
print "Welcome"
print mm.cmdline$
open "C:\Users\Jim\Documents\apps\maximite\DOS MMBasic\temp.txt" for input as #1
input #1, myfile$
close #1
print myfile$
print "Done"


You will need to edit the paths in both files.

Jim

VK7JH
MMedit
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 11:04pm 06 Sep 2015
Copy link to clipboard 
Print this post

Thanks to TZ I've improved all the calculation algorithms, unfortunately it doesn't make things much faster as most of the time is spent file positioning but it certainly looks cleaner.


'
' CFGEN.BAS V1.1
' V1.1 Improved algorithms thanks to TZ
' V1.11 Tidy Up
'
' Program to convert a .ELF file to Basic statements formated for use as CFunctions
' Runs under MMBasic for DOS V4.5
'
' It is recommended that the .ELF file is copied to the same directory as this file
' and that the filename is shortened to make life easier
'
' To run open a DOS box on the computer
' navigate to the directory containing the MMBasic.exe file and this program
' run MMBasic and you will get the normal ">" prompt
' Load this program
' Type run
'
' Then give the filename of the .elf file including the extension
' Choose "join" or "merge" to define the output format
' "join" is typically used for individual CFunctions, each function in the .ELF file is given
' its own header, all the CFunctions are output to a single file but can then be copied and
' pasted as required. When "join is chosen the "main" function is a dummy and is not included in the output
' "merge" is used for CFunctions such as drivers where one C function can be called from another
'
' Choose the name of the file for the Basic output. Do not include ".BAS", this will be appended automatically
'
' You can run MMBasic for DOS from MMEDIT, but in this case you will need to specify the correct directory information for the .ELF file
'
dim section_header, section_header_size, section_header_num
dim string_table_sector, string_table, text_section, text_position, text_size, text_link, symtab_section, strtab_section
dim symtab_offset, symtab_num, symstr_offset, first
dim text_add$ length 31
dim symbols$(100,2) length 31
line input ".ELF filename ? ",inname$
do
line input "mode(join, merge) ? ",m$
loop while (m$<>"join") and (m$<>"merge")
mode =0
if m$="merge" then mode=1
line input "CFunction name ? ",cname$
print "Created "+cname$+".bas"
open cname$+".bas" for output as #2
PRINT #2,"'File "+cname$+".bas written "+DATE$+" "+Time$
first=1 'first time into the various loops
print "processing ",inname$
open inname$ for random as #1
SEEK #1, 0
'
dat$ = INPUT$(32, #1) ' Get the .elf identification and unused header
dat$=input$(4,#1)
section_header=getnum4(dat$)
dat$=input$(10,#1) 'step past the flags ,header size, and program header info
dat$=input$(2,#1)
section_header_size=getnum2(dat$)
dat$=input$(2,#1)
section_header_num=getnum2(dat$)
dat$=input$(2,#1)
string_table_sector=getnum2(dat$)
'
i=section_header+ (Section_header_size*string_table_sector) + 16 'get to the offset in the string table sector
seek #1,i
dat$=input$(4,#1)
string_table= getnum4(dat$) 'get the offset to the string table
Print "Functions found:"
print "Address",chr$(9)+"Function"
for j=0 to section_header_num-1
i=section_header+ (Section_header_size*j) 'get to the next sector header
seek #1,i 'point to the .text section header
dat$=input$(4,#1) 'get the pointer to the sector name string
k=getnum4(dat$)
seek #1,k+string_table 'point to the name string for this sector
s$=""
d$=input$(1,#1)
do while asc(d$)<>0 'read in the zero terminated string
S$=S$+D$
d$=input$(1,#1)
loop
if s$=".text" and text_section=0 then 'store text sector number
text_section=j
endif
if s$=".symtab" and symtab_section=0 then 'store symbol table sector number
symtab_section=j
endif
if s$=".strtab" and strtab_section=0 then 'store symbol table strings sector number
strtab_section=j
endif
next j
'
i=section_header+ (Section_header_size*text_section) 'get to the .text offset
seek #1,i 'point to the .text section header
dat$=input$(12,#1)
dat$=input$(4,#1)
text_add$=getadd$(dat$)
dat$=input$(4,#1)
text_position=getnum4(dat$)
dat$=input$(4,#1)
text_size= getnum4(dat$)
dat$=input$(4,#1)
text_link= getnum4(dat$)
'
i=section_header+ 16+ (Section_header_size*(symtab_section))
seek #1,i 'point to the symbol table section header
dat$=input$(4,#1) 'get the offset to the symbol table
symtab_offset=getnum4(dat$)
dat$=input$(4,#1)
symtab_num=getnum4(dat$)/16
'
i=section_header+ 16+ (Section_header_size*(strtab_section))
seek #1,i 'point to the string table section header
dat$=input$(4,#1) 'get the offset to the symbol table
symstr_offset=getnum4(dat$)
'
m=0 'counter for the stored symbols array
for i=1 to symtab_num 'loop through all the symbols
seek #1,symtab_offset+(16*i) 'point to the next symbol in the .symtab section
dat$=input$(4,#1)
k=getnum4(dat$)
dat$=input$(4,#1)
a$=getadd$(dat$)
dat$=input$(4,#1)
dat$=input$(1,#1)
l=asc(dat$)
seek #1,k+symstr_offset 'point to the symbol name
s$=""
d$=input$(1,#1)
do while asc(d$)<>0
S$=S$+D$
d$=input$(1,#1)
loop
if l=18 and left$(s$,1)<>"_" then 'Only store function names
symbols$(m,1)=a$
symbols$(m,2)=s$
print symbols$(m,1),symbols$(m,2)
m=m+1
if s$="main" then main_offset$=a$
endif
next i
'
main$= right$("00000000" + hex$(subtract(right$(main_offset$,5), right$(text_add$,5))), 8) 'calculate the offset
'
seek #1,text_position
k=0
currentfunction=0
s$=text_add$
for i=1 to text_size step 4
for j=0 to m-1
if s$=symbols$(j,1) then 'address matches the start of a function
currentfunction=j
if k<>0 and mode then print #2,"" 'The last function didn't end with a newline so output one
if k<>0 and (not mode) and symbols$(j,2)<>"main" then print #2,""
k=0
if first and mode then ' First time in for a merged file output the Cfunction name
print #2,"CFunction "+cname$
print #2,chr$(9)+main$
endif
if mode then print #2,chr$(9)+"'"+symbols$(j,2)
if not mode and symbols$(j,2)<>"main" then
if not first then
print #2,"End CFunction"
print #2,"'"
endif
print #2,"CFunction "+symbols$(j,2)
print #2,chr$(9)+"00000000"
endif
first=0
endif
next j
if k=0 then print #2,chr$(9);
dat$=getadd$(input$(4,#1))
if left$(dat$,3)="0F4" then 'Jump instruction found convert to a branch
a$=getjumpaddress$(right$(dat$,5)) 'this the address for the jump
branchoffset=subtract(right$(s$,5),right$(a$,5))
branch$=subaddress$("0411FFFF",branchoffset)
if not mode and symbols$(currentfunction,2)<>"main" then print #2, branch$+" ";
if mode then print #2, branch$+" ";
else
if not mode and symbols$(currentfunction,2)<>"main" then print #2, dat$+" ";
if mode then print #2, dat$+" ";
endif
k=k+1
if k=8 then 'deal with line feed every eight words
if not mode and symbols$(currentfunction,2)<>"main" then print #2,""
if mode then print #2,""
k=0
endif
increment4(s$) 'step on the program counter
next i
if k<>0 then print #2,""
print #2,"End CFunction"
close #1
close #2
'
end

function subtract(b$,c$)
local f,g
f=val("&H"+b$)
g=VAL("&H"+c$)
subtract=(f-g)/4
end function

function getjumpaddress$(a$)
local f
f=VAL("&H"+a$)*4+1048576
getjumpaddress$=left$(text_add$,3)+right$(hex$(f),5)
end function

function getadd$(d$)
local a,b,c,d
a=asc(left$(d$,1))+256
b=asc(mid$(d$,2,1))+256
c=asc(mid$(d$,3,1))+256
d=asc(right$(d$,1))+256
getadd$=right$(hex$(d),2) +right$(hex$(c),2) +right$(hex$(b),2) +right$(hex$(a),2)
end function

function getnum4(d$)
local a,b,c,d
a=asc(left$(d$,1))
b=asc(mid$(d$,2,1))
c=asc(mid$(d$,3,1))
d=asc(right$(d$,1))
getnum4=((((d*256)+c)*256)+b)*256+a
end function

function getnum2(d$)
local a,b
a=asc(left$(d$,1))
b=asc(right$(d$,1))
getnum2=b*256+a
end function

sub increment4(value$)
Local V$(7) LENGTH 1, i, NewValue$ LENGTH 8
for i= 0 to 7: V$(i) = mid$(value$, i+1, 1): next
V$(7) = Chr$(Asc(V$(7)) + 4)
for i = 7 to 1 step -1
v = Asc(V$(i))
if v > 70 then ' "F"
V$(i) = Chr$(v - 23): V$(i-1) = Chr$(Asc(V$(i-1)) + 1)
else
if v >57 and v < 65 then V$(i) = Chr$(v + 7) ' "9" "A"
endif
NewValue$ = V$(i)+ NewValue$
next
value$ = V$(0) + NewValue$
end sub

function subaddress$(p$,b)
local a
a=val("&H"+RIGHT$(p$,4))+65536-b
subaddress$=left$(p$,4)+right$(hex$(a),4)
end function
Edited by matherp 2015-09-08
 
disco4now

Guru

Joined: 18/12/2014
Location: Australia
Posts: 1003
Posted: 02:05am 07 Sep 2015
Copy link to clipboard 
Print this post

Hi Peter,
Thanks for replacement CFunctGen. I have used your first posted version in anger and have successfully called DrawPixel using the MMBasic API.

I found it quite convenient to use via MMBasic, just run up a second copy of MMBasic and loaded CFunctGen.bas , remark out the prompts and hard code your file names etc and save a copy with the project name appended. This makes it easy to run multiple times as you do in development.

A good way to get long windows directory + file names into the clipboard is to open up the run dialogue and then drag the file to the input field. You can then get it from there into the clipboard and paste where you want.



So after being away for a couple of months away I am nearly caught up.

The C code below shows calling the DrawPixel routine in MMbasic from C via the MMbasic API.

/*
* File: newmain.c
* Author: gallardice
*
* Created on 6 September 2015, 8:43 PM
*/

#define _SUPPRESS_PLIB_WARNING
#include <plib.h>
#define FAM
#include "APIDefs.h"
#define DEVID (*(volatile unsigned int *)0xBF80F220)
#define PIC32MX170F256B_DEVID 0x06610053
#define PIC32MX270F256B_DEVID 0x06600053
#define PIC32MX170F256D_DEVID 0x0661A053
#define PIC32MX270F256D_DEVID 0x0660A053
#define HAS_28PINS ((DEVID & 0xfffffff) == PIC32MX170F256B_DEVID || (DEVID & 0xfffffff) == PIC32MX270F256B_DEVID)
long long drawPixel(long long *xp,long long *yp,long long *cp){
int x=*xp,y=*yp,c=*cp;
DrawPixel(x,y,c);
return(0);

}
//We need a main to keep the compiler happy
void main(){}


This is the CFunction generated by Peters program


CFunction drawPixel
00000000
27BDFFE0 AFBF001C 8C830000 8CA70000 3C029D00 8C420048 8CC40000 AFA40010
8C420000 00602021 00E02821 0040F809 00603021 00001021 00001821 8FBF001C
03E00008 27BD0020
End CFunction


Here is a snippet from MMBasic showing a loop writing two parrallel lines,
one via MMBasic command PIXEL and the other calling the CFunction drawPixel() which then calls the MMBasic binary via its API entry point DrawPixel.

dim result AS INTEGER
for I%=10 to 240 STEP 1
PIXEL I%-5,I%, RGB(green) 'MMBasic
result=drawPixel(I%,I%,RGB(red)) 'CFunction
NEXT I%


Thanks again Peter for all the good stuff.

Regards
Gerry


Latest F4 Latest H7 FotS
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 03:26am 07 Sep 2015
Copy link to clipboard 
Print this post

Can someone send me an ELF file AND the created output file.
I want to test something and having a working example will greatly simply testing it.

Microblocks. Build with logic.
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 03:55am 07 Sep 2015
Copy link to clipboard 
Print this post

  Quote  Can someone send me an ELF file AND the created output file


Here you go:

2015-09-07_135511_ILI9325.zip

I use winmerge to check each modification doesn't compromise the outputEdited by matherp 2015-09-08
 
robert.rozee
Guru

Joined: 31/12/2012
Location: New Zealand
Posts: 2442
Posted: 03:59am 07 Sep 2015
Copy link to clipboard 
Print this post

does anybody know what happened to the support site for CFunctions? is it down temporarily?

cheers,
rob :-)
 
paceman
Guru

Joined: 07/10/2011
Location: Australia
Posts: 1329
Posted: 04:29am 07 Sep 2015
Copy link to clipboard 
Print this post

  matherp said   Greg
Very useful - thanks. Is there a way of getting MMBasic to accept parameters on the command line? e.g.
MMBASIC cfgen.bas /f=test.elf /merge /o=myfile.bas

Not directly as I remember. Jim's method obviously works - the one in the middle box I posted above works well too but it's read from a batch file and called from the MMBasic program with SYSTEM.

For your development work, maybe a macro from MMEdit or TT could be used?
 
twofingers

Guru

Joined: 02/06/2014
Location: Germany
Posts: 1593
Posted: 02:22am 08 Sep 2015
Copy link to clipboard 
Print this post

Thanks Peter!

Good job. I think I have never seen a (functional) program for MMBasic for DOS.
I assumed it was just for testing purposes ...


  matherp said   Unfortunately the support site for CFunctions is no longer online so I have programmed a clunky but workable replacement for CFuncGen


I hope Peter C. (G8JCF) is doing well!

Michael


causality ≠ correlation ≠ coincidence
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 02:26pm 08 Sep 2015
Copy link to clipboard 
Print this post

Peter,
I have been playing with your cfungen program and converting it to a windows application.
So far I can agree with the example you provided. I do need to tidy up the user interface before I let you play with it.

I did find one bug.

I think
FOR i=1 TO symtab_num 'loop through all the symbols


should be
FOR i=0 TO symtab_num-1 'loop through all the symbols


As it stands your code ends up seeking beyond the end of the file.

I added a test
IF i >(symtab_num -2) THEN
PRINT "Woops! ",FORMAT$(k+symstr_offset, "%9.0f"),filesize
ENDIF
SEEK #1,k+symstr_offset 'point to the symbol name


and the resulting printout:
Woops! 184744 184755
Woops! 1651246464 184755

The first time the test is triggered, seek position is less than the file size but the second time, we are well over the file size.



MMBasic didn't throw an error but my PureBasic certainly did.

Jim

VK7JH
MMedit
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 10:33pm 08 Sep 2015
Copy link to clipboard 
Print this post

  Quote  I have been playing with your cfungen program and converting it to a windows application.


Excellent news. I've managed to spend an entire career in IT without ever having to do windows I/F work so your contribution will be greatly appreciated.

  Quote  I did find one bug.


Good catch, anyone using my code, please make the change.
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 10:56pm 08 Sep 2015
Copy link to clipboard 
Print this post

  matherp said   I've managed to spend an entire career in IT without ever having to do windows I/F work so your contribution will be greatly appreciated.


Gui programming can be a pain, especially when Microsoft keep changing things.
I found a bug in MMEdit where it was not starting DOS basic in the correct folder.
It will be fixed in the next release.

Here is my attempt at CFUNCTION generator.
It has only been tested with the one ELF file so beware....

Usage:
select the ELF file
Select the destination file (if you cancel, you can do a dummy run)
Choose Merge or Join.

The result is printed to the text window and saved to your chosen destination.

I will add a few more sanity checks but I want to know that it works first.

2015-09-09_085634_cfgen.zip

Jim
VK7JH
MMedit
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 11:06pm 08 Sep 2015
Copy link to clipboard 
Print this post

Jim

First look, the live window looks OK but the file produced has the first value on the same line as the CFunction in join mode

e.g.
CFunction npins 00000000
3C02BF81 8C44F220 7C84D800 3C030661 3463A053 1083000B 2402002C 3C02BF81
8C43F220 7C63D800 3C020660 3442A053 00621026 2403001C 2404002C 0082180A
00601021 3C03BF81 8C64F220 7C84D800 3C030580 3463A053 00832026 24030040
0064100A 3C03BF81 8C64F220 7C84D800 3C030580 3463B053 00832026 24030064
0064100A 03E00008 00021FC3
End CFunction


Also, can you put a time and date in the file as a comment - I did this in my current version.

Finally, please could you arrange that pressing join or merge will cause the file to be regenerated each time they are pressed by re-reading the source. This will allow the program to be left open and just press the button each time you want to update after a new .ELF is producedEdited by matherp 2015-09-10
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 02:21pm 09 Sep 2015
Copy link to clipboard 
Print this post

Fixed the layout problem with the file output - typo.
Added date as comment.
You can now rerun with the same file names as often as desired using 'Join' and 'Merge'
'New' lets you re-select the files.

As well as outputting to a file, the output is copied to the clipboard ready for pasting into a program.

Is there any call for the ability to read a commandline?

2015-09-10_002014_cfgen.zip

Jim
VK7JH
MMedit
 
     Page 1 of 2    
Print this page
The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025