summaryrefslogtreecommitdiff
path: root/rtl/core/mmu/mmu.sv
blob: 5928d007644c28a9b85e2c70956d024401335727 (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
module core_mmu
(
	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,

	output word  bus_data_wr,
	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;

	//TODO
	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

		unique case(next_master)
			INSN: begin
				bus_addr = insn_addr;
				bus_write = 0;
				bus_start = insn_start;
				bus_data_wr = {32{1'bx}};
			end

			DATA: begin
				bus_addr = data_addr;
				bus_write = data_write;
				bus_start = data_start;
				bus_data_wr = data_data_wr;
			end
		endcase

		if(hold_issue) begin
			bus_addr = hold_addr;
			bus_write = hold_write;
			bus_start = 1;
			bus_data_wr = hold_data_wr;
		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;
		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;
					end

					DATA: begin
						hold_addr <= insn_addr;
						hold_start <= insn_start;
						hold_write <= 0;
					end
				endcase
		end

endmodule