boot screen

This commit is contained in:
Polprzewodnikowy 2021-02-09 23:58:02 +01:00
parent 200f164363
commit 59491be835
23 changed files with 406 additions and 264 deletions

View File

@ -178,7 +178,7 @@ set_global_assignment -name TIMING_ANALYZER_DO_REPORT_TIMING ON
# Compiler Assignments # Compiler Assignments
# ==================== # ====================
set_global_assignment -name OPTIMIZATION_MODE "HIGH PERFORMANCE EFFORT" set_global_assignment -name OPTIMIZATION_MODE "AGGRESSIVE PERFORMANCE"
# Analysis & Synthesis Assignments # Analysis & Synthesis Assignments
# ================================ # ================================

View File

@ -10,7 +10,7 @@ module sd_dat (
input i_dat_width, input i_dat_width,
input i_dat_direction, input i_dat_direction,
input [6:0] i_dat_block_size, input [6:0] i_dat_block_size,
input [10:0] i_dat_num_blocks, input [7:0] i_dat_num_blocks,
input i_dat_start, input i_dat_start,
input i_dat_stop, input i_dat_stop,
output o_dat_busy, output o_dat_busy,
@ -64,16 +64,16 @@ module sd_dat (
// Block counter logic // Block counter logic
reg [10:0] r_block_counter; reg [7:0] r_block_counter;
wire w_read_start = i_dat_start && r_state[STATE_IDLE]; wire w_read_start = i_dat_start && r_state[STATE_IDLE];
wire w_read_stop = r_block_counter == 11'd0; wire w_read_stop = r_block_counter == 8'd0;
always @(posedge i_clk) begin always @(posedge i_clk) begin
if (w_read_start) begin if (w_read_start) begin
r_block_counter <= i_dat_num_blocks; r_block_counter <= i_dat_num_blocks;
end else if (w_data_end) begin end else if (w_data_end) begin
if (r_block_counter > 11'd0) begin if (r_block_counter > 8'd0) begin
r_block_counter <= r_block_counter - 1'd1; r_block_counter <= r_block_counter - 1'd1;
end end
end end

View File

@ -4,8 +4,8 @@ module sd_dma (
input [3:0] i_dma_bank, input [3:0] i_dma_bank,
input [23:0] i_dma_address, input [23:0] i_dma_address,
input [17:0] i_dma_length, input [14:0] i_dma_length,
output [17:0] o_dma_left, output reg [14:0] o_dma_left,
input i_dma_load_bank_address, input i_dma_load_bank_address,
input i_dma_load_length, input i_dma_load_length,
input i_dma_direction, input i_dma_direction,
@ -33,6 +33,58 @@ module sd_dma (
wire w_request_successful = o_request && !i_busy; wire w_request_successful = o_request && !i_busy;
always @(posedge i_clk) begin
if (i_dma_load_length && !o_dma_busy) begin
o_dma_left <= i_dma_length;
end else if (w_request_successful && o_dma_left > 15'd0) begin
o_dma_left <= o_dma_left - 1'd1;
end
end
always @(posedge i_clk) begin
if (i_reset) begin
o_dma_busy <= 1'b0;
end else begin
if (i_dma_start && !o_dma_busy) begin
o_dma_busy <= 1'b1;
end
if (i_dma_stop || (w_request_successful && o_dma_left == 15'd0)) begin
o_dma_busy <= 1'b0;
end
end
end
assign o_rx_fifo_pop = o_dma_busy && o_write && w_request_successful;
assign o_tx_fifo_push = o_dma_busy && !o_write && i_ack;
assign o_tx_fifo_data = i_data;
reg r_pending_ack;
always @(posedge i_clk) begin
if (i_reset || i_dma_stop) begin
r_pending_ack <= 1'b0;
end else if (o_dma_busy && !o_write) begin
if (w_request_successful) begin
r_pending_ack <= 1'b1;
end else if (i_ack) begin
r_pending_ack <= 1'b0;
end
end
end
assign o_request = o_dma_busy && (o_write ? (
!i_rx_fifo_empty
) : (
!r_pending_ack && !i_tx_fifo_full
));
always @(posedge i_clk) begin
if (i_dma_start && !o_dma_busy) begin
o_write <= i_dma_direction;
end
end
always @(posedge i_clk) begin always @(posedge i_clk) begin
if (i_dma_load_bank_address && !o_dma_busy) begin if (i_dma_load_bank_address && !o_dma_busy) begin
o_bank <= i_dma_bank; o_bank <= i_dma_bank;
@ -47,47 +99,6 @@ module sd_dma (
end end
end end
reg [17:0] r_remaining;
assign o_dma_left = r_remaining;
always @(posedge i_clk) begin
if (i_dma_load_length && !o_dma_busy) begin
r_remaining <= i_dma_length;
end else if (w_request_successful && r_remaining > 18'd0) begin
r_remaining <= r_remaining - 1'd1;
end
end
always @(posedge i_clk) begin
if (i_reset) begin
o_dma_busy <= 1'b0;
end else begin
if (i_dma_start && !o_dma_busy) begin
o_dma_busy <= 1'b1;
end
if (i_dma_stop || (w_request_successful && r_remaining == 18'd0)) begin
o_dma_busy <= 1'b0;
end
end
end
assign o_rx_fifo_pop = o_dma_busy && o_write && w_request_successful;
assign o_tx_fifo_data = i_data;
assign o_request = o_dma_busy && (o_write ? (
!i_rx_fifo_empty
) : (
1'b0 // TODO: Reading
));
always @(posedge i_clk) begin
if (i_dma_start) begin
o_write <= i_dma_direction;
end
end
assign o_data = i_rx_fifo_data; assign o_data = i_rx_fifo_data;
endmodule endmodule

View File

@ -7,22 +7,22 @@ module sd_fifo (
input i_fifo_pop, input i_fifo_pop,
output o_fifo_empty, output o_fifo_empty,
output o_fifo_full, output o_fifo_full,
output [7:0] o_fifo_items,
output reg o_fifo_underrun, output reg o_fifo_underrun,
output reg o_fifo_overrun, output reg o_fifo_overrun,
output [8:0] o_fifo_items,
input [31:0] i_fifo_data, input [31:0] i_fifo_data,
output [31:0] o_fifo_data output [31:0] o_fifo_data
); );
reg [31:0] r_fifo_mem [0:127]; reg [31:0] r_fifo_mem [0:255];
reg [7:0] r_fifo_wrptr; reg [8:0] r_fifo_wrptr;
reg [7:0] r_fifo_rdptr; reg [8:0] r_fifo_rdptr;
assign o_fifo_data = r_fifo_mem[r_fifo_rdptr[6:0]]; assign o_fifo_data = r_fifo_mem[r_fifo_rdptr[7:0]];
wire w_empty = r_fifo_wrptr[7] == r_fifo_rdptr[7]; wire w_empty = r_fifo_wrptr[8] == r_fifo_rdptr[8];
wire w_full_or_empty = r_fifo_wrptr[6:0] == r_fifo_rdptr[6:0]; wire w_full_or_empty = r_fifo_wrptr[7:0] == r_fifo_rdptr[7:0];
assign o_fifo_empty = w_empty && w_full_or_empty; assign o_fifo_empty = w_empty && w_full_or_empty;
assign o_fifo_full = !w_empty && w_full_or_empty; assign o_fifo_full = !w_empty && w_full_or_empty;
@ -30,20 +30,20 @@ module sd_fifo (
always @(posedge i_clk) begin always @(posedge i_clk) begin
if (i_reset) begin if (i_reset) begin
r_fifo_wrptr <= 8'd0; r_fifo_wrptr <= 9'd0;
r_fifo_rdptr <= 8'd0; r_fifo_rdptr <= 9'd0;
o_fifo_underrun <= 1'b0; o_fifo_underrun <= 1'b0;
o_fifo_overrun <= 1'b0; o_fifo_overrun <= 1'b0;
end else begin end else begin
if (i_fifo_flush) begin if (i_fifo_flush) begin
r_fifo_wrptr <= 8'd0; r_fifo_wrptr <= 9'd0;
r_fifo_rdptr <= 8'd0; r_fifo_rdptr <= 9'd0;
o_fifo_underrun <= 1'b0; o_fifo_underrun <= 1'b0;
o_fifo_overrun <= 1'b0; o_fifo_overrun <= 1'b0;
end end
if (i_fifo_push) begin if (i_fifo_push) begin
o_fifo_overrun <= o_fifo_overrun ? 1'b1 : o_fifo_full; o_fifo_overrun <= o_fifo_overrun ? 1'b1 : o_fifo_full;
r_fifo_mem[r_fifo_wrptr[6:0]] <= i_fifo_data; r_fifo_mem[r_fifo_wrptr[7:0]] <= i_fifo_data;
r_fifo_wrptr <= r_fifo_wrptr + 1'd1; r_fifo_wrptr <= r_fifo_wrptr + 1'd1;
end end
if (i_fifo_pop) begin if (i_fifo_pop) begin

View File

@ -85,8 +85,9 @@ module sd_interface (
wire w_rx_fifo_regs_pop; wire w_rx_fifo_regs_pop;
wire w_rx_fifo_dma_pop; wire w_rx_fifo_dma_pop;
wire w_rx_fifo_empty; wire w_rx_fifo_empty;
wire [7:0] w_rx_fifo_items; wire w_rx_fifo_full;
wire w_rx_fifo_overrun; wire w_rx_fifo_overrun;
wire [8:0] w_rx_fifo_items;
wire [31:0] w_rx_fifo_i_data; wire [31:0] w_rx_fifo_i_data;
wire [31:0] w_rx_fifo_o_data; wire [31:0] w_rx_fifo_o_data;
@ -98,10 +99,10 @@ module sd_interface (
.i_fifo_push(w_rx_fifo_push), .i_fifo_push(w_rx_fifo_push),
.i_fifo_pop(w_rx_fifo_regs_pop || w_rx_fifo_dma_pop), .i_fifo_pop(w_rx_fifo_regs_pop || w_rx_fifo_dma_pop),
.o_fifo_empty(w_rx_fifo_empty), .o_fifo_empty(w_rx_fifo_empty),
.o_fifo_full(), .o_fifo_full(w_rx_fifo_full),
.o_fifo_items(w_rx_fifo_items),
.o_fifo_underrun(), .o_fifo_underrun(),
.o_fifo_overrun(w_rx_fifo_overrun), .o_fifo_overrun(w_rx_fifo_overrun),
.o_fifo_items(w_rx_fifo_items),
.i_fifo_data(w_rx_fifo_i_data), .i_fifo_data(w_rx_fifo_i_data),
.o_fifo_data(w_rx_fifo_o_data) .o_fifo_data(w_rx_fifo_o_data)
); );
@ -115,6 +116,8 @@ module sd_interface (
wire w_tx_fifo_pop; wire w_tx_fifo_pop;
wire w_tx_fifo_empty; wire w_tx_fifo_empty;
wire w_tx_fifo_full; wire w_tx_fifo_full;
wire w_tx_fifo_underrun;
wire [8:0] w_tx_fifo_items;
reg [31:0] r_tx_fifo_i_data; reg [31:0] r_tx_fifo_i_data;
wire [31:0] w_tx_fifo_o_data; wire [31:0] w_tx_fifo_o_data;
@ -136,9 +139,9 @@ module sd_interface (
.i_fifo_pop(w_tx_fifo_pop), .i_fifo_pop(w_tx_fifo_pop),
.o_fifo_empty(w_tx_fifo_empty), .o_fifo_empty(w_tx_fifo_empty),
.o_fifo_full(w_tx_fifo_full), .o_fifo_full(w_tx_fifo_full),
.o_fifo_items(), .o_fifo_underrun(w_tx_fifo_underrun),
.o_fifo_underrun(),
.o_fifo_overrun(), .o_fifo_overrun(),
.o_fifo_items(w_tx_fifo_items),
.i_fifo_data(r_tx_fifo_i_data), .i_fifo_data(r_tx_fifo_i_data),
.o_fifo_data(w_tx_fifo_o_data) .o_fifo_data(w_tx_fifo_o_data)
); );
@ -149,7 +152,7 @@ module sd_interface (
wire w_dat_width; wire w_dat_width;
wire w_dat_direction; wire w_dat_direction;
wire [6:0] w_dat_block_size; wire [6:0] w_dat_block_size;
wire [10:0] w_dat_num_blocks; wire [7:0] w_dat_num_blocks;
wire w_dat_start; wire w_dat_start;
wire w_dat_stop; wire w_dat_stop;
wire w_dat_busy; wire w_dat_busy;
@ -187,8 +190,8 @@ module sd_interface (
wire [3:0] w_dma_bank; wire [3:0] w_dma_bank;
wire [23:0] w_dma_address; wire [23:0] w_dma_address;
wire [17:0] w_dma_length; wire [14:0] w_dma_length;
wire [17:0] w_dma_left; wire [14:0] w_dma_left;
wire w_dma_load_bank_address; wire w_dma_load_bank_address;
wire w_dma_load_length; wire w_dma_load_length;
wire w_dma_direction; wire w_dma_direction;
@ -260,14 +263,18 @@ module sd_interface (
.o_rx_fifo_flush(w_rx_fifo_flush), .o_rx_fifo_flush(w_rx_fifo_flush),
.o_rx_fifo_pop(w_rx_fifo_regs_pop), .o_rx_fifo_pop(w_rx_fifo_regs_pop),
.i_rx_fifo_items(w_rx_fifo_items), .i_rx_fifo_empty(w_rx_fifo_empty),
.i_rx_fifo_full(w_rx_fifo_full),
.i_rx_fifo_overrun(w_rx_fifo_overrun), .i_rx_fifo_overrun(w_rx_fifo_overrun),
.i_rx_fifo_items(w_rx_fifo_items),
.i_rx_fifo_data(w_rx_fifo_o_data), .i_rx_fifo_data(w_rx_fifo_o_data),
.o_tx_fifo_flush(w_tx_fifo_flush), .o_tx_fifo_flush(w_tx_fifo_flush),
.o_tx_fifo_push(w_tx_fifo_regs_push), .o_tx_fifo_push(w_tx_fifo_regs_push),
.i_tx_fifo_empty(w_tx_fifo_empty), .i_tx_fifo_empty(w_tx_fifo_empty),
.i_tx_fifo_full(w_tx_fifo_full), .i_tx_fifo_full(w_tx_fifo_full),
.i_tx_fifo_underrun(w_tx_fifo_underrun),
.i_tx_fifo_items(w_tx_fifo_items),
.o_tx_fifo_data(w_tx_fifo_i_data_regs), .o_tx_fifo_data(w_tx_fifo_i_data_regs),
.o_dma_bank(w_dma_bank), .o_dma_bank(w_dma_bank),

View File

@ -18,7 +18,7 @@ module sd_regs (
output reg o_dat_width, output reg o_dat_width,
output reg o_dat_direction, output reg o_dat_direction,
output reg [6:0] o_dat_block_size, output reg [6:0] o_dat_block_size,
output reg [10:0] o_dat_num_blocks, output reg [7:0] o_dat_num_blocks,
output reg o_dat_start, output reg o_dat_start,
output reg o_dat_stop, output reg o_dat_stop,
input i_dat_busy, input i_dat_busy,
@ -26,24 +26,28 @@ module sd_regs (
output reg o_rx_fifo_flush, output reg o_rx_fifo_flush,
output reg o_rx_fifo_pop, output reg o_rx_fifo_pop,
input [7:0] i_rx_fifo_items, input i_rx_fifo_empty,
input i_rx_fifo_full,
input i_rx_fifo_overrun, input i_rx_fifo_overrun,
input [8:0] i_rx_fifo_items,
input [31:0] i_rx_fifo_data, input [31:0] i_rx_fifo_data,
output reg o_tx_fifo_flush, output reg o_tx_fifo_flush,
output reg o_tx_fifo_push, output o_tx_fifo_push,
input i_tx_fifo_empty, input i_tx_fifo_empty,
input i_tx_fifo_full, input i_tx_fifo_full,
output reg [31:0] o_tx_fifo_data, input i_tx_fifo_underrun,
input [8:0] i_tx_fifo_items,
output [31:0] o_tx_fifo_data,
output reg [3:0] o_dma_bank, output [3:0] o_dma_bank,
output reg [23:0] o_dma_address, output [23:0] o_dma_address,
output reg [17:0] o_dma_length, output [14:0] o_dma_length,
input [3:0] i_dma_bank, input [3:0] i_dma_bank,
input [23:0] i_dma_address, input [23:0] i_dma_address,
input [17:0] i_dma_left, input [14:0] i_dma_left,
output reg o_dma_load_bank_address, output o_dma_load_bank_address,
output reg o_dma_load_length, output o_dma_load_length,
output reg o_dma_direction, output reg o_dma_direction,
output reg o_dma_start, output reg o_dma_start,
output reg o_dma_stop, output reg o_dma_stop,
@ -73,9 +77,11 @@ module sd_regs (
always @(*) begin always @(*) begin
o_dma_bank = i_data[31:28]; o_dma_bank = i_data[31:28];
o_dma_address = i_data[25:2]; o_dma_address = i_data[25:2];
o_dma_length = i_data[17:0]; o_dma_length = i_data[14:0];
o_dma_load_bank_address = w_write_request && !i_address[3] && (i_address[2:0] == SD_REG_DMA_ADDR); o_dma_load_bank_address = w_write_request && !i_address[3] && (i_address[2:0] == SD_REG_DMA_ADDR);
o_dma_load_length = w_write_request && !i_address[3] && (i_address[2:0] == SD_REG_DMA_LEN); o_dma_load_length = w_write_request && !i_address[3] && (i_address[2:0] == SD_REG_DMA_LEN);
o_tx_fifo_data = i_data;
o_tx_fifo_push = w_write_request && i_address[3] && !i_tx_fifo_full && !i_dma_busy;
o_busy = 1'b0; o_busy = 1'b0;
end end
@ -84,7 +90,6 @@ module sd_regs (
o_dat_start <= 1'b0; o_dat_start <= 1'b0;
o_rx_fifo_flush <= 1'b0; o_rx_fifo_flush <= 1'b0;
o_tx_fifo_flush <= 1'b0; o_tx_fifo_flush <= 1'b0;
o_tx_fifo_push <= 1'b0;
o_dma_start <= 1'b0; o_dma_start <= 1'b0;
o_dat_stop <= 1'b0; o_dat_stop <= 1'b0;
o_dma_stop <= 1'b0; o_dma_stop <= 1'b0;
@ -94,49 +99,62 @@ module sd_regs (
o_dat_width <= 1'b0; o_dat_width <= 1'b0;
o_dat_direction <= 1'b0; o_dat_direction <= 1'b0;
o_dat_block_size <= 7'd0; o_dat_block_size <= 7'd0;
o_dat_num_blocks <= 11'd0; o_dat_num_blocks <= 8'd0;
o_dma_direction <= 1'b0; o_dma_direction <= 1'b0;
end else if (w_write_request) begin end else if (w_write_request) begin
if (!i_address[3]) begin if (!i_address[3]) begin
case (i_address[2:0]) case (i_address[2:0])
SD_REG_SCR: begin SD_REG_SCR: begin
{o_dat_width, o_sd_clk_config} <= i_data[2:0]; if (!i_command_busy && !i_dat_busy) begin
o_sd_clk_config <= i_data[1:0];
end
if (!i_dat_busy) begin
o_dat_width <= i_data[2];
end
end end
SD_REG_ARG: begin SD_REG_ARG: begin
o_command_argument <= i_data; if (!i_command_busy) begin
o_command_argument <= i_data;
end
end end
SD_REG_CMD: begin SD_REG_CMD: begin
{ if (!i_command_busy) begin
o_command_skip_response, {
o_command_long_response, o_command_skip_response,
o_command_start, o_command_long_response,
o_command_index o_command_start,
} <= i_data[8:0]; o_command_index
} <= i_data[8:0];
end
end end
SD_REG_RSP: begin SD_REG_RSP: begin
end end
SD_REG_DAT: begin SD_REG_DAT: begin
{ if (!i_dat_busy || i_data[1]) begin
o_tx_fifo_flush, {
o_rx_fifo_flush, o_tx_fifo_flush,
o_dat_num_blocks, o_rx_fifo_flush,
o_dat_block_size, o_dat_num_blocks,
o_dat_direction, o_dat_block_size,
o_dat_stop, o_dat_direction,
o_dat_start o_dat_stop,
} <= i_data[22:0]; o_dat_start
} <= i_data[19:0];
end
end end
SD_REG_DMA_SCR: begin SD_REG_DMA_SCR: begin
{ if (!i_dma_busy || i_data[1]) begin
o_dma_direction, {
o_dma_stop, o_dma_direction,
o_dma_start o_dma_stop,
} <= i_data[2:0]; o_dma_start
} <= i_data[2:0];
end
end end
SD_REG_DMA_ADDR: begin SD_REG_DMA_ADDR: begin
@ -145,9 +163,6 @@ module sd_regs (
SD_REG_DMA_LEN: begin SD_REG_DMA_LEN: begin
end end
endcase endcase
end else begin
o_tx_fifo_push <= 1'b1;
o_tx_fifo_data <= i_data;
end end
end end
end end
@ -173,11 +188,9 @@ module sd_regs (
SD_REG_CMD: begin SD_REG_CMD: begin
o_data <= { o_data <= {
21'd0, 23'd0,
i_command_response_crc_error, i_command_response_crc_error,
i_command_timeout, i_command_timeout,
o_command_skip_response,
o_command_long_response,
i_command_busy, i_command_busy,
i_command_index i_command_index
}; };
@ -189,13 +202,15 @@ module sd_regs (
SD_REG_DAT: begin SD_REG_DAT: begin
o_data <= { o_data <= {
i_rx_fifo_items, 6'd0,
i_tx_fifo_items,
i_tx_fifo_full, i_tx_fifo_full,
i_tx_fifo_empty, i_tx_fifo_empty,
i_tx_fifo_underrun,
i_rx_fifo_items,
i_rx_fifo_full,
i_rx_fifo_empty,
i_rx_fifo_overrun, i_rx_fifo_overrun,
o_dat_num_blocks,
o_dat_block_size,
o_dat_direction,
i_dat_crc_error, i_dat_crc_error,
i_dat_busy i_dat_busy
}; };
@ -210,11 +225,13 @@ module sd_regs (
end end
SD_REG_DMA_LEN: begin SD_REG_DMA_LEN: begin
o_data <= {14'd0, i_dma_left}; o_data <= {17'd0, i_dma_left};
end end
endcase endcase
end else begin end else begin
o_rx_fifo_pop <= 1'b1; if (!i_rx_fifo_empty && !i_dma_busy) begin
o_rx_fifo_pop <= 1'b1;
end
o_data <= i_rx_fifo_data; o_data <= i_rx_fifo_data;
end end
end end

View File

@ -1,58 +1,67 @@
ROOTDIR = $(N64_INST) ROOTDIR = $(N64_INST)
GCCN64PREFIX = $(ROOTDIR)/bin/mips64-elf- GCCN64PREFIX = $(ROOTDIR)/bin/mips64-elf-
CHKSUM64PATH = $(ROOTDIR)/bin/chksum64
MKDFSPATH = $(ROOTDIR)/bin/mkdfs
HEADERPATH = $(ROOTDIR)/mips64-elf/lib
N64TOOL = $(ROOTDIR)/bin/n64tool
HEADERNAME = header
LINK_FLAGS = -L$(ROOTDIR)/mips64-elf/lib -ldragon -lc -lm -ldragonsys -Tn64.ld
CFLAGS = -std=gnu99 -march=vr4300 -mtune=vr4300 -Os -Wall -I./src -I./src/boot -I./src/fatfs -I./src/sc64 -I$(ROOTDIR)/mips64-elf/include
ASFLAGS = -mtune=vr4300 -march=vr4300
CC = $(GCCN64PREFIX)gcc CC = $(GCCN64PREFIX)gcc
AS = $(GCCN64PREFIX)as AS = $(GCCN64PREFIX)as
LD = $(GCCN64PREFIX)ld LD = $(GCCN64PREFIX)ld
OBJCOPY = $(GCCN64PREFIX)objcopy OBJCOPY = $(GCCN64PREFIX)objcopy
OBJDUMP = $(GCCN64PREFIX)objdump OBJDUMP = $(GCCN64PREFIX)objdump
SRC_DIRS = src src/boot src/fatfs src/sc64 CHKSUM64 = $(ROOTDIR)/bin/chksum64
SRC_FILES = $(wildcard $(patsubst %, %/*.c, . $(SRC_DIRS))) MKSPRITE = $(ROOTDIR)/bin/mksprite
OBJ_FILES = $(addprefix build/, $(notdir $(SRC_FILES:.c=.o))) N64TOOL = $(ROOTDIR)/bin/n64tool
VPATH = $(SRC_DIRS)
ROM_SIZE = 90k HEADER_PATH = $(ROOTDIR)/mips64-elf/lib
HEADER_NAME = header
ifeq ($(N64_BYTE_SWAP),true)
ROM_EXTENSION = .v64
N64_FLAGS = -b -l $(ROM_SIZE) -h $(HEADERPATH)/$(HEADERNAME) -o build/$(PROG_NAME)$(ROM_EXTENSION)
else
ROM_EXTENSION = .z64
N64_FLAGS = -l $(ROM_SIZE) -h $(HEADERPATH)/$(HEADERNAME) -o build/$(PROG_NAME)$(ROM_EXTENSION)
endif
PROG_NAME = SummerLoader64 PROG_NAME = SummerLoader64
all: make_output_dir build/$(PROG_NAME)$(ROM_EXTENSION) ROM_SIZE = 90k
SOURCE_DIR = src
BUILD_DIR = build
SRC_DIRS = $(SOURCE_DIR) $(sort $(dir $(wildcard $(SOURCE_DIR)/*/.)))
INC_DIRS = $(addprefix -I, . $(SRC_DIRS))
SRC_FILES = $(wildcard $(patsubst %, %/*.c, . $(SRC_DIRS)))
IMG_FILES = $(wildcard $(patsubst %, %/*.png, . $(SRC_DIRS)))
OBJ_FILES = $(addprefix $(BUILD_DIR)/, $(notdir $(IMG_FILES:.png=.o) $(SRC_FILES:.c=.o)))
VPATH = $(SRC_DIRS)
COMMONFLAGS = -march=vr4300 -mtune=vr4300
ASFLAGS = $(COMMONFLAGS)
CFLAGS = $(COMMONFLAGS) -std=gnu99 -Os -Wall -I$(ROOTDIR)/mips64-elf/include $(INC_DIRS)
LINK_FLAGS = -L$(ROOTDIR)/mips64-elf/lib -ldragon -lc -lm -ldragonsys -Tn64.ld
N64_FLAGS = -l $(ROM_SIZE) -h $(HEADER_PATH)/$(HEADER_NAME) -o $(BUILD_DIR)/$(PROG_NAME).z64
all: make_output_dir $(BUILD_DIR)/$(PROG_NAME).z64
$(OBJ_FILES): Makefile $(OBJ_FILES): Makefile
build/$(PROG_NAME)$(ROM_EXTENSION): build/$(PROG_NAME).elf $(BUILD_DIR)/$(PROG_NAME).z64: $(BUILD_DIR)/$(PROG_NAME).elf
$(OBJCOPY) build/$(PROG_NAME).elf build/$(PROG_NAME).bin -O binary $(OBJCOPY) $(BUILD_DIR)/$(PROG_NAME).elf $(BUILD_DIR)/$(PROG_NAME).bin -O binary
$(OBJDUMP) -S build/$(PROG_NAME).elf > build/$(PROG_NAME).lst $(OBJDUMP) -S $(BUILD_DIR)/$(PROG_NAME).elf > $(BUILD_DIR)/$(PROG_NAME).lst
rm -f build/$(PROG_NAME)$(ROM_EXTENSION) $(N64TOOL) $(N64_FLAGS) -t $(PROG_NAME) $(BUILD_DIR)/$(PROG_NAME).bin
$(N64TOOL) $(N64_FLAGS) -t $(PROG_NAME) build/$(PROG_NAME).bin $(CHKSUM64) $(BUILD_DIR)/$(PROG_NAME).z64
$(CHKSUM64PATH) build/$(PROG_NAME)$(ROM_EXTENSION) $(OBJCOPY) $(BUILD_DIR)/$(PROG_NAME).z64 $(BUILD_DIR)/$(PROG_NAME).hex -I binary -O ihex
$(OBJCOPY) build/$(PROG_NAME)$(ROM_EXTENSION) build/$(PROG_NAME).hex -I binary -O ihex
build/$(PROG_NAME).elf: $(OBJ_FILES) $(BUILD_DIR)/$(PROG_NAME).elf: $(OBJ_FILES)
$(LD) -o build/$(PROG_NAME).elf $(OBJ_FILES) $(LINK_FLAGS) $(LD) -o $(BUILD_DIR)/$(PROG_NAME).elf $(OBJ_FILES) $(LINK_FLAGS)
build/%.o: %.c $(BUILD_DIR)/%.o: %.c
$(COMPILE.c) $(OUTPUT_OPTION) $< $(COMPILE.c) $(OUTPUT_OPTION) $<
$(BUILD_DIR)/%.sprite: $(IMG_FILES)
$(MKSPRITE) 32 $< $@
$(BUILD_DIR)/%.o: $(BUILD_DIR)/%.sprite
$(OBJCOPY) -I binary -O elf32-bigmips -B mips:4000 --rename-section .data=.rodata $< $@
make_output_dir: make_output_dir:
$(shell mkdir ./build 2>/dev/null) $(shell mkdir ./$(BUILD_DIR) 2> /dev/null)
clean: clean:
rm -rf ./build $(shell rm -rf ./$(BUILD_DIR) 2> /dev/null)
.PHONY: all clean make_output_dir .PHONY: all clean make_output_dir

View File

@ -1,7 +1,3 @@
# SummerLoader64 # SummerLoader64
A N64 bootloader for SummerCart64. This project is mainly based on work by **`jago85`** contained in [Brutzelkarte_Bootloader repository](https://github.com/jago85/Brutzelkarte_Bootloader) with some modifications that made code a little bit more readable. A N64 bootloader for SummerCart64. This project is mainly based on work by **`jago85`** contained in [Brutzelkarte_Bootloader repository](https://github.com/jago85/Brutzelkarte_Bootloader) with some modifications that made code a little bit more readable.
## TODO
- Expand documentation

View File

@ -1,3 +1,10 @@
#!/bin/bash #!/bin/bash
docker run -t --mount type=bind,src="$(pwd)",target="/libdragon" anacierdem/libdragon:4.1.1 /bin/bash -c "/usr/bin/make clean; /usr/bin/make all N64_BYTE_SWAP=false" LIBDRAGON_DOCKER_VERSION=latest
docker \
run \
-t \
--mount type=bind,src=`realpath "$(dirname $0)"`,target="/libdragon" \
anacierdem/libdragon:$LIBDRAGON_DOCKER_VERSION \
/bin/bash -c "make clean && make all"

View File

@ -0,0 +1,12 @@
#ifndef ASSETS_H__
#define ASSETS_H__
#include <libdragon.h>
extern sprite_t _binary_build_sc64_logo_sprite_start[];
extern sprite_t _binary_build_sc64_logo_sprite_end[];
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -3,7 +3,10 @@
#include "n64_regs.h" #include "n64_regs.h"
static const struct crc32_to_cic_seed crc32_to_cic_seed[] = { static const struct crc32_to_cic_seed {
uint32_t ipl3_crc32;
uint16_t cic_seed;
} crc32_to_cic_seed[] = {
{ .ipl3_crc32 = 0x587BD543, .cic_seed = 0x00AC }, // CIC5101 { .ipl3_crc32 = 0x587BD543, .cic_seed = 0x00AC }, // CIC5101
{ .ipl3_crc32 = 0x6170A4A1, .cic_seed = 0x013F }, // CIC6101 { .ipl3_crc32 = 0x6170A4A1, .cic_seed = 0x013F }, // CIC6101
{ .ipl3_crc32 = 0x009E9EA3, .cic_seed = 0x013F }, // CIC7102 { .ipl3_crc32 = 0x009E9EA3, .cic_seed = 0x013F }, // CIC7102
@ -53,7 +56,7 @@ tv_type_t boot_get_tv_type(cart_header_t *cart_header) {
case 'W': case 'W':
case 'X': case 'X':
case 'Y': case 'Y':
return E_TV_TYPE_PAL; return TV_PAL;
case '7': case '7':
case 'A': case 'A':
case 'C': case 'C':
@ -62,11 +65,11 @@ tv_type_t boot_get_tv_type(cart_header_t *cart_header) {
case 'K': case 'K':
case 'N': case 'N':
case 'U': case 'U':
return E_TV_TYPE_NTSC; return TV_NTSC;
case 'B': case 'B':
return E_TV_TYPE_MPAL; return TV_MPAL;
default: default:
return E_TV_TYPE_UNKNOWN; return -1;
} }
} }
@ -78,7 +81,7 @@ void boot(cart_header_t *cart_header, uint16_t cic_seed, tv_type_t tv_type, uint
(cic_seed == crc32_to_cic_seed[8].cic_seed) || (cic_seed == crc32_to_cic_seed[8].cic_seed) ||
(cic_seed == crc32_to_cic_seed[9].cic_seed) (cic_seed == crc32_to_cic_seed[9].cic_seed)
); );
tv_type_t os_tv_type = tv_type == E_TV_TYPE_UNKNOWN ? OS_BOOT_CONFIG->tv_type : tv_type; tv_type_t os_tv_type = tv_type < 0 ? OS_BOOT_CONFIG->tv_type : tv_type;
volatile uint64_t gpr_regs[32]; volatile uint64_t gpr_regs[32];
@ -134,7 +137,7 @@ void boot(cart_header_t *cart_header, uint16_t cic_seed, tv_type_t tv_type, uint
gpr_regs[CPU_REG_S6] = BOOT_SEED_IPL3(cic_seed); gpr_regs[CPU_REG_S6] = BOOT_SEED_IPL3(cic_seed);
gpr_regs[CPU_REG_S7] = BOOT_SEED_OS_VERSION(cic_seed); gpr_regs[CPU_REG_S7] = BOOT_SEED_OS_VERSION(cic_seed);
gpr_regs[CPU_REG_SP] = CPU_ADDRESS_IN_REG(SP_MEM->imem[ARRAY_ITEMS(SP_MEM->imem) - 4]); gpr_regs[CPU_REG_SP] = CPU_ADDRESS_IN_REG(SP_MEM->imem[ARRAY_ITEMS(SP_MEM->imem) - 4]);
gpr_regs[CPU_REG_RA] = CPU_ADDRESS_IN_REG(SP_MEM->imem[(os_tv_type == E_TV_TYPE_PAL) ? 341 : 340]); gpr_regs[CPU_REG_RA] = CPU_ADDRESS_IN_REG(SP_MEM->imem[(os_tv_type == TV_PAL) ? 341 : 340]);
__asm__ ( __asm__ (
".set noat \n\t" ".set noat \n\t"

View File

@ -5,18 +5,6 @@
#include "platform.h" #include "platform.h"
struct crc32_to_cic_seed {
uint32_t ipl3_crc32;
uint16_t cic_seed;
};
typedef enum tv_type_e {
E_TV_TYPE_PAL,
E_TV_TYPE_NTSC,
E_TV_TYPE_MPAL,
E_TV_TYPE_UNKNOWN,
} tv_type_t;
struct cart_header_s { struct cart_header_s {
uint32_t pi_conf; uint32_t pi_conf;
uint32_t clock_rate; uint32_t clock_rate;

View File

@ -1,45 +0,0 @@
#include <stdio.h>
#include "error_display.h"
void error_display_and_halt(menu_load_error_t error, const char *path) {
init_interrupts();
display_init(RESOLUTION_320x240, DEPTH_32_BPP, 2, GAMMA_NONE, ANTIALIAS_RESAMPLE);
console_init();
console_set_render_mode(RENDER_MANUAL);
console_clear();
printf("SC64 Bootloader ver. %d.%02d error:\n\n%2d: ", BOOTLOADER_VERSION_MAJOR, BOOTLOADER_VERSION_MINOR, error);
switch (error) {
case E_MENU_OK:
printf("No error :O");
break;
case E_MENU_ERROR_NOT_SC64:
printf("SummerCart64 not detected");
break;
case E_MENU_ERROR_NO_CARD:
printf("SD Card not detected");
break;
case E_MENU_ERROR_NO_FILESYSTEM:
printf("No filesystem (FAT or exFAT)\nfound on SD Card");
break;
case E_MENU_ERROR_NO_FILE:
printf("Unable to locate menu file:\n(%s)", path);
break;
case E_MENU_ERROR_READ_ERROR:
printf("Error while reading data from\nSD Card");
break;
case E_MENU_ERROR_OTHER_ERROR:
default:
printf("Unknown error");
break;
}
console_render();
while (1);
}

View File

@ -1,8 +1,5 @@
#ifndef ERROR_DISPLAY_H__ #ifndef ERRORS_H__
#define ERROR_DISPLAY_H__ #define ERRORS_H__
#include "platform.h"
typedef enum menu_load_error_e { typedef enum menu_load_error_e {
@ -13,10 +10,8 @@ typedef enum menu_load_error_e {
E_MENU_ERROR_NO_FILE, E_MENU_ERROR_NO_FILE,
E_MENU_ERROR_READ_ERROR, E_MENU_ERROR_READ_ERROR,
E_MENU_ERROR_OTHER_ERROR, E_MENU_ERROR_OTHER_ERROR,
E_MENU_END,
} menu_load_error_t; } menu_load_error_t;
void error_display_and_halt(menu_load_error_t error, const char *path);
#endif #endif

View File

@ -48,6 +48,14 @@ DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) {
return RES_OK; return RES_OK;
} }
#if !FF_FS_READONLY
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) {
return RES_ERROR;
}
#endif
DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) { DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) {
return RES_PARERR; return RES_PARERR;
} }

View File

@ -8,7 +8,7 @@
/ Function Configurations / Function Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define FF_FS_READONLY 1 #define FF_FS_READONLY 0
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) /* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(), / Read-only configuration removes writing API functions, f_write(), f_sync(),
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()

View File

@ -0,0 +1,106 @@
#include <libdragon.h>
#include "platform.h"
#include "assets/assets.h"
#include "loader.h"
#define X_OFFSET (24)
#define Y_OFFSET (16)
#define Y_PADDING (12)
#define LAST_CHAR(s) (sizeof(s) - 1)
#define EDIT_CHAR(s, n) s[(n) >= 0 ? 0 : LAST_CHAR((s)) + (n)]
#define NTOA(n) ('0' + ((n) % 10))
static char version_string[] = "SC64 Bootloader ver. X.X";
static char error_number_string[] = "ERROR X";
static const char *error_strings[] = {
"No error :O",
"SummerCart64 not detected",
"SD Card not detected",
"No filesystem (FAT or exFAT)\nfound on SD Card",
"Unable to locate menu file",
"Error while reading data from\nSD Card",
"Unknown error",
};
static int x_offset = X_OFFSET;
static int y_offset = Y_OFFSET;
static display_context_t loader_get_display(void) {
display_context_t display;
do {
display = display_lock();
} while (!display);
x_offset = X_OFFSET;
y_offset = Y_OFFSET;
return display;
}
static void loader_draw_version_and_logo(display_context_t display) {
EDIT_CHAR(version_string, -3) = NTOA(BOOTLOADER_VERSION_MAJOR);
EDIT_CHAR(version_string, -1) = NTOA(BOOTLOADER_VERSION_MINOR);
graphics_draw_text(display, x_offset, y_offset, version_string);
y_offset += Y_PADDING;
sprite_t *logo = _binary_build_sc64_logo_sprite_start;
int center_x = (320 / 2) - (logo->width / 2);
int center_y = (240 / 2) - (logo->height / 2);
graphics_draw_sprite(display, center_x, center_y, logo);
}
void loader_init(void) {
display_context_t display;
init_interrupts();
audio_init(44100, 2);
audio_write_silence();
display_init(RESOLUTION_320x240, DEPTH_32_BPP, 2, GAMMA_NONE, ANTIALIAS_OFF);
display = loader_get_display();
loader_draw_version_and_logo(display);
display_show(display);
}
void loader_cleanup(void) {
audio_close();
display_close();
}
void loader_display_error_and_halt(menu_load_error_t error, const char *path) {
display_context_t display;
display = loader_get_display();
loader_draw_version_and_logo(display);
EDIT_CHAR(error_number_string, -1) = NTOA(error);
graphics_draw_text(display, x_offset, y_offset, error_number_string);
y_offset += Y_PADDING;
int error_string_index = error >= E_MENU_END ? (E_MENU_END - 1) : error;
const char *error_string = error_strings[error_string_index];
graphics_draw_text(display, x_offset, y_offset, error_string);
y_offset += Y_PADDING;
if (error == E_MENU_ERROR_NO_FILE) {
graphics_draw_text(display, x_offset, y_offset, path);
}
display_show(display);
while (1);
}

View File

@ -0,0 +1,13 @@
#ifndef LOADER_H__
#define LOADER_H__
#include "errors.h"
void loader_init(void);
void loader_cleanup(void);
void loader_display_error_and_halt(menu_load_error_t error, const char *path);
#endif

View File

@ -1,16 +1,17 @@
#include "boot.h" #include "boot/boot.h"
#include "error_display.h" #include "loader/loader.h"
#include "sc64/sc64.h"
#include "sc64.h" #include "sc64/sc64_sd_fs.h"
#include "sc64_sd_fs.h"
static const char *MENU_FILE_PATH = "SC64/MENU.z64"; static const char *MENU_FILE_PATH = "SC64/MENU.z64";
int main(void) { int main(void) {
loader_init();
if (sc64_get_version() != SC64_CART_VERSION_A) { if (sc64_get_version() != SC64_CART_VERSION_A) {
error_display_and_halt(E_MENU_ERROR_NOT_SC64, MENU_FILE_PATH); loader_display_error_and_halt(E_MENU_ERROR_NOT_SC64, "");
} }
sc64_enable_rom_switch(); sc64_enable_rom_switch();
@ -50,7 +51,7 @@ int main(void) {
} }
if (error != E_MENU_OK) { if (error != E_MENU_OK) {
error_display_and_halt(error, MENU_FILE_PATH); loader_display_error_and_halt(error, MENU_FILE_PATH);
} }
} }
@ -70,5 +71,7 @@ int main(void) {
tv_type = boot_get_tv_type(cart_header); tv_type = boot_get_tv_type(cart_header);
} }
loader_cleanup();
boot(cart_header, cic_seed, tv_type, ddipl_override); boot(cart_header, cic_seed, tv_type, ddipl_override);
} }

View File

@ -11,10 +11,6 @@
#define BOOTLOADER_VERSION_MAJOR (1) #define BOOTLOADER_VERSION_MAJOR (1)
#define BOOTLOADER_VERSION_MINOR (0) #define BOOTLOADER_VERSION_MINOR (0)
#define TRUE (1)
#define FALSE (0)
#define __IO volatile #define __IO volatile
typedef uint32_t reg_t; typedef uint32_t reg_t;

View File

@ -27,7 +27,7 @@ typedef struct sc64_cart_registers {
__IO reg_t USB_DMA_LEN; // USB transfer length for DMA to PC __IO reg_t USB_DMA_LEN; // USB transfer length for DMA to PC
__IO reg_t DDIPL_ADDR; // 64 Disk Drive IPL location in SDRAM __IO reg_t DDIPL_ADDR; // 64 Disk Drive IPL location in SDRAM
__IO reg_t SRAM_ADDR; // SRAM save emulation location in SDRAM __IO reg_t SRAM_ADDR; // SRAM save emulation location in SDRAM
__IO reg_t __reserved[1015]; __IO reg_t __unused[1015];
__IO reg_t USB_FIFO[1024]; // USB data from PC read FIFO memory end __IO reg_t USB_FIFO[1024]; // USB data from PC read FIFO memory end
} sc64_cart_registers_t; } sc64_cart_registers_t;
@ -35,6 +35,7 @@ typedef struct sc64_cart_registers {
#define SC64_CART ((__IO sc64_cart_registers_t *) SC64_CART_BASE) #define SC64_CART ((__IO sc64_cart_registers_t *) SC64_CART_BASE)
#define SC64_CART_SCR_FLASHRAM_ENABLE (1 << 9) #define SC64_CART_SCR_FLASHRAM_ENABLE (1 << 9)
#define SC64_CART_SCR_SRAM_768K_MODE (1 << 8) #define SC64_CART_SCR_SRAM_768K_MODE (1 << 8)
#define SC64_CART_SCR_SRAM_ENABLE (1 << 7) #define SC64_CART_SCR_SRAM_ENABLE (1 << 7)
@ -52,6 +53,7 @@ typedef struct sc64_cart_registers {
#define SC64_CART_BOOT_DDIPL_OVERRIDE (1 << 12) #define SC64_CART_BOOT_DDIPL_OVERRIDE (1 << 12)
#define SC64_CART_BOOT_TV_TYPE_BIT (10) #define SC64_CART_BOOT_TV_TYPE_BIT (10)
#define SC64_CART_BOOT_TV_TYPE_MASK (0x3 << SC64_CART_BOOT_TV_TYPE_BIT) #define SC64_CART_BOOT_TV_TYPE_MASK (0x3 << SC64_CART_BOOT_TV_TYPE_BIT)
#define SC64_CART_BOOT_ROM_LOADED (1 << 9)
#define SC64_CART_BOOT_CIC_SEED_BIT (0) #define SC64_CART_BOOT_CIC_SEED_BIT (0)
#define SC64_CART_BOOT_CIC_SEED_MASK (0x1FF << SC64_CART_BOOT_CIC_SEED_BIT) #define SC64_CART_BOOT_CIC_SEED_MASK (0x1FF << SC64_CART_BOOT_CIC_SEED_BIT)
@ -123,6 +125,7 @@ typedef struct sc64_sd_registers_s {
#define SC64_SD ((__IO sc64_sd_registers_t *) SC64_SD_BASE) #define SC64_SD ((__IO sc64_sd_registers_t *) SC64_SD_BASE)
#define SC64_SD_SCR_DAT_WIDTH (1 << 2) #define SC64_SD_SCR_DAT_WIDTH (1 << 2)
#define SC64_SD_SCR_CLK_MASK (0x3 << 0) #define SC64_SD_SCR_CLK_MASK (0x3 << 0)
#define SC64_SD_SCR_CLK_STOP (0 << 0) #define SC64_SD_SCR_CLK_STOP (0 << 0)
@ -130,43 +133,53 @@ typedef struct sc64_sd_registers_s {
#define SC64_SD_SCR_CLK_25_MHZ (2 << 0) #define SC64_SD_SCR_CLK_25_MHZ (2 << 0)
#define SC64_SD_SCR_CLK_50_MHZ (3 << 0) #define SC64_SD_SCR_CLK_50_MHZ (3 << 0)
#define SC64_SD_CMD_RESPONSE_CRC_ERROR (1 << 10)
#define SC64_SD_CMD_TIMEOUT (1 << 9) #define SC64_SD_CMD_RESPONSE_CRC_ERROR (1 << 8)
#define SC64_SD_CMD_TIMEOUT (1 << 7)
#define SC64_SD_CMD_BUSY (1 << 6)
#define SC64_SD_CMD_INDEX_GET(cmd) ((cmd) & 0x3F)
#define SC64_SD_CMD_SKIP_RESPONSE (1 << 8) #define SC64_SD_CMD_SKIP_RESPONSE (1 << 8)
#define SC64_SD_CMD_LONG_RESPONSE (1 << 7) #define SC64_SD_CMD_LONG_RESPONSE (1 << 7)
#define SC64_SD_CMD_BUSY (1 << 6)
#define SC64_SD_CMD_START (1 << 6) #define SC64_SD_CMD_START (1 << 6)
#define SC64_SD_CMD_INDEX_GET(cmd) ((cmd) & 0x3F)
#define SC64_SD_CMD_INDEX(i) ((i) & 0x3F) #define SC64_SD_CMD_INDEX(i) ((i) & 0x3F)
#define SC64_SD_DAT_RX_FIFO_FULL (1 << 31)
#define SC64_SD_DAT_RX_FIFO_ITEMS_GET(dat) (((dat) >> 24) & 0xFF) #define SC64_SD_DAT_TX_FIFO_ITEMS_GET(dat) (((dat) >> 17) & 0x1FF)
#define SC64_SD_DAT_TX_FIFO_FULL (1 << 23) #define SC64_SD_DAT_TX_FIFO_FULL (1 << 16)
#define SC64_SD_DAT_TX_FIFO_EMPTY (1 << 22) #define SC64_SD_DAT_TX_FIFO_EMPTY (1 << 15)
#define SC64_SD_DAT_TX_FIFO_FLUSH (1 << 22) #define SC64_SD_DAT_TX_FIFO_UNDERRUN (1 << 14)
#define SC64_SD_DAT_RX_FIFO_OVERRUN (1 << 21) #define SC64_SD_DAT_RX_FIFO_ITEMS_GET(dat) (((dat) >> 5) & 0x1FF)
#define SC64_SD_DAT_RX_FIFO_FLUSH (1 << 21) #define SC64_SD_DAT_RX_FIFO_FULL (1 << 4)
#define SC64_SD_DAT_NUM_BLOCKS_GET(dat) ((((dat) >> 10) & 0x7FF) + 1) #define SC64_SD_DAT_RX_FIFO_EMPTY (1 << 3)
#define SC64_SD_DAT_NUM_BLOCKS(nb) ((((nb) - 1) & 0x7FF) << 10) #define SC64_SD_DAT_RX_FIFO_OVERRUN (1 << 2)
#define SC64_SD_DAT_BLOCK_SIZE_GET(dat) (((((dat) >> 3) & 0x7F) + 1) * 4) #define SC64_SD_DAT_CRC_ERROR (1 << 1)
#define SC64_SD_DAT_BUSY (1 << 0)
#define SC64_SD_DAT_TX_FIFO_FLUSH (1 << 19)
#define SC64_SD_DAT_RX_FIFO_FLUSH (1 << 18)
#define SC64_SD_DAT_NUM_BLOCKS(nb) ((((nb) - 1) & 0xFF) << 10)
#define SC64_SD_DAT_BLOCK_SIZE(bs) (((((bs) / 4) - 1) & 0x7F) << 3) #define SC64_SD_DAT_BLOCK_SIZE(bs) (((((bs) / 4) - 1) & 0x7F) << 3)
#define SC64_SD_DAT_DIRECTION (1 << 2) #define SC64_SD_DAT_DIRECTION (1 << 2)
#define SC64_SD_DAT_CRC_ERROR (1 << 1)
#define SC64_SD_DAT_STOP (1 << 1) #define SC64_SD_DAT_STOP (1 << 1)
#define SC64_SD_DAT_BUSY (1 << 0)
#define SC64_SD_DAT_START (1 << 0) #define SC64_SD_DAT_START (1 << 0)
#define SC64_SD_DMA_SCR_BUSY (1 << 0)
#define SC64_SD_DMA_SCR_DIRECTION (1 << 2) #define SC64_SD_DMA_SCR_DIRECTION (1 << 2)
#define SC64_SD_DMA_SCR_STOP (1 << 1) #define SC64_SD_DMA_SCR_STOP (1 << 1)
#define SC64_SD_DMA_SCR_BUSY (1 << 0)
#define SC64_SD_DMA_SCR_START (1 << 0) #define SC64_SD_DMA_SCR_START (1 << 0)
#define SC64_SD_DMA_ADDR_GET(addr) ((addr) & 0x3FFFFFC) #define SC64_SD_DMA_ADDR_GET(addr) ((addr) & 0x3FFFFFC)
#define SC64_SD_DMA_BANK_GET(addr) (((addr) >> 28) & 0xF) #define SC64_SD_DMA_BANK_GET(addr) (((addr) >> 28) & 0xF)
#define SC64_SD_DMA_BANK_ADDR(b, a) ((((b) & 0xF) << 28) | ((a) & 0x3FFFFFC)) #define SC64_SD_DMA_BANK_ADDR(b, a) ((((b) & 0xF) << 28) | ((a) & 0x3FFFFFC))
#define SC64_SD_DMA_LEN_GET(len) (((len) & 0x3FFFF) * 4) #define SC64_SD_DMA_LEN_GET(len) (((len) & 0x7FFF) * 4)
#define SC64_SD_DMA_LEN(l) ((((l) / 4) - 1) & 0x3FFFF)
#define SC64_SD_DMA_LEN(l) ((((l) / 4) - 1) & 0x7FFF)
#endif #endif

View File

@ -15,6 +15,8 @@
#define SD_BLOCK_SIZE (512) #define SD_BLOCK_SIZE (512)
#define MAX_NUM_BLOCKS (256)
typedef enum sc64_sd_clock_e { typedef enum sc64_sd_clock_e {
CLOCK_STOP, CLOCK_STOP,
@ -86,6 +88,7 @@ static void sc64_sd_set_dat_width(sc64_sd_dat_width_t dat_width) {
static void sc64_sd_hw_init(void) { static void sc64_sd_hw_init(void) {
sc64_enable_sd(); sc64_enable_sd();
while (platform_pi_io_read(&SC64_SD->CMD) & SC64_SD_CMD_BUSY);
platform_pi_io_write(&SC64_SD->DMA_SCR, SC64_SD_DMA_SCR_STOP); platform_pi_io_write(&SC64_SD->DMA_SCR, SC64_SD_DMA_SCR_STOP);
platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_TX_FIFO_FLUSH | SC64_SD_DAT_RX_FIFO_FLUSH | SC64_SD_DAT_STOP); platform_pi_io_write(&SC64_SD->DAT, SC64_SD_DAT_TX_FIFO_FLUSH | SC64_SD_DAT_RX_FIFO_FLUSH | SC64_SD_DAT_STOP);
platform_pi_io_write(&SC64_SD->SCR, 0); platform_pi_io_write(&SC64_SD->SCR, 0);
@ -156,7 +159,7 @@ static void sc64_sd_dat_prepare(size_t num_blocks, size_t block_size, sc64_sd_da
platform_pi_io_write(&SC64_SD->DAT, ( platform_pi_io_write(&SC64_SD->DAT, (
SC64_SD_DAT_NUM_BLOCKS(num_blocks) | SC64_SD_DAT_NUM_BLOCKS(num_blocks) |
SC64_SD_DAT_BLOCK_SIZE(block_size) | SC64_SD_DAT_BLOCK_SIZE(block_size) |
(direction ? SC64_SD_DAT_DIRECTION : 0) | ((direction == DAT_DIR_TX) ? SC64_SD_DAT_DIRECTION : 0) |
SC64_SD_DAT_START SC64_SD_DAT_START
)); ));
} }
@ -179,7 +182,7 @@ static sc64_sd_err_t sc64_sd_dat_read(size_t block_size, void *buffer) {
if (SC64_SD_DAT_RX_FIFO_ITEMS_GET(reg) >= block_size) { if (SC64_SD_DAT_RX_FIFO_ITEMS_GET(reg) >= block_size) {
break; break;
} }
} while ((reg & SC64_SD_DAT_BUSY) && (timeout--)); } while ((reg & SC64_SD_DAT_BUSY) && (--timeout));
if (reg & SC64_SD_DAT_CRC_ERROR) { if (reg & SC64_SD_DAT_CRC_ERROR) {
return E_CRC_ERROR; return E_CRC_ERROR;
@ -350,7 +353,7 @@ sc64_sd_err_t sc64_sd_read_sectors(uint32_t starting_sector, size_t count, void
timeout = 100000; timeout = 100000;
do { do {
reg = platform_pi_io_read(&SC64_SD->DAT); reg = platform_pi_io_read(&SC64_SD->DAT);
} while ((reg & SC64_SD_DAT_BUSY) && (timeout--)); } while ((reg & SC64_SD_DAT_BUSY) && (--timeout));
if (reg & SC64_SD_DAT_CRC_ERROR) { if (reg & SC64_SD_DAT_CRC_ERROR) {
return E_CRC_ERROR; return E_CRC_ERROR;
@ -404,7 +407,7 @@ sc64_sd_err_t sc64_sd_read_sectors_dma(uint32_t starting_sector, size_t count, u
current_address = address; current_address = address;
do { do {
num_blocks = (sectors_left > 2048) ? 2048 : sectors_left; num_blocks = (sectors_left > MAX_NUM_BLOCKS) ? MAX_NUM_BLOCKS : sectors_left;
platform_pi_io_write(&SC64_SD->DMA_ADDR, SC64_SD_DMA_BANK_ADDR(bank, current_address)); platform_pi_io_write(&SC64_SD->DMA_ADDR, SC64_SD_DMA_BANK_ADDR(bank, current_address));
platform_pi_io_write(&SC64_SD->DMA_LEN, SC64_SD_DMA_LEN(num_blocks * SD_BLOCK_SIZE)); platform_pi_io_write(&SC64_SD->DMA_LEN, SC64_SD_DMA_LEN(num_blocks * SD_BLOCK_SIZE));
@ -421,7 +424,7 @@ sc64_sd_err_t sc64_sd_read_sectors_dma(uint32_t starting_sector, size_t count, u
timeout = 1000000; timeout = 1000000;
do { do {
reg = platform_pi_io_read(&SC64_SD->DAT); reg = platform_pi_io_read(&SC64_SD->DAT);
} while ((reg & SC64_SD_DAT_BUSY) && (timeout--)); } while ((reg & SC64_SD_DAT_BUSY) && (--timeout));
error = sc64_sd_cmd_send(12, 0, NO_FLAGS, &response); error = sc64_sd_cmd_send(12, 0, NO_FLAGS, &response);
if (error != E_OK) { if (error != E_OK) {