28 Commits

Author SHA1 Message Date
9c8d79bf67 update to v1.5 2024-12-06 17:11:46 +01:00
95701058f1 fix Windows linking 2024-12-06 17:11:27 +01:00
c7f52d9ce8 update to v1.4 2024-12-06 17:06:04 +01:00
4bc49bb200 upper case test.asm 2024-12-06 17:03:21 +01:00
bd07de84f9 update README 2024-12-06 17:03:07 +01:00
fb4883b840 add unused byte for easier reading in cpu 2024-12-06 16:35:10 +01:00
0dd3e6d83f update to 1.3 2024-12-05 16:37:15 +01:00
35501025ff don't be case sensitive for instructions 2024-12-05 16:34:20 +01:00
cf1a4d00af update to 1.2 2024-12-05 16:23:20 +01:00
785fb7a8e7 update run instruction 2024-12-05 16:22:12 +01:00
a4abd128f5 update example 2024-12-05 16:20:17 +01:00
e6b13abc15 change mult to mul 2024-12-05 16:18:39 +01:00
d5cd5a5849 xmake: remove tutorial 2024-12-05 16:06:33 +01:00
eb6cde02a7 absolute jump 2024-11-26 17:14:22 +01:00
9738ba1afd update to 1.1 2024-11-26 16:05:19 +01:00
432d706314 update README 2024-11-26 16:03:26 +01:00
be1c9f9fd7 add multiplication 2024-11-26 15:59:36 +01:00
f14d05a28a add reversing 2024-11-13 14:50:22 +01:00
6fcc51f2ca throw invalid arguments 2024-10-24 18:14:09 +02:00
777adffdea registry bound check 2024-10-24 18:11:19 +02:00
7c72155fea basic README 2024-10-23 21:09:20 +02:00
8452b98a97 set c++ standard 2024-10-23 20:51:41 +02:00
3207de80dd parse arguments 2024-10-23 20:48:18 +02:00
39eb113385 add multiple outputs 2024-10-23 20:12:11 +02:00
51f113804a fix jump forward 2024-10-23 20:05:41 +02:00
47e7a17a74 remove compile commands 2024-10-23 11:19:12 +02:00
d3cb3d82de add io file 2024-10-23 11:18:24 +02:00
40041b0f12 clean workspace 2024-10-23 11:13:59 +02:00
14 changed files with 320 additions and 5501678 deletions

2
.gitignore vendored
View File

@@ -5,4 +5,6 @@ build/
# MacOS Cache
.DS_Store
.vscode
a.out

View File

@@ -1,11 +1,8 @@
{
"configurations": [
{
"name": "Blitz",
"name": "Assembleur",
"cppStandard": "c++17",
"includePath": [
"include"
],
"compileCommands": ".vscode/compile_commands.json"
}
],

View File

@@ -1,11 +0,0 @@
[
{
"directory": "/home/simon/Programmation/Assembleur",
"arguments": ["/usr/bin/gcc", "-c", "-m64", "-fvisibility=hidden", "-fvisibility-inlines-hidden", "-O3", "-DNDEBUG", "-o", "build/.objs/Assembleur/linux/x86_64/release/src/main.cpp.o", "src/main.cpp"],
"file": "src/main.cpp"
},
{
"directory": "/home/simon/Programmation/Assembleur",
"arguments": ["/usr/bin/gcc", "-c", "-m64", "-fvisibility=hidden", "-fvisibility-inlines-hidden", "-O3", "-DNDEBUG", "-o", "build/.objs/Assembleur/linux/x86_64/release/src/Assembleur.cpp.o", "src/Assembleur.cpp"],
"file": "src/Assembleur.cpp"
}]

View File

@@ -1,5 +0,0 @@
{
"files.associations": {
"stdexcept": "cpp"
}
}

95
README.md Normal file
View File

@@ -0,0 +1,95 @@
# Assembleur
## Usage
```bash
./Assembleur [--help] [--reversed] [--version] [--output file] [--format type] file
```
There are 3 format types :
- "int" : 32 bits integers are written. Exemple : `10878976`
- "binint" : bits are written. Exemple : `00000000 10100110 00000000 00000000`
- "bin" : the file is written in pure binary
- "logisim" (default) : the file is written in binary for use in LogiSim
## Exemple
```assembly
operations:
ADD R1 R2 #1
SUB R1 R2 R3
AND R1 R2 #33
XOR R1 R2 R3
OR R1 R2 R3
SL R1 R2 R3
SR R1 R2 R3
MUL R1 R2 R3
io:
STR R1 R2 R3
LD R1 R2 R3
sauts:
JMP controle
JEQU R1 R2 io
JNEQ R1 R2 sauts
JSUP R1 R2 operations
JINF R1 R2 controle
controle:
CALL io
RET
```
Produces
```
00000100 10100000 00000000 00000001
00010000 10100110 00000000 00000000
00100100 10100000 00000000 00100001
01000000 10100110 00000000 00000000
00110000 10100110 00000000 00000000
01010000 10100110 00000000 00000000
01100000 10100110 00000000 00000000
01110000 10100110 00000000 00000000
01000000 10100110 00000000 00000000
01010000 10100110 00000000 00000000
11000000 00000000 00000000 00010000
11010000 10100000 00000000 00001001
11100000 10100000 00000000 00001011
11110000 10100000 00000000 00000001
11000000 10100000 00000000 00010000
11010000 00000000 00000000 00001001
11100000 00000000 00000000 00000000
```
## Releases
Pre-compiled binaries are available in the [Release](https://git.ale-pri.com/Persson-dev/Assembleur/releases) section.
## Build
If you wish to compile yourself, you must have [xmake](https://xmake.io) installed.
Instructions on how to install (and you should) [here](https://xmake.io/#/guide/installation)
```bash
xmake
```
## Run
```bash
xmake run Assembleur [args]
```
Example :
```bash
xmake run Assembleur test.asm -o memory
```
Parses the file `test.asm` and writes the output into the file `memory`
## Install
You can also add the binary to your path using
```bash
xmake install
```

View File

@@ -1,5 +1,6 @@
#include "Assembleur.h"
#include <algorithm>
#include <map>
#include <sstream>
#include <stdexcept>
@@ -12,7 +13,7 @@ enum TypeArithmetique {
Xor,
Sl,
Sr,
Not,
Mul,
};
enum TypeMemoire {
@@ -38,6 +39,7 @@ static std::map<std::string, Instruction> INSTRUCTION_KEYS = {
{"xor", {Arithmetique, Xor}},
{"sl", {Arithmetique, Sl}},
{"sr", {Arithmetique, Sr}},
{"mul", {Arithmetique, Mul}},
{"str", {Memoire, Str}},
{"ld", {Memoire, Ld}},
{"jmp", {SautControle, Jump}},
@@ -53,7 +55,7 @@ std::uint32_t Assembleur::ParseLabel(const std::string& a_Label) {
auto it = m_Labels.find(a_Label);
if (it == m_Labels.end()) {
throw std::runtime_error("Label " + a_Label + " not found !");
throw std::invalid_argument("Label " + a_Label + " not found !");
}
return it->second;
@@ -78,17 +80,11 @@ std::uint32_t Assembleur::ParseOperationImmediate(
}
std::uint32_t Assembleur::ParseJump(Instruction a_Instruction, const std::string& a_Label) {
int jump = a_Instruction.m_Line - ParseLabel(a_Label);
if (jump < 0)
jump = jump & 0x7FFFFFF | 0x4000000;
return IToInt(a_Instruction) | jump;
return IToInt(a_Instruction) | ParseLabel(a_Label) & 0x3FFFFFF;
}
std::uint32_t Assembleur::ParseJump(Instruction a_Instruction, std::uint8_t a_R1, std::uint8_t a_R2, const std::string& a_Label) {
int jump = a_Instruction.m_Line - ParseLabel(a_Label);
if (jump < 0)
jump = jump & 0xFFFFF | 100000;
return IToInt(a_Instruction) | a_R1 << 24 | a_R2 << 21 | jump;
return IToInt(a_Instruction) | a_R1 << 23 | a_R2 << 20 | ParseLabel(a_Label) & 0xFFFFF;
}
std::uint32_t Assembleur::ParseJump(Instruction a_Instruction) {
@@ -96,7 +92,7 @@ std::uint32_t Assembleur::ParseJump(Instruction a_Instruction) {
}
std::uint32_t Assembleur::ParseIO(Instruction a_Instruction, std::uint32_t a_R1, std::uint32_t a_R2, std::uint32_t a_R3) {
return IToInt(a_Instruction) | a_R1 << 24 | a_R2 << 21 | a_R3 << 18;
return IToInt(a_Instruction) | a_R1 << 23 | a_R2 << 20 | a_R3 << 17;
}
@@ -105,8 +101,11 @@ std::uint32_t Assembleur::ParseIO(Instruction a_Instruction, std::uint32_t a_R1,
static std::uint32_t ParseRegistry(const std::string& a_Str) {
if (a_Str.at(0) != 'R')
throw std::runtime_error("Registry " + a_Str + " not found !");
return std::stoi(a_Str.substr(1));
throw std::invalid_argument("Registry " + a_Str + " not found !");
std::uint32_t registry = std::stoi(a_Str.substr(1));
if (registry > 7)
throw std::invalid_argument("You can only have up to 8 registries !");
return registry;
}
static bool IsConstant(const std::string& a_Str) {
@@ -115,7 +114,7 @@ static bool IsConstant(const std::string& a_Str) {
static std::uint32_t ParseConstant(const std::string& a_Str) {
if (a_Str.at(0) != '#')
throw std::runtime_error("Registry " + a_Str + " not found !");
throw std::invalid_argument("Registry " + a_Str + " not found !");
return std::stoi(a_Str.substr(1));
}
@@ -124,13 +123,15 @@ std::uint32_t Assembleur::ParseInstruction(const std::string& a_Str, std::uint32
std::string ins;
ss >> ins;
// to lower case
std::transform(ins.begin(), ins.end(), ins.begin(), [](unsigned char c) { return std::tolower(c); });
auto it = INSTRUCTION_KEYS.find(ins);
if (it == INSTRUCTION_KEYS.end()) {
throw std::runtime_error("[Line " + std::to_string(a_RealLine) + "] " + "Instruction \"" + ins + "\" not found !");
throw std::invalid_argument("[Line " + std::to_string(a_RealLine) + "] " + "Instruction \"" + ins + "\" not found !");
}
Instruction instruction = it->second;
instruction.m_Line = a_Line;
try {
switch (instruction.m_Instruction) {
@@ -174,8 +175,8 @@ std::uint32_t Assembleur::ParseInstruction(const std::string& a_Str, std::uint32
}
}
} catch (std::runtime_error& e) {
throw std::runtime_error("[Line " + std::to_string(a_RealLine) + "] " + e.what());
} catch (std::invalid_argument& e) {
throw std::invalid_argument("[Line " + std::to_string(a_RealLine) + "] " + e.what());
}
return 0;

View File

@@ -13,7 +13,6 @@ enum TypeInstruction : std::uint8_t {
struct Instruction {
TypeInstruction m_Instruction;
std::uint8_t m_SubInstruction;
std::uint32_t m_Line;
};
class Assembleur {

110
src/IO.cpp Normal file
View File

@@ -0,0 +1,110 @@
#include "IO.h"
#include "Assembleur.h"
#include <algorithm>
#include <bitset>
#include <cstring>
#include <fstream>
#include <iomanip>
static std::uint32_t reverseInt(std::uint32_t a_Int) {
std::uint32_t result = 0;
for (int i = 0; i < 32; i++) {
result |= a_Int & 0x1;
result <<= 1;
a_Int >>= 1;
}
return result;
}
static void reverseDataByte(BinaryData& a_Data) {
for (std::uint32_t& element : a_Data) {
element = reverseInt(element);
}
}
BinaryData ParseFile(const std::string& fileName) {
std::ifstream file{fileName};
std::uint32_t lineNumber = 0, realLineNumber = 0;
std::string currentLine;
std::vector<std::string> lines;
Assembleur assembleur;
BinaryData output;
// parsing labels
while (getline(file, currentLine)) {
lines.push_back(currentLine);
lineNumber++;
realLineNumber++;
if (currentLine.find(":") != std::string::npos) {
std::string label = currentLine.substr(0, currentLine.size() - 1);
assembleur.AddLabel(label, lineNumber);
lineNumber--;
}
}
lineNumber = realLineNumber = 0;
// parsing instructions
for (std::string line : lines) {
lineNumber++;
realLineNumber++;
if (line.find(":") == std::string::npos) {
output.push_back(assembleur.ParseInstruction(line, lineNumber, realLineNumber));
} else {
lineNumber--;
}
}
return output;
}
void OutputFileBinary(BinaryData& a_Data, const std::string& fileName, bool a_Reverse) {
std::ofstream file{fileName};
if (a_Reverse)
reverseDataByte(a_Data);
file.write(reinterpret_cast<const char*>(a_Data.data()), a_Data.size() * sizeof(a_Data.at(0)));
}
void OutputFileIntegers(BinaryData& a_Data, const std::string& fileName, bool a_Reverse) {
std::ofstream file{fileName};
if (a_Reverse)
reverseDataByte(a_Data);
for (std::uint32_t number : a_Data) {
file << number << "\n";
}
}
void OutputFileBinIntegers(BinaryData& a_Data, const std::string& fileName, bool a_Reverse) {
std::ofstream file{fileName};
if (a_Reverse)
reverseDataByte(a_Data);
for (std::uint32_t number : a_Data) {
file << std::bitset<8>(number >> 24) << " " << std::bitset<8>(number >> 16) << " " << std::bitset<8>(number >> 8) << " "
<< std::bitset<8>(number) << "\n";
}
}
void OutputFileLogisim(BinaryData& a_Data, const std::string& fileName, const std::string& a_Header, bool a_Reverse) {
std::ofstream file{fileName};
file << a_Header << "\n";
std::uint64_t cursor = 0;
if (a_Reverse)
reverseDataByte(a_Data);
for (std::uint32_t number : a_Data) {
if (cursor % 8 == 0) {
file << std::setfill('0') << std::setw(4) << std::hex << cursor << std::dec << ": ";
file << std::bitset<8>(number >> 24) << " " << std::bitset<8>(number >> 16) << " " << std::bitset<8>(number >> 8) << " "
<< std::bitset<8>(number) << " ";
} else {
file << std::bitset<8>(number >> 24) << " " << std::bitset<8>(number >> 16) << " " << std::bitset<8>(number >> 8) << " "
<< std::bitset<8>(number) << "\n";
}
cursor += 4;
}
}

13
src/IO.h Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include <vector>
using BinaryData = std::vector<std::uint32_t>;
BinaryData ParseFile(const std::string& fileName);
void OutputFileBinary(BinaryData& a_Data, const std::string& fileName, bool a_Reverse);
void OutputFileIntegers(BinaryData& a_Data, const std::string& fileName, bool a_Reverse);
void OutputFileBinIntegers(BinaryData& a_Data, const std::string& fileName, bool a_Reverse);
void OutputFileLogisim(BinaryData& a_Data, const std::string& fileName, const std::string& a_Header, bool a_Reverse);

View File

@@ -1,49 +1,65 @@
#include <fstream>
#include <argparse/argparse.hpp>
#include <iostream>
#include <vector>
#include "Assembleur.h"
using BinaryData = std::vector<std::uint32_t>;
static BinaryData ParseFile(const std::string& fileName) {
std::ifstream file{fileName};
std::uint32_t lineNumber = 0, realLineNumber = 0;
std::string line;
Assembleur assembleur;
BinaryData output;
while (getline(file, line)) {
lineNumber++;
realLineNumber++;
if (line.find(":") != std::string::npos) {
std::string label = line.substr(0, line.size() - 1);
assembleur.AddLabel(label, lineNumber);
lineNumber--;
} else {
output.push_back(assembleur.ParseInstruction(line, lineNumber, realLineNumber));
}
}
return output;
}
static void OutputFile(const BinaryData& a_Data, const std::string& fileName) {
std::ofstream file {fileName};
file.write(reinterpret_cast<const char*>(a_Data.data()), a_Data.size() * sizeof(a_Data.at(0)));
}
#include "IO.h"
#define ASSEMBLEUR_VERSION "1.5"
int main(int argc, char** argv) {
try {
auto output = ParseFile("test.asm");
argparse::ArgumentParser program("Assembleur", ASSEMBLEUR_VERSION);
std::string inputFileName;
program.add_argument("file")
.help("The assembly file to compile")
.store_into(inputFileName);
std::string outputFileName;
program.add_argument("-o", "--output")
.help("Specify the output file.")
.metavar("file")
.default_value(std::string("a.out"))
.store_into(outputFileName);
std::string formatType;
program.add_argument("-f", "--format")
.help("Type of the output. [logisim|bin|int|binint]")
.metavar("type")
.default_value(std::string("logisim"))
.choices("logisim", "bin", "int", "binint")
.store_into(formatType);
std::string header;
program.add_argument("-h", "--header")
.help("Header of the file")
.metavar("header")
.default_value(std::string("v3.0 hex words addressed"))
.store_into(header);
bool reverse;
program.add_argument("-r", "--reversed").help("inverse bit orders").flag().store_into(reverse);
try {
program.parse_args(argc, argv);
} catch (const std::exception& err) {
std::cerr << err.what() << std::endl;
std::cerr << program;
std::exit(1);
}
try {
auto output = ParseFile(inputFileName);
if (formatType == "logisim") {
OutputFileLogisim(output, outputFileName, header, reverse);
} else if (formatType == "bin") {
OutputFileBinary(output, outputFileName, reverse);
} else if (formatType == "int") {
OutputFileIntegers(output, outputFileName, reverse);
} else {
OutputFileBinIntegers(output, outputFileName, reverse);
}
OutputFile(output, "test.bin");
} catch (std::runtime_error& e) {
std::cerr << e.what() << std::endl;
return 1;

View File

@@ -1,20 +1,21 @@
operations:
add R1 R2 R3
sub R1 R2 #69
and R1 R2 R3
xor R1 R2 R3
or R1 R2 R3
sl R1 R2 R3
sr R1 R2 R3
ADD R1 R2 #1
SUB R1 R2 R3
AND R1 R2 #33
XOR R1 R2 R3
OR R1 R2 R3
SL R1 R2 R3
SR R1 R2 R3
MUL R1 R2 R3
io:
str R1 R2 R3
ld R1 R2 R3
STR R1 R2 R3
LD R1 R2 R3
sauts:
jmp operations
jequ R1 R2 io
jneq R1 R2 sauts
jsup R1 R2 operations
jinf R1 R2 io
JMP controle
JEQU R1 R2 io
JNEQ R1 R2 sauts
JSUP R1 R2 operations
JINF R1 R2 controle
controle:
call io
ret
CALL io
RET

BIN
test.bin

Binary file not shown.

5501515
test.txt

File diff suppressed because it is too large Load Diff

View File

@@ -1,76 +1,15 @@
add_rules("mode.debug", "mode.release")
add_requires("argparse")
set_languages("c++17")
target("Assembleur")
set_kind("binary")
add_files("src/*.cpp")
set_rundir(".")
add_packages("argparse")
--
-- If you want to known more usage about xmake, please see https://xmake.io
--
-- ## FAQ
--
-- You can enter the project directory firstly before building project.
--
-- $ cd projectdir
--
-- 1. How to build project?
--
-- $ xmake
--
-- 2. How to configure project?
--
-- $ xmake f -p [macosx|linux|iphoneos ..] -a [x86_64|i386|arm64 ..] -m [debug|release]
--
-- 3. Where is the build output directory?
--
-- The default output directory is `./build` and you can configure the output directory.
--
-- $ xmake f -o outputdir
-- $ xmake
--
-- 4. How to run and debug target after building project?
--
-- $ xmake run [targetname]
-- $ xmake run -d [targetname]
--
-- 5. How to install target to the system directory or other output directory?
--
-- $ xmake install
-- $ xmake install -o installdir
--
-- 6. Add some frequently-used compilation flags in xmake.lua
--
-- @code
-- -- add debug and release modes
-- add_rules("mode.debug", "mode.release")
--
-- -- add macro definition
-- add_defines("NDEBUG", "_GNU_SOURCE=1")
--
-- -- set warning all as error
-- set_warnings("all", "error")
--
-- -- set language: c99, c++11
-- set_languages("c99", "c++11")
--
-- -- set optimization: none, faster, fastest, smallest
-- set_optimize("fastest")
--
-- -- add include search directories
-- add_includedirs("/usr/include", "/usr/local/include")
--
-- -- add link libraries and search directories
-- add_links("tbox")
-- add_linkdirs("/usr/local/lib", "/usr/lib")
--
-- -- add system link libraries
-- add_syslinks("z", "pthread")
--
-- -- add compilation and link flags
-- add_cxflags("-stdnolib", "-fno-strict-aliasing")
-- add_ldflags("-L/usr/local/lib", "-lpthread", {force = true})
--
-- @endcode
--
if is_os("windows") then
add_ldflags("-static", "-static-libstdc++")
end