Is there a restriction that firmware can be written only in compiled languages or Assembly languages or Machine code? Can Interpreted languages or Just In Time Compiled languages be used?
Embedded firmware is still software, so it is possible to write it in any Turing Complete language given sufficient time and memory (strictly speaking a Turing complete language has infinite resources). We often refer to the languages we use as Turing complete even though the machines do not have infinite resources.
Therefore a program could be written in native machine code, assembler (both of which require quite detailed knowledge of the internals of the device) or a higher level language (which may be compiled or interpreted).
The only real limitation is the available toolset.
Compiled languages are quite efficient but sometimes don't do precisely what you really want (optmisers will strip out instructions that it believes are not necessary even when you think they are although there are ways around that).
The only way to define precisely what is actually run is to write the code with a non-optimising assembler or by hand assembling machine code. This may or may not be more efficient than a compiled solution (it can be depending on how you structure the code).
In some circumstances, we use a compiler and hand tweak the assembly output (not for the faint of heart) in some very demanding situataions.
"The definition of firmware need to be rock solid to continue with this question" is spot-on observation made by @Jeroen3 in this answer.
Any software running on MCU is after all just a bunch of hardware-defined instructions. There are three ways to go from programming language to these instructions:
- Use language which semantics covers the hardware architecture. These languages can be directly compiled into binary code for uploading to MCU.
- Use linked framework libraries providing hardware-level translation of the language abstractions. This approach allows pretty much ANY language to be used for writing firmware. But the framework itself still falls into the category 1.
- Use an interpreted language with interpreter or Virtual Machine (VM) which is written in the language of category 1 or 2.
As you can see, whatever language is used for the bulk of firmware code, there always will be a layer of the category 1 language somewhere before you get your firmware binary or the VM on which to execute it.
So, the answer does depend on the definition of firmware. Or rather on whether or not you include underlying layers into the definition.
There are some basic requirements when it comes to languages that can compile to firmware. That is, the language dealing with direct low level register access.
- Pointers, you can't define register locations without them.
- Configurable operator widths. Not all parts of chip can do 8 bit r/w, some must do 8 bit r/w.
One case of firmware is the BIOS used for booting computers.
A while ago, Sun worstation and PowerPC Machintoshes BIOS were based on the OpenFirmware/OpenBoot standard which uses a FORTH interpreter, the goal was to allow peripherals to provide initialisation/setup code portable across different CPU architectures.
The processor reads instructions from memory, interprets them as machine code (for that particular type of processor), and executes them.
That's it. That's all it does.
As long as you can get a file with machine code for the processor to execute, you can create this file in any way you want.
You can use machine code.
Or you can use a language with a compiler that outputs machine code.
Or you can use a language with a compiler that outputs bytecode, and a bytecode interpreter written in machine code.
Or you can use a language with a compiler that outputs bytecode, and a bytecode interpreter written in a language with a compiler that outputs machine code.
Or you can use an interpreted language, and an interpreter written in machine code.
Or you can use an interpreted language, and an interpreter written in a language with a compiler that outputs machine code.
Or you can use an interpreted language, and an interpreter written in a language with a compiler that outputs bytecode, and a bytecode interpreter written machine code.
Or you can use an interpreted language, and an interpreter written in a language with a compiler that outputs bytecode, and a bytecode interpreter written in a language with a compiler that outputs machine code.
You see? You can do whatever you want, as long as there is machine code at the bottom of the stack. You can even mix-and-match for different parts of the firmware. You want to use Python code in your firmware? Sure, you can do that, if you put a Python interpreter (compiled to machine code) in your firmware as well, and you have enough memory for the interpreter.
Firmware simply means software stored in hardware.
For example, a blank EPROM chip is hardware. The data to go in it is software. The resultant programmed part is termed firmware.
Because it can no longer be called hardware and it certainly isn't software. The term was coined to give a name to this combination of parts.
The part is no longer a blank EPROM and should no longer be called 'the EPROM' although people will and do. It should have a new name and, in professional engineering environments, a part number.
So, for an 'ABC' machine, its hardware ('27C512 EPROM') plus its software ('ABC programming file') makes its firmware ('ABC Firmware').
This is no different to a bracket not being called a 'bent metal strip'. It was a metal strip drawn from stores. A manufacturing operation was performed. Now it has a new part number and name: bracket.
As an aside, so often, I see in companies a board with on it: 'the FPGA' or 'the microcontroller', as all the documentation and engineers call it. Actually, the FPGA or microcontroller is the blank part only. Once programmed, it should have been given a new name that denotes its function. If and when someone adds a second FPGA to that board, confusion is created.