summaryrefslogtreecommitdiff
path: root/rtl/core/mmu/arbiter.sv
blob: b0da7c88b1490392d0a1818d7f1d5dd69f71df35 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
module core_mmu_arbiter
(
	input  logic      clk,
	                  rst_n,

	input  logic      bus_ready,
	                  bus_ex_fail,
	input  word       bus_data_rd,
	                  data_data_wr,
	input  ptr        insn_addr,
	                  data_addr,
	input  logic      insn_start,
	                  data_start,
	                  data_write,
	                  data_ex_lock,
	input  logic[3:0] data_data_be,

	output word       bus_data_wr,
	output logic[3:0] bus_data_be,
	output ptr        bus_addr,
	output logic      bus_start,
	                  bus_write,
	                  bus_ex_lock,
	                  insn_ready,
	                  data_ready,
	                  data_ex_fail,
	output word       insn_data_rd,
	                  data_data_rd
);

	enum int unsigned
	{
		INSN,
		DATA
	} master, next_master;

	ptr hold_addr;
	word hold_data_wr;
	logic active, hold_ex_lock, hold_start, hold_write, hold_issue, hold_free, transition;
	logic[3:0] hold_data_be;

	assign data_ex_fail = bus_ex_fail;
	assign insn_data_rd = bus_data_rd;
	assign data_data_rd = bus_data_rd;

	always_comb begin
		next_master = master;
		if(bus_ready || !active)
			unique case(master)
				DATA: next_master = data_start ? DATA : INSN;
				INSN: next_master = !data_start && !hold_start ? INSN : DATA;
			endcase

		// Causa UNOPTFLAT en Verilator con assign
		transition = master != next_master;
		hold_issue = transition && hold_start;
		hold_free = transition || !hold_start;

		insn_ready = 0;
		data_ready = 0;

		unique case(master)
			INSN: insn_ready = bus_ready;
			DATA: data_ready = bus_ready;
		endcase

		bus_data_wr = data_data_wr;
		unique case(next_master)
			INSN: begin
				bus_addr = insn_addr;
				bus_write = 0;
				bus_start = insn_start;
				bus_data_be = 4'b1111;
				bus_ex_lock = 0;
			end

			DATA: begin
				bus_addr = data_addr;
				bus_write = data_write;
				bus_start = data_start;
				bus_data_be = data_data_be;
				bus_ex_lock = data_ex_lock;
			end
		endcase

		if(hold_issue) begin
			bus_addr = hold_addr;
			bus_write = hold_write;
			bus_start = 1;
			bus_data_wr = hold_data_wr;
			bus_data_be = hold_data_be;
			bus_ex_lock = hold_ex_lock;
		end
	end

	always_ff @(posedge clk or negedge rst_n)
		if(!rst_n) begin
			master <= INSN;
			active <= 0;

			hold_addr <= 30'b0;
			hold_start <= 0;
			hold_write <= 0;
			hold_data_wr <= 0;
			hold_data_be <= 0;
			hold_ex_lock <= 0;
		end else begin
			master <= next_master;
			active <= bus_start || (active && !bus_ready);

			if(hold_free)
				unique case(next_master)
					INSN: begin
						hold_addr <= data_addr;
						hold_start <= data_start;
						hold_write <= data_write;
						hold_data_wr <= data_data_wr;
						hold_data_be <= data_data_be;
						hold_ex_lock <= data_ex_lock;
					end

					DATA: begin
						hold_addr <= insn_addr;
						hold_start <= insn_start;
						hold_write <= 0;
						hold_data_be <= 4'b1111;
						hold_ex_lock <= 0;
					end
				endcase
		end

endmodule