summaryrefslogtreecommitdiff
path: root/rtl/core/mmu/arbiter.sv
blob: 5a75ddfe0a9d8f104e850fd74f046d7b129ebd8d (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
module core_mmu_arbiter
(
	input  logic      clk,
	                  rst_n,

	input  logic      bus_ready,
	input  word       bus_data_rd,
	                  data_data_wr,
	input  ptr        insn_addr,
	                  data_addr,
	input  logic      insn_start,
	                  data_start,
	                  data_write,
	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,
	                  insn_ready,
	                  data_ready,
	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_start, hold_write, hold_issue, hold_free, transition;
	logic[3:0] hold_data_be;

	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;
			end

			DATA: begin
				bus_addr = data_addr;
				bus_write = data_write;
				bus_start = data_start;
				bus_data_be = data_data_be;
			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;
		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;
		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;
					end

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

endmodule