Merge branch 'main' into new-irq

This commit is contained in:
Mateusz Faderewski 2024-05-20 17:05:39 +02:00
commit e163ae814f
54 changed files with 183246 additions and 69372 deletions

View File

@ -147,6 +147,9 @@ jobs:
- name: Download SummerCart64 repository
uses: actions/checkout@v4
- name: Copy BOM file to the website folder
run: cp ./hw/pcb/sc64v2_bom.html ./web
- name: Setup GitHub pages
uses: actions/configure-pages@v4

View File

@ -1,4 +1,4 @@
# SummerCart64 - a fully open source Nintendo 64 flashcart
# SummerCart64 - a fully open source N64 flashcart
[<img src="assets/sc64_logo.svg" />](assets/sc64_logo.svg)
**For non-technical description of the SummerCart64, please head to the https://summercart64.dev website!**
@ -52,7 +52,7 @@ Note that my time is limited so I can't answer all questions.
Most up to date information about purchasing/manufacturing options is available on https://summercart64.dev website!
If you want to order it yourself then I've prepared all necessary manufacturing files on the [PCBWay Shared Project](https://www.pcbway.com/project/shareproject/SC64_an_open_source_Nintendo_64_flashcart_14b9688a.html) site.
If you want to order it yourself then I've prepared all necessary manufacturing files on the [PCBWay Shared Project](https://www.pcbway.com/project/member/shareproject/?bmbno=1046ED64-8AEE-44) site.
**Be careful**: this is an advanced project and it is assumed that you have enough knowledge about electronics.
Selecting wrong options or giving PCB manufacturer wrong information might result in an undesired time and/or money loss.
@ -61,7 +61,7 @@ Boards also come unprogrammed from the manufacturer - you need to do **initial p
To avoid problems _**please**_ read **both** [build guide](./docs/06_build_guide.md) and description on the shared project page **in full**.
If you have even slightest doubt about the ordering or programming process, it is better to leave it to someone experienced - ask in the [n64brew Discord server](https://discord.gg/WqFgNWf) if that's the case.
**Full disclosure**: for every order made through [this link](https://www.pcbway.com/project/shareproject/SC64_an_open_source_Nintendo_64_flashcart_14b9688a.html) I will receive 10% of PCB manufacturing and PCB assembly service cost (price of the components is not included in the split). This is a great way of supporting further project development.
**Full disclosure**: for every order made through [this link](https://www.pcbway.com/project/member/shareproject/?bmbno=1046ED64-8AEE-44) I will receive 10% of PCB manufacturing and PCB assembly service cost (price of the components is not included in the split). This is a great way of supporting further project development.
If you don't need a physical product but still want to support me then check my [GitHub sponsors](https://github.com/sponsors/Polprzewodnikowy) page.
@ -87,8 +87,10 @@ If you don't need a physical product but still want to support me then check my
This project wouldn't be possible without these contributions:
- [64drive](https://64drive.retroactive.be) orders being on permanent hold long before creating this repository.
- [64drive](https://64drive.retroactive.be) ([archived](https://web.archive.org/web/20240406215731/https://64drive.retroactive.be/)) orders being on permanent hold long before creating this repository.
- [EverDrive-64 X7](https://krikzz.com/our-products/cartridges/ed64x7.html) being disappointment for homebrew development (slow USB upload, unjustified price and overcomplicated SD card access).
- Context: Both aforementioned products were priced at $199 in 2020. 64drive features made it a vastly more useful tool for homebrew development.
Since then, 64drive had never been restocked and EverDrive-64 X7 price was lowered to $159 (as of May 2024).
- [Jan Goldacker (@jago85)](https://github.com/jago85) and his projects:
- [Brutzelkarte](https://github.com/jago85/Brutzelkarte_FPGA) providing solid base for starting this project and sparking hope for true open source N64 flashcarts.
- [UltraCIC_C](https://github.com/jago85/UltraCIC_C) reimplementation for easy integration in modern microcontrollers. Thanks also goes to everyone involved in N64 CIC reverse engineering.

View File

@ -17,7 +17,7 @@ TOP_FILES=(
FILES=(
"./assets/*"
"./docs/*"
"./hw/pcb/sc64_hw_v2.0a_bom.html"
"./hw/pcb/sc64v2_bom.html"
"./hw/pcb/sc64v2.kicad_pcb"
"./hw/pcb/sc64v2.kicad_pro"
"./hw/pcb/sc64v2.kicad_sch"

View File

@ -42,7 +42,7 @@ Please download latest release before proceeding with the instructions.
### **Components**
1. Locate interactive BOM file inside `hw/pcb` folder
1. Locate interactive BOM file inside `hw/pcb` folder (alternatively, check out this [BOM discussion](https://github.com/Polprzewodnikowy/SummerCart64/discussions/27))
2. Order all parts listed in the BOM file or use PCB assembly service together with your PCB order
---
@ -75,6 +75,7 @@ You will require the following hardware:
- A USB to UART (serial) adapter (with 3.3V signaling is required, e.g. TTL-232R-3V3).
You will require the following applications and packages:
- [Latest FTDI drivers](https://ftdichip.com/drivers/)
- [FT_PROG](https://ftdichip.com/utilities/#ft_prog) - FTDI FT232H EEPROM programming software.
- [Python 3](https://www.python.org/downloads/) with `pip3` - necessary for initial programming script: `primer.py` (Windows install: check option add python to PATH).
- [`sc64-extra-{version}.zip`](https://github.com/Polprzewodnikowy/SummerCart64/releases) - programming scripts and firmware files, download the latest version.
@ -82,10 +83,11 @@ You will require the following applications and packages:
**Programming must be done in specific order for `primer.py` script to work correctly.**
Preparations:
1. Install FT_PROG.
2. Install Python 3.
3. Unpack `sc64-extra-{version}.zip` into a folder.
4. Open terminal and navigate to the folder you've unpacked SC64 files.
1. Install latest FTDI drivers (especially on Windows 10).
2. Install FT_PROG.
3. Install Python 3.
4. Unpack `sc64-extra-{version}.zip` into a folder.
5. Open terminal and navigate to the folder you've unpacked SC64 files.
First, program the ***FT232H EEPROM***:
1. Connect the SC64 board to your PC with a USB-C cable.

View File

@ -1,4 +1,4 @@
# SummerCart64 - a fully open source Nintendo 64 flashcart
# SummerCart64 - a fully open source N64 flashcart
[<img src="../assets/sc64_logo.svg" />](../assets/sc64_logo.svg)
## Documentation

View File

@ -96,6 +96,9 @@ IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "sdram_ras" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "sdram_we" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "test_point[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "test_point[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "test_point[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "usb_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
IOBUF PORT "usb_cs" PULLMODE=UP IO_TYPE=LVCMOS33 ;
IOBUF PORT "usb_miosi[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 ;
@ -194,6 +197,9 @@ LOCATE COMP "sdram_dqm[0]" SITE "97" ;
LOCATE COMP "sdram_dqm[1]" SITE "73" ;
LOCATE COMP "sdram_ras" SITE "94" ;
LOCATE COMP "sdram_we" SITE "96" ;
LOCATE COMP "test_point[0]" SITE "23" ;
LOCATE COMP "test_point[1]" SITE "24" ;
LOCATE COMP "test_point[2]" SITE "25" ;
LOCATE COMP "usb_clk" SITE "12" ;
LOCATE COMP "usb_cs" SITE "11" ;
LOCATE COMP "usb_miosi[0]" SITE "22" ;
@ -213,3 +219,43 @@ BLOCK PATH TO PORT "mcu_int" ;
BLOCK PATH TO PORT "n64_irq" ;
BLOCK PATH FROM PORT "usb_pwrsav" ;
BLOCK PATH FROM PORT "sd_det" ;
DEFINE PORT GROUP "sdram_output" "sdram_cs"
"sdram_ras"
"sdram_cas"
"sdram_we"
"sdram_ba[1]"
"sdram_ba[0]"
"sdram_a[12]"
"sdram_a[11]"
"sdram_a[10]"
"sdram_a[9]"
"sdram_a[8]"
"sdram_a[7]"
"sdram_a[6]"
"sdram_a[5]"
"sdram_a[4]"
"sdram_a[3]"
"sdram_a[2]"
"sdram_a[1]"
"sdram_a[0]"
"sdram_dqm[1]"
"sdram_dqm[0]" ;
DEFINE PORT GROUP "sdram_bidir" "sdram_dq[15]"
"sdram_dq[14]"
"sdram_dq[13]"
"sdram_dq[12]"
"sdram_dq[11]"
"sdram_dq[10]"
"sdram_dq[9]"
"sdram_dq[8]"
"sdram_dq[7]"
"sdram_dq[6]"
"sdram_dq[5]"
"sdram_dq[4]"
"sdram_dq[3]"
"sdram_dq[2]"
"sdram_dq[1]"
"sdram_dq[0]" ;
INPUT_SETUP GROUP "sdram_bidir"INPUT_DELAY 5.400000 ns HOLD -2.500000 ns CLKNET "clk" CLK_OFFSET -0.250000 X ;
CLOCK_TO_OUT GROUP "sdram_output" OUTPUT_DELAY 1.500000 ns MIN 0.800000 ns CLKNET "clk" CLKOUT PORT "sdram_clk" ;
CLOCK_TO_OUT GROUP "sdram_bidir" OUTPUT_DELAY 1.500000 ns MIN 0.800000 ns CLKNET "clk" CLKOUT PORT "sdram_clk" ;

View File

@ -234,7 +234,7 @@ module memory_flash (
if (reset) begin
state <= STATE_IDLE;
end else begin
if (!busy && (start || finish)) begin
if ((start || finish) && !busy) begin
counter <= counter + 1'd1;
end
@ -248,6 +248,7 @@ module memory_flash (
end else if (mem_bus.request) begin
current_address <= {mem_bus.address[23:1], 1'b0};
if (mem_bus.write) begin
current_address[0] <= (~mem_bus.wmask[1]);
state <= STATE_WRITE_ENABLE;
end else begin
state <= STATE_READ_START;
@ -263,7 +264,7 @@ module memory_flash (
end
3'd1: begin
finish <= 1'b1;
wdata <= 8'd4;
wdata <= 8'd5;
if (!busy) begin
counter <= 3'd0;
if (flash_scb.erase_pending) begin
@ -296,7 +297,7 @@ module memory_flash (
end
3'd4: begin
finish <= 1'b1;
wdata <= 8'd4;
wdata <= 8'd5;
if (!busy) begin
flash_scb.erase_done <= 1'b1;
counter <= 3'd0;
@ -314,17 +315,17 @@ module memory_flash (
end
3'd1: begin
start <= 1'b1;
wdata <= mem_bus.address[23:16];
wdata <= current_address[23:16];
end
3'd2: begin
start <= 1'b1;
wdata <= mem_bus.address[15:8];
wdata <= current_address[15:8];
end
3'd3: begin
start <= 1'b1;
wdata <= mem_bus.address[7:0];
wdata <= current_address[7:0];
if (!busy) begin
counter <= 3'd0;
counter <= 3'd0 + current_address[0];
state <= STATE_PROGRAM;
end
end
@ -336,26 +337,33 @@ module memory_flash (
3'd0: begin
start <= 1'b1;
wdata <= mem_bus.wdata[15:8];
if (start && !busy) begin
current_address <= current_address + 1'd1;
if (!mem_bus.wmask[0]) begin
counter <= 3'd2;
mem_bus.ack <= 1'b1;
end
end
end
3'd1: begin
start <= 1'b1;
wdata <= mem_bus.wdata[7:0];
if (!busy) begin
mem_bus.ack <= 1'b1;
current_address <= current_address + 2'd2;
current_address <= current_address + 1'd1;
end
end
3'd2: begin
if (current_address[7:0] == 8'h00) begin
state <= STATE_PROGRAM_END;
end else if (flash_scb.erase_pending) begin
state <= STATE_PROGRAM_END;
end else if (mem_bus.request && !mem_bus.ack) begin
if (!mem_bus.write || (mem_bus.address[23:0] != current_address)) begin
state <= STATE_PROGRAM_END;
end else begin
if (mem_bus.write && mem_bus.wmask[1] && (mem_bus.address[23:0] == current_address)) begin
counter <= 3'd0;
end else begin
state <= STATE_PROGRAM_END;
end
end else if (!busy) begin
state <= STATE_PROGRAM_END;
end
end
endcase
@ -363,8 +371,8 @@ module memory_flash (
STATE_PROGRAM_END: begin
finish <= 1'b1;
wdata <= 8'd4;
if (!busy) begin
wdata <= 8'd5;
if (finish && !busy) begin
counter <= 3'd0;
state <= STATE_WAIT;
end
@ -407,15 +415,15 @@ module memory_flash (
3'd1: begin
start <= 1'b1;
quad_enable <= 1'b1;
wdata <= mem_bus.address[23:16];
wdata <= current_address[23:16];
end
3'd2: begin
start <= 1'b1;
wdata <= mem_bus.address[15:8];
wdata <= current_address[15:8];
end
3'd3: begin
start <= 1'b1;
wdata <= mem_bus.address[7:0];
wdata <= current_address[7:0];
end
3'd4: begin
start <= 1'b1;

View File

@ -37,8 +37,13 @@ module n64_cic (
end
logic cic_dq_out;
logic cic_dq_oe;
assign n64_cic_dq = cic_dq_out ? 1'bZ : 1'b0;
always_ff @(posedge clk) begin
cic_dq_oe <= ~cic_dq_out;
end
assign n64_cic_dq = cic_dq_oe ? 1'b0 : 1'bZ;
// Timer (divider and counter)

View File

@ -51,7 +51,10 @@ module top (
output mcu_miso,
// Unused I/O
output n64_video_sync
output n64_video_sync,
output [2:0] test_point
);
logic clk;
@ -278,4 +281,6 @@ module top (
assign n64_video_sync = 1'bZ;
assign test_point = 3'b000;
endmodule

View File

@ -1,7 +1,7 @@
/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.12.1.454 */
/* Verilog netlist generated by SCUBA Diamond (64-bit) 3.13.0.56.2 */
/* Module Version: 5.7 */
/* C:\lscc\diamond\3.12\ispfpga\bin\nt64\scuba.exe -w -n pll_lattice_generated -lang verilog -synth synplify -arch xo2c00 -type pll -fin 50 -fclkop 100 -fclkop_tol 0.0 -fclkos 100 -fclkos_tol 0.0 -trimp 0 -phasep 0 -trimp_r -trims 0 -phases 90 -trims_r -phase_cntl STATIC -fb_mode 1 -lock */
/* Sat Mar 19 17:10:12 2022 */
/* C:\lscc\diamond\3.13\ispfpga\bin\nt64\scuba.exe -w -n pll_lattice_generated -lang verilog -synth synplify -arch xo2c00 -type pll -fin 50 -fclkop 100 -fclkop_tol 0.0 -fclkos 100 -fclkos_tol 0.0 -trimp 0 -phasep 0 -trimp_r -trims 0 -phases 270 -trims_r -phase_cntl STATIC -fb_mode 1 -lock */
/* Sun May 05 06:07:05 2024 */
`timescale 1 ns / 1 ps
@ -29,8 +29,8 @@ module pll_lattice_generated (CLKI, CLKOP, CLKOS, LOCK)/* synthesis NGD_DRC_MASK
defparam PLLInst_0.CLKOS3_CPHASE = 0 ;
defparam PLLInst_0.CLKOS2_FPHASE = 0 ;
defparam PLLInst_0.CLKOS2_CPHASE = 0 ;
defparam PLLInst_0.CLKOS_FPHASE = 2 ;
defparam PLLInst_0.CLKOS_CPHASE = 5 ;
defparam PLLInst_0.CLKOS_FPHASE = 6 ;
defparam PLLInst_0.CLKOS_CPHASE = 7 ;
defparam PLLInst_0.CLKOP_FPHASE = 0 ;
defparam PLLInst_0.CLKOP_CPHASE = 4 ;
defparam PLLInst_0.PLL_LOCK_MODE = 0 ;

View File

@ -17,8 +17,8 @@ module pll (
);
ODDRXE oddrxe_sdram_clk_inst (
.D0(1'b0),
.D1(1'b1),
.D0(1'b1),
.D1(1'b0),
.SCLK(pll_sdram_clk),
.RST(1'b0),
.Q(buf_sdram_clk)

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -3,14 +3,17 @@
"3dviewports": [],
"design_settings": {
"defaults": {
"board_outline_line_width": 0.09999999999999999,
"copper_line_width": 0.19999999999999998,
"apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false,
"board_outline_line_width": 0.1,
"copper_line_width": 0.2,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": false,
"courtyard_line_width": 0.049999999999999996,
"courtyard_line_width": 0.05,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
@ -21,7 +24,7 @@
"text_position": 0,
"units_format": 1
},
"fab_line_width": 0.09999999999999999,
"fab_line_width": 0.1,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
@ -34,9 +37,9 @@
"other_text_thickness": 0.15,
"other_text_upright": false,
"pads": {
"drill": 0.762,
"height": 1.524,
"width": 1.524
"drill": 2.5,
"height": 2.5,
"width": 2.5
},
"silk_line_width": 0.15,
"silk_text_italic": false,
@ -63,20 +66,27 @@
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"connection_width": "warning",
"copper_edge_clearance": "error",
"copper_sliver": "warning",
"courtyards_overlap": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint": "error",
"footprint_symbol_mismatch": "warning",
"footprint_type_mismatch": "error",
"hole_clearance": "error",
"hole_near_hole": "error",
"invalid_outline": "error",
"isolated_copper": "warning",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"lib_footprint_issues": "warning",
"lib_footprint_mismatch": "warning",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore",
@ -86,9 +96,14 @@
"padstack": "error",
"pth_inside_courtyard": "ignore",
"shorting_items": "error",
"silk_edge_clearance": "warning",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"solder_mask_bridge": "error",
"starved_thermal": "error",
"text_height": "warning",
"text_thickness": "warning",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_dangling": "warning",
@ -97,7 +112,6 @@
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zone_has_empty_net": "error",
"zones_intersect": "error"
},
"rules": {
@ -105,25 +119,99 @@
"allow_microvias": false,
"max_error": 0.005,
"min_clearance": 0.127,
"min_copper_edge_clearance": 0.19999999999999998,
"min_connection": 0.0,
"min_copper_edge_clearance": 0.2,
"min_hole_clearance": 0.254,
"min_hole_to_hole": 0.5,
"min_microvia_diameter": 0.19999999999999998,
"min_microvia_drill": 0.09999999999999999,
"min_microvia_diameter": 0.2,
"min_microvia_drill": 0.1,
"min_resolved_spokes": 2,
"min_silk_clearance": 0.0,
"min_text_height": 0.8,
"min_text_thickness": 0.08,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.127,
"min_via_annular_width": 0.13,
"min_via_diameter": 0.6,
"solder_mask_clearance": 0.0,
"solder_mask_min_width": 0.0,
"solder_mask_to_copper_clearance": 0.0,
"use_height_for_length_calcs": true
},
"teardrop_options": [
{
"td_onpadsmd": true,
"td_onroundshapesonly": false,
"td_ontrackend": false,
"td_onviapad": true
}
],
"teardrop_parameters": [
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_round_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_rect_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_track_end",
"td_width_to_size_filter_ratio": 0.9
}
],
"track_widths": [
0.0,
0.508,
0.762
],
"tuning_pattern_settings": {
"diff_pair_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 1.0
},
"diff_pair_skew_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
},
"single_track_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
}
},
"via_dimensions": [
{
"diameter": 0.0,
@ -133,6 +221,13 @@
"zones_allow_external_fillets": false,
"zones_use_no_outline": true
},
"ipc2581": {
"dist": "",
"distpn": "",
"internal_id": "",
"mfg": "",
"mpn": ""
},
"layer_presets": [],
"viewports": []
},
@ -391,14 +486,75 @@
"gencad": "",
"idf": "",
"netlist": "",
"plot": "",
"pos_files": "",
"specctra_dsn": "",
"step": "",
"svg": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"bom_fmt_presets": [],
"bom_fmt_settings": {
"field_delimiter": ",",
"keep_line_breaks": false,
"keep_tabs": false,
"name": "CSV",
"ref_delimiter": ",",
"ref_range_delimiter": "",
"string_delimiter": "\""
},
"bom_presets": [],
"bom_settings": {
"exclude_dnp": false,
"fields_ordered": [
{
"group_by": false,
"label": "Reference",
"name": "Reference",
"show": true
},
{
"group_by": true,
"label": "Value",
"name": "Value",
"show": true
},
{
"group_by": false,
"label": "Datasheet",
"name": "Datasheet",
"show": true
},
{
"group_by": false,
"label": "Footprint",
"name": "Footprint",
"show": true
},
{
"group_by": false,
"label": "Qty",
"name": "${QUANTITY}",
"show": true
},
{
"group_by": true,
"label": "DNP",
"name": "${DNP}",
"show": true
}
],
"filter_string": "",
"group_symbols": true,
"name": "Grouped By Value",
"sort_asc": true,
"sort_field": "Oznaczenie"
},
"connection_grid_size": 50.0,
"drawing": {
"dashed_lines_dash_length_ratio": 12.0,
"dashed_lines_gap_length_ratio": 3.0,
@ -412,6 +568,11 @@
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"operating_point_overlay_i_precision": 3,
"operating_point_overlay_i_range": "~A",
"operating_point_overlay_v_precision": 3,
"operating_point_overlay_v_range": "~V",
"overbar_offset_ratio": 1.23,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.15
},
@ -437,6 +598,7 @@
"spice_external_command": "spice \"%I\"",
"spice_model_current_sheet_as_root": true,
"spice_save_all_currents": false,
"spice_save_all_dissipations": false,
"spice_save_all_voltages": false,
"subpart_first_id": 65,
"subpart_id_separator": 0
@ -444,7 +606,7 @@
"sheets": [
[
"e63e39d7-6ac0-4ffd-8aa3-1841a4541b55",
""
"Główny"
]
],
"text_variables": {}

File diff suppressed because it is too large Load Diff

4669
hw/pcb/sc64v2_bom.html generated Normal file

File diff suppressed because one or more lines are too long

12
hw/shell/README.md Normal file
View File

@ -0,0 +1,12 @@
# SummerCart64 shell design files
This folder contains several different designs of the SummerCart64 shell and button
`./` folder contains original design made by [Mateusz Faderewski 'Polprzewodnikowy'](https://github.com/Polprzewodnikowy) in the Autodesk Fusion 360 and exported `.stl` files ready for 3D print.
`./injection mold` folder contains adapted design for injection molding process by [Mena 'Pheeeeenom'](https://github.com/Pheeeeenom).
`./button` folder contains designs for the button on the back of the SummerCart64. Designs are:
- `sc64_shell_button_b3fs-101x.stl` - for the Omron B3FS-101x button (by [Mason Stooksbury](https://github.com/MasonStooksbury))
- `sc64_shell_button_b3fs-105x.step` - for the Omron B3FS-105x button (by [Mena 'Pheeeeenom'](https://github.com/Pheeeeenom))
- `sc64_shell_button_b3fs-105x_with_end_stop.step` - for the Omron B3FS-105x button but with additional flange to prevent it from coming out of the shell (by [Mena 'Pheeeeenom'](https://github.com/Pheeeeenom))

View File

@ -0,0 +1,600 @@
ISO-10303-21;
HEADER;
/* Generated by software containing ST-Developer
* from STEP Tools, Inc. (www.steptools.com)
*/
FILE_DESCRIPTION(
/* description */ (''),
/* implementation_level */ '2;1');
FILE_NAME(
/* name */ 'sc64_shell_button v3.step',
/* time_stamp */ '2024-01-03T20:51:50-06:00',
/* author */ (''),
/* organization */ (''),
/* preprocessor_version */ 'ST-DEVELOPER v20',
/* originating_system */ 'Autodesk Translation Framework v12.14.0.127',
/* authorisation */ '');
FILE_SCHEMA (('AUTOMOTIVE_DESIGN { 1 0 10303 214 3 1 1 }'));
ENDSEC;
DATA;
#10=MECHANICAL_DESIGN_GEOMETRIC_PRESENTATION_REPRESENTATION('',(#13),#504);
#11=SHAPE_REPRESENTATION_RELATIONSHIP('SRR','None',#510,#12);
#12=ADVANCED_BREP_SHAPE_REPRESENTATION('',(#14),#503);
#13=STYLED_ITEM('',(#522),#14);
#14=MANIFOLD_SOLID_BREP('ButtonCap',#299);
#15=CYLINDRICAL_SURFACE('',#320,3.);
#16=TOROIDAL_SURFACE('',#316,2.8,0.2);
#17=ELLIPSE('',#309,57.3219678278922,3.);
#18=ELLIPSE('',#311,57.3219678278922,3.);
#19=ELLIPSE('',#315,57.3219678278922,3.);
#20=ELLIPSE('',#322,57.3219678278922,3.);
#21=CIRCLE('',#307,3.);
#22=CIRCLE('',#313,3.);
#23=CIRCLE('',#317,2.8);
#24=CIRCLE('',#318,0.2);
#25=CIRCLE('',#319,3.);
#26=CIRCLE('',#321,3.);
#27=CIRCLE('',#323,3.);
#28=CIRCLE('',#324,3.);
#29=FACE_OUTER_BOUND('',#45,.T.);
#30=FACE_OUTER_BOUND('',#46,.T.);
#31=FACE_OUTER_BOUND('',#47,.T.);
#32=FACE_OUTER_BOUND('',#48,.T.);
#33=FACE_OUTER_BOUND('',#49,.T.);
#34=FACE_OUTER_BOUND('',#50,.T.);
#35=FACE_OUTER_BOUND('',#51,.T.);
#36=FACE_OUTER_BOUND('',#52,.T.);
#37=FACE_OUTER_BOUND('',#53,.T.);
#38=FACE_OUTER_BOUND('',#54,.T.);
#39=FACE_OUTER_BOUND('',#55,.T.);
#40=FACE_OUTER_BOUND('',#56,.T.);
#41=FACE_OUTER_BOUND('',#57,.T.);
#42=FACE_OUTER_BOUND('',#58,.T.);
#43=FACE_OUTER_BOUND('',#59,.T.);
#44=FACE_OUTER_BOUND('',#60,.T.);
#45=EDGE_LOOP('',(#187,#188,#189,#190));
#46=EDGE_LOOP('',(#191,#192,#193,#194,#195,#196,#197,#198));
#47=EDGE_LOOP('',(#199,#200,#201,#202));
#48=EDGE_LOOP('',(#203,#204,#205,#206,#207,#208,#209,#210));
#49=EDGE_LOOP('',(#211,#212,#213,#214));
#50=EDGE_LOOP('',(#215,#216,#217,#218,#219,#220));
#51=EDGE_LOOP('',(#221,#222,#223,#224));
#52=EDGE_LOOP('',(#225,#226,#227,#228));
#53=EDGE_LOOP('',(#229,#230,#231,#232));
#54=EDGE_LOOP('',(#233,#234,#235,#236));
#55=EDGE_LOOP('',(#237,#238,#239,#240));
#56=EDGE_LOOP('',(#241,#242,#243,#244,#245,#246,#247,#248,#249,#250,#251,
#252));
#57=EDGE_LOOP('',(#253));
#58=EDGE_LOOP('',(#254,#255,#256,#257));
#59=EDGE_LOOP('',(#258,#259,#260,#261));
#60=EDGE_LOOP('',(#262,#263,#264,#265,#266,#267,#268));
#61=LINE('',#420,#90);
#62=LINE('',#422,#91);
#63=LINE('',#424,#92);
#64=LINE('',#425,#93);
#65=LINE('',#429,#94);
#66=LINE('',#431,#95);
#67=LINE('',#432,#96);
#68=LINE('',#434,#97);
#69=LINE('',#436,#98);
#70=LINE('',#438,#99);
#71=LINE('',#439,#100);
#72=LINE('',#442,#101);
#73=LINE('',#443,#102);
#74=LINE('',#447,#103);
#75=LINE('',#449,#104);
#76=LINE('',#451,#105);
#77=LINE('',#453,#106);
#78=LINE('',#454,#107);
#79=LINE('',#455,#108);
#80=LINE('',#457,#109);
#81=LINE('',#460,#110);
#82=LINE('',#463,#111);
#83=LINE('',#466,#112);
#84=LINE('',#471,#113);
#85=LINE('',#474,#114);
#86=LINE('',#478,#115);
#87=LINE('',#488,#116);
#88=LINE('',#497,#117);
#89=LINE('',#498,#118);
#90=VECTOR('',#333,10.);
#91=VECTOR('',#334,10.);
#92=VECTOR('',#335,10.);
#93=VECTOR('',#336,10.);
#94=VECTOR('',#339,10.);
#95=VECTOR('',#340,10.);
#96=VECTOR('',#341,10.);
#97=VECTOR('',#342,10.);
#98=VECTOR('',#343,10.);
#99=VECTOR('',#344,10.);
#100=VECTOR('',#345,10.);
#101=VECTOR('',#348,10.);
#102=VECTOR('',#349,10.);
#103=VECTOR('',#352,10.);
#104=VECTOR('',#353,10.);
#105=VECTOR('',#354,10.);
#106=VECTOR('',#355,10.);
#107=VECTOR('',#356,10.);
#108=VECTOR('',#357,10.);
#109=VECTOR('',#360,10.);
#110=VECTOR('',#363,10.);
#111=VECTOR('',#366,10.);
#112=VECTOR('',#369,10.);
#113=VECTOR('',#376,10.);
#114=VECTOR('',#379,10.);
#115=VECTOR('',#384,10.);
#116=VECTOR('',#397,3.);
#117=VECTOR('',#410,10.);
#118=VECTOR('',#411,10.);
#119=VERTEX_POINT('',#418);
#120=VERTEX_POINT('',#419);
#121=VERTEX_POINT('',#421);
#122=VERTEX_POINT('',#423);
#123=VERTEX_POINT('',#427);
#124=VERTEX_POINT('',#428);
#125=VERTEX_POINT('',#430);
#126=VERTEX_POINT('',#433);
#127=VERTEX_POINT('',#435);
#128=VERTEX_POINT('',#437);
#129=VERTEX_POINT('',#441);
#130=VERTEX_POINT('',#445);
#131=VERTEX_POINT('',#446);
#132=VERTEX_POINT('',#448);
#133=VERTEX_POINT('',#450);
#134=VERTEX_POINT('',#452);
#135=VERTEX_POINT('',#459);
#136=VERTEX_POINT('',#461);
#137=VERTEX_POINT('',#465);
#138=VERTEX_POINT('',#469);
#139=VERTEX_POINT('',#473);
#140=VERTEX_POINT('',#477);
#141=VERTEX_POINT('',#481);
#142=VERTEX_POINT('',#483);
#143=VERTEX_POINT('',#487);
#144=VERTEX_POINT('',#489);
#145=VERTEX_POINT('',#491);
#146=EDGE_CURVE('',#119,#120,#61,.T.);
#147=EDGE_CURVE('',#121,#119,#62,.T.);
#148=EDGE_CURVE('',#122,#121,#63,.T.);
#149=EDGE_CURVE('',#120,#122,#64,.T.);
#150=EDGE_CURVE('',#123,#124,#65,.T.);
#151=EDGE_CURVE('',#125,#123,#66,.T.);
#152=EDGE_CURVE('',#125,#119,#67,.T.);
#153=EDGE_CURVE('',#126,#120,#68,.T.);
#154=EDGE_CURVE('',#127,#126,#69,.T.);
#155=EDGE_CURVE('',#128,#127,#70,.T.);
#156=EDGE_CURVE('',#124,#128,#71,.T.);
#157=EDGE_CURVE('',#129,#125,#72,.T.);
#158=EDGE_CURVE('',#129,#121,#73,.T.);
#159=EDGE_CURVE('',#130,#131,#74,.T.);
#160=EDGE_CURVE('',#132,#130,#75,.T.);
#161=EDGE_CURVE('',#133,#132,#76,.T.);
#162=EDGE_CURVE('',#134,#133,#77,.T.);
#163=EDGE_CURVE('',#134,#122,#78,.T.);
#164=EDGE_CURVE('',#131,#129,#79,.T.);
#165=EDGE_CURVE('',#126,#134,#80,.T.);
#166=EDGE_CURVE('',#123,#135,#81,.F.);
#167=EDGE_CURVE('',#136,#135,#21,.T.);
#168=EDGE_CURVE('',#136,#131,#82,.F.);
#169=EDGE_CURVE('',#124,#137,#83,.F.);
#170=EDGE_CURVE('',#135,#137,#17,.T.);
#171=EDGE_CURVE('',#138,#136,#18,.T.);
#172=EDGE_CURVE('',#138,#130,#84,.F.);
#173=EDGE_CURVE('',#139,#128,#85,.F.);
#174=EDGE_CURVE('',#137,#139,#22,.T.);
#175=EDGE_CURVE('',#140,#127,#86,.F.);
#176=EDGE_CURVE('',#139,#140,#19,.T.);
#177=EDGE_CURVE('',#141,#141,#23,.T.);
#178=EDGE_CURVE('',#141,#142,#24,.T.);
#179=EDGE_CURVE('',#142,#142,#25,.T.);
#180=EDGE_CURVE('',#142,#143,#87,.T.);
#181=EDGE_CURVE('',#143,#144,#26,.T.);
#182=EDGE_CURVE('',#144,#145,#20,.T.);
#183=EDGE_CURVE('',#145,#138,#27,.T.);
#184=EDGE_CURVE('',#140,#143,#28,.T.);
#185=EDGE_CURVE('',#132,#145,#88,.F.);
#186=EDGE_CURVE('',#133,#144,#89,.F.);
#187=ORIENTED_EDGE('',*,*,#146,.F.);
#188=ORIENTED_EDGE('',*,*,#147,.F.);
#189=ORIENTED_EDGE('',*,*,#148,.F.);
#190=ORIENTED_EDGE('',*,*,#149,.F.);
#191=ORIENTED_EDGE('',*,*,#150,.F.);
#192=ORIENTED_EDGE('',*,*,#151,.F.);
#193=ORIENTED_EDGE('',*,*,#152,.T.);
#194=ORIENTED_EDGE('',*,*,#146,.T.);
#195=ORIENTED_EDGE('',*,*,#153,.F.);
#196=ORIENTED_EDGE('',*,*,#154,.F.);
#197=ORIENTED_EDGE('',*,*,#155,.F.);
#198=ORIENTED_EDGE('',*,*,#156,.F.);
#199=ORIENTED_EDGE('',*,*,#157,.F.);
#200=ORIENTED_EDGE('',*,*,#158,.T.);
#201=ORIENTED_EDGE('',*,*,#147,.T.);
#202=ORIENTED_EDGE('',*,*,#152,.F.);
#203=ORIENTED_EDGE('',*,*,#159,.F.);
#204=ORIENTED_EDGE('',*,*,#160,.F.);
#205=ORIENTED_EDGE('',*,*,#161,.F.);
#206=ORIENTED_EDGE('',*,*,#162,.F.);
#207=ORIENTED_EDGE('',*,*,#163,.T.);
#208=ORIENTED_EDGE('',*,*,#148,.T.);
#209=ORIENTED_EDGE('',*,*,#158,.F.);
#210=ORIENTED_EDGE('',*,*,#164,.F.);
#211=ORIENTED_EDGE('',*,*,#165,.F.);
#212=ORIENTED_EDGE('',*,*,#153,.T.);
#213=ORIENTED_EDGE('',*,*,#149,.T.);
#214=ORIENTED_EDGE('',*,*,#163,.F.);
#215=ORIENTED_EDGE('',*,*,#164,.T.);
#216=ORIENTED_EDGE('',*,*,#157,.T.);
#217=ORIENTED_EDGE('',*,*,#151,.T.);
#218=ORIENTED_EDGE('',*,*,#166,.T.);
#219=ORIENTED_EDGE('',*,*,#167,.F.);
#220=ORIENTED_EDGE('',*,*,#168,.T.);
#221=ORIENTED_EDGE('',*,*,#150,.T.);
#222=ORIENTED_EDGE('',*,*,#169,.T.);
#223=ORIENTED_EDGE('',*,*,#170,.F.);
#224=ORIENTED_EDGE('',*,*,#166,.F.);
#225=ORIENTED_EDGE('',*,*,#159,.T.);
#226=ORIENTED_EDGE('',*,*,#168,.F.);
#227=ORIENTED_EDGE('',*,*,#171,.F.);
#228=ORIENTED_EDGE('',*,*,#172,.T.);
#229=ORIENTED_EDGE('',*,*,#156,.T.);
#230=ORIENTED_EDGE('',*,*,#173,.F.);
#231=ORIENTED_EDGE('',*,*,#174,.F.);
#232=ORIENTED_EDGE('',*,*,#169,.F.);
#233=ORIENTED_EDGE('',*,*,#155,.T.);
#234=ORIENTED_EDGE('',*,*,#175,.F.);
#235=ORIENTED_EDGE('',*,*,#176,.F.);
#236=ORIENTED_EDGE('',*,*,#173,.T.);
#237=ORIENTED_EDGE('',*,*,#177,.T.);
#238=ORIENTED_EDGE('',*,*,#178,.T.);
#239=ORIENTED_EDGE('',*,*,#179,.T.);
#240=ORIENTED_EDGE('',*,*,#178,.F.);
#241=ORIENTED_EDGE('',*,*,#179,.F.);
#242=ORIENTED_EDGE('',*,*,#180,.T.);
#243=ORIENTED_EDGE('',*,*,#181,.T.);
#244=ORIENTED_EDGE('',*,*,#182,.T.);
#245=ORIENTED_EDGE('',*,*,#183,.T.);
#246=ORIENTED_EDGE('',*,*,#171,.T.);
#247=ORIENTED_EDGE('',*,*,#167,.T.);
#248=ORIENTED_EDGE('',*,*,#170,.T.);
#249=ORIENTED_EDGE('',*,*,#174,.T.);
#250=ORIENTED_EDGE('',*,*,#176,.T.);
#251=ORIENTED_EDGE('',*,*,#184,.T.);
#252=ORIENTED_EDGE('',*,*,#180,.F.);
#253=ORIENTED_EDGE('',*,*,#177,.F.);
#254=ORIENTED_EDGE('',*,*,#161,.T.);
#255=ORIENTED_EDGE('',*,*,#185,.T.);
#256=ORIENTED_EDGE('',*,*,#182,.F.);
#257=ORIENTED_EDGE('',*,*,#186,.F.);
#258=ORIENTED_EDGE('',*,*,#160,.T.);
#259=ORIENTED_EDGE('',*,*,#172,.F.);
#260=ORIENTED_EDGE('',*,*,#183,.F.);
#261=ORIENTED_EDGE('',*,*,#185,.F.);
#262=ORIENTED_EDGE('',*,*,#162,.T.);
#263=ORIENTED_EDGE('',*,*,#186,.T.);
#264=ORIENTED_EDGE('',*,*,#181,.F.);
#265=ORIENTED_EDGE('',*,*,#184,.F.);
#266=ORIENTED_EDGE('',*,*,#175,.T.);
#267=ORIENTED_EDGE('',*,*,#154,.T.);
#268=ORIENTED_EDGE('',*,*,#165,.T.);
#269=PLANE('',#301);
#270=PLANE('',#302);
#271=PLANE('',#303);
#272=PLANE('',#304);
#273=PLANE('',#305);
#274=PLANE('',#306);
#275=PLANE('',#308);
#276=PLANE('',#310);
#277=PLANE('',#312);
#278=PLANE('',#314);
#279=PLANE('',#325);
#280=PLANE('',#326);
#281=PLANE('',#327);
#282=PLANE('',#328);
#283=ADVANCED_FACE('',(#29),#269,.F.);
#284=ADVANCED_FACE('',(#30),#270,.F.);
#285=ADVANCED_FACE('',(#31),#271,.F.);
#286=ADVANCED_FACE('',(#32),#272,.F.);
#287=ADVANCED_FACE('',(#33),#273,.F.);
#288=ADVANCED_FACE('',(#34),#274,.F.);
#289=ADVANCED_FACE('',(#35),#275,.F.);
#290=ADVANCED_FACE('',(#36),#276,.F.);
#291=ADVANCED_FACE('',(#37),#277,.F.);
#292=ADVANCED_FACE('',(#38),#278,.F.);
#293=ADVANCED_FACE('',(#39),#16,.T.);
#294=ADVANCED_FACE('',(#40),#15,.T.);
#295=ADVANCED_FACE('',(#41),#279,.T.);
#296=ADVANCED_FACE('',(#42),#280,.F.);
#297=ADVANCED_FACE('',(#43),#281,.F.);
#298=ADVANCED_FACE('',(#44),#282,.F.);
#299=CLOSED_SHELL('',(#283,#284,#285,#286,#287,#288,#289,#290,#291,#292,
#293,#294,#295,#296,#297,#298));
#300=AXIS2_PLACEMENT_3D('',#416,#329,#330);
#301=AXIS2_PLACEMENT_3D('',#417,#331,#332);
#302=AXIS2_PLACEMENT_3D('',#426,#337,#338);
#303=AXIS2_PLACEMENT_3D('',#440,#346,#347);
#304=AXIS2_PLACEMENT_3D('',#444,#350,#351);
#305=AXIS2_PLACEMENT_3D('',#456,#358,#359);
#306=AXIS2_PLACEMENT_3D('',#458,#361,#362);
#307=AXIS2_PLACEMENT_3D('',#462,#364,#365);
#308=AXIS2_PLACEMENT_3D('',#464,#367,#368);
#309=AXIS2_PLACEMENT_3D('',#467,#370,#371);
#310=AXIS2_PLACEMENT_3D('',#468,#372,#373);
#311=AXIS2_PLACEMENT_3D('',#470,#374,#375);
#312=AXIS2_PLACEMENT_3D('',#472,#377,#378);
#313=AXIS2_PLACEMENT_3D('',#475,#380,#381);
#314=AXIS2_PLACEMENT_3D('',#476,#382,#383);
#315=AXIS2_PLACEMENT_3D('',#479,#385,#386);
#316=AXIS2_PLACEMENT_3D('',#480,#387,#388);
#317=AXIS2_PLACEMENT_3D('',#482,#389,#390);
#318=AXIS2_PLACEMENT_3D('',#484,#391,#392);
#319=AXIS2_PLACEMENT_3D('',#485,#393,#394);
#320=AXIS2_PLACEMENT_3D('',#486,#395,#396);
#321=AXIS2_PLACEMENT_3D('',#490,#398,#399);
#322=AXIS2_PLACEMENT_3D('',#492,#400,#401);
#323=AXIS2_PLACEMENT_3D('',#493,#402,#403);
#324=AXIS2_PLACEMENT_3D('',#494,#404,#405);
#325=AXIS2_PLACEMENT_3D('',#495,#406,#407);
#326=AXIS2_PLACEMENT_3D('',#496,#408,#409);
#327=AXIS2_PLACEMENT_3D('',#499,#412,#413);
#328=AXIS2_PLACEMENT_3D('',#500,#414,#415);
#329=DIRECTION('axis',(0.,0.,1.));
#330=DIRECTION('refdir',(1.,0.,0.));
#331=DIRECTION('center_axis',(0.,0.,1.));
#332=DIRECTION('ref_axis',(1.,0.,0.));
#333=DIRECTION('',(-1.,0.,0.));
#334=DIRECTION('',(0.,1.,0.));
#335=DIRECTION('',(1.,0.,0.));
#336=DIRECTION('',(0.,-1.,0.));
#337=DIRECTION('center_axis',(0.,1.,0.));
#338=DIRECTION('ref_axis',(-1.,0.,0.));
#339=DIRECTION('',(-0.0523359562429438,0.,0.998629534754574));
#340=DIRECTION('',(-1.,0.,0.));
#341=DIRECTION('',(0.,0.,1.));
#342=DIRECTION('',(0.,0.,1.));
#343=DIRECTION('',(-1.,0.,0.));
#344=DIRECTION('',(-0.0523359562429438,0.,-0.998629534754574));
#345=DIRECTION('',(-1.,0.,0.));
#346=DIRECTION('center_axis',(1.,0.,0.));
#347=DIRECTION('ref_axis',(0.,1.,0.));
#348=DIRECTION('',(0.,1.,0.));
#349=DIRECTION('',(0.,0.,1.));
#350=DIRECTION('center_axis',(0.,-1.,0.));
#351=DIRECTION('ref_axis',(1.,0.,0.));
#352=DIRECTION('',(0.0523359562429438,0.,-0.998629534754574));
#353=DIRECTION('',(1.,0.,0.));
#354=DIRECTION('',(0.0523359562429438,0.,0.998629534754574));
#355=DIRECTION('',(1.,0.,0.));
#356=DIRECTION('',(0.,0.,1.));
#357=DIRECTION('',(1.,0.,0.));
#358=DIRECTION('center_axis',(-1.,0.,0.));
#359=DIRECTION('ref_axis',(0.,-1.,0.));
#360=DIRECTION('',(0.,-1.,0.));
#361=DIRECTION('center_axis',(0.,0.,1.));
#362=DIRECTION('ref_axis',(1.,0.,0.));
#363=DIRECTION('',(0.,-1.,0.));
#364=DIRECTION('center_axis',(0.,0.,1.));
#365=DIRECTION('ref_axis',(1.,0.,0.));
#366=DIRECTION('',(0.,-1.,0.));
#367=DIRECTION('center_axis',(0.998629534754574,0.,0.0523359562429438));
#368=DIRECTION('ref_axis',(0.,1.,0.));
#369=DIRECTION('',(0.,-1.,0.));
#370=DIRECTION('center_axis',(0.998629534754574,0.,0.0523359562429438));
#371=DIRECTION('ref_axis',(0.0523359562429438,0.,-0.998629534754574));
#372=DIRECTION('center_axis',(0.998629534754574,0.,0.0523359562429438));
#373=DIRECTION('ref_axis',(0.,1.,0.));
#374=DIRECTION('center_axis',(0.998629534754574,0.,0.0523359562429438));
#375=DIRECTION('ref_axis',(0.0523359562429438,0.,-0.998629534754574));
#376=DIRECTION('',(0.,-1.,0.));
#377=DIRECTION('center_axis',(0.,0.,1.));
#378=DIRECTION('ref_axis',(1.,0.,0.));
#379=DIRECTION('',(0.,1.,0.));
#380=DIRECTION('center_axis',(0.,0.,1.));
#381=DIRECTION('ref_axis',(1.,0.,0.));
#382=DIRECTION('center_axis',(-0.998629534754574,0.,0.0523359562429438));
#383=DIRECTION('ref_axis',(0.,-1.,0.));
#384=DIRECTION('',(0.,1.,0.));
#385=DIRECTION('center_axis',(-0.998629534754574,0.,0.0523359562429438));
#386=DIRECTION('ref_axis',(0.0523359562429438,0.,0.998629534754574));
#387=DIRECTION('center_axis',(0.,0.,1.));
#388=DIRECTION('ref_axis',(1.,0.,0.));
#389=DIRECTION('center_axis',(0.,0.,-1.));
#390=DIRECTION('ref_axis',(1.,0.,0.));
#391=DIRECTION('center_axis',(0.,-1.,0.));
#392=DIRECTION('ref_axis',(-1.,0.,0.));
#393=DIRECTION('center_axis',(0.,0.,1.));
#394=DIRECTION('ref_axis',(1.,0.,0.));
#395=DIRECTION('center_axis',(0.,0.,1.));
#396=DIRECTION('ref_axis',(1.,0.,0.));
#397=DIRECTION('',(0.,0.,-1.));
#398=DIRECTION('center_axis',(0.,0.,1.));
#399=DIRECTION('ref_axis',(1.,0.,0.));
#400=DIRECTION('center_axis',(-0.998629534754574,0.,0.0523359562429438));
#401=DIRECTION('ref_axis',(0.0523359562429438,0.,0.998629534754574));
#402=DIRECTION('center_axis',(0.,0.,1.));
#403=DIRECTION('ref_axis',(1.,0.,0.));
#404=DIRECTION('center_axis',(0.,0.,1.));
#405=DIRECTION('ref_axis',(1.,0.,0.));
#406=DIRECTION('center_axis',(0.,0.,1.));
#407=DIRECTION('ref_axis',(1.,0.,0.));
#408=DIRECTION('center_axis',(-0.998629534754574,0.,0.0523359562429438));
#409=DIRECTION('ref_axis',(0.,-1.,0.));
#410=DIRECTION('',(0.,1.,0.));
#411=DIRECTION('',(0.,1.,0.));
#412=DIRECTION('center_axis',(0.,0.,1.));
#413=DIRECTION('ref_axis',(1.,0.,0.));
#414=DIRECTION('center_axis',(0.,0.,1.));
#415=DIRECTION('ref_axis',(1.,0.,0.));
#416=CARTESIAN_POINT('',(0.,0.,0.));
#417=CARTESIAN_POINT('Origin',(-32.5,40.25,8.6));
#418=CARTESIAN_POINT('',(-31.25,41.5,8.6));
#419=CARTESIAN_POINT('',(-33.75,41.5,8.6));
#420=CARTESIAN_POINT('',(-33.75,41.5,8.6));
#421=CARTESIAN_POINT('',(-31.25,39.,8.6));
#422=CARTESIAN_POINT('',(-31.25,41.5,8.6));
#423=CARTESIAN_POINT('',(-33.75,39.,8.6));
#424=CARTESIAN_POINT('',(-31.25,39.,8.6));
#425=CARTESIAN_POINT('',(-33.75,39.,8.6));
#426=CARTESIAN_POINT('Origin',(-31.25,41.5,4.6));
#427=CARTESIAN_POINT('',(-31.3117572189413,41.5,4.6));
#428=CARTESIAN_POINT('',(-31.4165727775074,41.5,6.6));
#429=CARTESIAN_POINT('',(-31.3118701541713,41.5,4.60215493256167));
#430=CARTESIAN_POINT('',(-31.25,41.5,4.6));
#431=CARTESIAN_POINT('',(-31.875,41.5,4.6));
#432=CARTESIAN_POINT('',(-31.25,41.5,4.6));
#433=CARTESIAN_POINT('',(-33.75,41.5,4.6));
#434=CARTESIAN_POINT('',(-33.75,41.5,4.6));
#435=CARTESIAN_POINT('',(-33.6882427810587,41.5,4.6));
#436=CARTESIAN_POINT('',(-31.875,41.5,4.6));
#437=CARTESIAN_POINT('',(-33.5834272224926,41.5,6.6));
#438=CARTESIAN_POINT('',(-33.6847060304338,41.5,4.66748522210396));
#439=CARTESIAN_POINT('',(-31.875,41.5,6.6));
#440=CARTESIAN_POINT('Origin',(-31.25,39.,4.6));
#441=CARTESIAN_POINT('',(-31.25,39.,4.6));
#442=CARTESIAN_POINT('',(-31.25,39.625,4.6));
#443=CARTESIAN_POINT('',(-31.25,39.,4.6));
#444=CARTESIAN_POINT('Origin',(-33.75,39.,4.6));
#445=CARTESIAN_POINT('',(-31.4165727775074,39.,6.6));
#446=CARTESIAN_POINT('',(-31.3117572189413,39.,4.6));
#447=CARTESIAN_POINT('',(-31.3152939695662,39.,4.66748522210396));
#448=CARTESIAN_POINT('',(-33.5834272224926,39.,6.6));
#449=CARTESIAN_POINT('',(-33.125,39.,6.6));
#450=CARTESIAN_POINT('',(-33.6882427810587,39.,4.6));
#451=CARTESIAN_POINT('',(-33.6881298458287,39.,4.60215493256167));
#452=CARTESIAN_POINT('',(-33.75,39.,4.6));
#453=CARTESIAN_POINT('',(-33.125,39.,4.6));
#454=CARTESIAN_POINT('',(-33.75,39.,4.6));
#455=CARTESIAN_POINT('',(-33.125,39.,4.6));
#456=CARTESIAN_POINT('Origin',(-33.75,41.5,4.6));
#457=CARTESIAN_POINT('',(-33.75,40.875,4.6));
#458=CARTESIAN_POINT('Origin',(-32.5,40.25,4.6));
#459=CARTESIAN_POINT('',(-31.3117572189413,43.004646818244,4.6));
#460=CARTESIAN_POINT('',(-31.3117572189413,38.8190911978746,4.6));
#461=CARTESIAN_POINT('',(-31.3117572189413,37.495353181756,4.6));
#462=CARTESIAN_POINT('Origin',(-32.5,40.25,4.6));
#463=CARTESIAN_POINT('',(-31.3117572189413,38.8190911978746,4.6));
#464=CARTESIAN_POINT('Origin',(-31.312152245655,37.3881823957492,4.60753755871915));
#465=CARTESIAN_POINT('',(-31.4165727775074,43.0475320290502,6.6));
#466=CARTESIAN_POINT('',(-31.4165727775074,38.8190911978746,6.6));
#467=CARTESIAN_POINT('Origin',(-32.5,40.25,27.2730229235879));
#468=CARTESIAN_POINT('Origin',(-31.312152245655,37.3881823957492,4.60753755871915));
#469=CARTESIAN_POINT('',(-31.4165727775074,37.4524679709498,6.6));
#470=CARTESIAN_POINT('Origin',(-32.5,40.25,27.2730229235879));
#471=CARTESIAN_POINT('',(-31.4165727775074,38.8190911978746,6.6));
#472=CARTESIAN_POINT('Origin',(-32.5,40.25,6.6));
#473=CARTESIAN_POINT('',(-33.5834272224926,43.0475320290502,6.6));
#474=CARTESIAN_POINT('',(-33.5834272224926,41.6809088021254,6.6));
#475=CARTESIAN_POINT('Origin',(-32.5,40.25,6.6));
#476=CARTESIAN_POINT('Origin',(-33.687847754345,43.1118176042508,4.60753755871915));
#477=CARTESIAN_POINT('',(-33.6882427810587,43.004646818244,4.6));
#478=CARTESIAN_POINT('',(-33.6882427810587,41.6809088021254,4.6));
#479=CARTESIAN_POINT('Origin',(-32.5,40.25,27.2730229235879));
#480=CARTESIAN_POINT('Origin',(-32.5,40.25,9.9));
#481=CARTESIAN_POINT('',(-35.3,40.25,10.1));
#482=CARTESIAN_POINT('Origin',(-32.5,40.25,10.1));
#483=CARTESIAN_POINT('',(-35.5,40.25,9.9));
#484=CARTESIAN_POINT('Origin',(-35.3,40.25,9.9));
#485=CARTESIAN_POINT('Origin',(-32.5,40.25,9.9));
#486=CARTESIAN_POINT('Origin',(-32.5,40.25,4.6));
#487=CARTESIAN_POINT('',(-35.5,40.25,4.59999999999997));
#488=CARTESIAN_POINT('',(-35.5,40.25,4.6));
#489=CARTESIAN_POINT('',(-33.6882427810587,37.495353181756,4.6));
#490=CARTESIAN_POINT('Origin',(-32.5,40.25,4.6));
#491=CARTESIAN_POINT('',(-33.5834272224926,37.4524679709498,6.6));
#492=CARTESIAN_POINT('Origin',(-32.5,40.25,27.2730229235879));
#493=CARTESIAN_POINT('Origin',(-32.5,40.25,6.6));
#494=CARTESIAN_POINT('Origin',(-32.5,40.25,4.6));
#495=CARTESIAN_POINT('Origin',(-32.5,40.25,10.1));
#496=CARTESIAN_POINT('Origin',(-33.687847754345,43.1118176042508,4.60753755871915));
#497=CARTESIAN_POINT('',(-33.5834272224926,41.6809088021254,6.6));
#498=CARTESIAN_POINT('',(-33.6882427810587,41.6809088021254,4.6));
#499=CARTESIAN_POINT('Origin',(-32.5,40.25,6.6));
#500=CARTESIAN_POINT('Origin',(-32.5,40.25,4.6));
#501=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#505,
'DISTANCE_ACCURACY_VALUE',
'Maximum model space distance between geometric entities at asserted c
onnectivities');
#502=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.01),#505,
'DISTANCE_ACCURACY_VALUE',
'Maximum model space distance between geometric entities at asserted c
onnectivities');
#503=(
GEOMETRIC_REPRESENTATION_CONTEXT(3)
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#501))
GLOBAL_UNIT_ASSIGNED_CONTEXT((#505,#506,#507))
REPRESENTATION_CONTEXT('','3D')
);
#504=(
GEOMETRIC_REPRESENTATION_CONTEXT(3)
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#502))
GLOBAL_UNIT_ASSIGNED_CONTEXT((#505,#506,#507))
REPRESENTATION_CONTEXT('','3D')
);
#505=(
LENGTH_UNIT()
NAMED_UNIT(*)
SI_UNIT(.MILLI.,.METRE.)
);
#506=(
NAMED_UNIT(*)
PLANE_ANGLE_UNIT()
SI_UNIT($,.RADIAN.)
);
#507=(
NAMED_UNIT(*)
SI_UNIT($,.STERADIAN.)
SOLID_ANGLE_UNIT()
);
#508=SHAPE_DEFINITION_REPRESENTATION(#509,#510);
#509=PRODUCT_DEFINITION_SHAPE('',$,#512);
#510=SHAPE_REPRESENTATION('',(#300),#503);
#511=PRODUCT_DEFINITION_CONTEXT('part definition',#516,'design');
#512=PRODUCT_DEFINITION('sc64_shell reworked','sc64_shell reworked v10',
#513,#511);
#513=PRODUCT_DEFINITION_FORMATION('',$,#518);
#514=PRODUCT_RELATED_PRODUCT_CATEGORY('sc64_shell reworked v10',
'sc64_shell reworked v10',(#518));
#515=APPLICATION_PROTOCOL_DEFINITION('international standard',
'automotive_design',2009,#516);
#516=APPLICATION_CONTEXT(
'Core Data for Automotive Mechanical Design Process');
#517=PRODUCT_CONTEXT('part definition',#516,'mechanical');
#518=PRODUCT('sc64_shell reworked','sc64_shell reworked v10',$,(#517));
#519=PRESENTATION_STYLE_ASSIGNMENT((#523));
#520=PRESENTATION_STYLE_ASSIGNMENT((#524));
#521=PRESENTATION_STYLE_ASSIGNMENT((#525));
#522=PRESENTATION_STYLE_ASSIGNMENT((#526));
#523=SURFACE_STYLE_USAGE(.BOTH.,#527);
#524=SURFACE_STYLE_USAGE(.BOTH.,#528);
#525=SURFACE_STYLE_USAGE(.BOTH.,#529);
#526=SURFACE_STYLE_USAGE(.BOTH.,#530);
#527=SURFACE_SIDE_STYLE('',(#531));
#528=SURFACE_SIDE_STYLE('',(#532));
#529=SURFACE_SIDE_STYLE('',(#533));
#530=SURFACE_SIDE_STYLE('',(#534));
#531=SURFACE_STYLE_FILL_AREA(#535);
#532=SURFACE_STYLE_FILL_AREA(#536);
#533=SURFACE_STYLE_FILL_AREA(#537);
#534=SURFACE_STYLE_FILL_AREA(#538);
#535=FILL_AREA_STYLE('Steel - Satin',(#539));
#536=FILL_AREA_STYLE('Plastic - Translucent Matte (Blue)',(#540));
#537=FILL_AREA_STYLE('Powder Coat - Rough (White)',(#541));
#538=FILL_AREA_STYLE('Plastic - Glossy (Black)',(#542));
#539=FILL_AREA_STYLE_COLOUR('Steel - Satin',#543);
#540=FILL_AREA_STYLE_COLOUR('Plastic - Translucent Matte (Blue)',#544);
#541=FILL_AREA_STYLE_COLOUR('Powder Coat - Rough (White)',#545);
#542=FILL_AREA_STYLE_COLOUR('Plastic - Glossy (Black)',#546);
#543=COLOUR_RGB('Steel - Satin',0.627450980392157,0.627450980392157,0.627450980392157);
#544=COLOUR_RGB('Plastic - Translucent Matte (Blue)',0.188235294117647,
0.231372549019608,0.588235294117647);
#545=COLOUR_RGB('Powder Coat - Rough (White)',0.964705882352941,0.964705882352941,
0.952941176470588);
#546=COLOUR_RGB('Plastic - Glossy (Black)',0.0980392156862745,0.0980392156862745,
0.0980392156862745);
ENDSEC;
END-ISO-10303-21;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,9 @@
#define BUFFER_BLOCKS_MAX (sizeof(SC64_BUFFERS->BUFFER) / SD_SECTOR_SIZE)
sc64_error_t sc64_error_fatfs;
DSTATUS disk_status (BYTE pdrv) {
if (pdrv > 0) {
return STA_NODISK;
@ -20,7 +23,7 @@ DSTATUS disk_status (BYTE pdrv) {
sc64_sd_card_status_t sd_card_status;
if ((error = sc64_sd_card_get_status(&sd_card_status)) != SC64_OK) {
error_display("Could not get SD card status: %d", error);
error_display("Could not get SD card status\n (%08X) - %s", error, sc64_error_description(error));
}
if (!(sd_card_status & SD_CARD_STATUS_INSERTED)) {
@ -38,7 +41,7 @@ DSTATUS disk_initialize (BYTE pdrv) {
return STA_NODISK;
}
sc64_sd_card_init();
sc64_error_fatfs = sc64_sd_card_init();
return disk_status(pdrv);
}
@ -53,7 +56,7 @@ DRESULT disk_read (BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) {
while (count > 0) {
uint32_t blocks = ((count > BUFFER_BLOCKS_MAX) ? BUFFER_BLOCKS_MAX : count);
size_t length = (blocks * SD_SECTOR_SIZE);
if (sc64_sd_read_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks) != SC64_OK) {
if ((sc64_error_fatfs = sc64_sd_read_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks)) != SC64_OK) {
return RES_ERROR;
}
if (((uint32_t) (buff) % 8) == 0) {
@ -67,7 +70,7 @@ DRESULT disk_read (BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) {
count -= blocks;
}
} else {
if (sc64_sd_read_sectors(physical_address, sector, count) != SC64_OK) {
if ((sc64_error_fatfs = sc64_sd_read_sectors(physical_address, sector, count)) != SC64_OK) {
return RES_ERROR;
}
}
@ -91,7 +94,7 @@ DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) {
memcpy(aligned_buffer, buff, length);
pi_dma_write((io32_t *) (SC64_BUFFERS->BUFFER), aligned_buffer, length);
}
if (sc64_sd_write_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks) != SC64_OK) {
if ((sc64_error_fatfs = sc64_sd_write_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks)) != SC64_OK) {
return RES_ERROR;
}
buff += length;
@ -99,7 +102,7 @@ DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) {
count -= blocks;
}
} else {
if (sc64_sd_write_sectors(physical_address, sector, count) != SC64_OK) {
if ((sc64_error_fatfs = sc64_sd_write_sectors(physical_address, sector, count)) != SC64_OK) {
return RES_ERROR;
}
}
@ -122,7 +125,7 @@ DWORD get_fattime(void) {
sc64_rtc_time_t t;
if ((error = sc64_get_time(&t)) != SC64_OK) {
error_display("Command TIME_GET failed: %d", error);
error_display("Command TIME_GET failed\n (%08X) - %s", error, sc64_error_description(error));
}
return (

View File

@ -15,7 +15,7 @@
/ and optional writing functions as well. */
#define FF_FS_MINIMIZE 2
#define FF_FS_MINIMIZE 0
/* This option defines minimization level to remove some basic API functions.
/
/ 0: Basic functions are fully enabled.
@ -47,7 +47,7 @@
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
#define FF_USE_LABEL 0
#define FF_USE_LABEL 1
/* This option switches volume label functions, f_getlabel() and f_setlabel().
/ (0:Disable or 1:Enable) */

View File

@ -8,13 +8,15 @@
init_tv_type_t __tv_type;
init_reset_type_t __reset_type;
uint32_t __entropy;
void init (init_tv_type_t tv_type, init_reset_type_t reset_type) {
void init (init_tv_type_t tv_type, init_reset_type_t reset_type, uint32_t entropy) {
sc64_error_t error;
__tv_type = tv_type;
__reset_type = reset_type;
__entropy = entropy;
sc64_unlock();
@ -26,7 +28,7 @@ void init (init_tv_type_t tv_type, init_reset_type_t reset_type) {
exception_enable_interrupts();
if ((error = sc64_set_config(CFG_ID_BOOTLOADER_SWITCH, false)) != SC64_OK) {
error_display("Command CONFIG_SET [BOOTLOADER_SWITCH] failed: %d", error);
error_display("Command CONFIG_SET [BOOTLOADER_SWITCH] failed\n (%08X) - %s", error, sc64_error_description(error));
}
if (test_check()) {

View File

@ -2,6 +2,9 @@
#define INIT_H__
#include <stdint.h>
typedef enum {
INIT_TV_TYPE_PAL = 0,
INIT_TV_TYPE_NTSC = 1,
@ -16,9 +19,10 @@ typedef enum {
extern init_tv_type_t __tv_type;
extern init_reset_type_t __reset_type;
extern uint32_t __entropy;
void init (init_tv_type_t tv_type, init_reset_type_t reset_type);
void init (init_tv_type_t tv_type, init_reset_type_t reset_type, uint32_t entropy);
void deinit (void);

View File

@ -12,7 +12,7 @@ void main (void) {
sc64_boot_params_t sc64_boot_params;
if ((error = sc64_get_boot_params(&sc64_boot_params)) != SC64_OK) {
error_display("Could not obtain boot info: %d", error);
error_display("Could not obtain boot info\n (%08X) - %s", error, sc64_error_description(error));
}
boot_params_t boot_params;
@ -40,7 +40,7 @@ void main (void) {
break;
default:
error_display("Unknown boot mode selected [%d]\n", sc64_boot_params.boot_mode);
error_display("Unknown boot mode selected (%d)\n", sc64_boot_params.boot_mode);
break;
}

View File

@ -8,8 +8,11 @@
#define ROM_ADDRESS (0x10000000)
extern sc64_error_t sc64_error_fatfs;
static const char *fatfs_error_codes[] = {
"Succeeded",
"No error",
"A hard error occurred in the low level disk I/O layer",
"Assertion failed",
"The physical drive cannot work",
@ -35,7 +38,14 @@ static const char *fatfs_error_codes[] = {
#define FF_CHECK(x, message, ...) { \
fresult = x; \
if (fresult != FR_OK) { \
error_display(message ".\nReason: %s", __VA_ARGS__ __VA_OPT__(,) fatfs_error_codes[fresult]); \
error_display( \
message "\n" \
" > FatFs error: %s\n" \
" > SD card error: %s (%08X)", \
__VA_ARGS__ __VA_OPT__(,) \
fatfs_error_codes[fresult], \
sc64_error_description(sc64_error_fatfs), sc64_error_fatfs \
); \
} \
}
@ -55,15 +65,15 @@ void menu_load (void) {
do {
if ((error = sc64_writeback_pending(&writeback_pending)) != SC64_OK) {
error_display("Command WRITEBACK_PENDING failed: %d", error);
error_display("Command WRITEBACK_PENDING failed\n (%08X) - %s", error, sc64_error_description(error));
}
} while (writeback_pending);
if ((error = sc64_writeback_disable()) != SC64_OK) {
error_display("Could not disable writeback: %d", error);
error_display("Could not disable save writeback\n (%08X) - %s", error, sc64_error_description(error));
}
FF_CHECK(f_mount(&fs, "", 1), "SD card initialize error. No SD card or invalid partition table");
FF_CHECK(f_mount(&fs, "", 1), "SD card initialize error");
FF_CHECK(f_open(&fil, "sc64menu.n64", FA_READ), "Could not open menu executable (sc64menu.n64)");
fix_menu_file_size(&fil);
FF_CHECK(f_read(&fil, (void *) (ROM_ADDRESS), f_size(&fil), &bytes_read), "Could not read menu file");

View File

@ -89,6 +89,61 @@ static sc64_error_t sc64_execute_cmd (sc64_cmd_t *cmd) {
}
const char *sc64_error_description (sc64_error_t error) {
sc64_error_type_t type = (sc64_error_type_t) ((error >> 24) & 0xFF);
error &= 0xFFFFFF;
if (type == ERROR_TYPE_CFG) {
switch ((sc64_cfg_error_t) (error)) {
case SC64_OK: return "No error";
case CFG_ERROR_UNKNOWN_COMMAND: return "Unknown command";
case CFG_ERROR_INVALID_ARGUMENT: return "Invalid argument";
case CFG_ERROR_INVALID_ADDRESS: return "Invalid address";
case CFG_ERROR_INVALID_ID: return "Invalid ID";
default: return "Unknown error (CFG)";
}
}
if (type == ERROR_TYPE_SD_CARD) {
switch ((sc64_sd_error_t) (error)) {
case SD_OK: return "No error (SD)";
case SD_ERROR_NO_CARD_IN_SLOT: return "No SD card in the slot";
case SD_ERROR_NOT_INITIALIZED: return "SD card is not initialized";
case SD_ERROR_INVALID_ARGUMENT: return "Invalid argument (SD)";
case SD_ERROR_INVALID_ADDRESS: return "Invalid address (SD)";
case SD_ERROR_INVALID_OPERATION: return "Invalid operation (SD)";
case SD_ERROR_CMD2_IO: return "CMD2 I/O";
case SD_ERROR_CMD3_IO: return "CMD3 I/O";
case SD_ERROR_CMD6_CHECK_IO: return "CMD6 I/O (check)";
case SD_ERROR_CMD6_CHECK_CRC: return "CMD6 CRC (check)";
case SD_ERROR_CMD6_CHECK_TIMEOUT: return "CMD6 timeout (check)";
case SD_ERROR_CMD6_CHECK_RESPONSE: return "CMD6 invalid response (check)";
case SD_ERROR_CMD6_SWITCH_IO: return "CMD6 I/O (switch)";
case SD_ERROR_CMD6_SWITCH_CRC: return "CMD6 CRC (switch)";
case SD_ERROR_CMD6_SWITCH_TIMEOUT: return "CMD6 timeout (switch)";
case SD_ERROR_CMD6_SWITCH_RESPONSE: return "CMD6 invalid response (switch)";
case SD_ERROR_CMD7_IO: return "CMD7 I/O";
case SD_ERROR_CMD8_IO: return "CMD8 I/O";
case SD_ERROR_CMD9_IO: return "CMD9 I/O";
case SD_ERROR_CMD10_IO: return "CMD10 I/O";
case SD_ERROR_CMD18_IO: return "CMD18 I/O";
case SD_ERROR_CMD18_CRC: return "CMD18 CRC";
case SD_ERROR_CMD18_TIMEOUT: return "CMD18 timeout";
case SD_ERROR_CMD25_IO: return "CMD25 I/O";
case SD_ERROR_CMD25_CRC: return "CMD25 CRC";
case SD_ERROR_CMD25_TIMEOUT: return "CMD25 timeout";
case SD_ERROR_ACMD6_IO: return "ACMD6 I/O";
case SD_ERROR_ACMD41_IO: return "ACMD41 I/O";
case SD_ERROR_ACMD41_OCR: return "ACMD41 OCR";
case SD_ERROR_ACMD41_TIMEOUT: return "ACMD41 timeout";
default: return "Unknown error (SD)";
}
}
return "Unknown error (type)";
}
void sc64_unlock (void) {
pi_io_write(&SC64_REGS->KEY, SC64_KEY_RESET);
pi_io_write(&SC64_REGS->KEY, SC64_KEY_UNLOCK_1);
@ -396,8 +451,7 @@ sc64_error_t sc64_writeback_enable (void *address) {
sc64_error_t sc64_writeback_disable (void) {
sc64_error_t error;
uint32_t save_type;
error = sc64_get_config(CFG_ID_SAVE_TYPE, &save_type);
if (error != SC64_OK) {
if ((error = sc64_get_config(CFG_ID_SAVE_TYPE, &save_type)) != SC64_OK) {
return error;
}
return sc64_set_config(CFG_ID_SAVE_TYPE, save_type);

View File

@ -8,14 +8,52 @@
typedef enum {
SC64_OK,
SC64_ERROR_BAD_ARGUMENT,
SC64_ERROR_BAD_ADDRESS,
SC64_ERROR_BAD_CONFIG_ID,
SC64_ERROR_TIMEOUT,
SC64_ERROR_SD_CARD,
SC64_ERROR_UNKNOWN_CMD = -1
} sc64_error_t;
ERROR_TYPE_CFG = 0,
ERROR_TYPE_SD_CARD = 1,
} sc64_error_type_t;
typedef enum {
SC64_OK = 0,
CFG_ERROR_UNKNOWN_COMMAND = 1,
CFG_ERROR_INVALID_ARGUMENT = 2,
CFG_ERROR_INVALID_ADDRESS = 3,
CFG_ERROR_INVALID_ID = 4,
} sc64_cfg_error_t;
typedef enum {
SD_OK = 0,
SD_ERROR_NO_CARD_IN_SLOT = 1,
SD_ERROR_NOT_INITIALIZED = 2,
SD_ERROR_INVALID_ARGUMENT = 3,
SD_ERROR_INVALID_ADDRESS = 4,
SD_ERROR_INVALID_OPERATION = 5,
SD_ERROR_CMD2_IO = 6,
SD_ERROR_CMD3_IO = 7,
SD_ERROR_CMD6_CHECK_IO = 8,
SD_ERROR_CMD6_CHECK_CRC = 9,
SD_ERROR_CMD6_CHECK_TIMEOUT = 10,
SD_ERROR_CMD6_CHECK_RESPONSE = 11,
SD_ERROR_CMD6_SWITCH_IO = 12,
SD_ERROR_CMD6_SWITCH_CRC = 13,
SD_ERROR_CMD6_SWITCH_TIMEOUT = 14,
SD_ERROR_CMD6_SWITCH_RESPONSE = 15,
SD_ERROR_CMD7_IO = 16,
SD_ERROR_CMD8_IO = 17,
SD_ERROR_CMD9_IO = 18,
SD_ERROR_CMD10_IO = 19,
SD_ERROR_CMD18_IO = 20,
SD_ERROR_CMD18_CRC = 21,
SD_ERROR_CMD18_TIMEOUT = 22,
SD_ERROR_CMD25_IO = 23,
SD_ERROR_CMD25_CRC = 24,
SD_ERROR_CMD25_TIMEOUT = 25,
SD_ERROR_ACMD6_IO = 26,
SD_ERROR_ACMD41_IO = 27,
SD_ERROR_ACMD41_OCR = 28,
SD_ERROR_ACMD41_TIMEOUT = 29,
} sc64_sd_error_t;
typedef uint32_t sc64_error_t;
typedef enum {
CFG_ID_BOOTLOADER_SWITCH,
@ -133,6 +171,8 @@ typedef struct {
#define SC64_BUFFERS ((sc64_buffers_t *) SC64_BUFFERS_BASE)
const char *sc64_error_description (sc64_error_t error);
void sc64_unlock (void);
void sc64_lock (void);
bool sc64_check_presence (void);

View File

@ -10,6 +10,7 @@ entry_handler:
lui $t0, 0xA400
lbu $a0, 9($t0) # TV type
lbu $a1, 10($t0) # Reset type
lw $a2, 4($t0) # Entropy
la $t0, init
jalr $t0

View File

@ -2,12 +2,56 @@
#include <stdlib.h>
#include "display.h"
#include "error.h"
#include "fatfs/ff.h"
#include "init.h"
#include "io.h"
#include "sc64.h"
#include "test.h"
#define TEST_BUFFER_SIZE (128 * 1024)
#define SD_TEST_FILE_SIZE (16 * 1024 * 1024)
#define SDRAM_ADDRESS (0x10000000)
#define SDRAM_SIZE (64 * 1024 * 1024)
typedef struct {
char *name;
void (*fill) (uint32_t *buffer, int size, uint32_t offset, uint32_t pattern);
uint32_t pattern;
int fade;
} sdram_test_t;
static uint32_t random_seed = 0;
static uint32_t w_buffer[TEST_BUFFER_SIZE / sizeof(uint32_t)] __attribute__((aligned(8)));
static uint32_t r_buffer[TEST_BUFFER_SIZE / sizeof(uint32_t)] __attribute__((aligned(8)));
static void fill_own_address (uint32_t *buffer, int size, uint32_t pattern, uint32_t offset) {
for (int i = 0; i < (size / sizeof(uint32_t)); i++) {
uint32_t value = offset + (i * sizeof(uint32_t));
value ^= pattern;
buffer[i] = value;
}
}
static void fill_pattern (uint32_t *buffer, int size, uint32_t pattern, uint32_t offset) {
for (int i = 0; i < (size / sizeof(uint32_t)); i++) {
buffer[i] = pattern;
}
}
static void fill_random (uint32_t *buffer, int size, uint32_t pattern, uint32_t offset) {
for (int i = 0; i < (size / sizeof(uint32_t)); i++) {
buffer[i] = (rand() << 31) | rand();
}
}
static void test_sc64_cfg (void) {
sc64_error_t error;
uint32_t button_state;
@ -21,25 +65,22 @@ static void test_sc64_cfg (void) {
do {
if ((error = sc64_get_config(CFG_ID_BUTTON_STATE, &button_state)) != SC64_OK) {
error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error);
error_display("Command CONFIG_GET [BUTTON_STATE] failed\n (%08X) - %s", error, sc64_error_description(error));
}
} while (button_state != 0);
display_printf("done\n\n");
if ((error = sc64_get_identifier(&identifier)) != SC64_OK) {
error_display("Command IDENTIFIER_GET failed: %d", error);
return;
error_display("Command IDENTIFIER_GET failed\n (%08X) - %s", error, sc64_error_description(error));
}
if ((error = sc64_get_version(&major, &minor, &revision)) != SC64_OK) {
error_display("Command VERSION_GET failed: %d", error);
return;
error_display("Command VERSION_GET failed\n (%08X) - %s", error, sc64_error_description(error));
}
if ((error = sc64_get_diagnostic(DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE, &tmp)) != SC64_OK) {
error_display("Command DIAGNOSTIC_GET failed: %d", error);
return;
error_display("Command DIAGNOSTIC_GET failed\n (%08X) - %s", error, sc64_error_description(error));
}
uint16_t voltage = (uint16_t) (tmp >> 16);
@ -49,15 +90,10 @@ static void test_sc64_cfg (void) {
display_printf("SC64 firmware version: %d.%d.%d\n\n", major, minor, revision);
display_printf("Voltage: %d.%03d V\n", (voltage / 1000), (voltage % 1000));
display_printf("Temperature: %d.%01d `C\n", (temperature / 10), (temperature % 10));
}
static void test_rtc (void) {
sc64_error_t error;
sc64_rtc_time_t t;
display_printf("Temperature: %d.%01d `C\n\n", (temperature / 10), (temperature % 10));
const char *weekdays[8] = {
"",
"Unknown day",
"Monday",
"Tuesday",
"Wednesday",
@ -67,8 +103,10 @@ static void test_rtc (void) {
"Sunday",
};
sc64_rtc_time_t t;
if ((error = sc64_get_time(&t)) != SC64_OK) {
error_display("Command TIME_GET failed: %d", error);
error_display("Command TIME_GET failed\n (%08X) - %s", error, sc64_error_description(error));
}
display_printf("RTC current time:\n ");
@ -79,14 +117,52 @@ static void test_rtc (void) {
display_printf("\n");
}
static void test_sd_card (void) {
static void test_pi (void) {
int count = 16384;
int size = sizeof(SC64_BUFFERS->BUFFER);
srand(random_seed);
display_printf("Testing %d write/read cycles of %dkiB to the SC64 buffer\n\n", count, size / 1024);
for (int i = 0; i < count; i++) {
fill_random(w_buffer, size, 0, 0);
if ((i % (count / 256)) == 0) {
display_printf(".");
}
pi_dma_write((io32_t *) (SC64_BUFFERS->BUFFER), w_buffer, size);
pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), r_buffer, size);
for (int i = 0; i < size / sizeof(uint32_t); i++) {
if (w_buffer[i] != r_buffer[i]) {
error_display(
"PI test failed:\n"
" > Mismatch error at address 0x%08lX\n"
" > 0x%08lX (W) != 0x%08lX (R)",
(uint32_t) (SC64_BUFFERS->BUFFER) + (i * sizeof(uint32_t)),
w_buffer[i],
r_buffer[i]
);
}
}
}
random_seed += c0_count();
display_printf("\n");
}
static void test_sd_card_io (void) {
sc64_error_t error;
sc64_sd_card_status_t card_status;
uint8_t card_info[32] __attribute__((aligned(8)));
uint8_t sector[512] __attribute__((aligned(8)));
if ((error = sc64_sd_card_get_status(&card_status)) != SC64_OK) {
error_display("Could not get SD card info: %d", error);
error_display("Could not get SD card info\n (%08X) - %s", error, sc64_error_description(error));
}
if (card_status & SD_CARD_STATUS_INSERTED) {
@ -95,13 +171,16 @@ static void test_sd_card (void) {
display_printf("SD card is not inserted\n");
}
if ((error = sc64_sd_card_deinit()) != SC64_OK) {
error_display("SD card deinit error\n (%08X) - %s", error, sc64_error_description(error));
}
if ((error = sc64_sd_card_init()) != SC64_OK) {
display_printf("SD card init error: %d\n", error);
return;
return display_printf("SD card init error\n (%08X) - %s\n", error, sc64_error_description(error));
}
if ((error = sc64_sd_card_get_status(&card_status)) != SC64_OK) {
error_display("Could not get SD card info: %d", error);
error_display("Could not get SD card info\n (%08X) - %s", error, sc64_error_description(error));
}
if (card_status & SD_CARD_STATUS_INITIALIZED) {
@ -118,8 +197,7 @@ static void test_sd_card (void) {
}
if ((error = sc64_sd_card_get_info((uint32_t *) (SC64_BUFFERS->BUFFER))) != SC64_OK) {
display_printf("SD card get info error: %d\n", error);
return;
error_display("SD card get info error\n (%08X) - %s", error, sc64_error_description(error));
}
pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), card_info, sizeof(card_info));
@ -139,8 +217,7 @@ static void test_sd_card (void) {
display_printf("\n");
if ((error = sc64_sd_read_sectors((void *) (SC64_BUFFERS->BUFFER), 0, 1)) != SC64_OK) {
display_printf("SD card read sector 0 error: %d\n", error);
return;
return display_printf("SD card read sector 0 error\n (%08X) - %s\n", error, sc64_error_description(error));
}
pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), sector, sizeof(sector));
@ -157,88 +234,273 @@ static void test_sd_card (void) {
display_printf(" Boot signature: 0x%02X%02X\n", sector[510], sector[511]);
}
#define SDRAM_ADDRESS (0x10000000)
#define SDRAM_SIZE (64 * 1024 * 1024)
#define BUFFER_SIZE (128 * 1024)
static void test_sd_card_fatfs (void) {
sc64_error_t error;
FRESULT fresult;
FATFS fs;
TCHAR label[23];
DWORD vsn;
FIL fil;
UINT left;
UINT bytes;
static uint32_t w_buffer[BUFFER_SIZE / sizeof(uint32_t)] __attribute__((aligned(8)));
static uint32_t r_buffer[BUFFER_SIZE / sizeof(uint32_t)] __attribute__((aligned(8)));
if ((error = sc64_sd_card_deinit()) != SC64_OK) {
error_display("SD card deinit error\n (%08X) - %s", error, sc64_error_description(error));
}
if ((fresult = f_mount(&fs, "", 1)) != FR_OK) {
display_printf("f_mount error: %d\n", fresult);
}
if ((fresult = f_getlabel("", label, &vsn)) != FR_OK) {
display_printf("f_getlabel error: %d\n", fresult);
} else {
display_printf("Volume [%s] / [%08lX]\n\n", label, vsn);
}
if ((fresult = f_open(&fil, "sc64test.bin", FA_CREATE_ALWAYS | FA_WRITE)) != FR_OK) {
display_printf("f_open (write) error: %d\n", fresult);
}
srand(random_seed);
left = SD_TEST_FILE_SIZE;
while (left) {
if ((left % (SD_TEST_FILE_SIZE / 64)) == 0) {
display_printf("w");
}
UINT block_size = (left > TEST_BUFFER_SIZE) ? TEST_BUFFER_SIZE : left;
fill_random(w_buffer, block_size, 0, 0);
if ((fresult = f_write(&fil, w_buffer, block_size, &bytes)) != FR_OK) {
display_printf("\nf_write error: %d", fresult);
break;
}
if (bytes != block_size) {
display_printf("\nf_write (%ld!=%ld) error: %d", bytes, block_size, fresult);
break;
}
left -= block_size;
}
display_printf("\n");
if ((fresult = f_close(&fil)) != FR_OK) {
display_printf("f_close (write) error: %d\n", fresult);
}
if ((fresult = f_open(&fil, "sc64test.bin", FA_OPEN_EXISTING | FA_READ)) != FR_OK) {
display_printf("f_open (read) error: %d\n", fresult);
}
if (f_size(&fil) != SD_TEST_FILE_SIZE) {
display_printf("f_size (%d!=%d) error\n", f_size(&fil), SD_TEST_FILE_SIZE);
}
srand(random_seed);
left = SD_TEST_FILE_SIZE;
while (left) {
if ((left % (SD_TEST_FILE_SIZE / 64)) == 0) {
display_printf("r");
}
UINT block_size = (left > TEST_BUFFER_SIZE) ? TEST_BUFFER_SIZE : left;
fill_random(w_buffer, block_size, 0, 0);
if ((fresult = f_read(&fil, r_buffer, block_size, &bytes)) != FR_OK) {
display_printf("\nf_read error: %d", fresult);
break;
}
if (bytes != block_size) {
display_printf("\nf_read (%ld!=%ld) error: %d", bytes, block_size, fresult);
break;
}
for (UINT i = 0; i < (block_size / sizeof(uint32_t)); i++) {
if (w_buffer[i] != r_buffer[i]) {
error_display(
"SD card (FatFs) test failed:\n"
" > Mismatch error at file offset 0x%08lX\n"
" > 0x%08lX (W) != 0x%08lX (R)",
f_tell(&fil) + (i * sizeof(uint32_t)),
w_buffer[i],
r_buffer[i]
);
}
}
left -= block_size;
}
display_printf("\n");
if ((fresult = f_close(&fil)) != FR_OK) {
display_printf("f_close (read) error: %d\n", fresult);
}
if ((fresult = f_unlink("sc64test.bin")) != FR_OK) {
display_printf("f_unlink error: %d\n", fresult);
}
if ((fresult = f_unmount("")) != FR_OK) {
display_printf("f_unmount error: %d\n", fresult);
}
random_seed += c0_count();
}
static void test_sdram (void) {
sc64_error_t error;
static int phase = 0;
if ((error = sc64_set_config(CFG_ID_ROM_WRITE_ENABLE, true))) {
error_display("Command CONFIG_SET [ROM_WRITE_ENABLE] failed: %d", error);
return;
}
if ((error = sc64_set_config(CFG_ID_ROM_SHADOW_ENABLE, false))) {
error_display("Command CONFIG_SET [ROM_SHADOW_ENABLE] failed: %d", error);
return;
}
pi_io_config(0x0B, 0x05, 0x0C, 0x02);
display_printf("PI config - PGS: 0x0B, LAT: 0x05, PWD: 0x0C, RLS: 0x02\n");
const struct patterns_s {
bool constant;
uint32_t value;
} patterns[] = {
{ .constant = true, .value = 0x00000000 },
{ .constant = true, .value = 0xFFFFFFFF },
{ .constant = true, .value = 0xFFFF0000 },
{ .constant = true, .value = 0x0000FFFF },
{ .constant = true, .value = 0xF0F0F0F0 },
{ .constant = true, .value = 0x0F0F0F0F },
{ .constant = true, .value = 0xAAAAAAAA },
{ .constant = true, .value = 0x55555555 },
{ .constant = true, .value = 0xA5A5A5A5 },
{ .constant = true, .value = 0x5A5A5A5A },
{ .constant = false },
{ .constant = false },
sdram_test_t phase_0_tests[] = {
{ .name = "Own address: ", .fill = fill_own_address, .pattern = 0x00000000, .fade = 0 },
{ .name = "Own address~: ", .fill = fill_own_address, .pattern = 0xFFFFFFFF, .fade = 0 },
{ .name = "All zeros: ", .fill = fill_pattern, .pattern = 0x00000000, .fade = 0 },
{ .name = "All ones: ", .fill = fill_pattern, .pattern = 0xFFFFFFFF, .fade = 0 },
{ .name = "0xAAAA5555: ", .fill = fill_pattern, .pattern = 0xAAAA5555, .fade = 0 },
{ .name = "0x5555AAAA: ", .fill = fill_pattern, .pattern = 0x5555AAAA, .fade = 0 },
{ .name = "Random (1/4): ", .fill = fill_random, .pattern = 0x00000000, .fade = 0 },
{ .name = "Random (2/4): ", .fill = fill_random, .pattern = 0x00000000, .fade = 0 },
{ .name = "Random (3/4): ", .fill = fill_random, .pattern = 0x00000000, .fade = 0 },
{ .name = "Random (4/4): ", .fill = fill_random, .pattern = 0x00000000, .fade = 0 },
{ .name = NULL },
};
srand(c0_count());
sdram_test_t phase_1_tests[] = {
{ .name = "0x00010001: ", .fill = fill_pattern, .pattern = 0x00010001, .fade = 0 },
{ .name = "0xFFFEFFFE: ", .fill = fill_pattern, .pattern = 0xFFFEFFFE, .fade = 0 },
{ .name = "0x00020002: ", .fill = fill_pattern, .pattern = 0x00020002, .fade = 0 },
{ .name = "0xFFFDFFFD: ", .fill = fill_pattern, .pattern = 0xFFFDFFFD, .fade = 0 },
{ .name = "0x00040004: ", .fill = fill_pattern, .pattern = 0x00040004, .fade = 0 },
{ .name = "0xFFFBFFFB: ", .fill = fill_pattern, .pattern = 0xFFFBFFFB, .fade = 0 },
{ .name = "0x00080008: ", .fill = fill_pattern, .pattern = 0x00080008, .fade = 0 },
{ .name = "0xFFF7FFF7: ", .fill = fill_pattern, .pattern = 0xFFF7FFF7, .fade = 0 },
{ .name = NULL },
};
for (int pattern = 0; pattern < sizeof(patterns) / sizeof(patterns[0]); pattern++) {
if (patterns[pattern].constant) {
display_printf("Pattern: 0x%08X ", patterns[pattern].value);
for (int i = 0; i < BUFFER_SIZE / sizeof(uint32_t); i++) {
w_buffer[i] = patterns[pattern].value;
}
} else {
display_printf("Pattern: random ");
sdram_test_t phase_2_tests[] = {
{ .name = "0x00100010: ", .fill = fill_pattern, .pattern = 0x00100010, .fade = 0 },
{ .name = "0xFFEFFFEF: ", .fill = fill_pattern, .pattern = 0xFFEFFFEF, .fade = 0 },
{ .name = "0x00200020: ", .fill = fill_pattern, .pattern = 0x00200020, .fade = 0 },
{ .name = "0xFFDFFFDF: ", .fill = fill_pattern, .pattern = 0xFFDFFFDF, .fade = 0 },
{ .name = "0x00400040: ", .fill = fill_pattern, .pattern = 0x00400040, .fade = 0 },
{ .name = "0xFFBFFFBF: ", .fill = fill_pattern, .pattern = 0xFFBFFFBF, .fade = 0 },
{ .name = "0x00800080: ", .fill = fill_pattern, .pattern = 0x00800080, .fade = 0 },
{ .name = "0xFF7FFF7F: ", .fill = fill_pattern, .pattern = 0xFF7FFF7F, .fade = 0 },
{ .name = NULL },
};
sdram_test_t phase_3_tests[] = {
{ .name = "0x01000100: ", .fill = fill_pattern, .pattern = 0x01000100, .fade = 0 },
{ .name = "0xFEFFFEFF: ", .fill = fill_pattern, .pattern = 0xFEFFFEFF, .fade = 0 },
{ .name = "0x02000200: ", .fill = fill_pattern, .pattern = 0x02000200, .fade = 0 },
{ .name = "0xFDFFFDFF: ", .fill = fill_pattern, .pattern = 0xFDFFFDFF, .fade = 0 },
{ .name = "0x04000400: ", .fill = fill_pattern, .pattern = 0x04000400, .fade = 0 },
{ .name = "0xFBFFFBFF: ", .fill = fill_pattern, .pattern = 0xFBFFFBFF, .fade = 0 },
{ .name = "0x08000800: ", .fill = fill_pattern, .pattern = 0x08000800, .fade = 0 },
{ .name = "0xF7FFF7FF: ", .fill = fill_pattern, .pattern = 0xF7FFF7FF, .fade = 0 },
{ .name = NULL },
};
sdram_test_t phase_4_tests[] = {
{ .name = "0x10001000: ", .fill = fill_pattern, .pattern = 0x10001000, .fade = 0 },
{ .name = "0xEFFFEFFF: ", .fill = fill_pattern, .pattern = 0xEFFFEFFF, .fade = 0 },
{ .name = "0x20002000: ", .fill = fill_pattern, .pattern = 0x20002000, .fade = 0 },
{ .name = "0xDFFFDFFF: ", .fill = fill_pattern, .pattern = 0xDFFFDFFF, .fade = 0 },
{ .name = "0x40004000: ", .fill = fill_pattern, .pattern = 0x40004000, .fade = 0 },
{ .name = "0xBFFFBFFF: ", .fill = fill_pattern, .pattern = 0xBFFFBFFF, .fade = 0 },
{ .name = "0x80008000: ", .fill = fill_pattern, .pattern = 0x80008000, .fade = 0 },
{ .name = "0x7FFF7FFF: ", .fill = fill_pattern, .pattern = 0x7FFF7FFF, .fade = 0 },
{ .name = NULL },
};
sdram_test_t phase_5_tests[] = {
{ .name = "Fadeout (0): ", .fill = fill_pattern, .pattern = 0x00000000, .fade = 60 },
{ .name = "Fadeout (1): ", .fill = fill_pattern, .pattern = 0xFFFFFFFF, .fade = 60 },
{ .name = NULL },
};
sdram_test_t *test = NULL;
switch (phase) {
case 0: test = phase_0_tests; break;
case 1: test = phase_1_tests; break;
case 2: test = phase_2_tests; break;
case 3: test = phase_3_tests; break;
case 4: test = phase_4_tests; break;
case 5: test = phase_5_tests; break;
}
for (int offset = 0; offset < SDRAM_SIZE; offset += BUFFER_SIZE) {
if (!patterns[pattern].constant) {
for (int i = 0; i < BUFFER_SIZE / sizeof(uint32_t); i++) {
w_buffer[i] = (rand() << 31) | rand();
}
while (test->name != NULL) {
display_printf("%s ", test->name);
srand(random_seed);
for (int offset = 0; offset < SDRAM_SIZE; offset += TEST_BUFFER_SIZE) {
if ((offset % (SDRAM_SIZE / 16)) == 0) {
display_printf("w");
}
pi_dma_write((io32_t *) (SDRAM_ADDRESS + offset), w_buffer, BUFFER_SIZE);
test->fill(w_buffer, TEST_BUFFER_SIZE, test->pattern, offset);
pi_dma_read((io32_t *) (SDRAM_ADDRESS + offset), r_buffer, BUFFER_SIZE);
pi_dma_write((io32_t *) (SDRAM_ADDRESS + offset), w_buffer, TEST_BUFFER_SIZE);
}
for (int i = 0; i < BUFFER_SIZE / sizeof(uint32_t); i++) {
if (w_buffer[i] != r_buffer[i]) {
display_printf(
"\nMISMATCH: [0x%08X]: 0x%08X (R) != 0x%08X (W)\n",
SDRAM_ADDRESS + offset,
r_buffer[i],
w_buffer[i]
for (int fade = test->fade; fade > 0; fade--) {
display_printf(" %3ds", fade);
delay_ms(1000);
display_printf("\b\b\b\b\b");
}
srand(random_seed);
for (int offset = 0; offset < SDRAM_SIZE; offset += TEST_BUFFER_SIZE) {
if ((offset % (SDRAM_SIZE / 16)) == 0) {
display_printf("r");
}
test->fill(w_buffer, TEST_BUFFER_SIZE, test->pattern, offset);
pi_dma_read((io32_t *) (SDRAM_ADDRESS + offset), r_buffer, TEST_BUFFER_SIZE);
uint64_t *test_data = (uint64_t *) (w_buffer);
uint64_t *check_data = (uint64_t *) (r_buffer);
for (int i = 0; i < TEST_BUFFER_SIZE / sizeof(uint64_t); i++) {
if (test_data[i] != check_data[i]) {
error_display(
"SDRAM test failed, %s\n"
" > Mismatch error at address 0x%08lX\n"
" > 0x%016llX (W) != 0x%016llX (R)",
test->name,
SDRAM_ADDRESS + offset + (i * sizeof(uint64_t)),
test_data[i],
check_data[i]
);
while (true);
}
}
}
if ((offset % (SDRAM_SIZE / 32)) == 0) {
display_printf(".");
}
}
random_seed += c0_count();
display_printf(" OK\n");
test += 1;
}
phase += 1;
if (phase > 5) {
phase = 0;
}
}
@ -252,7 +514,7 @@ bool test_check (void) {
}
if ((error = sc64_get_config(CFG_ID_BUTTON_STATE, &button_state)) != SC64_OK) {
error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error);
error_display("Command CONFIG_GET [BUTTON_STATE] failed\n (%08X) - %s", error, sc64_error_description(error));
}
return (button_state != 0);
@ -263,12 +525,32 @@ static struct {
void (*fn) (void);
} tests[] = {
{ "SC64 CFG", test_sc64_cfg },
{ "RTC", test_rtc },
{ "SD card", test_sd_card },
{ "SDRAM", test_sdram },
{ "PI", test_pi },
{ "SD card (I/O)", test_sd_card_io },
{ "SD card (FatFs)", test_sd_card_fatfs },
{ "SDRAM (1/6)", test_sdram },
{ "SDRAM (2/6)", test_sdram },
{ "SDRAM (3/6)", test_sdram },
{ "SDRAM (4/6)", test_sdram },
{ "SDRAM (5/6)", test_sdram },
{ "SDRAM (6/6)", test_sdram },
};
void test_execute (void) {
sc64_error_t error;
pi_io_config(0x0F, 0x05, 0x0C, 0x02);
if ((error = sc64_set_config(CFG_ID_ROM_WRITE_ENABLE, true)) != SC64_OK) {
error_display("Command CONFIG_SET [ROM_WRITE_ENABLE] failed\n (%08X) - %s", error, sc64_error_description(error));
}
if ((error = sc64_set_config(CFG_ID_ROM_SHADOW_ENABLE, false)) != SC64_OK) {
error_display("Command CONFIG_SET [ROM_SHADOW_ENABLE] failed\n (%08X) - %s", error, sc64_error_description(error));
}
random_seed = __entropy + c0_count();
const int test_count = sizeof(tests) / sizeof(tests[0]);
int current = 0;
@ -286,9 +568,10 @@ void test_execute (void) {
}
display_printf("Next test [ %s ] starts in: ", tests[current].title);
for (int delay = 5; delay > 0; delay--) {
display_printf("\b%d", delay);
for (int delay = 10; delay > 0; delay--) {
display_printf("%2ds", delay);
delay_ms(1000);
display_printf("\b\b\b", delay);
}
}
}

View File

@ -92,16 +92,6 @@ typedef enum {
TV_TYPE_PASSTHROUGH = 3
} tv_type_t;
typedef enum {
CFG_ERROR_OK = 0,
CFG_ERROR_BAD_ARGUMENT = 1,
CFG_ERROR_BAD_ADDRESS = 2,
CFG_ERROR_BAD_CONFIG_ID = 3,
CFG_ERROR_TIMEOUT = 4,
CFG_ERROR_SD_CARD = 5,
CFG_ERROR_UNKNOWN_CMD = -1,
} cfg_error_t;
typedef enum {
SD_CARD_OP_DEINIT = 0,
SD_CARD_OP_INIT = 1,
@ -121,6 +111,18 @@ typedef enum {
BRAM = (1 << 2),
} translate_type_t;
typedef enum {
ERROR_TYPE_CFG = 0,
ERROR_TYPE_SD_CARD = 1,
} error_type_t;
typedef enum {
CFG_OK = 0,
CFG_ERROR_UNKNOWN_COMMAND = 1,
CFG_ERROR_INVALID_ARGUMENT = 2,
CFG_ERROR_INVALID_ADDRESS = 3,
CFG_ERROR_INVALID_ID = 4,
} cfg_error_t;
struct process {
bool cmd_queued;
@ -162,9 +164,9 @@ static void cfg_cmd_reply_success (void) {
fpga_reg_set(REG_CFG_CMD, CFG_CMD_DONE);
}
static void cfg_cmd_reply_error (cfg_error_t error) {
static void cfg_cmd_reply_error (error_type_t type, uint32_t error) {
p.cmd_queued = false;
fpga_reg_set(REG_CFG_DATA_0, error);
fpga_reg_set(REG_CFG_DATA_0, ((type & 0xFF) << 24) | (error & 0xFFFFFF));
fpga_reg_set(REG_CFG_DATA_1, 0);
fpga_reg_set(REG_CFG_CMD, CFG_CMD_ERROR | CFG_CMD_DONE);
}
@ -551,7 +553,7 @@ void cfg_process (void) {
case CMD_ID_CONFIG_GET:
if (cfg_query(p.data)) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_CONFIG_ID);
return cfg_cmd_reply_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ID);
}
break;
@ -559,7 +561,7 @@ void cfg_process (void) {
uint32_t prev[2] = { p.data[0], 0 };
cfg_query(prev);
if (cfg_update(p.data)) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_CONFIG_ID);
return cfg_cmd_reply_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ID);
}
p.data[1] = prev[1];
break;
@ -567,13 +569,13 @@ void cfg_process (void) {
case CMD_ID_SETTING_GET:
if (cfg_query_setting(p.data)) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_CONFIG_ID);
return cfg_cmd_reply_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ID);
}
break;
case CMD_ID_SETTING_SET:
if (cfg_update_setting(p.data)) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_CONFIG_ID);
return cfg_cmd_reply_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ID);
}
break;
@ -587,7 +589,7 @@ void cfg_process (void) {
case CMD_ID_USB_READ:
if (cfg_translate_address(&p.data[0], p.data[1], (SDRAM | BRAM))) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_ADDRESS);
return cfg_cmd_reply_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS);
}
if (!usb_prepare_read(p.data)) {
return;
@ -596,7 +598,7 @@ void cfg_process (void) {
case CMD_ID_USB_WRITE: {
if (cfg_translate_address(&p.data[0], p.data[1] & 0xFFFFFF, (SDRAM | BRAM))) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_ADDRESS);
return cfg_cmd_reply_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS);
}
usb_tx_info_t packet_info;
usb_create_packet(&packet_info, PACKET_CMD_DEBUG_OUTPUT);
@ -629,10 +631,10 @@ void cfg_process (void) {
case SD_CARD_OP_INIT: {
led_activity_on();
bool error = sd_card_init();
sd_error_t error = sd_card_init();
led_activity_off();
if (error) {
return cfg_cmd_reply_error(CFG_ERROR_SD_CARD);
if (error != SD_OK) {
return cfg_cmd_reply_error(ERROR_TYPE_SD_CARD, error);
}
break;
}
@ -643,27 +645,32 @@ void cfg_process (void) {
case SD_CARD_OP_GET_INFO:
if (cfg_translate_address(&p.data[0], SD_CARD_INFO_SIZE, (SDRAM | BRAM))) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_ADDRESS);
return cfg_cmd_reply_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ADDRESS);
}
if (sd_card_get_info(p.data[0])) {
return cfg_cmd_reply_error(CFG_ERROR_SD_CARD);
sd_error_t error = sd_card_get_info(p.data[0]);
if (error != SD_OK) {
return cfg_cmd_reply_error(ERROR_TYPE_SD_CARD, error);
}
break;
case SD_CARD_OP_BYTE_SWAP_ON:
if (sd_set_byte_swap(true)) {
return cfg_cmd_reply_error(CFG_ERROR_SD_CARD);
case SD_CARD_OP_BYTE_SWAP_ON: {
sd_error_t error = sd_set_byte_swap(true);
if (error != SD_OK) {
return cfg_cmd_reply_error(ERROR_TYPE_SD_CARD, error);
}
break;
}
case SD_CARD_OP_BYTE_SWAP_OFF:
if (sd_set_byte_swap(false)) {
return cfg_cmd_reply_error(CFG_ERROR_SD_CARD);
case SD_CARD_OP_BYTE_SWAP_OFF: {
sd_error_t error = sd_set_byte_swap(false);
if (error != SD_OK) {
return cfg_cmd_reply_error(ERROR_TYPE_SD_CARD, error);
}
break;
}
default:
return cfg_cmd_reply_error(CFG_ERROR_BAD_ARGUMENT);
return cfg_cmd_reply_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_OPERATION);
}
break;
@ -673,16 +680,16 @@ void cfg_process (void) {
case CMD_ID_SD_READ: {
if (p.data[1] >= 0x800000) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_ARGUMENT);
return cfg_cmd_reply_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ARGUMENT);
}
if (cfg_translate_address(&p.data[0], p.data[1] * SD_SECTOR_SIZE, (SDRAM | FLASH | BRAM))) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_ADDRESS);
if (cfg_translate_address(&p.data[0], (p.data[1] * SD_SECTOR_SIZE), (SDRAM | FLASH | BRAM))) {
return cfg_cmd_reply_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ADDRESS);
}
led_activity_on();
bool error = sd_read_sectors(p.data[0], p.sd_card_sector, p.data[1]);
sd_error_t error = sd_read_sectors(p.data[0], p.sd_card_sector, p.data[1]);
led_activity_off();
if (error) {
return cfg_cmd_reply_error(CFG_ERROR_SD_CARD);
if (error != SD_OK) {
return cfg_cmd_reply_error(ERROR_TYPE_SD_CARD, error);
}
p.sd_card_sector += p.data[1];
break;
@ -690,16 +697,16 @@ void cfg_process (void) {
case CMD_ID_SD_WRITE: {
if (p.data[1] >= 0x800000) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_ARGUMENT);
return cfg_cmd_reply_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ARGUMENT);
}
if (cfg_translate_address(&p.data[0], p.data[1] * SD_SECTOR_SIZE, (SDRAM | FLASH | BRAM))) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_ADDRESS);
if (cfg_translate_address(&p.data[0], (p.data[1] * SD_SECTOR_SIZE), (SDRAM | FLASH | BRAM))) {
return cfg_cmd_reply_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ADDRESS);
}
led_activity_on();
bool error = sd_write_sectors(p.data[0], p.sd_card_sector, p.data[1]);
sd_error_t error = sd_write_sectors(p.data[0], p.sd_card_sector, p.data[1]);
led_activity_off();
if (error) {
return cfg_cmd_reply_error(CFG_ERROR_SD_CARD);
if (error != SD_OK) {
return cfg_cmd_reply_error(ERROR_TYPE_SD_CARD, error);
}
p.sd_card_sector += p.data[1];
break;
@ -707,7 +714,7 @@ void cfg_process (void) {
case CMD_ID_DISK_MAPPING_SET:
if (cfg_translate_address(&p.data[0], p.data[1], (SDRAM | BRAM))) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_ADDRESS);
return cfg_cmd_reply_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS);
}
dd_set_disk_mapping(p.data[0], p.data[1]);
break;
@ -718,7 +725,7 @@ void cfg_process (void) {
case CMD_ID_WRITEBACK_SD_INFO:
if (cfg_translate_address(&p.data[0], WRITEBACK_SECTOR_TABLE_SIZE, (SDRAM | BRAM))) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_ADDRESS);
return cfg_cmd_reply_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS);
}
writeback_load_sector_table(p.data[0]);
writeback_enable(WRITEBACK_SD);
@ -726,13 +733,13 @@ void cfg_process (void) {
case CMD_ID_FLASH_PROGRAM:
if (p.data[1] >= DATA_BUFFER_SIZE) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_ARGUMENT);
return cfg_cmd_reply_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ARGUMENT);
}
if (cfg_translate_address(&p.data[0], p.data[1], FLASH)) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_ADDRESS);
return cfg_cmd_reply_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS);
}
if (flash_program(DATA_BUFFER_ADDRESS, p.data[0], p.data[1])) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_ARGUMENT);
return cfg_cmd_reply_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ARGUMENT);
}
break;
@ -745,21 +752,21 @@ void cfg_process (void) {
case CMD_ID_FLASH_ERASE_BLOCK:
if (cfg_translate_address(&p.data[0], FLASH_ERASE_BLOCK_SIZE, FLASH)) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_ADDRESS);
return cfg_cmd_reply_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS);
}
if (flash_erase_block(p.data[0])) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_ARGUMENT);
return cfg_cmd_reply_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ARGUMENT);
}
break;
case CMD_ID_DIAGNOSTIC_GET:
if (cfg_read_diagnostic_data(p.data)) {
return cfg_cmd_reply_error(CFG_ERROR_BAD_CONFIG_ID);
return cfg_cmd_reply_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ID);
}
break;
default:
return cfg_cmd_reply_error(CFG_ERROR_UNKNOWN_CMD);
return cfg_cmd_reply_error(ERROR_TYPE_CFG, CFG_ERROR_UNKNOWN_COMMAND);
}
cfg_cmd_reply_success();

View File

@ -137,9 +137,9 @@ static bool dd_block_read_request (void) {
uint32_t sector_table[DD_SD_SECTOR_TABLE_SIZE];
uint32_t sectors = dd_fill_sd_sector_table(index, sector_table, false);
led_activity_on();
bool error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_read_sectors);
sd_error_t error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_read_sectors);
led_activity_off();
dd_set_block_ready(!error);
dd_set_block_ready(error == SD_OK);
} else {
usb_tx_info_t packet_info;
usb_create_packet(&packet_info, PACKET_CMD_DD_REQUEST);
@ -161,9 +161,9 @@ static bool dd_block_write_request (void) {
uint32_t sector_table[DD_SD_SECTOR_TABLE_SIZE];
uint32_t sectors = dd_fill_sd_sector_table(index, sector_table, true);
led_activity_on();
bool error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_write_sectors);
sd_error_t error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_write_sectors);
led_activity_off();
dd_set_block_ready(!error);
dd_set_block_ready(error == SD_OK);
} else {
usb_tx_info_t packet_info;
usb_create_packet(&packet_info, PACKET_CMD_DD_REQUEST);

View File

@ -8,10 +8,13 @@
bool flash_program (uint32_t src, uint32_t dst, uint32_t length) {
if (((src + length) > FLASH_ADDRESS) && (src < (FLASH_ADDRESS + FLASH_SIZE))) {
if ((dst < FLASH_ADDRESS) || ((dst + length) > (FLASH_ADDRESS + FLASH_SIZE))) {
return true;
}
if ((dst < FLASH_ADDRESS) || ((dst + length) > (FLASH_ADDRESS + FLASH_SIZE))) {
if ((src <= dst) && ((src + length) > dst)) {
return true;
}
if ((dst <= src) && ((dst + length) > src)) {
return true;
}
while (length > 0) {

View File

@ -61,7 +61,6 @@ typedef enum {
#define ALIGN(value, align) (((value) + ((typeof(value))(align) - 1)) & ~((typeof(value))(align) - 1))
#define SWAP16(x) ((((x) & 0xFF) << 8) | (((x) & 0xFF00) >> 8))
#define SWAP32(x) (((x) & 0xFF) << 24 | ((x) & 0xFF00) << 8 | ((x) & 0xFF0000) >> 8 | ((x) & 0xFF000000) >> 24)
#define FPGA_ID (0x64)

View File

@ -339,12 +339,12 @@ static void hw_i2c_init (void) {
I2C1->CR1 |= I2C_CR1_PE;
}
i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length) {
i2c_error_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length) {
hw_timeout_start();
while (I2C1->ISR & I2C_ISR_BUSY) {
if (hw_timeout_elapsed(I2C_TIMEOUT_US_BUSY)) {
return I2C_ERR_BUSY;
return I2C_ERROR_BUSY;
}
}
@ -372,11 +372,11 @@ i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint
}
if (isr & I2C_ISR_NACKF) {
return I2C_ERR_NACK;
return I2C_ERROR_NACK;
}
if (hw_timeout_elapsed(tx_timeout)) {
return I2C_ERR_TIMEOUT;
return I2C_ERROR_TIMEOUT;
}
}
@ -386,7 +386,7 @@ i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint
while (!(I2C1->ISR & I2C_ISR_TC)) {
if (hw_timeout_elapsed(tx_timeout)) {
return I2C_ERR_TIMEOUT;
return I2C_ERROR_TIMEOUT;
}
}
}
@ -415,7 +415,7 @@ i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint
}
if (hw_timeout_elapsed(rx_timeout)) {
return I2C_ERR_TIMEOUT;
return I2C_ERROR_TIMEOUT;
}
}
}

View File

@ -27,10 +27,10 @@ typedef enum {
typedef enum {
I2C_OK,
I2C_ERR_BUSY,
I2C_ERR_TIMEOUT,
I2C_ERR_NACK,
} i2c_err_t;
I2C_ERROR_BUSY,
I2C_ERROR_TIMEOUT,
I2C_ERROR_NACK,
} i2c_error_t;
typedef uint64_t hw_flash_t;
@ -72,7 +72,7 @@ void hw_spi_stop (void);
void hw_spi_rx (uint8_t *data, int length);
void hw_spi_tx (uint8_t *data, int length);
i2c_err_t hw_i2c_trx (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length);
i2c_error_t hw_i2c_trx (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length);
void hw_crc32_reset (void);
uint32_t hw_crc32_calculate (uint8_t *data, uint32_t length);

View File

@ -133,9 +133,9 @@ static bool lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint
packet_length += length;
}
i2c_err_t err = hw_i2c_trx(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length));
i2c_error_t error = hw_i2c_trx(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length));
return (err != I2C_OK);
return (error != I2C_OK);
#else
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE);

View File

@ -56,10 +56,7 @@ void led_blink_error (led_error_t error) {
break;
}
error_active = (
cic_error |
rtc_error
);
error_active = true;
}
void led_clear_error (led_error_t error) {
@ -72,17 +69,6 @@ void led_clear_error (led_error_t error) {
rtc_error = false;
break;
}
error_active = (
cic_error |
rtc_error
);
if (!error_active) {
activity_pulse = false;
activity_pulse_timer = 0;
error_timer = 0;
}
}
@ -105,6 +91,13 @@ void led_process (void) {
blinks = CIC_ERROR_BLINKS;
} else if (rtc_error) {
blinks = RTC_ERROR_BLINKS;
} else {
activity_pulse = false;
activity_pulse_timer = 0;
error_active = false;
error_timer = 0;
hw_gpio_reset(GPIO_ID_LED);
return;
}
bool led_on = false;

View File

@ -9,6 +9,10 @@
#define CMD6_ARG_CHECK_HS (0x00FFFFF1UL)
#define CMD6_ARG_SWITCH_HS (0x80FFFFF1UL)
#define CMD6_DATA_LENGTH (64)
#define CMD6_INVALID_CURRENT_LIMIT(b) ((((b)[0] << 8) | (b)[1]) == 0)
#define CMD6_HS_SUPPORTED(b) ((b)[13] & (1 << 1))
#define CMD6_HS_ENABLED(b) (((b)[16] & 0x0F) == 0x01)
#define CMD8_ARG_SUPPLY_VOLTAGE_27_36_V (1 << 8)
#define CMD8_ARG_CHECK_PATTERN (0xAA << 0)
@ -18,6 +22,9 @@
#define ACMD41_ARG_OCR (0x300000 << 0)
#define ACMD41_ARG_HCS (1 << 30)
#define R1_APP_CMD (1 << 5)
#define R1_ILLEGAL_COMMAND (1 << 22)
#define R3_OCR (0x300000 << 0)
#define R3_CCS (1 << 30)
#define R3_BUSY (1 << 31)
@ -27,12 +34,9 @@
#define R7_SUPPLY_VOLTAGE_27_36_V (1 << 8)
#define R7_CHECK_PATTERN (0xAA << 0)
#define SWITCH_FUNCTION_CURRENT_LIMIT (SD_INIT_BUFFER_ADDRESS + 0)
#define SWITCH_FUNCTION_GROUP_1 (SD_INIT_BUFFER_ADDRESS + 12)
#define SWITCH_FUNCTION_GROUP_1_HS (1 << 1)
#define TIMEOUT_INIT_MS (1000)
#define DAT_CRC16_LENGTH (8)
#define DAT_BLOCK_MAX_COUNT (256)
#define DAT_TIMEOUT_INIT_MS (2000)
#define DAT_TIMEOUT_DATA_MS (5000)
@ -62,9 +66,17 @@ typedef enum {
typedef enum {
DAT_OK,
DAT_ERR_IO,
DAT_ERR_TIMEOUT,
} dat_err_t;
DAT_ERROR_IO,
DAT_ERROR_TIMEOUT,
} dat_error_t;
typedef enum {
CMD6_OK,
CMD6_ERROR_ILLEGAL_CMD,
CMD6_ERROR_IO,
CMD6_ERROR_CRC,
CMD6_ERROR_TIMEOUT,
} cmd6_error_t;
struct process {
@ -150,7 +162,11 @@ static bool sd_cmd (uint8_t cmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) {
}
static bool sd_acmd (uint8_t acmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) {
if (sd_cmd(55, p.rca, RSP_R1, NULL)) {
uint32_t acmd_rsp;
if (sd_cmd(55, p.rca, RSP_R1, &acmd_rsp)) {
return true;
}
if (!(acmd_rsp & R1_APP_CMD)) {
return true;
}
if (sd_cmd(acmd, arg, rsp_type, rsp)) {
@ -185,7 +201,7 @@ static void sd_dat_abort (void) {
fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH);
}
static dat_err_t sd_dat_wait (uint16_t timeout_ms) {
static dat_error_t sd_dat_wait (uint16_t timeout_ms) {
timer_countdown_start(TIMER_ID_SD, timeout_ms);
do {
@ -194,7 +210,7 @@ static dat_err_t sd_dat_wait (uint16_t timeout_ms) {
if ((!(sd_dat & SD_DAT_BUSY)) && (!(sd_dma_scr & DMA_SCR_BUSY))) {
if (sd_dat & SD_DAT_ERROR) {
sd_dat_abort();
return DAT_ERR_IO;
return DAT_ERROR_IO;
}
return DAT_OK;
}
@ -202,19 +218,85 @@ static dat_err_t sd_dat_wait (uint16_t timeout_ms) {
sd_dat_abort();
return DAT_ERR_TIMEOUT;
return DAT_ERROR_TIMEOUT;
}
static bool sd_dat_check_crc16 (uint8_t *data, uint32_t length) {
uint16_t device_crc[4];
uint16_t controller_crc[4];
for (int crc = 0; crc < 4; crc++) {
device_crc[crc] = 0;
controller_crc[crc] = 0;
}
for (uint32_t index = length; index < (length + DAT_CRC16_LENGTH); index++) {
uint8_t byte = data[index];
for (int nibble = 0; nibble < 2; nibble++) {
for (int crc = 0; crc < 4; crc++) {
device_crc[crc] <<= 1;
device_crc[crc] |= (byte >> (7 - crc)) & (1 << 0);
}
byte <<= 4;
}
}
for (uint32_t index = 0; index < length; index++) {
uint8_t byte = data[index];
for (int nibble = 0; nibble < 2; nibble++) {
for (int crc = 0; crc < 4; crc++) {
uint8_t inv = ((controller_crc[crc] >> 15) ^ (byte >> (7 - crc))) & (1 << 0);
controller_crc[crc] ^= (inv << 11) | (inv << 4);
controller_crc[crc] <<= 1;
controller_crc[crc] |= inv;
}
byte <<= 4;
}
}
for (int crc = 0; crc < 4; crc++) {
if (controller_crc[crc] != device_crc[crc]) {
return true;
}
}
return false;
}
static cmd6_error_t sd_cmd6 (uint32_t arg, uint8_t *buffer) {
uint32_t rsp;
sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ);
if (sd_cmd(6, arg, RSP_R1, NULL)) {
sd_dat_abort();
if ((!sd_cmd(13, p.rca, RSP_R1, &rsp)) && (rsp & R1_ILLEGAL_COMMAND)) {
return CMD6_ERROR_ILLEGAL_CMD;
}
return CMD6_ERROR_IO;
}
if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERROR_TIMEOUT) {
return CMD6_ERROR_TIMEOUT;
}
fpga_mem_read(SD_INIT_BUFFER_ADDRESS, CMD6_DATA_LENGTH + DAT_CRC16_LENGTH, buffer);
if (sd_dat_check_crc16(buffer, CMD6_DATA_LENGTH)) {
return CMD6_ERROR_CRC;
}
return CMD6_OK;
}
bool sd_card_init (void) {
sd_error_t sd_card_init (void) {
uint32_t arg;
uint32_t rsp;
uint16_t tmp;
uint8_t cmd6_buffer[CMD6_DATA_LENGTH + DAT_CRC16_LENGTH];
p.byte_swap = false;
if (p.card_initialized) {
return false;
return SD_OK;
}
if (!sd_card_is_inserted()) {
return SD_ERROR_NO_CARD_IN_SLOT;
}
p.card_initialized = true;
@ -224,13 +306,12 @@ bool sd_card_init (void) {
sd_cmd(0, 0, RSP_NONE, NULL);
arg = (CMD8_ARG_SUPPLY_VOLTAGE_27_36_V | CMD8_ARG_CHECK_PATTERN);
if (sd_cmd(8, arg, RSP_R7, &rsp)) {
if (sd_cmd(8, (CMD8_ARG_SUPPLY_VOLTAGE_27_36_V | CMD8_ARG_CHECK_PATTERN), RSP_R7, &rsp)) {
arg = ACMD41_ARG_OCR;
} else {
if (rsp != (R7_SUPPLY_VOLTAGE_27_36_V | R7_CHECK_PATTERN)) {
sd_card_deinit();
return true;
return SD_ERROR_CMD8_IO;
}
arg = (ACMD41_ARG_HCS | ACMD41_ARG_OCR);
}
@ -239,89 +320,106 @@ bool sd_card_init (void) {
do {
if (timer_countdown_elapsed(TIMER_ID_SD)) {
sd_card_deinit();
return true;
return SD_ERROR_ACMD41_TIMEOUT;
}
if (sd_acmd(41, arg, RSP_R3, &rsp)) {
sd_card_deinit();
return true;
return SD_ERROR_ACMD41_IO;
}
if (rsp & R3_BUSY) {
if ((rsp & R3_OCR) == 0) {
sd_card_deinit();
return true;
return SD_ERROR_ACMD41_OCR;
}
p.card_type_block = (rsp & R3_CCS);
break;
}
} while (true);
sd_set_clock(CLOCK_25MHZ);
if (sd_cmd(2, 0, RSP_R2, NULL)) {
sd_card_deinit();
return true;
return SD_ERROR_CMD2_IO;
}
if (sd_cmd(3, 0, RSP_R6, &rsp)) {
sd_card_deinit();
return true;
return SD_ERROR_CMD3_IO;
}
p.rca = (rsp & R6_RCA_MASK);
if (sd_cmd(9, p.rca, RSP_R2, p.csd)) {
sd_card_deinit();
return true;
}
if (sd_cmd(10, p.rca, RSP_R2, p.cid)) {
sd_card_deinit();
return true;
}
if (sd_cmd(7, p.rca, RSP_R1b, NULL)) {
sd_card_deinit();
return true;
return SD_ERROR_CMD7_IO;
}
sd_set_clock(CLOCK_25MHZ);
if (sd_acmd(6, ACMD6_ARG_BUS_WIDTH_4BIT, RSP_R1, NULL)) {
sd_card_deinit();
return true;
return SD_ERROR_ACMD6_IO;
}
sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ);
if (sd_cmd(6, CMD6_ARG_CHECK_HS, RSP_R1, NULL)) {
sd_dat_abort();
switch (sd_cmd6(CMD6_ARG_CHECK_HS, cmd6_buffer)) {
case CMD6_OK: {
if (CMD6_INVALID_CURRENT_LIMIT(cmd6_buffer)) {
sd_card_deinit();
return true;
return SD_ERROR_CMD6_CHECK_RESPONSE;
}
if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERR_TIMEOUT) {
if (CMD6_HS_SUPPORTED(cmd6_buffer)) {
switch (sd_cmd6(CMD6_ARG_SWITCH_HS, cmd6_buffer)) {
case CMD6_OK: {
if (CMD6_INVALID_CURRENT_LIMIT(cmd6_buffer)) {
sd_card_deinit();
return true;
return SD_ERROR_CMD6_SWITCH_RESPONSE;
}
fpga_mem_read(SWITCH_FUNCTION_CURRENT_LIMIT, 2, (uint8_t *) (&tmp));
if (SWAP16(tmp) == 0) {
sd_card_deinit();
return true;
}
fpga_mem_read(SWITCH_FUNCTION_GROUP_1, 2, (uint8_t *) (&tmp));
if (SWAP16(tmp) & SWITCH_FUNCTION_GROUP_1_HS) {
sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ);
if (sd_cmd(6, CMD6_ARG_SWITCH_HS, RSP_R1, NULL)) {
sd_dat_abort();
sd_card_deinit();
return true;
}
if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERR_TIMEOUT) {
sd_card_deinit();
return true;
}
fpga_mem_read(SWITCH_FUNCTION_GROUP_1, 2, (uint8_t *) (&tmp));
if (SWAP16(tmp) & SWITCH_FUNCTION_GROUP_1_HS) {
if (CMD6_HS_ENABLED(cmd6_buffer)) {
sd_set_clock(CLOCK_50MHZ);
}
break;
}
case CMD6_ERROR_IO:
sd_card_deinit();
return SD_ERROR_CMD6_SWITCH_IO;
case CMD6_ERROR_CRC:
sd_card_deinit();
return SD_ERROR_CMD6_SWITCH_CRC;
case CMD6_ERROR_TIMEOUT:
sd_card_deinit();
return SD_ERROR_CMD6_SWITCH_TIMEOUT;
case CMD6_ERROR_ILLEGAL_CMD:
break;
}
}
break;
}
case CMD6_ERROR_IO:
sd_card_deinit();
return SD_ERROR_CMD6_CHECK_IO;
case CMD6_ERROR_CRC:
sd_card_deinit();
return SD_ERROR_CMD6_CHECK_CRC;
case CMD6_ERROR_TIMEOUT:
sd_card_deinit();
return SD_ERROR_CMD6_CHECK_TIMEOUT;
case CMD6_ERROR_ILLEGAL_CMD:
break;
}
return false;
sd_cmd(7, 0, RSP_NONE, NULL);
if (sd_cmd(9, p.rca, RSP_R2, p.csd)) {
return SD_ERROR_CMD9_IO;
}
if (sd_cmd(10, p.rca, RSP_R2, p.cid)) {
return SD_ERROR_CMD10_IO;
}
if (sd_cmd(7, p.rca, RSP_R1b, NULL)) {
return SD_ERROR_CMD7_IO;
}
return SD_OK;
}
void sd_card_deinit (void) {
@ -354,29 +452,33 @@ uint32_t sd_card_get_status (void) {
);
}
bool sd_card_get_info (uint32_t address) {
sd_error_t sd_card_get_info (uint32_t address) {
if (!p.card_initialized) {
return true;
return SD_ERROR_NOT_INITIALIZED;
}
fpga_mem_write(address, sizeof(p.csd), p.csd);
address += sizeof(p.csd);
fpga_mem_write(address, sizeof(p.cid), p.cid);
address += sizeof(p.cid);
return false;
return SD_OK;
}
bool sd_set_byte_swap (bool enabled) {
sd_error_t sd_set_byte_swap (bool enabled) {
if (!p.card_initialized) {
return true;
return SD_ERROR_NOT_INITIALIZED;
}
p.byte_swap = enabled;
return false;
return SD_OK;
}
bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
if (!p.card_initialized || (count == 0)) {
return true;
sd_error_t sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
if (!p.card_initialized) {
return SD_ERROR_NOT_INITIALIZED;
}
if (count == 0) {
return SD_ERROR_INVALID_ARGUMENT;
}
if (!p.card_type_block) {
@ -386,12 +488,13 @@ bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
while (count > 0) {
uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count);
if (sd_cmd(25, sector, RSP_R1, NULL)) {
return true;
return SD_ERROR_CMD25_IO;
}
sd_dat_prepare(address, blocks, DAT_WRITE);
if (sd_dat_wait(DAT_TIMEOUT_DATA_MS) != DAT_OK) {
dat_error_t error = sd_dat_wait(DAT_TIMEOUT_DATA_MS);
if (error != DAT_OK) {
sd_cmd(12, 0, RSP_R1b, NULL);
return true;
return (error == DAT_ERROR_IO) ? SD_ERROR_CMD25_CRC : SD_ERROR_CMD25_TIMEOUT;
}
sd_cmd(12, 0, RSP_R1b, NULL);
address += (blocks * SD_SECTOR_SIZE);
@ -402,13 +505,17 @@ bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
return false;
}
bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
if (!p.card_initialized || (count == 0)) {
return true;
sd_error_t sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
if (!p.card_initialized) {
return SD_ERROR_NOT_INITIALIZED;
}
if (count == 0) {
return SD_ERROR_INVALID_ARGUMENT;
}
if (p.byte_swap && ((address % 2) != 0)) {
return true;
return SD_ERROR_INVALID_ARGUMENT;
}
if (!p.card_type_block) {
@ -420,11 +527,12 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
sd_dat_prepare(address, blocks, DAT_READ);
if (sd_cmd(18, sector, RSP_R1, NULL)) {
sd_dat_abort();
return true;
return SD_ERROR_CMD18_IO;
}
if (sd_dat_wait(DAT_TIMEOUT_DATA_MS) != DAT_OK) {
dat_error_t error = sd_dat_wait(DAT_TIMEOUT_DATA_MS);
if (error != DAT_OK) {
sd_cmd(12, 0, RSP_R1b, NULL);
return true;
return (error == DAT_ERROR_IO) ? SD_ERROR_CMD18_CRC : SD_ERROR_CMD18_TIMEOUT;
}
sd_cmd(12, 0, RSP_R1b, NULL);
address += (blocks * SD_SECTOR_SIZE);
@ -432,21 +540,21 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
count -= blocks;
}
return false;
return SD_OK;
}
bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors) {
sd_error_t sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors) {
uint32_t starting_sector = 0;
uint32_t sectors_to_process = 0;
if (count == 0) {
return true;
return SD_ERROR_INVALID_ARGUMENT;
}
for (uint32_t i = 0; i < count; i++) {
if (sector_table[i] == 0) {
return true;
return SD_ERROR_INVALID_ARGUMENT;
}
sectors_to_process += 1;
if ((i < (count - 1)) && ((sector_table[i] + 1) == sector_table[i + 1])) {
@ -454,14 +562,14 @@ bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t cou
}
bool error = sd_process_sectors(address, sector_table[starting_sector], sectors_to_process);
if (error) {
return true;
return error;
}
address += (sectors_to_process * SD_SECTOR_SIZE);
starting_sector += sectors_to_process;
sectors_to_process = 0;
}
return false;
return SD_OK;
}

View File

@ -10,20 +10,53 @@
#define SD_CARD_INFO_SIZE (32)
typedef bool sd_process_sectors_t (uint32_t address, uint32_t sector, uint32_t count);
typedef enum {
SD_OK = 0,
SD_ERROR_NO_CARD_IN_SLOT = 1,
SD_ERROR_NOT_INITIALIZED = 2,
SD_ERROR_INVALID_ARGUMENT = 3,
SD_ERROR_INVALID_ADDRESS = 4,
SD_ERROR_INVALID_OPERATION = 5,
SD_ERROR_CMD2_IO = 6,
SD_ERROR_CMD3_IO = 7,
SD_ERROR_CMD6_CHECK_IO = 8,
SD_ERROR_CMD6_CHECK_CRC = 9,
SD_ERROR_CMD6_CHECK_TIMEOUT = 10,
SD_ERROR_CMD6_CHECK_RESPONSE = 11,
SD_ERROR_CMD6_SWITCH_IO = 12,
SD_ERROR_CMD6_SWITCH_CRC = 13,
SD_ERROR_CMD6_SWITCH_TIMEOUT = 14,
SD_ERROR_CMD6_SWITCH_RESPONSE = 15,
SD_ERROR_CMD7_IO = 16,
SD_ERROR_CMD8_IO = 17,
SD_ERROR_CMD9_IO = 18,
SD_ERROR_CMD10_IO = 19,
SD_ERROR_CMD18_IO = 20,
SD_ERROR_CMD18_CRC = 21,
SD_ERROR_CMD18_TIMEOUT = 22,
SD_ERROR_CMD25_IO = 23,
SD_ERROR_CMD25_CRC = 24,
SD_ERROR_CMD25_TIMEOUT = 25,
SD_ERROR_ACMD6_IO = 26,
SD_ERROR_ACMD41_IO = 27,
SD_ERROR_ACMD41_OCR = 28,
SD_ERROR_ACMD41_TIMEOUT = 29,
} sd_error_t;
typedef sd_error_t sd_process_sectors_t (uint32_t address, uint32_t sector, uint32_t count);
bool sd_card_init (void);
sd_error_t sd_card_init (void);
void sd_card_deinit (void);
bool sd_card_is_inserted (void);
uint32_t sd_card_get_status (void);
bool sd_card_get_info (uint32_t address);
bool sd_set_byte_swap (bool enabled);
sd_error_t sd_card_get_info (uint32_t address);
sd_error_t sd_set_byte_swap (bool enabled);
bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count);
bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count);
sd_error_t sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count);
sd_error_t sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count);
bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors);
sd_error_t sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors);
void sd_init (void);

View File

@ -8,6 +8,8 @@
#define SDRAM_ADDRESS (0x00000000UL)
#define SDRAM_LENGTH (64 * 1024 * 1024)
#define FLASH_USABLE_LENGTH (14 * 1024 * 1024)
#define UPDATE_ADDRESS_END (SDRAM_ADDRESS + SDRAM_LENGTH + FLASH_USABLE_LENGTH)
#define UPDATE_MAGIC_START (0x54535055UL)
#define BOOTLOADER_ADDRESS (0x04E00000UL)
@ -234,10 +236,10 @@ update_error_t update_prepare (uint32_t address, uint32_t length) {
uint32_t data_address;
uint32_t data_length;
if ((address >= (SDRAM_ADDRESS + SDRAM_LENGTH)) || (length > SDRAM_LENGTH)) {
if ((address >= UPDATE_ADDRESS_END) || (length > (SDRAM_LENGTH + FLASH_USABLE_LENGTH))) {
return UPDATE_ERROR_ADDRESS;
}
if (end_address > (SDRAM_ADDRESS + SDRAM_LENGTH)) {
if (end_address > UPDATE_ADDRESS_END) {
return UPDATE_ERROR_ADDRESS;
}

View File

@ -82,9 +82,9 @@ static void writeback_save_to_sd (void) {
return;
}
bool error = sd_optimize_sectors(address, p.sectors, (length / SD_SECTOR_SIZE), sd_write_sectors);
sd_error_t error = sd_optimize_sectors(address, p.sectors, (length / SD_SECTOR_SIZE), sd_write_sectors);
if (error) {
if (error != SD_OK) {
writeback_disable();
return;
}

37
sw/deployer/Cargo.lock generated
View File

@ -696,6 +696,12 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro-hack"
version = "0.5.20+deprecated"
@ -729,6 +735,36 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rayon"
version = "1.9.0"
@ -810,6 +846,7 @@ dependencies = [
"include-flate",
"md5",
"panic-message",
"rand",
"rust-ini",
"serial2",
"serialport",

View File

@ -19,6 +19,7 @@ image = "0.24.5"
include-flate = { version = "0.2.0", features = ["stable"] }
md5 = "0.7.0"
panic-message = "0.3.0"
rand = "0.8.5"
rust-ini = "0.18.0"
serial2 = "0.2.20"
serialport = "4.3.0"

View File

@ -75,6 +75,9 @@ enum Commands {
command: FirmwareCommands,
},
/// Test SC64 hardware
Test,
/// Expose SC64 device over network
Server(ServerArgs),
}
@ -212,7 +215,7 @@ enum FirmwareCommands {
Backup(FirmwareArgs),
/// Update SC64 firmware from provided file
Update(FirmwareArgs),
Update(FirmwareUpdateArgs),
}
#[derive(Args)]
@ -221,6 +224,16 @@ struct FirmwareArgs {
firmware: PathBuf,
}
#[derive(Args)]
struct FirmwareUpdateArgs {
/// Path to the firmware file
firmware: PathBuf,
/// Put firmware update in the Flash memory instead of SDRAM
#[arg(long)]
use_flash_memory: bool,
}
#[derive(Args)]
struct ServerArgs {
/// Listen on provided address:port
@ -323,6 +336,7 @@ fn handle_command(command: &Commands, port: Option<String>, remote: Option<Strin
Commands::Reset => handle_reset_command(connection),
Commands::Set { command } => handle_set_command(connection, command),
Commands::Firmware { command } => handle_firmware_command(connection, command),
Commands::Test => handle_test_command(connection),
Commands::Server(args) => handle_server_command(connection, args),
};
match result {
@ -738,8 +752,14 @@ fn handle_info_command(connection: Connection) -> Result<(), sc64::Error> {
println!(" LED blink: {}", state.led_enable);
println!(" IS-Viewer 64 offset: 0x{:08X}", state.isv_address);
println!("{}", "SummerCart64 diagnostic information:".bold());
println!(" Last PI address: 0x{:08X}", state.fpga_debug_data.last_pi_address);
println!(" PI FIFO flags: {}", state.fpga_debug_data.pi_fifo_flags);
println!(
" Last PI address: 0x{:08X}",
state.fpga_debug_data.last_pi_address
);
println!(
" PI FIFO flags: {}",
state.fpga_debug_data.pi_fifo_flags
);
println!(" Current CIC step: {}", state.fpga_debug_data.cic_step);
println!(" Diagnostic data: {}", state.diagnostic_data);
@ -765,7 +785,7 @@ fn handle_set_command(connection: Connection, command: &SetCommands) -> Result<(
sc64.set_datetime(datetime)?;
println!(
"SC64 RTC datetime synchronized to: {}",
datetime.format("%Y-%m-%d %H:%M:%S %Z").to_string().green()
datetime.format("%Y-%m-%d %H:%M:%S").to_string().green()
);
}
@ -835,6 +855,12 @@ fn handle_firmware_command(
println!("{}", "Firmware metadata:".bold());
println!("{}", format!("{}", metadata).bright_blue().to_string());
println!("{}", "Firmware file verification was successful".green());
if args.use_flash_memory {
println!(
"{}",
"Warning: using Flash memory to perform firmware update".yellow()
);
}
let answer = prompt(format!("{}", "Continue with update process? [y/N] ".bold()));
if answer.to_ascii_lowercase() != "y" {
println!("{}", "Firmware update process aborted".red());
@ -847,7 +873,7 @@ fn handle_firmware_command(
log_wait(
format!("Updating firmware, this might take a while [{update_name}]"),
|| sc64.update_firmware(&firmware),
|| sc64.update_firmware(&firmware, args.use_flash_memory),
)?;
Ok(())
@ -855,6 +881,98 @@ fn handle_firmware_command(
}
}
fn handle_test_command(connection: Connection) -> Result<(), sc64::Error> {
let mut sc64 = init_sc64(connection, false)?;
println!("{}: SDRAM (pattern)", "[SC64 Tests]".bold());
let sdram_pattern_tests = [
(sc64::MemoryTestPattern::OwnAddress(false), None),
(sc64::MemoryTestPattern::OwnAddress(true), None),
(sc64::MemoryTestPattern::AllZeros, None),
(sc64::MemoryTestPattern::AllOnes, None),
(sc64::MemoryTestPattern::Custom(0xAAAA5555), None),
(sc64::MemoryTestPattern::Custom(0x5555AAAA), None),
(sc64::MemoryTestPattern::Random, None),
(sc64::MemoryTestPattern::Random, None),
(sc64::MemoryTestPattern::Random, None),
(sc64::MemoryTestPattern::Random, None),
(sc64::MemoryTestPattern::Custom(0x00010001), None),
(sc64::MemoryTestPattern::Custom(0xFFFEFFFE), None),
(sc64::MemoryTestPattern::Custom(0x00020002), None),
(sc64::MemoryTestPattern::Custom(0xFFFDFFFD), None),
(sc64::MemoryTestPattern::Custom(0x00040004), None),
(sc64::MemoryTestPattern::Custom(0xFFFBFFFB), None),
(sc64::MemoryTestPattern::Custom(0x00080008), None),
(sc64::MemoryTestPattern::Custom(0xFFF7FFF7), None),
(sc64::MemoryTestPattern::Custom(0x00100010), None),
(sc64::MemoryTestPattern::Custom(0xFFEFFFEF), None),
(sc64::MemoryTestPattern::Custom(0x00200020), None),
(sc64::MemoryTestPattern::Custom(0xFFDFFFDF), None),
(sc64::MemoryTestPattern::Custom(0x00400040), None),
(sc64::MemoryTestPattern::Custom(0xFFBFFFBF), None),
(sc64::MemoryTestPattern::Custom(0x00800080), None),
(sc64::MemoryTestPattern::Custom(0xFF7FFF7F), None),
(sc64::MemoryTestPattern::Custom(0x01000100), None),
(sc64::MemoryTestPattern::Custom(0xFEFFFEFF), None),
(sc64::MemoryTestPattern::Custom(0x02000200), None),
(sc64::MemoryTestPattern::Custom(0xFDFFFDFF), None),
(sc64::MemoryTestPattern::Custom(0x04000400), None),
(sc64::MemoryTestPattern::Custom(0xFBFFFBFF), None),
(sc64::MemoryTestPattern::Custom(0x08000800), None),
(sc64::MemoryTestPattern::Custom(0xF7FFF7FF), None),
(sc64::MemoryTestPattern::Custom(0x10001000), None),
(sc64::MemoryTestPattern::Custom(0xEFFFEFFF), None),
(sc64::MemoryTestPattern::Custom(0x20002000), None),
(sc64::MemoryTestPattern::Custom(0xDFFFDFFF), None),
(sc64::MemoryTestPattern::Custom(0x40004000), None),
(sc64::MemoryTestPattern::Custom(0xBFFFBFFF), None),
(sc64::MemoryTestPattern::Custom(0x80008000), None),
(sc64::MemoryTestPattern::Custom(0x7FFF7FFF), None),
(sc64::MemoryTestPattern::AllZeros, Some(60)),
(sc64::MemoryTestPattern::AllOnes, Some(60)),
];
let sdram_pattern_tests_count = sdram_pattern_tests.len();
let mut sdram_tests_failed = false;
for (i, (pattern, fade)) in sdram_pattern_tests.into_iter().enumerate() {
let fadeout_text = if let Some(fade) = fade {
format!(", fadeout {fade} seconds")
} else {
"".to_string()
};
print!(
" ({} / {sdram_pattern_tests_count}) Testing {pattern}{fadeout_text}... ",
i + 1
);
stdout().flush().unwrap();
let result = sc64.test_sdram_pattern(pattern, fade)?;
if let Some((address, (written, read))) = result.first_error {
sdram_tests_failed = true;
println!("{}", "error!".bright_red());
println!(" Found a mismatch at address 0x{address:08X}",);
println!(" 0x{written:08X} (W) != 0x{read:08X} (R)");
println!(" Total errors found: {}", result.all_errors.len());
} else {
println!("{}", "ok".bright_green());
}
}
if sdram_tests_failed {
println!(
"{}",
"Some SDRAM tests failed, SDRAM chip might be defective".bright_red()
);
} else {
println!("{}", "All SDRAM tests passed without error".bright_green());
}
Ok(())
}
fn handle_server_command(connection: Connection, args: &ServerArgs) -> Result<(), sc64::Error> {
let port = if let Connection::Local(port) = connection {
port

View File

@ -12,8 +12,8 @@ pub use self::{
server::ServerEvent,
types::{
BootMode, ButtonMode, ButtonState, CicSeed, DataPacket, DdDiskState, DdDriveType, DdMode,
DebugPacket, DiagnosticData, DiskPacket, DiskPacketKind, FpgaDebugData, SaveType,
SaveWriteback, Switch, TvType,
DebugPacket, DiagnosticData, DiskPacket, DiskPacketKind, FpgaDebugData, MemoryTestPattern,
MemoryTestPatternResult, SaveType, SaveWriteback, Switch, TvType,
},
};
@ -26,10 +26,12 @@ use self::{
},
};
use chrono::{DateTime, Local};
use rand::Rng;
use std::{
cmp::min,
io::{Read, Seek, Write},
time::Instant,
{cmp::min, time::Duration},
thread::sleep,
time::{Duration, Instant},
};
pub struct SC64 {
@ -89,7 +91,8 @@ const SRAM_1M_LENGTH: usize = 128 * 1024;
const BOOTLOADER_ADDRESS: u32 = 0x04E0_0000;
const FIRMWARE_ADDRESS: u32 = 0x0010_0000; // Arbitrary offset in SDRAM memory
const FIRMWARE_ADDRESS_SDRAM: u32 = 0x0010_0000; // Arbitrary offset in SDRAM memory
const FIRMWARE_ADDRESS_FLASH: u32 = 0x0410_0000; // Arbitrary offset in Flash memory
const FIRMWARE_UPDATE_TIMEOUT: Duration = Duration::from_secs(90);
const ISV_BUFFER_LENGTH: usize = 64 * 1024;
@ -668,19 +671,43 @@ impl SC64 {
pub fn backup_firmware(&mut self) -> Result<Vec<u8>, Error> {
self.command_state_reset()?;
let (status, length) = self.command_firmware_backup(FIRMWARE_ADDRESS)?;
let (status, length) = self.command_firmware_backup(FIRMWARE_ADDRESS_SDRAM)?;
if !matches!(status, FirmwareStatus::Ok) {
return Err(Error::new(
format!("Firmware backup error: {}", status).as_str(),
));
}
self.command_memory_read(FIRMWARE_ADDRESS, length as usize)
self.command_memory_read(FIRMWARE_ADDRESS_SDRAM, length as usize)
}
pub fn update_firmware(&mut self, data: &[u8]) -> Result<(), Error> {
pub fn update_firmware(&mut self, data: &[u8], use_flash_memory: bool) -> Result<(), Error> {
const FLASH_UPDATE_SUPPORTED_MINOR_VERSION: u16 = 19;
let status = if use_flash_memory {
let unsupported_version_error = Error::new(format!(
"Your firmware doesn't support updating from Flash memory, minimum required version: {}.{}.x",
SUPPORTED_MAJOR_VERSION, FLASH_UPDATE_SUPPORTED_MINOR_VERSION
).as_str());
self.command_version_get()
.and_then(|(major, minor, revision)| {
if major != SUPPORTED_MAJOR_VERSION
|| minor < FLASH_UPDATE_SUPPORTED_MINOR_VERSION
{
return Err(unsupported_version_error.clone());
} else {
Ok((major, minor, revision))
}
})
.map_err(|_| unsupported_version_error.clone())?;
self.command_state_reset()?;
self.command_memory_write(FIRMWARE_ADDRESS, data)?;
let status = self.command_firmware_update(FIRMWARE_ADDRESS, data.len())?;
self.flash_erase(FIRMWARE_ADDRESS_FLASH, data.len())?;
self.command_memory_write(FIRMWARE_ADDRESS_FLASH, data)?;
self.command_flash_wait_busy(true)?;
self.command_firmware_update(FIRMWARE_ADDRESS_FLASH, data.len())?
} else {
self.command_state_reset()?;
self.command_memory_write(FIRMWARE_ADDRESS_SDRAM, data)?;
self.command_firmware_update(FIRMWARE_ADDRESS_SDRAM, data.len())?
};
if !matches!(status, FirmwareStatus::Ok) {
return Err(Error::new(
format!("Firmware update verify error: {}", status).as_str(),
@ -723,6 +750,65 @@ impl SC64 {
}
}
pub fn test_sdram_pattern(
&mut self,
pattern: MemoryTestPattern,
fade: Option<u64>,
) -> Result<MemoryTestPatternResult, Error> {
let item_size = std::mem::size_of::<u32>();
let mut test_data = vec![0u32; SDRAM_LENGTH / item_size];
match pattern {
MemoryTestPattern::OwnAddress(inverted) => {
for (index, item) in test_data.iter_mut().enumerate() {
let mut value = (index * item_size) as u32;
if inverted {
value ^= 0xFFFFFFFFu32;
}
*item = value;
}
}
MemoryTestPattern::AllZeros => test_data.fill(0x00000000u32),
MemoryTestPattern::AllOnes => test_data.fill(0xFFFFFFFFu32),
MemoryTestPattern::Custom(pattern) => test_data.fill(pattern),
MemoryTestPattern::Random => rand::thread_rng().fill(&mut test_data[..]),
};
let raw_test_data: Vec<u8> = test_data.iter().flat_map(|v| v.to_be_bytes()).collect();
let mut writer: &[u8] = &raw_test_data;
self.memory_write_chunked(&mut writer, SDRAM_ADDRESS, SDRAM_LENGTH, None)?;
if let Some(fade) = fade {
sleep(Duration::from_secs(fade));
}
let mut raw_check_data = vec![0u8; SDRAM_LENGTH];
let mut reader: &mut [u8] = &mut raw_check_data;
self.memory_read_chunked(&mut reader, SDRAM_ADDRESS, SDRAM_LENGTH)?;
let check_data = raw_check_data
.chunks(4)
.map(|a| u32::from_be_bytes(a[0..4].try_into().unwrap()));
let all_errors: Vec<(usize, (u32, u32))> = test_data
.into_iter()
.zip(check_data)
.enumerate()
.filter(|(_, (a, b))| a != b)
.map(|(i, (a, b))| (i * item_size, (a, b)))
.collect();
let first_error = if all_errors.len() > 0 {
Some(all_errors.get(0).copied().unwrap())
} else {
None
};
return Ok(MemoryTestPatternResult {
first_error,
all_errors,
});
}
fn memory_read_chunked(
&mut self,
writer: &mut dyn Write,

View File

@ -983,6 +983,36 @@ impl Display for DiagnosticData {
}
}
pub enum MemoryTestPattern {
OwnAddress(bool),
AllZeros,
AllOnes,
Random,
Custom(u32),
}
pub struct MemoryTestPatternResult {
pub first_error: Option<(usize, (u32, u32))>,
pub all_errors: Vec<(usize, (u32, u32))>,
}
impl Display for MemoryTestPattern {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MemoryTestPattern::OwnAddress(inverted) => f.write_fmt(format_args!(
"Own address{}",
if *inverted { "~" } else { "" }
)),
MemoryTestPattern::AllZeros => f.write_str("All zeros"),
MemoryTestPattern::AllOnes => f.write_str("All ones"),
MemoryTestPattern::Random => f.write_str("Random"),
MemoryTestPattern::Custom(pattern) => {
f.write_fmt(format_args!("Pattern 0x{pattern:08X}"))
}
}
}
}
macro_rules! get_config {
($sc64:ident, $config:ident) => {{
if let Config::$config(value) = $sc64.command_config_get(ConfigId::$config)? {

46
web/bom.html Normal file
View File

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<title>SummerCart64 - Bill of materials</title>
<meta property="og:title" content="SummerCart64 - Bill of materials" />
<meta property="og:description" content="SummerCart64 - a fully open source N64 flashcart" />
<meta property="og:url" content="https://summercart64.dev/bom.html" />
<meta property="og:image" content="https://summercart64.dev/sc64-embed.png" />
<meta property="og:type" content="website" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="favicon.svg" sizes="any" type="image/svg+xml">
<link rel="stylesheet" href="./styles.css">
<script src="./script.js"></script>
</head>
<body>
<div class="menu-container">
<div class="menu-bar">
<div class="menu-buttons">
<a href="/"><img src="sc64.svg"></a>
<div class="menu-button" onclick="showMenu(event)">
<div class="menu-button-line"></div>
<div class="menu-button-line"></div>
<div class="menu-button-line"></div>
</div>
</div>
<menu class="mobile-hidden">
<li><a href="/">Home</a></li>
<li><a href="/features.html">Features</a></li>
<li><a href="https://menu.summercart64.dev">Menu</a></li>
<li><a href="https://github.com/Polprzewodnikowy/SummerCart64/releases/latest">Downloads</a></li>
<li class="active"><a href="/bom.html">Bill of materials</a></li>
<li><a href="https://github.com/Polprzewodnikowy/SummerCart64">GitHub</a></li>
</menu>
</div>
</div>
<iframe class="bom" src="/sc64v2_bom.html"></iframe>
<footer>
<span>© 2020 - 2024 <a href="https://mateuszfaderewski.pl">Mateusz Faderewski</a></span>
</footer>
</body>
</html>

View File

@ -30,6 +30,7 @@
<li class="active"><a href="/features.html">Features</a></li>
<li><a href="https://menu.summercart64.dev">Menu</a></li>
<li><a href="https://github.com/Polprzewodnikowy/SummerCart64/releases/latest">Downloads</a></li>
<li><a href="/bom.html">Bill of materials</a></li>
<li><a href="https://github.com/Polprzewodnikowy/SummerCart64">GitHub</a></li>
</menu>
</div>

View File

@ -30,6 +30,7 @@
<li><a href="/features.html">Features</a></li>
<li><a href="https://menu.summercart64.dev">Menu</a></li>
<li><a href="https://github.com/Polprzewodnikowy/SummerCart64/releases/latest">Downloads</a></li>
<li><a href="/bom.html">Bill of materials</a></li>
<li><a href="https://github.com/Polprzewodnikowy/SummerCart64">GitHub</a></li>
</menu>
</div>
@ -68,8 +69,7 @@
product page</a> on Phenom Mod store</li>
<li>Group buys available at <a href="https://discord.gg/WqFgNWf">N64brew Discord Server</a> - check
threads in the <code><strong>#summer-cart-64</strong></code> channel.</li>
<li><a
href="https://www.pcbway.com/project/shareproject/SC64_an_open_source_Nintendo_64_flashcart_14b9688a.html">PCBWay
<li><a href="https://www.pcbway.com/project/member/shareproject/?bmbno=1046ED64-8AEE-44">PCBWay
Shared Project</a> page - both assembled boards and bare PCBs are available.</li>
<li>Manual PCB and components order - DIY friendly option.</li>
</ul>

View File

@ -123,7 +123,7 @@ a:hover {
font-weight: 600;
}
@media only screen and (max-width: 768px) {
@media only screen and (max-width: 800px) {
.menu-bar {
flex-flow: row wrap;
margin: 0;
@ -255,6 +255,13 @@ main .separator {
margin: var(--main-separator-margin) 0;
}
iframe.bom {
display: flex;
flex-grow: 1;
margin-top: var(--menu-height);
border: none;
}
footer {
display: flex;
flex-flow: column;