Skip to content

Commit 790d654

Browse files
committedJun 3, 2012
MMU DTLB page fault handling working on FPGA
1 parent 23f3785 commit 790d654

File tree

10 files changed

+313
-200
lines changed

10 files changed

+313
-200
lines changed
 

‎cores/lm32/rtl/lm32_cpu.v

+1-1
Original file line numberDiff line numberDiff line change
@@ -2143,7 +2143,7 @@ begin
21432143
`LM32_CSR_JRX: csr_read_data_x = jrx_csr_read_data;
21442144
`endif
21452145
`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;
21472147

21482148
default: csr_read_data_x = {`LM32_WORD_WIDTH{1'bx}};
21492149
endcase

‎cores/lm32/rtl/lm32_dcache.v

+19-54
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ module lm32_dcache (
110110
csr_write_enable,
111111
exception_x,
112112
eret_q_x,
113+
exception_m,
113114
// ----- Outputs -----
114115
stall_request,
115116
restart_request,
@@ -118,7 +119,7 @@ module lm32_dcache (
118119
refilling,
119120
load_data,
120121
// To pipeline
121-
dtlb_miss_q,
122+
dtlb_miss_int,
122123
kernel_mode,
123124
pa,
124125
csr_read_data
@@ -138,7 +139,6 @@ parameter dtlb_sets = 1024; // Number of lines of DTLB
138139
parameter page_size = 4096; // System page size
139140

140141
`define LM32_DTLB_IDX_RNG addr_dtlb_index_msb:addr_dtlb_index_lsb
141-
//`define LM32_DTLB_INVALID_TAG { {9{1'b1}}, `FALSE}
142142
`define LM32_DTLB_ADDRESS_PFN_RNG addr_pfn_msb:addr_pfn_lsb
143143
`define LM32_PAGE_OFFSET_RNG addr_page_offset_msb:addr_page_offset_lsb
144144
`define LM32_DTLB_INVALID_ADDRESS { vpfn_width{1'b1} }
@@ -206,6 +206,7 @@ input [`LM32_CSR_RNG] csr; // CSR read/write index
206206
input [`LM32_WORD_RNG] csr_write_data; // Data to write to specified CSR
207207
input csr_write_enable; // CSR write enable
208208
input exception_x; // An exception occured in the X stage
209+
input exception_m;
209210
input eret_q_x;
210211

211212
/////////////////////////////////////////////////////
@@ -231,9 +232,7 @@ wire [`LM32_WORD_RNG] load_data;
231232
output kernel_mode;
232233
wire kernel_mode;
233234

234-
output dtlb_miss_q;
235-
//output dtlb_miss;
236-
//output dtlb_miss_int;
235+
output dtlb_miss_int;
237236

238237
/////////////////////////////////////////////////////
239238
// Internal nets and registers
@@ -294,8 +293,8 @@ reg [addr_dtlb_index_width-1:0] dtlb_update_set;
294293
reg dtlb_flushing;
295294
reg [addr_dtlb_index_width-1:0] dtlb_flush_set;
296295
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;
299298
reg [`LM32_WORD_RNG] dtlb_miss_addr;
300299
wire dtlb_data_valid;
301300
wire [`LM32_DTLB_LOOKUP_RANGE] dtlb_lookup;
@@ -465,27 +464,14 @@ end
465464
generate
466465
for (i = 0; i < associativity; i = i + 1)
467466
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});
470467

471468
assign dtlb_read_tag = dtlb_read_data[`LM32_DTLB_TAG_RANGE];
472469
assign dtlb_data_valid = dtlb_read_data[`LM32_DTLB_VALID_BIT];
473470
assign dtlb_lookup = dtlb_read_data[`LM32_DTLB_LOOKUP_RANGE];
474471

475472
assign way_match[i] = (kernel_mode_reg == `LM32_KERNEL_MODE) ?
476473
({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});
489475
end
490476
endgenerate
491477

@@ -555,13 +541,7 @@ assign dtlb_data_read_address = address_x[`LM32_DTLB_IDX_RNG];
555541
assign dtlb_tag_read_address = address_x[`LM32_DTLB_IDX_RNG];
556542

557543
// 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];
565545

566546
assign dtlb_data_read_port_enable = (stall_x == `FALSE) || !stall_m;
567547
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
610590
assign tmem_write_data[`LM32_DC_TAGS_TAG_RNG] = refill_address[`LM32_DC_ADDR_TAG_RNG];
611591

612592
// Signals that indicate which state we are in
613-
assign flushing = state[0]; //|| dtlb_miss;
593+
assign flushing = state[0];
614594
assign check = state[1];
615595
assign refill = state[2];
616596

@@ -683,8 +663,6 @@ begin
683663
end
684664
else if (dflush == `TRUE)
685665
state <= `LM32_DC_STATE_FLUSH;
686-
// else if (dtlb_miss == `TRUE)
687-
// refill_address <= physical_address;
688666
end
689667

690668
// Refill a cache line
@@ -718,35 +696,24 @@ begin
718696
end
719697
end
720698

721-
assign csr_read_data = latest_store_tlb_lookup;
699+
assign csr_read_data = dtlb_miss_addr;
722700

723701
assign dtlb_miss = (kernel_mode_reg == `LM32_USER_MODE) && (load_q_m || store_q_m) && ~(dtlb_data_valid);
724702

725703
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
726704
begin
727705
if (rst_i == `TRUE)
728-
dtlb_miss_int <= 0;
706+
dtlb_miss_q <= `FALSE;
729707
else
730708
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;
735713
end
736714
end
737715

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);
750717

751718
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
752719
begin
@@ -768,10 +735,8 @@ begin
768735
dtlb_flushing <= 0;
769736
if (dtlb_miss == `TRUE)
770737
begin
771-
// dtlb_flushing <= 0;
772-
// dtlb_flush_set <= address_m[addr_dtlb_index_width-1:0];
773738
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);
775740
end
776741
if (csr_write_enable && csr_write_data[0])
777742
begin
@@ -827,9 +792,9 @@ begin
827792
kernel_mode_reg <= `LM32_KERNEL_MODE;
828793
else
829794
begin
830-
if (/*exception_x || */switch_to_kernel_mode)
795+
if (exception_x || switch_to_kernel_mode)
831796
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)
833798
kernel_mode_reg <= `LM32_USER_MODE;
834799
end
835800
end

‎cores/lm32/rtl/lm32_load_store_unit.v

+2-2
Original file line numberDiff line numberDiff line change
@@ -429,15 +429,15 @@ lm32_dcache #(
429429
.csr_write_enable (csr_write_enable),
430430
.exception_x (exception_x),
431431
.eret_q_x (eret_q_x),
432+
.exception_m (exception_m),
432433
// ----- Outputs -----
433434
.stall_request (dcache_stall_request),
434435
.restart_request (dcache_restart_request),
435436
.refill_request (dcache_refill_request),
436437
.refill_address (dcache_refill_address),
437438
.refilling (dcache_refilling),
438439
.load_data (dcache_data_m),
439-
// .dtlb_miss (dtlb_miss),
440-
.dtlb_miss_q (dtlb_miss),
440+
.dtlb_miss_int (dtlb_miss),
441441
.kernel_mode (kernel_mode),
442442
.pa (physical_address),
443443
.csr_read_data (csr_read_data)
+57-139
Original file line numberDiff line numberDiff line change
@@ -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-
221
/*
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/>.
2916
*/
3017

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>
5421

55-
unsigned int get_mmu_mapping_for(unsigned int vaddr) {
56-
int i;
57-
vaddr = get_pfn(vaddr);
22+
void dtlb_exception_handling_tests() {
5823

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

63-
return A_BAD_ADDR;
64-
}
28+
asm volatile("mv %0, sp" : "=r"(stack) :: );
6529

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);
7932

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);
8535

86-
static void check_for_error(int ret) {
87-
if (ret)
88-
return;
36+
printf("stack == 0x%08X\n", stack);
8937

90-
if (ret == NO_EMPTY_SLOT) {
91-
puts("No empty slot in MMU mappings structure anymore");
92-
panic();
93-
}
38+
addr = 0x44004004;
9439

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);
10043

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

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);
10551

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);
10754

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

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
11265
check_for_error(ret);
11366

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

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);
15977

16078
}

‎software/bios/dtlb_miss_handler.c

+38-3
Original file line numberDiff line numberDiff line change
@@ -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+
118
#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) :: );
227

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+
}
439

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);
742

843
}

‎software/include/base/mmu.h

+29
Original file line numberDiff line numberDiff line change
@@ -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

‎software/include/hal/mmu.h

+20
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,22 @@
1515
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717

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+
};
1834

1935
#define enable_dtlb() do { \
2036
asm volatile ("xor r11, r11, r11\n\t" \
@@ -33,3 +49,7 @@
3349
} while(0);
3450

3551
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

‎software/libbase/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
MMDIR=../..
22
include $(MMDIR)/software/include.mak
33

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
55
OBJECTS=$(OBJECTS_ALL) softfloat.o softfloat-glue.o vsnprintf.o atof.o malloc.o
66
OBJECTS_LIGHT=$(OBJECTS_ALL) vsnprintf-nofloat.o
77

‎software/libbase/mmu.c

+116
Original file line numberDiff line numberDiff line change
@@ -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+
}

‎software/libhal/mmu.c

+30
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717

18+
#include <hal/mmu.h>
19+
#include <base/mmu.h>
20+
1821
/* @vpfn : virtual page frame number
1922
* @pfn : physical page frame number
2023
*/
@@ -42,3 +45,30 @@ inline void mmu_dtlb_invalidate(unsigned int vaddr)
4245
"ori r11, r11, 0x21\n\t"
4346
"wcsr tlbctrl, r11":::"r11");
4447
}
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 commit comments

Comments
 (0)
Please sign in to comment.