Skip to content

Commit

Permalink
Local branch, .dsb, .dsw implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
erhanbaris committed Aug 20, 2024
1 parent 1283b75 commit 79566ff
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 138 deletions.
84 changes: 66 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,27 @@

Yet another 6502 Asm compiler project. The goal is make a multi platform (include web) compiler generator. Project is still in very early stage and there is no easy way to use it. You can check the code or wait to get more usable version.

Example code what compiler can compile now.
```assembly
.ORG $0600 ; change location
## Building
timu6502 builded with latest Rust Language. You have to install Rust Language. After installetion execute ```cargo build --release``` command. The executable will be located under _target/release/_ folder.
Compiler tested under Windows and MacOS operating system. It should work under Linux OS but not yet tested.


## Usage
timu6502 is terminal based compiler. So, basic usage is:
```bash
timu6502asm test.asm --target test.bin
timu6502asm test.asm --binary-dump
timu6502asm test.asm --token-dump
timu6502asm test.asm --token-dump --slient
timu6502asm --help
```
If the compilation operation failed, process exit code will be **1** and print error descriptions if silent mode is off.

## Branches
Basically, branches is referencing the location at the execution code. If you want to jump location, it is hard to calculate and remember the address, but, with branches you just need to remember branch name and the compiler will be assign address automatically.

Example:
```assembly
JSR init
JSR loop
JSR end
Expand All @@ -26,28 +43,59 @@ loop:
end:
BRK
```
As you can see in the example there are **init**, **loop** and **end** branches defined and used with the instruction code.

Also, compiler has a support for local branches.
```assembly
branch1:
@local1:
INX
@local2:
INY
jump @local1
Expected output:
branch2:
@local1:
DEX
@local2:
DEY
jump @local1
```
0600: 20 09 06 20 0c 06 20 12 06 a2 00 60 e8 e0 05 d0
0610: fb 60 00

As you can see in the example there are **init**, **loop** and **end** branches defined and used with the instruction code.

Also, compiler has a support for local branches.
```assembly
branch1:
@local1:
INX
@local2:
INY
jump @local1
branch2:
@local1:
DEX
@local2:
DEY
jump @local1
```

## Building
timu6502 builded with latest Rust Language. You have to install Rust Language. After installetion execute ```cargo build --release``` command. The executable will be located under _target/release/_ folder.
Compiler tested under Windows and MacOS operating system. It should work under Linux OS but not yet tested.
## Variable
You can define static variable and use it with instruction.

Example:
```assembly
var1 = $10
var2 = 22
var3 = %11001100
## Usage
timu6502 is terminal based compiler. So, basic usage is:
```bash
timu6502asm test.asm --target test.bin
timu6502asm test.asm --binary-dump
timu6502asm test.asm --token-dump
timu6502asm test.asm --token-dump --slient
timu6502asm --help
CPX #var1
```
If the compilation operation failed, process exit code will be **1** and print error descriptions if silent mode is off.

## Data types
Compiler works with primative data types.
Expand Down
42 changes: 16 additions & 26 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use log::{info, warn}; // Use log crate when building application
use std::{println as info, println as warn}; // Workaround to use prinltn! for logs.
use thiserror::Error;

use crate::{context::Context, directive::{DirectiveEnum, DirectiveType, DirectiveValue, SYSTEM_DIRECTIVES}, opcode::{ModeType, BRANCH_INSTS, INSTS_SIZE, JUMP_INSTS}, parser::{Parser, Token, TokenType}, tool::print_error};
use crate::{context::Context, directive::{DirectiveEnum, DirectiveType, DirectiveValue, SYSTEM_DIRECTIVES}, opcode::{BRANCH_INSTS, INSTS_SIZE}, parser::{Parser, Token, TokenType}, tool::print_error};

#[derive(Debug, PartialEq)]
pub enum InstrValue {
Expand Down Expand Up @@ -41,8 +41,6 @@ pub enum BranchType {
#[derive(Debug)]
pub enum Ast {
InstrImplied(usize),
InstrBranch(usize, String),
InstrJump(usize, String),
Instr(usize, InstrInfo),
Branch(String, BranchType),
Directive(DirectiveEnum, Vec<DirectiveValue>)
Expand Down Expand Up @@ -74,6 +72,9 @@ pub enum AstGeneratorError {

#[error("IO Error ({0})")]
IOError(#[from] std::io::Error),

#[error("'{0}' reference already defined)")]
ReferenceAlreadyDefined(String)
}

impl AstGeneratorError {
Expand Down Expand Up @@ -319,7 +320,11 @@ impl AstGenerator {
self.cleanup_space(context)?;

let values = self.parse_list(context, |_| true)?;
context.references.borrow_mut().insert(name.to_owned(), values);
let has_reference = context.references.borrow_mut().insert(name.to_owned(), values).is_some();

if has_reference {
return Err(AstGeneratorError::ReferenceAlreadyDefined(name.to_owned()));
}
Ok(())
}

Expand Down Expand Up @@ -373,6 +378,7 @@ impl AstGenerator {
inst_info.value = InstrValue::Reference(keyword.to_owned());
}
},
Token::LocalKeyword(keyword) => inst_info.value = InstrValue::LocalReference(keyword.to_owned()),
Token::Byte(byte) => inst_info.value = InstrValue::Byte(*byte),
Token::Word(word) => inst_info.value = InstrValue::Word(*word),
_ => return Err(AstGeneratorError::syntax_issue(context, token_index, "Invalid numbering number format".to_string()))
Expand Down Expand Up @@ -445,30 +451,14 @@ impl AstGenerator {
else if BRANCH_INSTS.contains(&positon) {
// Branch inst
self.eat_space(context)?;
let text = self.eat_text(context)?;
context.add_ast(token_index, Ast::InstrBranch(positon, text));
}

else if JUMP_INSTS.contains(&positon) {
// Jump inst
self.eat_space(context)?;
let index = self.index.get();

if let Ok(value) = self.parse_instr_value(context) {
context.add_ast(token_index, Ast::Instr(positon, value));
return Ok(())
}

self.index.set(index); // Restore index
let value = self.parse_instr_value(context)?;

let token_index= self.eat()?;
let token = &context.tokens.borrow()[token_index];
if let Token::Keyword(name) = &token.token {
context.add_ast(token_index, Ast::InstrJump(positon, name.clone()));
return Ok(())
match value.value {
InstrValue::Byte(_) => context.add_ast(token_index, Ast::Instr(positon, value)),
InstrValue::Reference(_) => context.add_ast(token_index, Ast::Instr(positon, value)),
InstrValue::LocalReference(_) => context.add_ast(token_index, Ast::Instr(positon, value)),
_ => return Err(AstGeneratorError::syntax_issue(context, token_index, "Relative number or branch name expected".to_string()))
}

return Err(AstGeneratorError::syntax_issue(context, token_index, "Branch name, absolute address or indirect address expected".to_string()))
}

else {
Expand Down
Loading

0 comments on commit 79566ff

Please sign in to comment.