Building a C-like Compiler and VHDL Microprocessor
This project was a true crash course in bridging the gap between theory and practice. As part of my studies at INSA Toulouse, I set out to design both a compiler for a simplified C-like language and a custom VHDL microprocessor capable of executing the generated machine code. It was the first time I had to take an abstract idea—"make a language run on a processor"—and actually implement the entire chain.
The Challenge
At first, the task looked overwhelming: three moving parts that all had to work together. On one side, the compiler had to translate human-readable code into structured instructions. On the other, a microprocessor needed to understand and execute those instructions. And between them was the delicate interface: assembly code that had to be syntactically precise and semantically sound.
Compiler: From Text to Instructions
I began with the compiler, which we split into two classic stages: lexical analysis and syntax analysis.
Lexical Analysis with Flex
Using Flex, I built a lexical analyzer that could recognize tokens such as keywords (if, while),
identifiers, numbers (including hexadecimal and scientific notation), and operators (+, -, *).
It also handled comments gracefully and threw errors for unknown tokens.
Running the lexer felt like watching raw code come alive, structured into pieces ready for deeper analysis.
Syntax Analysis with Bison
The syntax analyzer, written with Bison, checked these tokens against grammar rules.
It supported function declarations, arithmetic expressions, conditionals, and loops.
To keep everything consistent, I used a symbol table to track variables and functions,
while an assembly table produced machine-ready instructions.
This was where the compiler truly "spoke" to the hardware level.
Microprocessor: Bringing Code to Life
With the compiler generating assembly, the next step was to build a processor that could run it. Designed in VHDL, my microprocessor followed a RISC 5-stage pipeline architecture. It included:
- Instruction set:
ADD,MUL,SOU,COP,AFC,LOAD,STORE - A register bank and memory management system
- An ALU capable of arithmetic and logical operations
- Hazard detection in the second pipeline stage to handle conflicts
For me, the breakthrough moment was watching my own assembly instructions actually run in a Vivado simulation—proof that the compiler and microprocessor were finally in sync.
Lessons Learned
This project taught me that building a system end-to-end is more than just coding each part correctly. It's about designing clear interfaces between layers, and anticipating how design choices in one layer ripple down into the others. Debugging across both the compiler and the processor forced me to think systematically, which is a skill I now carry into my work in cybersecurity.
Figures