Skip to content

Commit 1557a05

Browse files
committed
fix #15: add annotated output format
1 parent eaf702f commit 1557a05

File tree

15 files changed

+793
-489
lines changed

15 files changed

+793
-489
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "customasm"
3-
version = "0.10.0"
3+
version = "0.10.1"
44
edition = "2018"
55
authors = ["Henrique Lorenzi <[email protected]>"]
66

README.md

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ Usage: customasm [options] <asm-file-1> ... <asm-file-N>
2727
2828
Options:
2929
-f, --format FORMAT The format of the output file. Possible formats:
30-
binary, binstr, hexstr, bindump, hexdump,
31-
mif, intelhex, deccomma, hexcomma, decc, hexc,
32-
logisim8, logisim16
30+
binary, annotated, annotatedbin, binstr, hexstr,
31+
bindump, hexdump, mif, intelhex, deccomma, hexcomma,
32+
decc, hexc, logisim8, logisim16
3333
3434
-o, --output FILE The name of the output file.
3535
-p, --print Print output to stdout instead of writing to a file.
@@ -73,12 +73,16 @@ multiply3x4:
7373

7474
...the assembler would use the `#cpudef` rules to convert the instructions into binary code:
7575

76-
```
77-
0x0100: 11 00 ; load r1, 0
78-
0x0102: 12 03 ; load r2, 3
79-
0x0104: 13 04 ; load r3, 4
80-
0x0106: 21 ; add r1, r2
81-
0x0107: 33 01 ; sub r3, 1
82-
0x0109: 40 01 06 ; jnz .loop
83-
0x010c: 50 ; ret
76+
```asm
77+
outp | addr | data
78+
79+
100:0 | 100 | ; multiply3x4:
80+
100:0 | 100 | 11 00 ; load r1, 0
81+
102:0 | 102 | 12 03 ; load r2, 3
82+
104:0 | 104 | 13 04 ; load r3, 4
83+
106:0 | 106 | ; .loop:
84+
106:0 | 106 | 21 ; add r1, r2
85+
107:0 | 107 | 33 01 ; sub r3, 1
86+
109:0 | 109 | 40 01 06 ; jnz .loop
87+
10c:0 | 10c | 50 ; ret
8488
```

examples/nes/ines_nrom.asm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#bankdef "header" { #addr 0x0, #size 0x10, #outp 0x0 }
22
#bankdef "prg" { #addr 0x8000, #size 0x7ffa, #outp 0x10 }
3-
#bankdef "vectors" { #addr 0x7ffa, #size 0x6, #outp 0x800a }
3+
#bankdef "vectors" { #addr 0xfffa, #size 0x6, #outp 0x800a }
44
#bankdef "zeropage" { #addr 0x0, #size 0x100 }
55
#bankdef "ram" { #addr 0x200, #size 0x600 }
66

src/asm/assembler.rs

Lines changed: 102 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use crate::diagn::{Span, RcReport};
22
use crate::expr::{Expression, ExpressionValue, ExpressionEvalContext};
3-
use crate::asm::{AssemblerParser, BinaryOutput, LabelManager, LabelContext};
3+
use crate::asm::{AssemblerParser, LabelManager, LabelContext};
44
use crate::asm::BankDef;
5+
use crate::asm::Bank;
56
use crate::asm::BinaryBlock;
67
use crate::asm::cpudef::CpuDef;
78
use crate::util::FileServer;
@@ -16,7 +17,7 @@ pub struct AssemblerState
1617
pub parsed_exprs: Vec<ParsedExpression>,
1718

1819
pub bankdefs: Vec<BankDef>,
19-
pub blocks: Vec<BinaryBlock>,
20+
pub blocks: Vec<Bank>,
2021
pub cur_bank: usize,
2122
pub cur_block: usize
2223
}
@@ -48,6 +49,16 @@ pub struct ParsedExpression
4849
}
4950

5051

52+
#[derive(Debug, Clone, PartialEq)]
53+
pub struct BitRangeSpan
54+
{
55+
pub start: usize,
56+
pub end: usize,
57+
pub addr: usize,
58+
pub span: Span
59+
}
60+
61+
5162
impl AssemblerState
5263
{
5364
pub fn new() -> AssemblerState
@@ -66,7 +77,7 @@ impl AssemblerState
6677
};
6778

6879
state.bankdefs.push(BankDef::new("", 0, 0, Some(0), false, None));
69-
state.blocks.push(BinaryBlock::new(""));
80+
state.blocks.push(Bank::new(""));
7081
state
7182
}
7283

@@ -90,6 +101,9 @@ impl AssemblerState
90101
self.resolve_exprs(report.clone())?;
91102
self.check_bank_overlap(report.clone());
92103

104+
//for block in &self.blocks
105+
// { println!("{:#?}", block.bits.spans); }
106+
93107
match report.has_errors()
94108
{
95109
true => Err(()),
@@ -98,9 +112,9 @@ impl AssemblerState
98112
}
99113

100114

101-
pub fn get_binary_output(&self) -> BinaryOutput
115+
pub fn get_binary_output(&self) -> BinaryBlock
102116
{
103-
let mut output = BinaryOutput::new();
117+
let mut output = BinaryBlock::new();
104118

105119
for block in &self.blocks
106120
{
@@ -114,13 +128,32 @@ impl AssemblerState
114128

115129
if let Some(output_index) = bankdef.outp
116130
{
117-
for i in 0..block.len()
118-
{ output.write(output_index * bits + i, block.read(i)); }
131+
let mut sorted_spans = block.bits.spans.clone();
132+
sorted_spans.sort_by(|a, b| a.start.cmp(&b.start));
133+
134+
let mut sorted_span_index = 0;
135+
136+
for i in 0..block.bits.len()
137+
{
138+
let bitrange_index = sorted_spans[sorted_span_index..].iter().position(|s| i >= s.start && i < s.end);
139+
let bitrange = bitrange_index.map(|i| &sorted_spans[sorted_span_index + i]);
140+
141+
if let Some(bitrange_index) = bitrange_index
142+
{ sorted_span_index += bitrange_index; }
143+
144+
if let Some(bitrange) = bitrange
145+
{ output.write(output_index * bits + i, block.bits.read(i), Some((bitrange.addr, &bitrange.span))); }
146+
else
147+
{ output.write(output_index * bits + i, block.bits.read(i), None); }
148+
}
149+
150+
for bitrange in block.bits.spans.iter().filter(|s| s.start == s.end)
151+
{ output.mark_label(output_index * bits + bitrange.start, bitrange.addr, &bitrange.span); }
119152

120153
if bankdef.fill
121154
{
122-
for i in block.len()..(bankdef.size * bits)
123-
{ output.write(output_index * bits + i, false); }
155+
for i in block.bits.len()..(bankdef.size * bits)
156+
{ output.write(output_index * bits + i, false, None); }
124157
}
125158
}
126159
}
@@ -148,7 +181,7 @@ impl AssemblerState
148181
ExpressionContext
149182
{
150183
block: self.cur_block,
151-
offset: block.len(),
184+
offset: block.bits.len(),
152185
label_ctx: self.labels.get_cur_context()
153186
}
154187
}
@@ -195,7 +228,7 @@ impl AssemblerState
195228
let bits = self.cpudef.as_ref().unwrap().bits;
196229
let block = &self.blocks[self.cur_block];
197230

198-
let excess_bits = block.len() % bits;
231+
let excess_bits = block.bits.len() % bits;
199232
if excess_bits != 0
200233
{
201234
let bits_short = bits - excess_bits;
@@ -206,7 +239,7 @@ impl AssemblerState
206239
let bankdef_index = self.find_bankdef(&block.bank_name).unwrap();
207240
let bankdef = &self.bankdefs[bankdef_index];
208241

209-
let block_offset = block.len() / bits;
242+
let block_offset = block.bits.len() / bits;
210243
let addr = match block_offset.checked_add(bankdef.addr)
211244
{
212245
Some(addr) => addr,
@@ -220,6 +253,28 @@ impl AssemblerState
220253
}
221254

222255

256+
fn get_bitrange_address(&self, report: RcReport, span: &Span) -> Result<usize, ()>
257+
{
258+
if self.cpudef.is_none()
259+
{ return Ok(0); }
260+
261+
let bits = self.cpudef.as_ref().unwrap().bits;
262+
let block = &self.blocks[self.cur_block];
263+
264+
let bankdef_index = self.find_bankdef(&block.bank_name).unwrap();
265+
let bankdef = &self.bankdefs[bankdef_index];
266+
267+
let block_offset = block.bits.len() / bits;
268+
let addr = match block_offset.checked_add(bankdef.addr)
269+
{
270+
Some(addr) => addr,
271+
None => return Err(report.error_span("address overflowed valid range", span))
272+
};
273+
274+
Ok(addr)
275+
}
276+
277+
223278
pub fn check_valid_address(&self, report: RcReport, block_index: usize, addr: usize, span: &Span) -> Result<(), ()>
224279
{
225280
let block = &self.blocks[block_index];
@@ -236,52 +291,69 @@ impl AssemblerState
236291
}
237292

238293

239-
pub fn output_bits_until_aligned(&mut self, report: RcReport, multiple_of: usize, span: &Span) -> Result<(), ()>
294+
pub fn output_bits_until_aligned(&mut self, report: RcReport, multiple_of: usize, report_span: &Span, output_span: Option<&Span>) -> Result<(), ()>
240295
{
241296
if multiple_of == 0
242-
{ return Err(report.error_span("invalid alignment", span)); }
297+
{ return Err(report.error_span("invalid alignment", report_span)); }
243298

244-
self.check_cpudef_active(report.clone(), span)?;
299+
self.check_cpudef_active(report.clone(), report_span)?;
245300

246301
let bits = self.cpudef.as_ref().unwrap().bits;
247302

248-
while self.blocks[self.cur_block].len() % (bits * multiple_of) != 0
249-
{ self.output_bit(report.clone(), false, true, span)?; }
303+
while self.blocks[self.cur_block].bits.len() % (bits * multiple_of) != 0
304+
{ self.output_bit(report.clone(), false, true, report_span, output_span)?; }
250305

251306
Ok(())
252307
}
253308

254309

255-
pub fn output_bit(&mut self, report: RcReport, bit: bool, skipping: bool, span: &Span) -> Result<(), ()>
310+
pub fn output_bit(&mut self, report: RcReport, bit: bool, skipping: bool, report_span: &Span, output_span: Option<&Span>) -> Result<(), ()>
256311
{
257312
{
258313
let block = &self.blocks[self.cur_block];
259314
let bankdef = &self.bankdefs[self.cur_bank];
260315

261316
if bankdef.outp.is_none() && !skipping
262-
{ return Err(report.error_span("attempt to place data in non-writable bank", span)); }
317+
{ return Err(report.error_span("attempt to place data in non-writable bank", report_span)); }
263318

264319
if self.cur_bank != 0
265320
{
266-
self.check_cpudef_active(report.clone(), span)?;
321+
self.check_cpudef_active(report.clone(), report_span)?;
267322

268-
if block.len() / self.cpudef.as_ref().unwrap().bits >= bankdef.size
269-
{ return Err(report.error_span("data overflowed bank size", span)); }
323+
if block.bits.len() / self.cpudef.as_ref().unwrap().bits >= bankdef.size
324+
{ return Err(report.error_span("data overflowed bank size", report_span)); }
270325
}
271326
}
272327

273-
self.blocks[self.cur_block].append(bit);
328+
let bitrange = match output_span
329+
{
330+
Some(output_span) =>
331+
{
332+
let addr = self.get_bitrange_address(report, output_span)?;
333+
Some((addr, output_span))
334+
}
335+
None => None
336+
};
337+
338+
self.blocks[self.cur_block].bits.append(bit, bitrange);
274339
Ok(())
275340
}
276341

277342

278-
pub fn output_zero_bits(&mut self, report: RcReport, num: usize, skipping: bool, span: &Span) -> Result<(), ()>
343+
pub fn output_zero_bits(&mut self, report: RcReport, num: usize, skipping: bool, report_span: &Span, output_span: Option<&Span>) -> Result<(), ()>
279344
{
280345
for _ in 0..num
281-
{ self.output_bit(report.clone(), false, skipping, span)?; }
346+
{ self.output_bit(report.clone(), false, skipping, report_span, output_span)?; }
282347

283348
Ok(())
284349
}
350+
351+
352+
pub fn mark_label(&mut self, addr: usize, output_span: &Span)
353+
{
354+
let index = self.blocks[self.cur_block].bits.len();
355+
self.blocks[self.cur_block].bits.mark_label(index, addr, output_span);
356+
}
285357

286358

287359
pub fn resolve_instrs(&mut self, report: RcReport) -> Result<(), ()>
@@ -342,12 +414,14 @@ impl AssemblerState
342414

343415
let value = self.expr_eval(report.clone(), &instr.ctx, &rule.production, &mut args_eval_ctx)?;
344416

417+
let addr = self.get_bitrange_address(report, &instr.span)?;
418+
345419
let block = &mut self.blocks[instr.ctx.block];
346420

347421
for i in 0..(left - right + 1)
348422
{
349423
let bit = value.get_bit(left - right - i);
350-
block.write(instr.ctx.offset + i, bit);
424+
block.bits.write(instr.ctx.offset + i, bit, Some((addr, &instr.span)));
351425
}
352426

353427
Ok(())
@@ -374,7 +448,7 @@ impl AssemblerState
374448
for i in 0..expr.width
375449
{
376450
let bit = value.get_bit(expr.width - i - 1);
377-
block.write(expr.ctx.offset + i, bit);
451+
block.bits.write(expr.ctx.offset + i, bit, None);
378452
}
379453

380454
Ok(())
@@ -455,7 +529,7 @@ impl ExpressionContext
455529
let bits = state.cpudef.as_ref().unwrap().bits;
456530
let block = &state.blocks[self.block];
457531

458-
if block.len() % bits != 0
532+
if block.bits.len() % bits != 0
459533
{ return Err({ report.error_span("address is not aligned to a byte", span); true }); }
460534

461535
let bankdef = state.find_bankdef(&block.bank_name).unwrap();

src/asm/bank.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use crate::asm::BinaryBlock;
2+
3+
4+
pub struct Bank
5+
{
6+
pub bank_name: String,
7+
pub bits: BinaryBlock
8+
}
9+
10+
11+
impl Bank
12+
{
13+
pub fn new<S>(bank_name: S) -> Bank
14+
where S: Into<String>
15+
{
16+
Bank
17+
{
18+
bank_name: bank_name.into(),
19+
bits: BinaryBlock::new()
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)