Skip to content

Commit 2d8a12f

Browse files
committedNov 11, 2023
WOOOOOOOOOOOOOOOOOOOO
0 parents  commit 2d8a12f

11 files changed

+1533
-0
lines changed
 

‎.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/target
2+
/Cargo.lock

‎.vscode/settings.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"files.associations": {
3+
"stdbool.h": "c"
4+
}
5+
}

‎Cargo.toml

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "tomasulos"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
env_logger = "0.10.1"
10+
log = "0.4.20"

‎a.out

16.1 KB
Binary file not shown.

‎main.c

+220
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
// Tomasulo's Algorithm in C
2+
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <stdint.h>
6+
#include <stdbool.h>
7+
#include <assert.h>
8+
9+
typedef enum Opcode {
10+
FADD, FSUB, FMUL, FDIV, FLD, FST,
11+
ADD, SUB, MUL, DIV, LD, ST,
12+
BEQ, BNE
13+
} Opcode;
14+
15+
typedef enum Stage {
16+
ISSUE, EXECUTE, MEM_ACCESS, WRITE_RESULT, COMMIT
17+
} Stage;
18+
19+
void opcode_print(Opcode opcode) {
20+
switch (opcode) {
21+
case FADD:
22+
printf("fadd");
23+
break;
24+
case FSUB:
25+
printf("fsub");
26+
break;
27+
case FMUL:
28+
printf("fmul");
29+
break;
30+
case FDIV:
31+
printf("fdiv");
32+
break;
33+
case FLD:
34+
printf("fld");
35+
break;
36+
case FST:
37+
printf("fst");
38+
break;
39+
case ADD:
40+
printf("add");
41+
break;
42+
case SUB:
43+
printf("sub");
44+
break;
45+
case MUL:
46+
printf("mul");
47+
break;
48+
case DIV:
49+
printf("div");
50+
break;
51+
case LD:
52+
printf("ld");
53+
break;
54+
case ST:
55+
printf("st");
56+
break;
57+
case BEQ:
58+
printf("beq");
59+
break;
60+
case BNE:
61+
printf("bne");
62+
break;
63+
}
64+
}
65+
66+
typedef struct Operand {
67+
union {
68+
uint8_t reg_num;
69+
uint32_t imm;
70+
struct {
71+
// The register number of the indirect register
72+
uint8_t indirect_reg_num;
73+
// The offset from the indirect register
74+
uint32_t offset;
75+
// The predicted address of the indirect operation (given to the simulator)
76+
uint64_t addr;
77+
};
78+
79+
// The reservation station number that will produce the value
80+
// for this operand
81+
uint64_t reservation_station_entry;
82+
};
83+
84+
enum {
85+
// A floating point register
86+
FREG,
87+
// An integer register
88+
IREG,
89+
// An immediate value
90+
IMM,
91+
// An indirect memory address
92+
INDIRECT,
93+
// A reservation station entry
94+
RESERVATION_STATION_ENTRY,
95+
// An unused operand
96+
UNUSED
97+
} type;
98+
} Operand;
99+
100+
void operand_print(Operand operand) {
101+
switch (operand.type) {
102+
case FREG:
103+
printf("f%d", operand.reg_num);
104+
break;
105+
case IREG:
106+
printf("x%d", operand.reg_num);
107+
break;
108+
case IMM:
109+
printf("%d", operand.imm);
110+
break;
111+
case INDIRECT:
112+
printf("%d(x%d):%ld", operand.offset, operand.indirect_reg_num, operand.addr);
113+
break;
114+
case RESERVATION_STATION_ENTRY:
115+
printf("#%ld", operand.reservation_station_entry);
116+
break;
117+
118+
case UNUSED:
119+
default:
120+
break;
121+
}
122+
}
123+
124+
bool operand_is_used(Operand operand) {
125+
return operand.type != UNUSED;
126+
}
127+
128+
#define F(n) ((Operand){ .type = FREG, .reg_num = n })
129+
#define X(n) ((Operand){ .type = IREG, .reg_num = n })
130+
#define I(n) ((Operand){ .type = IMM, .imm = n })
131+
#define M(r, o, a) ((Operand){ .type = INDIRECT, .indirect_reg_num = r.reg_num, .offset = o, .addr = a })
132+
133+
const Operand UNUSED_OPERAND = { .type = UNUSED };
134+
135+
typedef struct Op {
136+
Opcode opcode;
137+
// The operands of the operation
138+
Operand dst, src[2];
139+
140+
// The stage of the operation
141+
Stage stage;
142+
} Op;
143+
144+
void op_print(Op op) {
145+
opcode_print(op.opcode);
146+
printf(" ");
147+
operand_print(op.dst);
148+
printf(", ");
149+
if (operand_is_used(op.src[0])) {
150+
operand_print(op.src[0]);
151+
printf(", ");
152+
}
153+
if (operand_is_used(op.src[1])) {
154+
operand_print(op.src[1]);
155+
}
156+
}
157+
158+
Op op_new_fld(Operand dst, Operand src) {
159+
Op op;
160+
op.opcode = FLD;
161+
op.dst = dst;
162+
assert(dst.type == FREG);
163+
op.src[0] = src;
164+
assert(src.type == INDIRECT);
165+
op.src[1] = UNUSED_OPERAND;
166+
return op;
167+
}
168+
169+
bool op_only_uses_reservation_station_entries(Op op) {
170+
for (int i = 0; i < 3; i++) {
171+
if (op.dst.type != RESERVATION_STATION_ENTRY) {
172+
return false;
173+
}
174+
if (op.src[i].type != RESERVATION_STATION_ENTRY) {
175+
return false;
176+
}
177+
}
178+
return true;
179+
}
180+
181+
182+
typedef struct ReorderBuffer {
183+
// The number of entries in the reorder buffer
184+
uint64_t size;
185+
// The number of entries in the reorder buffer that are currently in use
186+
uint64_t used;
187+
// The reorder buffer entries
188+
uint64_t *entries;
189+
} ReorderBuffer;
190+
191+
ReorderBuffer reorder_buffer_new(uint64_t size) {
192+
ReorderBuffer reorder_buffer;
193+
reorder_buffer.size = size;
194+
reorder_buffer.used = 0;
195+
reorder_buffer.entries = calloc(size, sizeof(uint64_t));
196+
return reorder_buffer;
197+
}
198+
199+
typedef struct CommonDataBus {
200+
// The reorder buffer entry that is currently on the common data bus
201+
uint64_t reorder_buffer_entry;
202+
// Is the common data bus currently in use?
203+
bool in_use;
204+
} CommonDataBus;
205+
206+
207+
typedef struct ReservationStation {
208+
// The number of entries in the reservation station
209+
uint64_t size;
210+
// The number of entries in the reservation station that are currently in use
211+
uint64_t used;
212+
// The reservation station entries
213+
Op *entries;
214+
} ReservationStation;
215+
216+
int main(int argc, char *argv[]) {
217+
Op op = op_new_fld(F(3), M(X(2), 5, 0x1000));
218+
op_print(op);
219+
printf("\n");
220+
}

‎src/config.rs

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use std::fmt::{self, Display, Formatter};
2+
3+
pub struct Config {
4+
pub eff_addr_buffer_entries: u64,
5+
pub fp_add_buffer_entries: u64,
6+
pub fp_mul_buffer_entries: u64,
7+
pub int_buffer_entries: u64,
8+
pub reorder_buffer_entries: u64,
9+
10+
pub fp_add_buffer_latency: u64,
11+
pub fp_sub_buffer_latency: u64,
12+
pub fp_mul_buffer_latency: u64,
13+
pub fp_div_buffer_latency: u64,
14+
}
15+
16+
17+
impl Display for Config {
18+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
19+
// Configuration
20+
// -------------
21+
// buffers:
22+
// eff addr: 2
23+
// fp adds: 3
24+
// fp muls: 3
25+
// ints: 2
26+
// reorder: 5
27+
28+
// latencies:
29+
// fp add: 2
30+
// fp sub: 2
31+
// fp mul: 5
32+
// fp div: 10
33+
34+
writeln!(f, "Configuration")?;
35+
writeln!(f, "-------------")?;
36+
writeln!(f, "buffers:")?;
37+
writeln!(f, " eff addr: {}", self.eff_addr_buffer_entries)?;
38+
writeln!(f, " fp adds: {}", self.fp_add_buffer_entries)?;
39+
writeln!(f, " fp muls: {}", self.fp_mul_buffer_entries)?;
40+
writeln!(f, " ints: {}", self.int_buffer_entries)?;
41+
writeln!(f, " reorder: {}", self.reorder_buffer_entries)?;
42+
writeln!(f)?;
43+
writeln!(f, "latencies:")?;
44+
writeln!(f, " fp add: {}", self.fp_add_buffer_latency)?;
45+
writeln!(f, " fp sub: {}", self.fp_sub_buffer_latency)?;
46+
writeln!(f, " fp mul: {}", self.fp_mul_buffer_latency)?;
47+
writeln!(f, " fp div: {}", self.fp_div_buffer_latency)?;
48+
writeln!(f)
49+
}
50+
}

‎src/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
mod config;
2+
mod op;
3+
mod pipeline;
4+
mod table;
5+
6+
pub use config::*;
7+
pub use op::*;
8+
pub use pipeline::*;
9+
pub use table::*;

‎src/main.rs

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use tomasulos::*;
2+
use log::*;
3+
4+
const CONFIG: Config = Config {
5+
eff_addr_buffer_entries: 2,
6+
fp_add_buffer_entries: 3,
7+
fp_mul_buffer_entries: 3,
8+
int_buffer_entries: 2,
9+
reorder_buffer_entries: 5,
10+
11+
fp_add_buffer_latency: 2,
12+
fp_sub_buffer_latency: 2,
13+
fp_mul_buffer_latency: 5,
14+
fp_div_buffer_latency: 10,
15+
};
16+
17+
fn main() {
18+
env_logger::init();
19+
20+
let mut reorder_buffer = ReorderBuffer::from(&CONFIG);
21+
// // let mut stations = ReservationStations::new(&CONFIG);
22+
// reorder_buffer.add(RiscVOp::parse("flw f6,32(x2):0")).unwrap();
23+
// info!("{}", reorder_buffer);
24+
// reorder_buffer.tick(&CONFIG);
25+
// reorder_buffer.add(RiscVOp::parse("flw f2,48(x3):4")).unwrap();
26+
// info!("{}", reorder_buffer);
27+
// reorder_buffer.tick(&CONFIG);
28+
// reorder_buffer.add(RiscVOp::parse("fmul f0,f2,f4")).unwrap();
29+
// info!("{}", reorder_buffer);
30+
// reorder_buffer.tick(&CONFIG);
31+
// reorder_buffer.add(RiscVOp::parse("fsub f8,f6,f2")).unwrap();
32+
// info!("{}", reorder_buffer);
33+
// reorder_buffer.tick(&CONFIG);
34+
// reorder_buffer.add(RiscVOp::parse("fdiv f10,f0,f6")).unwrap();
35+
// info!("{}", reorder_buffer);
36+
// reorder_buffer.tick(&CONFIG);
37+
// reorder_buffer.add(RiscVOp::parse("fadd f6,f8,f2")).unwrap();
38+
// info!("{}", reorder_buffer);
39+
// reorder_buffer.tick(&CONFIG);
40+
// info!("{}", reorder_buffer);
41+
// reorder_buffer.tick(&CONFIG);
42+
// info!("{}", reorder_buffer);
43+
// reorder_buffer.tick(&CONFIG);
44+
45+
let instructions = vec![
46+
RiscVOp::parse("flw f6,32(x2):0"),
47+
RiscVOp::parse("flw f2,48(x3):4"),
48+
RiscVOp::parse("fmul f0,f2,f4"),
49+
RiscVOp::parse("fsub f8,f6,f2"),
50+
RiscVOp::parse("fdiv f10,f0,f6"),
51+
RiscVOp::parse("fadd f6,f8,f2"),
52+
RiscVOp::parse("fdiv f13,f10,f6"),
53+
];
54+
55+
let mut table = TomasuloTable::new();
56+
println!("{}", CONFIG);
57+
table.run(instructions, &CONFIG);
58+
println!("{}", table);
59+
60+
// let mut i = 0;
61+
// let mut cycle = 0;
62+
// loop {
63+
// if cycle > 30 {
64+
// break;
65+
// }
66+
// if reorder_buffer.get_finished_instructions() >= instructions.len() {
67+
// break;
68+
// }
69+
// if i < instructions.len() {
70+
// let op = instructions[i].clone();
71+
// if reorder_buffer.add(op).is_ok() {
72+
// i += 1;
73+
// }
74+
// }
75+
// cycle += 1;
76+
// info!("Cycle {}\n\n{}", cycle, reorder_buffer);
77+
// reorder_buffer.tick(&CONFIG);
78+
// }
79+
80+
// flw f2,48(x3):4
81+
// fmul.s f0,f2,f4
82+
// fsub.s f8,f6,f2
83+
// fdiv.s f10,f0,f6
84+
// fadd.s f6,f8,f2
85+
// // reorder_buffer.tick(0, &CONFIG);
86+
// info!("Cycle 1\n\n{}", reorder_buffer);
87+
// reorder_buffer.add(RiscVOp::parse("flw f2,48(x3):4"), 1);
88+
// info!("Cycle 2\n\n{}", reorder_buffer);
89+
// reorder_buffer.add(RiscVOp::parse("fmul f0,f2,f4"), 2);
90+
// info!("Cycle 3\n\n{}", reorder_buffer);
91+
// reorder_buffer.add(RiscVOp::parse("fsub f8,f6,f2"), 3);
92+
// info!("{}", reorder_buffer);
93+
}

‎src/op.rs

+402
Large diffs are not rendered by default.

‎src/pipeline.rs

+548
Large diffs are not rendered by default.

‎src/table.rs

+194
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
use super::*;
2+
use log::*;
3+
use std::fmt::{self, Display, Formatter};
4+
pub struct TomasuloTable {
5+
rows: Vec<Row>
6+
}
7+
8+
impl TomasuloTable {
9+
pub fn new() -> Self {
10+
Self {
11+
rows: vec![],
12+
}
13+
}
14+
15+
pub fn run(&mut self, instructions: Vec<RiscVOp>, config: &Config) {
16+
let mut reorder_buffer = ReorderBuffer::from(config);
17+
18+
let mut i = 0;
19+
let mut cycle = 1;
20+
loop {
21+
if reorder_buffer.get_finished_instructions() >= instructions.len() {
22+
break;
23+
}
24+
if i < instructions.len() {
25+
let op = instructions[i].clone();
26+
if reorder_buffer.add(op).is_ok() {
27+
while self.rows.len() <= i {
28+
self.rows.push(Row {
29+
op: None,
30+
issued: None,
31+
start_ex: None,
32+
end_ex: None,
33+
mem_access: None,
34+
write_back: None,
35+
committed: None,
36+
});
37+
}
38+
self.rows[i].issued = Some(cycle);
39+
i += 1;
40+
}
41+
}
42+
let stages = reorder_buffer.get_stages();
43+
for (instruction_num, op, stage) in stages {
44+
while self.rows.len() <= instruction_num {
45+
self.rows.push(Row {
46+
op: None,
47+
issued: None,
48+
start_ex: None,
49+
end_ex: None,
50+
mem_access: None,
51+
write_back: None,
52+
committed: None,
53+
});
54+
}
55+
56+
self.rows[instruction_num].op = Some(op);
57+
match stage {
58+
Stage::Execute(1) if self.rows[instruction_num].start_ex.is_none() => {
59+
self.rows[instruction_num].start_ex = Some(cycle);
60+
self.rows[instruction_num].end_ex = Some(cycle);
61+
},
62+
Stage::Execute(1) if self.rows[instruction_num].start_ex.is_some() => self.rows[instruction_num].end_ex = Some(cycle),
63+
Stage::Execute(_) if self.rows[instruction_num].start_ex.is_none() => self.rows[instruction_num].start_ex = Some(cycle),
64+
Stage::MemAccess => self.rows[instruction_num].mem_access = Some(cycle),
65+
Stage::WriteBack => self.rows[instruction_num].write_back = Some(cycle),
66+
Stage::Commit => self.rows[instruction_num].committed = Some(cycle),
67+
_ => {}
68+
}
69+
}
70+
cycle += 1;
71+
info!("Cycle {}\n\n{}", cycle, reorder_buffer);
72+
reorder_buffer.tick(config);
73+
74+
75+
let stages = reorder_buffer.get_stages();
76+
77+
for (instruction_num, op, stage) in stages {
78+
while self.rows.len() <= instruction_num {
79+
self.rows.push(Row {
80+
op: None,
81+
issued: None,
82+
start_ex: None,
83+
end_ex: None,
84+
mem_access: None,
85+
write_back: None,
86+
committed: None,
87+
});
88+
}
89+
90+
self.rows[instruction_num].op = Some(op);
91+
match stage {
92+
Stage::Execute(1) if self.rows[instruction_num].start_ex.is_none() => {
93+
self.rows[instruction_num].start_ex = Some(cycle);
94+
self.rows[instruction_num].end_ex = Some(cycle);
95+
},
96+
Stage::Execute(1) if self.rows[instruction_num].start_ex.is_some() => self.rows[instruction_num].end_ex = Some(cycle),
97+
Stage::Execute(_) if self.rows[instruction_num].start_ex.is_none() => self.rows[instruction_num].start_ex = Some(cycle),
98+
Stage::MemAccess => self.rows[instruction_num].mem_access = Some(cycle),
99+
Stage::WriteBack => self.rows[instruction_num].write_back = Some(cycle),
100+
Stage::Commit => self.rows[instruction_num].committed = Some(cycle),
101+
_ => {}
102+
}
103+
}
104+
// self.rows[i].issued = stages[0];
105+
}
106+
}
107+
}
108+
109+
impl Display for TomasuloTable {
110+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
111+
writeln!(f, " Pipeline Simulation\n-----------------------------------------------------------")?;
112+
writeln!(f, " Memory Writes\n Instruction Issues Executes Read Result Commits\n--------------------- ------ -------- ------ ------ -------")?;
113+
for row in &self.rows {
114+
writeln!(f, "{}", row)?;
115+
}
116+
Ok(())
117+
}
118+
}
119+
120+
struct Row {
121+
op: Option<RiscVOp>,
122+
issued: Option<u64>,
123+
start_ex: Option<u64>,
124+
end_ex: Option<u64>,
125+
mem_access: Option<u64>,
126+
write_back: Option<u64>,
127+
committed: Option<u64>,
128+
}
129+
130+
impl Display for Row {
131+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
132+
if let Some(op) = &self.op {
133+
write!(f, "{:22}", format!("{op}"))?;
134+
} else {
135+
write!(f, "{:22}", "?")?;
136+
}
137+
138+
if let Some(issued) = &self.issued {
139+
write!(f, "{:>6}", issued)?;
140+
} else {
141+
write!(f, "{:>6}", "?")?;
142+
}
143+
144+
if let Some(start_ex) = &self.start_ex {
145+
write!(f, "{:>4}", start_ex)?;
146+
} else {
147+
write!(f, "{:>4}", "?")?;
148+
}
149+
150+
write!(f, " -")?;
151+
152+
if let Some(end_ex) = &self.end_ex {
153+
write!(f, "{:>3}", end_ex)?;
154+
} else {
155+
write!(f, "{:>3}", "?")?;
156+
}
157+
158+
if let Some(mem_access) = &self.mem_access {
159+
write!(f, "{:>7}", mem_access)?;
160+
} else {
161+
if let Some(op) = self.op {
162+
if op.accesses_memory() {
163+
write!(f, "{:>7}", "?")?;
164+
} else {
165+
write!(f, "{:>7}", "")?;
166+
}
167+
} else {
168+
write!(f, "{:>7}", "?")?;
169+
}
170+
}
171+
172+
if let Some(write_back) = &self.write_back {
173+
write!(f, "{:>7}", write_back)?;
174+
} else {
175+
if let Some(op) = self.op {
176+
if op.writes_back() {
177+
write!(f, "{:>7}", "?")?;
178+
} else {
179+
write!(f, "{:>7}", "")?;
180+
}
181+
} else {
182+
write!(f, "{:>7}", "?")?;
183+
}
184+
}
185+
186+
if let Some(committed) = &self.committed {
187+
write!(f, "{:>8}", committed)?;
188+
} else {
189+
write!(f, "{:>8}", "?")?;
190+
}
191+
192+
Ok(())
193+
}
194+
}

0 commit comments

Comments
 (0)
Please sign in to comment.