Line 1... |
Line 1... |
/*
|
/*
|
* Simply RISC M1 Memory Management Unit
|
* Simply RISC M1 Memory Management Unit
|
*
|
*
|
* It will include the following components:
|
* This block converts Harvard architecture requests to access the
|
* - Instruction Cache
|
* small internal prefetch buffer, and just in case the external
|
* - Data Cache
|
* Wishbone bus.
|
* - TLB
|
* Memory size is 256 word * 4 byte = 1024 byte,
|
* but for now it's just a fake MMU.
|
* so 10 address bits are required => [9:0]
|
|
* and being the lower 2 bits unused the offset in memory is [9:2].
|
*/
|
*/
|
|
|
module m1_mmu (
|
module m1_mmu (
|
sys_clock_i, sys_reset_i,
|
|
imem_addr_i, imem_data_o, imem_read_i, imem_busy_o,
|
|
dmem_addr_i, dmem_data_o, dmem_data_i, dmem_read_i, dmem_write_i, dmem_busy_o ,dmem_sel_i
|
|
);
|
|
|
|
// System
|
// System
|
input sys_clock_i, sys_reset_i;
|
input sys_clock_i, // System Clock
|
|
input sys_reset_i, // System Reset
|
|
|
// Instruction Memory
|
// Instruction Memory
|
input[31:0] imem_addr_i;
|
input imem_read_i, // I$ Read
|
output[31:0] imem_data_o;
|
input[31:0] imem_addr_i, // I$ Address
|
input imem_read_i;
|
output imem_done_o, // I$ Done
|
output imem_busy_o;
|
output[31:0] imem_data_o, // I$ Data
|
|
|
// Data Memory
|
// Data Memory
|
input[31:0] dmem_addr_i;
|
input dmem_read_i, // D$ Read
|
output[31:0] dmem_data_o;
|
input dmem_write_i, // D$ Write
|
input[31:0] dmem_data_i;
|
input[31:0] dmem_addr_i, // D$ Address
|
input dmem_read_i;
|
input[31:0] dmem_data_i, // D$ Write Data
|
input dmem_write_i;
|
input[3:0] dmem_sel_i, // D$ Byte selector
|
output dmem_busy_o;
|
output dmem_done_o, // D$ Done
|
|
output[31:0] dmem_data_o, // D$ Read Data
|
// Fake Instruction and Data Memories
|
|
reg[31:0] imem_data[0:1023]; // 4KB I$
|
// Wishbone Master interface
|
reg[31:0] dmem_data[0:255]; // 1KB D$
|
output wb_cyc_o, // Cycle Start
|
|
output wb_stb_o, // Strobe Request
|
|
output wb_we_o, // Write Enable
|
//Selector
|
output[31:0] wb_adr_o, // Address Bus
|
input[3:0] dmem_sel_i;
|
output[31:0] wb_dat_o, // Data Out
|
reg[31:0] data_temp;
|
output[3:0] wb_sel_o, // Byte Select
|
|
input wb_ack_i, // Ack
|
// Initialize fake memories
|
input[31:0] wb_dat_i // Data In
|
integer i;
|
|
initial begin
|
|
|
|
// I$ is initialized from file
|
|
$readmemh("code.txt", imem_data);
|
|
|
|
// D$ defaults to zeroes
|
|
for(i=0; i<256; i=i+1) dmem_data[i] = 0;
|
|
|
|
end
|
|
|
|
assign imem_busy_o = 0;
|
|
assign dmem_busy_o = 0;
|
|
|
|
|
|
assign imem_data_o = imem_data[{2'b00, imem_addr_i[31:2]}];
|
|
assign dmem_data_o = dmem_data[{2'b00, dmem_addr_i[31:2]}];
|
|
|
|
|
);
|
|
|
always @(dmem_write_i or dmem_read_i) begin
|
/*
|
|
* Registers
|
|
*/
|
|
|
if(dmem_write_i) begin
|
// Prefetch buffer
|
|
reg[31:0] MEM[255:0];
|
|
|
if(dmem_sel_i[0]) begin
|
// Initialize memory content
|
data_temp = dmem_data[{2'b00, dmem_addr_i[31:2]}];
|
initial begin
|
data_temp[7:0] = dmem_data_i[7:0];
|
`include "m1_mmu_initial.vh"
|
dmem_data[{2'b00, dmem_addr_i[31:2]}] = data_temp;
|
|
end
|
|
if(dmem_sel_i[1]) begin
|
|
data_temp = dmem_data[{2'b00, dmem_addr_i[31:2]}];
|
|
data_temp[15:8] = dmem_data_i[15:8];
|
|
dmem_data[{2'b00, dmem_addr_i[31:2]}] = data_temp;
|
|
end
|
|
if(dmem_sel_i[2]) begin
|
|
data_temp = dmem_data[{2'b00, dmem_addr_i[31:2]}];
|
|
data_temp[24:16] = dmem_data_i[24:16];
|
|
dmem_data[{2'b00, dmem_addr_i[31:2]}] = data_temp;
|
|
end
|
|
if(dmem_sel_i[3]) begin
|
|
data_temp = dmem_data[{2'b00, dmem_addr_i[31:2]}];
|
|
data_temp[31:24] = dmem_data_i[31:24];
|
|
dmem_data[{2'b00, dmem_addr_i[31:2]}] = data_temp;
|
|
end
|
|
$display("INFO: MEMH(%m): WRITE_ADDR=%X, WRITE_DATA=%X", dmem_addr_i, dmem_data_i);
|
|
end
|
end
|
|
|
|
/*
|
|
* Wires
|
|
*/
|
|
|
if(dmem_read_i) begin
|
// See if there are pending requests
|
$display("INFO: MEMH(%m): READ_ADDR=%X, READ_DATA=%X", dmem_addr_i, dmem_data[{2'b00, dmem_addr_i[31:2]}]);
|
wire access_pending_imem = imem_read_i;
|
end
|
wire access_pending_dmem = 0;
|
end
|
wire access_pending_ext = (dmem_read_i || dmem_write_i);
|
|
|
|
// Default grant for memories
|
|
assign imem_done_o = access_pending_imem;
|
|
assign dmem_done_o = access_pending_dmem || (access_pending_ext && wb_ack_i);
|
|
|
|
// Set Wishbone outputs
|
|
assign wb_cyc_o = access_pending_ext;
|
|
assign wb_stb_o = access_pending_ext;
|
|
assign wb_we_o = access_pending_ext && dmem_write_i;
|
|
assign wb_sel_o = dmem_sel_i;
|
|
assign wb_adr_o = dmem_addr_i;
|
|
assign wb_dat_o = dmem_data_i;
|
|
|
|
// Return read data
|
|
assign imem_data_o = MEM[imem_addr_i[9:2]];
|
|
assign dmem_data_o = wb_dat_i;
|
|
|
endmodule
|
endmodule
|
|
|
|
|
No newline at end of file
|
No newline at end of file
|