Skip to content

Commit

Permalink
feat: ARM support
Browse files Browse the repository at this point in the history
  • Loading branch information
WillLillis committed Aug 15, 2024
1 parent 218c7f5 commit b2f6932
Show file tree
Hide file tree
Showing 2,157 changed files with 675,903 additions and 102 deletions.
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ z80 = false
x86 = false
x86_64 = true
z80 = false
arm = false
```

### [OPTIONAL] Extend functionality via `compile_commands.json`/`compile_flags.txt`
Expand Down Expand Up @@ -111,7 +112,16 @@ git repository.
suggests the remap `inoremap <silent> ,s <C-r>=CocActionAsync('showSignatureHelp')<CR>`
to trigger signature help in insert mode.

## Acknowledgements
## Acknowledgements / Sources

Current rust package builds on top of the [opcodes python
package](https://github.com/Maratyszcza/Opcodes)
- x86 and x86-64 instruction documentation builds on top of the [opcodes python package](https://github.com/Maratyszcza/Opcodes)

- x86 and x86-64 register documentation sourced from:
- OS Dev's [x86](https://wiki.osdev.org/CPU_Registers_x86) and [x86-64](https://wiki.osdev.org/CPU_Registers_x86-64)
pages
- Various [Wikipedia pages](https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions)
for SIMD specifics

- GAS directives sourced from SourceWare's [pseudo-ops page](https://sourceware.org/binutils/docs-2.41/as/Pseudo-Ops.html)

- ARM instruction documentation builds on top of ARM's official [Exploration tools documentation](https://developer.arm.com/Architectures/A-Profile%20Architecture#Software-Download)
6 changes: 5 additions & 1 deletion asm-lsp_config_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,13 @@
"z80": {
"description": "Flag to turn features related to the z80 instruction set on/off.",
"type": "boolean"
},
"arm": {
"description": "Flag to turn features related to the arm instruction set on/off.",
"type": "boolean"
}
},
"required": [ "x86", "x86_64", "z80" ]
"required": [ "x86", "x86_64", "z80", "arm" ]
}
},
"required": [ "version", "assemblers", "instruction_sets" ]
Expand Down
41 changes: 30 additions & 11 deletions asm_docs_parsing/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

134 changes: 68 additions & 66 deletions asm_docs_parsing/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::path::PathBuf;

use ::asm_lsp::x86_parser::{populate_instructions, populate_registers};
use asm_lsp::populate_directives;
use ::asm_lsp::parser::{populate_instructions, populate_registers};
use asm_lsp::{
parser::populate_arm_instructions, populate_directives, Arch, Directive, Instruction, Register,
};

use anyhow::{anyhow, Result};
use clap::{Parser, Subcommand};
Expand All @@ -16,17 +18,26 @@ enum DocType {

#[derive(Parser, Debug)]
struct SerializeDocs {
#[clap(required = true, help = "Path to the xml docs file")]
#[clap(
required = true,
help = "Path to the xml docs file or directory of docs files"
)]
input_path: PathBuf,
#[arg(long, short, help = "Path to store the output file")]
output_path: Option<PathBuf>,
output_path: PathBuf,
#[arg(
long,
short,
required = true,
help = "Serialize input as set of `instruction`, `register`, or `directive` items"
)]
doc_type: DocType,
#[arg(
long,
short,
help = "Architecture. Must be specified if `input_path` is a directory, ignored otherwise"
)]
arch: Option<Arch>,
}

#[derive(Subcommand)]
Expand All @@ -39,84 +50,75 @@ fn run(opts: &SerializeDocs) -> Result<()> {
match opts.doc_type {
DocType::Instruction => {
let path = opts.input_path.canonicalize()?;
let conts = std::fs::read_to_string(path)?;
let instrs = populate_instructions(&conts)?;
// For now we'll assume all instructions out of a single file share
// a common architecture
let arch = if let Some(instr) = instrs.first() {
if let Some(arch) = instr.arch {
arch
} else {
let instrs: Vec<Instruction>;
match (path.is_dir(), opts.arch) {
(true, Some(arch)) => {
if arch == Arch::ARM {
instrs = populate_arm_instructions(&opts.input_path)?;
} else {
return Err(anyhow!(
"Directory parsing for {arch} instructions is not supported"
));
}
}
(true, None) => {
return Err(anyhow!(
"Failed to determine architecture -- Empty 'arch' field"
"`Arch` argument must be supplied when `input_path` is a directory"
));
}
} else {
return Err(anyhow!(
"Failed to determine architecture -- Zero instructions read in"
));
};
(false, arch_in) => {
if arch_in.is_some() {
println!("WARNING: `Arch` argument is ignored when `input_path` isn't a directory");
}
let conts = std::fs::read_to_string(&path)?;
instrs = populate_instructions(&conts)?;
}
}
if instrs.is_empty() {
return Err(anyhow!("Zero instructions read in"));
}
let serialized = bincode::serialize(&instrs)?;
let output_path: PathBuf = if let Some(ref path) = opts.output_path {
path.to_owned()
} else {
format!("{arch}_instrs").into()
};
std::fs::write(output_path, serialized)?;
std::fs::write(&opts.output_path, serialized)?;
}
DocType::Register => {
let path = opts.input_path.canonicalize()?;
let conts = std::fs::read_to_string(path)?;
let regs = populate_registers(&conts)?;
// For now we'll assume all registers out of a single file share
// a common architecture
let arch = if let Some(instr) = regs.first() {
if let Some(arch) = instr.arch {
arch
} else {
return Err(anyhow!(
"Failed to determine architecture -- Empty 'arch' field"
));
let conts = std::fs::read_to_string(&path)?;
let regs: Vec<Register> = match (path.is_dir(), opts.arch) {
(true, _) => {
return Err(anyhow!("Directory parsing is not supported for registers"));
}
(false, arch_in) => {
if arch_in.is_some() {
println!("WARNING: `Arch` argument is ignored when `input_path` isn't a directory");
}
populate_registers(&conts)?
}
} else {
return Err(anyhow!(
"Failed to determine architecture -- Zero registers read in"
));
};
if regs.is_empty() {
return Err(anyhow!("Zero registers read in"));
}
let serialized = bincode::serialize(&regs)?;
let output_path: PathBuf = if let Some(ref path) = opts.output_path {
path.to_owned()
} else {
format!("{arch}_regs").into()
};
std::fs::write(output_path, serialized)?;
std::fs::write(&opts.output_path, serialized)?;
}
DocType::Directive => {
let path = opts.input_path.canonicalize()?;
let conts = std::fs::read_to_string(path)?;
let directives = populate_directives(&conts)?;
// For now we'll assume all directives out of a single file share
// a common assembler
let assembler = if let Some(instr) = directives.first() {
if let Some(assem) = instr.assembler {
assem
} else {
return Err(anyhow!(
"Failed to determine architecture -- Empty 'assembler' field"
));
let conts = std::fs::read_to_string(&path)?;
let directives: Vec<Directive> = match (path.is_dir(), opts.arch) {
(true, _) => {
return Err(anyhow!("Directory parsing is not supported for directives"));
}
(false, arch_in) => {
if arch_in.is_some() {
println!("WARNING: `Arch` argument is ignored when `input_path` isn't a directory");
}
populate_directives(&conts)?
}
} else {
return Err(anyhow!(
"Failed to determine assembler -- Zero directives read in"
));
};
if directives.is_empty() {
return Err(anyhow!("Zero directives read in"));
}
let serialized = bincode::serialize(&directives)?;
let output_path: PathBuf = if let Some(ref path) = opts.output_path {
path.to_owned()
} else {
format!("{assembler}_directives").into()
};
std::fs::write(output_path, serialized)?;
std::fs::write(&opts.output_path, serialized)?;
}
}
Ok(())
Expand Down
Binary file modified docs_store/directives/serialized/gas
Binary file not shown.
Loading

0 comments on commit b2f6932

Please sign in to comment.