Skip to content
This repository
Browse code

MMU DTLB page fault handling working on FPGA

  • Loading branch information...
commit 790d6542035bad60a5468c3cec5b69e7c4c7175e 1 parent 23f3785
Yann Sionneau authored June 03, 2012
2  cores/lm32/rtl/lm32_cpu.v
@@ -2143,7 +2143,7 @@ begin
2143 2143
     `LM32_CSR_JRX:  csr_read_data_x = jrx_csr_read_data;
2144 2144
 `endif
2145 2145
     `LM32_CSR_CFG2: csr_read_data_x = cfg2;
2146  
-    `LM32_CSR_TLB_DBG: csr_read_data_x = load_store_csr_read_data_x;
  2146
+    `LM32_CSR_TLB_VADDRESS: csr_read_data_x = load_store_csr_read_data_x;
2147 2147
       
2148 2148
     default:        csr_read_data_x = {`LM32_WORD_WIDTH{1'bx}};
2149 2149
     endcase
73  cores/lm32/rtl/lm32_dcache.v
@@ -110,6 +110,7 @@ module lm32_dcache (
110 110
     csr_write_enable,
111 111
     exception_x,
112 112
     eret_q_x,
  113
+    exception_m,
113 114
     // ----- Outputs -----
114 115
     stall_request,
115 116
     restart_request,
@@ -118,7 +119,7 @@ module lm32_dcache (
118 119
     refilling,
119 120
     load_data,
120 121
    // To pipeline
121  
-    dtlb_miss_q,
  122
+    dtlb_miss_int,
122 123
     kernel_mode,
123 124
     pa,
124 125
     csr_read_data
@@ -138,7 +139,6 @@ parameter dtlb_sets = 1024;				// Number of lines of DTLB
138 139
 parameter page_size = 4096;				// System page size
139 140
 
140 141
 `define LM32_DTLB_IDX_RNG		addr_dtlb_index_msb:addr_dtlb_index_lsb
141  
-//`define LM32_DTLB_INVALID_TAG		{ {9{1'b1}}, `FALSE}
142 142
 `define LM32_DTLB_ADDRESS_PFN_RNG	addr_pfn_msb:addr_pfn_lsb
143 143
 `define LM32_PAGE_OFFSET_RNG		addr_page_offset_msb:addr_page_offset_lsb
144 144
 `define LM32_DTLB_INVALID_ADDRESS	{ vpfn_width{1'b1} }
@@ -206,6 +206,7 @@ input [`LM32_CSR_RNG] csr;				// CSR read/write index
206 206
 input [`LM32_WORD_RNG] csr_write_data;			// Data to write to specified CSR
207 207
 input csr_write_enable;					// CSR write enable
208 208
 input exception_x;					// An exception occured in the X stage
  209
+input exception_m;
209 210
 input eret_q_x;
210 211
 
211 212
 /////////////////////////////////////////////////////
@@ -231,9 +232,7 @@ wire   [`LM32_WORD_RNG] load_data;
231 232
 output kernel_mode;
232 233
 wire kernel_mode;
233 234
 
234  
-output dtlb_miss_q;
235  
-//output dtlb_miss;
236  
-//output dtlb_miss_int;
  235
+output dtlb_miss_int;
237 236
 
238 237
 /////////////////////////////////////////////////////
239 238
 // Internal nets and registers 
@@ -294,8 +293,8 @@ reg [addr_dtlb_index_width-1:0] dtlb_update_set;
294 293
 reg dtlb_flushing;
295 294
 reg [addr_dtlb_index_width-1:0] dtlb_flush_set;
296 295
 wire dtlb_miss;
297  
-reg dtlb_miss_q = 0;
298  
-reg dtlb_miss_int = 0;
  296
+reg dtlb_miss_q = `FALSE;
  297
+wire dtlb_miss_int;
299 298
 reg [`LM32_WORD_RNG] dtlb_miss_addr;
300 299
 wire dtlb_data_valid;
301 300
 wire [`LM32_DTLB_LOOKUP_RANGE] dtlb_lookup;
@@ -465,8 +464,6 @@ end
465 464
 generate
466 465
     for (i = 0; i < associativity; i = i + 1)
467 466
     begin : match
468  
-// FIXME : We need to put physical address coming out from MMU instead of address_m[]
469  
-//assign way_match[i] = ({way_tag[i], way_valid[i]} == {address_m[`LM32_DC_ADDR_TAG_RNG], `TRUE});
470 467
 
471 468
 assign dtlb_read_tag = dtlb_read_data[`LM32_DTLB_TAG_RANGE];
472 469
 assign dtlb_data_valid = dtlb_read_data[`LM32_DTLB_VALID_BIT];
@@ -474,18 +471,7 @@ assign dtlb_lookup = dtlb_read_data[`LM32_DTLB_LOOKUP_RANGE];
474 471
 
475 472
 assign way_match[i] = (kernel_mode_reg == `LM32_KERNEL_MODE) ?
476 473
 		      ({way_tag[i], way_valid[i]} == {address_m[`LM32_DC_ADDR_TAG_RNG], `TRUE})
477  
-		      : /*dtlb_data_valid && (dtlb_read_tag == address_m[`LM32_DC_ADDR_TAG_RNG]) && 
478  
-		     */ ({way_tag[i], way_valid[i]} == {dtlb_lookup, `TRUE});
479  
-
480  
-/*always @(*)
481  
-begin
482  
-	if (kernel_mode_reg == `LM32_KERNEL_MODE)
483  
-		way_match[i] <= ({way_tag[i], way_valid[i]} == {address_m[`LM32_DC_ADDR_TAG_RNG], `TRUE});
484  
-	else if (dtlb_read_tag == `LM32_DTLB_TAG_INVALID) // DTLB tag is invalid
485  
-		way_match[i] <= `FALSE;
486  
-	else
487  
-		way_match[i] <= ({way_tag[i], way_valid[i]} == {dtlb_read_data, `TRUE});
488  
-end*/
  474
+		      : ({way_tag[i], way_valid[i]} == {dtlb_lookup, `TRUE});
489 475
     end
490 476
 endgenerate
491 477
 
@@ -555,13 +541,7 @@ assign dtlb_data_read_address = address_x[`LM32_DTLB_IDX_RNG];
555 541
 assign dtlb_tag_read_address = address_x[`LM32_DTLB_IDX_RNG];
556 542
 
557 543
 // tlb_update_address will receive data from a CSR register
558  
-assign dtlb_data_write_address = /*(dtlb_flushing == `TRUE) 
559  
-				 ? dtlb_flush_set
560  
-				 : */dtlb_update_vaddr_csr_reg[`LM32_DTLB_IDX_RNG];
561  
-
562  
-assign dtlb_tag_write_address = (dtlb_flushing == `TRUE)
563  
-				? dtlb_flush_set
564  
-				: dtlb_update_vaddr_csr_reg[`LM32_DTLB_IDX_RNG];
  544
+assign dtlb_data_write_address = dtlb_update_vaddr_csr_reg[`LM32_DTLB_IDX_RNG];
565 545
 
566 546
 assign dtlb_data_read_port_enable = (stall_x == `FALSE) || !stall_m;
567 547
 assign dtlb_write_port_enable = dtlb_updating || dtlb_flushing;
@@ -610,7 +590,7 @@ assign tmem_write_data[`LM32_DC_TAGS_VALID_RNG] = ((last_refill == `TRUE) || (va
610 590
 assign tmem_write_data[`LM32_DC_TAGS_TAG_RNG] = refill_address[`LM32_DC_ADDR_TAG_RNG];
611 591
 
612 592
 // Signals that indicate which state we are in
613  
-assign flushing = state[0]; //|| dtlb_miss;
  593
+assign flushing = state[0];
614 594
 assign check = state[1];
615 595
 assign refill = state[2];
616 596
 
@@ -683,8 +663,6 @@ begin
683 663
             end
684 664
             else if (dflush == `TRUE)
685 665
                 state <= `LM32_DC_STATE_FLUSH;
686  
-//           else if (dtlb_miss == `TRUE)
687  
-//		refill_address <= physical_address;
688 666
         end
689 667
 
690 668
         // Refill a cache line
@@ -718,35 +696,24 @@ begin
718 696
 	end
719 697
 end
720 698
 
721  
-assign csr_read_data = latest_store_tlb_lookup;
  699
+assign csr_read_data = dtlb_miss_addr;
722 700
 
723 701
 assign dtlb_miss = (kernel_mode_reg == `LM32_USER_MODE) && (load_q_m || store_q_m) && ~(dtlb_data_valid);
724 702
 
725 703
 always @(posedge clk_i `CFG_RESET_SENSITIVITY)
726 704
 begin
727 705
 	if (rst_i == `TRUE)
728  
-		dtlb_miss_int <= 0;
  706
+		dtlb_miss_q <= `FALSE;
729 707
 	else
730 708
 	begin
731  
-		if (dtlb_miss)
732  
-			dtlb_miss_int <= 1;
733  
-		else
734  
-			dtlb_miss_int <= 0;
  709
+		if (dtlb_miss && ~dtlb_miss_q)
  710
+			dtlb_miss_q <= `TRUE;
  711
+		else if (dtlb_miss_q && exception_m)
  712
+			dtlb_miss_q <= `FALSE;
735 713
 	end
736 714
 end
737 715
 
738  
-always @(posedge clk_i `CFG_RESET_SENSITIVITY)
739  
-begin
740  
-	if (rst_i == `TRUE)
741  
-		dtlb_miss_q <= 0;
742  
-	else
743  
-	begin
744  
-		if (dtlb_miss_int)
745  
-			dtlb_miss_q <= 1;
746  
-		else
747  
-			dtlb_miss_q <= 0;
748  
-	end
749  
-end
  716
+assign dtlb_miss_int = (dtlb_miss || dtlb_miss_q);
750 717
 
751 718
 always @(posedge clk_i `CFG_RESET_SENSITIVITY)
752 719
 begin
@@ -768,10 +735,8 @@ begin
768 735
 			dtlb_flushing <= 0;
769 736
 			if (dtlb_miss == `TRUE)
770 737
 			begin
771  
-//				dtlb_flushing <= 0;
772  
-//				dtlb_flush_set <= address_m[addr_dtlb_index_width-1:0];
773 738
 				dtlb_miss_addr <= address_m;
774  
-				$display("ERROR : DTLB MISS on addr 0x%08X at time %t", address_m, $time);
  739
+				$display("WARNING : DTLB MISS on addr 0x%08X at time %t", address_m, $time);
775 740
 			end
776 741
 			if (csr_write_enable && csr_write_data[0])
777 742
 			begin
@@ -827,9 +792,9 @@ begin
827 792
 		kernel_mode_reg <= `LM32_KERNEL_MODE;
828 793
 	else
829 794
 	begin
830  
-		if (/*exception_x || */switch_to_kernel_mode)
  795
+		if (exception_x || switch_to_kernel_mode)
831 796
 			kernel_mode_reg <= `LM32_KERNEL_MODE;
832  
-		else if (/*eret_q_x || */switch_to_user_mode)
  797
+		else if (eret_q_x || switch_to_user_mode)
833 798
 			kernel_mode_reg <= `LM32_USER_MODE;
834 799
 	end
835 800
 end
4  cores/lm32/rtl/lm32_load_store_unit.v
@@ -429,6 +429,7 @@ lm32_dcache #(
429 429
     .csr_write_enable	    (csr_write_enable),
430 430
     .exception_x	    (exception_x),
431 431
     .eret_q_x		    (eret_q_x),
  432
+    .exception_m	    (exception_m),
432 433
     // ----- Outputs -----
433 434
     .stall_request          (dcache_stall_request),
434 435
     .restart_request        (dcache_restart_request),
@@ -436,8 +437,7 @@ lm32_dcache #(
436 437
     .refill_address         (dcache_refill_address),
437 438
     .refilling              (dcache_refilling),
438 439
     .load_data              (dcache_data_m),
439  
-//    .dtlb_miss		    (dtlb_miss),
440  
-    .dtlb_miss_q	    (dtlb_miss),
  440
+    .dtlb_miss_int	    (dtlb_miss),
441 441
     .kernel_mode	    (kernel_mode),
442 442
     .pa			    (physical_address),
443 443
     .csr_read_data	    (csr_read_data)
196  software/bios/dtlb_exception_handling_tests.c
... ...
@@ -1,160 +1,78 @@
1  
-#include <hal/mmu.h>
2  
-
3  
-#define PAGE_SIZE	(4096)
4  
-
5  
-#define MAX_MMU_SLOTS	10
6  
-#define NO_EMPTY_SLOT	(MAX_MMU_SLOTS + 1)
7  
-
8  
-#define A_BAD_ADDR	(0)
9  
-
10  
-#define NULL (0)
11  
-
12  
-#define get_pfn(x)	(x & ~(PAGE_SIZE - 1))
13  
-
14  
-struct mmu_mapping {
15  
-
16  
-	unsigned int vaddr;
17  
-	unsigned int paddr;
18  
-	char valid;
19  
-
20  
-} mappings[10];
21  
-
22 1
 /*
23  
- * This records in a global structure all MMU mappings
24  
- * If such a mapping already exists the function returns immediately.
25  
- * If such a mapping does not exist yet, vaddr is mapped to paddr and 
26  
- * the mapping is recorded in the mappings[] global structure array in
27  
- * an empty slot.
28  
- * If there is no empty slot anymore then we fail
  2
+ * Milkymist SoC (Software)
  3
+ * Copyright (C) 2012 Yann Sionneau <yann.sionneau@gmail.com>
  4
+ *
  5
+ * This program is free software: you can redistribute it and/or modify
  6
+ * it under the terms of the GNU General Public License as published by
  7
+ * the Free Software Foundation, version 3 of the License.
  8
+ *
  9
+ * This program is distributed in the hope that it will be useful,
  10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12
+ * GNU General Public License for more details.
  13
+ *
  14
+ * You should have received a copy of the GNU General Public License
  15
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
29 16
  */
30 17
 
31  
-unsigned int mmu_map(unsigned int vaddr, unsigned int paddr) {
32  
-	int i;
33  
-	int empty_slot = NO_EMPTY_SLOT;
34  
-	vaddr = get_pfn(vaddr);
35  
-
36  
-	for (i = 0 ; i < MAX_MMU_SLOTS ; ++i)
37  
-	{
38  
-		if (!mappings[i].valid)
39  
-			empty_slot = i;
40  
-		if (vaddr == mappings[i].vaddr && paddr == mappings[i].paddr)
41  
-			return 1;
42  
-	}
43  
-	
44  
-	if (empty_slot == NO_EMPTY_SLOT)
45  
-		return empty_slot;
46  
-
47  
-	mappings[empty_slot].vaddr = vaddr;
48  
-	mappings[empty_slot].paddr = paddr;
49  
-	mappings[empty_slot].valid = 1;
50  
-	mmu_dtlb_map(vaddr, paddr);
51  
-
52  
-	return 1;
53  
-}
  18
+#include <hal/mmu.h>
  19
+#include <base/mmu.h>
  20
+#include <base/stdio.h>
54 21
 
55  
-unsigned int get_mmu_mapping_for(unsigned int vaddr) {
56  
-	int i;
57  
-	vaddr = get_pfn(vaddr);
  22
+void dtlb_exception_handling_tests() {
58 23
 
59  
-	for (i = 0 ; i < MAX_MMU_SLOTS ; ++i)
60  
-		if (mappings[i].valid && vaddr == mappings[i].vaddr)
61  
-			return mappings[i].paddr;
  24
+	register unsigned int stack, addr;
  25
+	unsigned int data;
  26
+	int ret;
62 27
 
63  
-	return A_BAD_ADDR;
64  
-}
  28
+	asm volatile("mv %0, sp" : "=r"(stack) :: );
65 29
 
66  
-unsigned int invalidate_mmu_mapping(unsigned int vaddr) {
67  
-	int i;
68  
-	vaddr = get_pfn(vaddr);
69  
-	for (i = 0 ; i < MAX_MMU_SLOTS ; ++i)
70  
-	{
71  
-		if (mappings[i].valid && vaddr == mappings[i].vaddr) {
72  
-			mmu_dtlb_invalidate(vaddr);
73  
-			mappings[i].valid = 0;
74  
-			return 1;
75  
-		}
76  
-	}
77  
-	return 0;
78  
-}
  30
+	ret = mmu_map(stack, stack);
  31
+	check_for_error(ret);
79 32
 
80  
-static void panic(void) {
81  
-	puts("PANIC !");
82  
-	while(1)
83  
-		asm volatile("nop");
84  
-}
  33
+	ret = mmu_map(stack-0x1000, stack-0x1000);
  34
+	check_for_error(ret);
85 35
 
86  
-static void check_for_error(int ret) {
87  
-	if (ret)
88  
-		return;
  36
+	printf("stack == 0x%08X\n", stack);
89 37
 
90  
-	if (ret == NO_EMPTY_SLOT) {
91  
-		puts("No empty slot in MMU mappings structure anymore");
92  
-		panic();
93  
-	}
  38
+	addr = 0x44004004;
94 39
 
95  
-	if ( !ret ) {
96  
-		puts("Unknown issue");
97  
-		panic();
98  
-	}
99  
-}
  40
+	printf("\n=> Mapping 0x%08X to 0x%08X\n", addr, addr);
  41
+	ret = mmu_map(addr, addr);
  42
+	check_for_error(ret);
100 43
 
101  
-void dtlb_exception_handling_tests() {
  44
+	data = 42;
  45
+	printf("=> Writing %d to physical address 0x%08X\n", data, addr);
  46
+	*(unsigned int *)addr = data;
102 47
 
103  
-	register unsigned int stack, addr, data;
104  
-	int ret;
  48
+	printf("=> Activating the MMU and reading form virtual address 0x%08X\n", addr);
  49
+	data = read_word_with_mmu_enabled(addr);
  50
+	printf("\n<= Reading %d from virtual address 0x%08X\n\n", data, addr);
105 51
 
106  
-	asm volatile("mv %0, sp" : "=r"(stack) :: );
  52
+	printf("=> Invalidating the mapping of virtual address 0x%08X in the TLB\n", addr);
  53
+	mmu_dtlb_invalidate(addr);
107 54
 
108  
-	ret = mmu_map(stack, stack);
109  
-	check_for_error(ret);
  55
+	data = 43;
  56
+	printf("=> Writing %d to physical address 0x%08X\n", data, addr);
  57
+	*(unsigned int *)addr = data;
110 58
 
111  
-	ret = mmu_map(stack-0x1000, stack-0x1000);
  59
+	printf("=> Activating the MMU and reading form virtual address 0x%08X\n", addr);
  60
+	data = read_word_with_mmu_enabled(addr);
  61
+	printf("\n<= Reading %d from virtual address 0x%08X\n\n", data, addr);
  62
+
  63
+	printf("=> Mapping 0x%08X to 0%08X\n", addr, addr+0x1000);
  64
+	ret = mmu_map(addr, addr+0x1000); // Map to something else
112 65
 	check_for_error(ret);
113 66
 
114  
-	printf("stack == 0x%08X\n", stack);
  67
+	printf("=> Invalidating the mapping of virtual address 0x%08X in the TLB\n", addr);
  68
+	mmu_dtlb_invalidate(addr); // AND invalidate the mapping
  69
+
  70
+	data = 44;
  71
+	printf("=> Writting %d to physical address 0x%08X\n", data, addr+0x1000);
  72
+	*(unsigned int *)(addr + 0x1000) = data;
115 73
 
116  
-	addr = 0x44002342; // Random address
117  
-	*(unsigned int *)addr = 42;
118  
-//	mmu_map(addr, addr);
119  
-
120  
-	printf("Address 0x%08X mapped to itself, value : ", addr);
121  
-
122  
-	asm volatile(
123  
-		"xor r11, r11, r11\n\t"
124  
-		"ori r11, r11, 0x11\n\t"
125  
-		"wcsr tlbctrl, r11\n\t" // this activates the mmu
126  
-		"xor r0, r0, r0\n\t"
127  
-		"xor r11, r11, r11\n\t"
128  
-		"or r11, r11, %1\n\t"
129  
-		"lw  %0, (r11+0)\n\t"
130  
-		"xor r11, r11, r11\n\t"
131  
-		"ori r11, r11, 0x9\n\t"
132  
-		"wcsr tlbctrl, r11\n\t" // this disactivates the mmu
133  
-		"xor r0, r0, r0" : "=&r"(data) : "r"(addr) : "r11"
134  
-	);
135  
-
136  
-	printf("%d\n", data);
137  
-
138  
-	invalidate_mmu_mapping(addr);
139  
-
140  
-	printf("DTLB has just been invalidated, next access to 0x%08X should trigger a DTLB exception\n", addr);
141  
-
142  
-	printf("Address 0x%08X not mapped, value : ", addr);
143  
-
144  
-	asm volatile(
145  
-		"xor r11, r11, r11\n\t"
146  
-		"ori r11, r11, 0x11\n\t"
147  
-		"wcsr tlbctrl, r11\n\t" // this activates the mmu
148  
-		"xor r0, r0, r0\n\t"
149  
-		"xor r11, r11, r11\n\t"
150  
-		"or r11, r11, %1\n\t"
151  
-		"lw  %0, (r11+0)\n\t"
152  
-		"xor r11, r11, r11\n\t"
153  
-		"ori r11, r11, 0x9\n\t"
154  
-		"wcsr tlbctrl, r11\n\t" // this disactivates the mmu
155  
-		"xor r0, r0, r0" : "=&r"(data) : "r"(addr) : "r11"
156  
-	);
157  
-
158  
-	printf("%d\n", data);
  74
+	printf("=> Activating the MMU and reading form virtual address 0x%08X\n", addr);
  75
+	data = read_word_with_mmu_enabled(addr);
  76
+	printf("\n<= Reading %d from virtual address 0x%08X\n\n", data, addr);
159 77
 
160 78
 }
41  software/bios/dtlb_miss_handler.c
... ...
@@ -1,8 +1,43 @@
  1
+/*
  2
+ * Milkymist SoC (Software)
  3
+ * Copyright (C) 2012 Yann Sionneau <yann.sionneau@gmail.com>
  4
+ *
  5
+ * This program is free software: you can redistribute it and/or modify
  6
+ * it under the terms of the GNU General Public License as published by
  7
+ * the Free Software Foundation, version 3 of the License.
  8
+ *
  9
+ * This program is distributed in the hope that it will be useful,
  10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12
+ * GNU General Public License for more details.
  13
+ *
  14
+ * You should have received a copy of the GNU General Public License
  15
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16
+ */
  17
+
1 18
 #include <hal/mmu.h>
  19
+#include <base/mmu.h>
  20
+
  21
+void dtlb_miss_handler(void)
  22
+{
  23
+	unsigned int vaddr, paddr;
  24
+
  25
+	// retrieve virtual address which caused the page fault
  26
+	asm volatile("rcsr %0, dtlbma" : "=r"(vaddr) :: );
2 27
 
3  
-void dtlb_miss_handler(void) {
  28
+	/*
  29
+	* check if there is an existing mapping for that virtual address
  30
+	* if yes: refill the DTLB with it
  31
+	* if not: we panic() !
  32
+	*/
  33
+	paddr = get_mmu_mapping_for(vaddr);
  34
+	if (paddr == A_BAD_ADDR)
  35
+	{
  36
+		puts("[TLB miss handler] Unrecoverable page fault !");
  37
+		panic();
  38
+	}
4 39
 
5  
-	disable_dtlb();
6  
-	printf("TOTO");
  40
+	printf("[TLB miss handler] Refilling DTLB with mapping 0x%08X->0x%08X\n", vaddr, paddr);
  41
+	mmu_dtlb_map(vaddr, paddr);
7 42
 
8 43
 }
29  software/include/base/mmu.h
... ...
@@ -0,0 +1,29 @@
  1
+/*
  2
+ * Milkymist SoC (Software)
  3
+ * Copyright (C) 2012 Yann Sionneau <yann.sionneau@gmail.com>
  4
+ *
  5
+ * This program is free software: you can redistribute it and/or modify
  6
+ * it under the terms of the GNU General Public License as published by
  7
+ * the Free Software Foundation, version 3 of the License.
  8
+ *
  9
+ * This program is distributed in the hope that it will be useful,
  10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12
+ * GNU General Public License for more details.
  13
+ *
  14
+ * You should have received a copy of the GNU General Public License
  15
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16
+ */
  17
+
  18
+#ifndef __BASE_MMU_H__
  19
+#define __BASE_MMU_H__
  20
+
  21
+#include <hal/mmu.h>
  22
+
  23
+unsigned int mmu_map(unsigned int vaddr, unsigned int paddr);
  24
+unsigned int get_mmu_mapping_for(unsigned int vaddr);
  25
+unsigned char remove_mmu_mapping_for(unsigned int vaddr);
  26
+void panic(void);
  27
+void check_for_error(int ret);
  28
+
  29
+#endif
20  software/include/hal/mmu.h
@@ -15,6 +15,22 @@
15 15
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16
  */
17 17
 
  18
+#ifndef __MMU_H__
  19
+#define __MMU_H__
  20
+
  21
+#define PAGE_SIZE	(4096)
  22
+#define MAX_MMU_SLOTS	10
  23
+#define NO_EMPTY_SLOT	(MAX_MMU_SLOTS + 1)
  24
+#define A_BAD_ADDR	0xffffffff
  25
+#define get_pfn(x)	(x & ~(PAGE_SIZE - 1))
  26
+
  27
+struct mmu_mapping {
  28
+
  29
+	unsigned int vaddr;
  30
+	unsigned int paddr;
  31
+	char valid;
  32
+
  33
+};
18 34
 
19 35
 #define enable_dtlb() do { \
20 36
 	asm volatile	("xor r11, r11, r11\n\t" \
@@ -33,3 +49,7 @@
33 49
 } while(0);
34 50
 
35 51
 void mmu_dtlb_map(unsigned int vpfn, unsigned int pfn);
  52
+unsigned int read_word_with_mmu_enabled(unsigned int vaddr);
  53
+void mmu_dtlb_invalidate(unsigned int vaddr);
  54
+
  55
+#endif
2  software/libbase/Makefile
... ...
@@ -1,7 +1,7 @@
1 1
 MMDIR=../..
2 2
 include $(MMDIR)/software/include.mak
3 3
 
4  
-OBJECTS_ALL=divsi3.o libc.o crc16.o crc32.o console.o blockdev.o fatfs.o system.o board.o uart.o
  4
+OBJECTS_ALL=divsi3.o libc.o crc16.o crc32.o console.o blockdev.o fatfs.o system.o board.o uart.o mmu.o
5 5
 OBJECTS=$(OBJECTS_ALL) softfloat.o softfloat-glue.o vsnprintf.o atof.o malloc.o
6 6
 OBJECTS_LIGHT=$(OBJECTS_ALL) vsnprintf-nofloat.o
7 7
 
116  software/libbase/mmu.c
... ...
@@ -0,0 +1,116 @@
  1
+/*
  2
+ * Milkymist SoC (Software)
  3
+ * Copyright (C) 2012 Yann Sionneau <yann.sionneau@gmail.com>
  4
+ *
  5
+ * This program is free software: you can redistribute it and/or modify
  6
+ * it under the terms of the GNU General Public License as published by
  7
+ * the Free Software Foundation, version 3 of the License.
  8
+ *
  9
+ * This program is distributed in the hope that it will be useful,
  10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12
+ * GNU General Public License for more details.
  13
+ *
  14
+ * You should have received a copy of the GNU General Public License
  15
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16
+ */
  17
+
  18
+/* @vpfn : virtual page frame number
  19
+ * @pfn  : physical page frame number
  20
+ */
  21
+
  22
+#include <hal/mmu.h>
  23
+#include <base/mmu.h>
  24
+
  25
+struct mmu_mapping mappings[MAX_MMU_SLOTS];
  26
+
  27
+/*
  28
+ * This records in a global structure all MMU mappings
  29
+ * If such a mapping already exists the function returns immediately.
  30
+ * If such a mapping does not exist yet, vaddr is mapped to paddr and
  31
+ * the mapping is recorded in the mappings[] global structure array in
  32
+ * an empty slot.
  33
+ * If there is no empty slot anymore then we fail
  34
+ */
  35
+
  36
+unsigned int mmu_map(unsigned int vaddr, unsigned int paddr) {
  37
+	int i;
  38
+	int empty_slot = NO_EMPTY_SLOT;
  39
+	vaddr = get_pfn(vaddr);
  40
+	paddr = get_pfn(paddr);
  41
+
  42
+	for (i = 0 ; i < MAX_MMU_SLOTS ; ++i)
  43
+	{
  44
+		if (!mappings[i].valid)
  45
+			empty_slot = i;
  46
+		if ((vaddr == mappings[i].vaddr) && (paddr == mappings[i].paddr) && mappings[i].valid)
  47
+		{
  48
+			puts("Already mapped !");
  49
+			return 1;
  50
+		}
  51
+	}
  52
+
  53
+	if (empty_slot == NO_EMPTY_SLOT)
  54
+	{
  55
+		puts("No more slots !");
  56
+		return empty_slot;
  57
+	}
  58
+
  59
+	mappings[empty_slot].vaddr = vaddr;
  60
+	mappings[empty_slot].paddr = paddr;
  61
+	mappings[empty_slot].valid = 1;
  62
+	mmu_dtlb_map(vaddr, paddr);
  63
+	printf("mapping 0x%08X->0x%08X in slot %d [0x%p]\n", vaddr, paddr, empty_slot, &mappings[empty_slot]);
  64
+
  65
+	return 1;
  66
+}
  67
+
  68
+unsigned int get_mmu_mapping_for(unsigned int vaddr) {
  69
+	int i;
  70
+	vaddr = get_pfn(vaddr);
  71
+
  72
+	for (i = 0 ; i < MAX_MMU_SLOTS ; ++i)
  73
+		if (mappings[i].valid && (vaddr == mappings[i].vaddr))
  74
+			return mappings[i].paddr;
  75
+
  76
+	return A_BAD_ADDR;
  77
+}
  78
+
  79
+unsigned char remove_mmu_mapping_for(unsigned int vaddr) {
  80
+	int i;
  81
+	vaddr = get_pfn(vaddr);
  82
+
  83
+	for (i = 0 ; i < MAX_MMU_SLOTS ; ++i)
  84
+	{
  85
+		if (mappings[i].valid && (vaddr == mappings[i].vaddr))
  86
+		{
  87
+			mmu_dtlb_invalidate(vaddr);
  88
+			mappings[i].valid = 0;
  89
+			return 1;
  90
+		}
  91
+	}
  92
+	return 0;
  93
+}
  94
+
  95
+void panic(void) {
  96
+	puts("PANIC !");
  97
+	while(1)
  98
+		asm volatile("nop");
  99
+}
  100
+
  101
+void check_for_error(int ret) {
  102
+	if (ret == 1)
  103
+		return;
  104
+
  105
+	if (ret == NO_EMPTY_SLOT)
  106
+	{
  107
+		puts("No empty slot in MMU mappings structure anymore");
  108
+		panic();
  109
+	}
  110
+
  111
+	if ( !ret )
  112
+	{
  113
+		puts("Unknown issue");
  114
+		panic();
  115
+	}
  116
+}
30  software/libhal/mmu.c
@@ -15,6 +15,9 @@
15 15
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16
  */
17 17
 
  18
+#include <hal/mmu.h>
  19
+#include <base/mmu.h>
  20
+
18 21
 /* @vpfn : virtual page frame number
19 22
  * @pfn  : physical page frame number
20 23
  */
@@ -42,3 +45,30 @@ inline void mmu_dtlb_invalidate(unsigned int vaddr)
42 45
 		      "ori r11, r11, 0x21\n\t"
43 46
 		      "wcsr tlbctrl, r11":::"r11");
44 47
 }
  48
+
  49
+/* This function activates the MMU
  50
+ * then reads from virtual address "vaddr"
  51
+ * and store the result in temporary variable "data".
  52
+ * Then MMU is disactivated and the content of "data"
  53
+ * is returned.
  54
+ */
  55
+
  56
+unsigned int read_word_with_mmu_enabled(unsigned int vaddr)
  57
+{
  58
+	register unsigned int data;
  59
+	asm volatile(
  60
+		"xor r11, r11, r11\n\t"
  61
+		"ori r11, r11, 0x11\n\t"
  62
+		"wcsr tlbctrl, r11\n\t" // Activates the MMU
  63
+		"xor r0, r0, r0\n\t"
  64
+		"xor r11, r11, r11\n\t"
  65
+		"or r11, r11, %1\n\t"
  66
+		"lw  %0, (r11+0)\n\t" // Reads from virtual address "addr"
  67
+		"xor r11, r11, r11\n\t"
  68
+		"ori r11, r11, 0x9\n\t"
  69
+		"wcsr tlbctrl, r11\n\t" // Disactivates the MMU
  70
+		"xor r0, r0, r0\n\t" : "=&r"(data) : "r"(vaddr) : "r11"
  71
+	);
  72
+
  73
+	return data;
  74
+}

0 notes on commit 790d654

Please sign in to comment.
Something went wrong with that request. Please try again.