mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-22 05:59:15 +01:00
Merge branch 'main' into new-irq
This commit is contained in:
commit
e163ae814f
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@ -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
|
||||
|
||||
|
10
README.md
10
README.md
@ -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.
|
||||
|
2
build.sh
2
build.sh
@ -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"
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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" ;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 ;
|
||||
|
@ -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)
|
||||
|
4414
hw/pcb/sc64_hw_v2.0a_bom.html
generated
4414
hw/pcb/sc64_hw_v2.0a_bom.html
generated
File diff suppressed because one or more lines are too long
100088
hw/pcb/sc64v2.kicad_pcb
100088
hw/pcb/sc64v2.kicad_pcb
File diff suppressed because it is too large
Load Diff
@ -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": {}
|
||||
|
52188
hw/pcb/sc64v2.kicad_sch
52188
hw/pcb/sc64v2.kicad_sch
File diff suppressed because it is too large
Load Diff
4669
hw/pcb/sc64v2_bom.html
generated
Normal file
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
12
hw/shell/README.md
Normal 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))
|
600
hw/shell/button/sc64_shell_button_b3fs-105x.step
Normal file
600
hw/shell/button/sc64_shell_button_b3fs-105x.step
Normal 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;
|
1073
hw/shell/button/sc64_shell_button_b3fs-105x_with_end_stop.step
Normal file
1073
hw/shell/button/sc64_shell_button_b3fs-105x_with_end_stop.step
Normal file
File diff suppressed because it is too large
Load Diff
27534
hw/shell/injection mold/sc64_bottom.step
Normal file
27534
hw/shell/injection mold/sc64_bottom.step
Normal file
File diff suppressed because it is too large
Load Diff
41323
hw/shell/injection mold/sc64_shell.stp
Normal file
41323
hw/shell/injection mold/sc64_shell.stp
Normal file
File diff suppressed because it is too large
Load Diff
18846
hw/shell/injection mold/sc64_top.step
Normal file
18846
hw/shell/injection mold/sc64_top.step
Normal file
File diff suppressed because it is too large
Load Diff
@ -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 (
|
||||
|
4
sw/bootloader/src/fatfs/ffconf.h
vendored
4
sw/bootloader/src/fatfs/ffconf.h
vendored
@ -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) */
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
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;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
} else {
|
||||
display_printf("Pattern: random ");
|
||||
|
||||
test->fill(w_buffer, TEST_BUFFER_SIZE, test->pattern, offset);
|
||||
|
||||
pi_dma_write((io32_t *) (SDRAM_ADDRESS + offset), w_buffer, TEST_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
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_read((io32_t *) (SDRAM_ADDRESS + offset), r_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]
|
||||
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;
|
||||
|
||||
@ -285,10 +567,11 @@ void test_execute (void) {
|
||||
current = 0;
|
||||
}
|
||||
|
||||
display_printf("Next test [ %s ] starts in: ", tests[current].title);
|
||||
for (int delay = 5; delay > 0; delay--) {
|
||||
display_printf("\b%d", delay);
|
||||
display_printf("Next test [ %s ] starts in: ", tests[current].title);
|
||||
for (int delay = 10; delay > 0; delay--) {
|
||||
display_printf("%2ds", delay);
|
||||
delay_ms(1000);
|
||||
display_printf("\b\b\b", delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
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_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();
|
||||
switch (sd_cmd6(CMD6_ARG_CHECK_HS, cmd6_buffer)) {
|
||||
case CMD6_OK: {
|
||||
if (CMD6_INVALID_CURRENT_LIMIT(cmd6_buffer)) {
|
||||
sd_card_deinit();
|
||||
return SD_ERROR_CMD6_CHECK_RESPONSE;
|
||||
}
|
||||
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 SD_ERROR_CMD6_SWITCH_RESPONSE;
|
||||
}
|
||||
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 true;
|
||||
}
|
||||
if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERR_TIMEOUT) {
|
||||
return SD_ERROR_CMD6_CHECK_IO;
|
||||
case CMD6_ERROR_CRC:
|
||||
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_set_clock(CLOCK_50MHZ);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -6,12 +6,14 @@
|
||||
#include "vendor.h"
|
||||
|
||||
|
||||
#define SDRAM_ADDRESS (0x00000000UL)
|
||||
#define SDRAM_LENGTH (64 * 1024 * 1024)
|
||||
#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)
|
||||
#define BOOTLOADER_LENGTH (0x001E0000UL)
|
||||
#define UPDATE_MAGIC_START (0x54535055UL)
|
||||
#define BOOTLOADER_ADDRESS (0x04E00000UL)
|
||||
#define BOOTLOADER_LENGTH (0x001E0000UL)
|
||||
|
||||
|
||||
typedef enum {
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
37
sw/deployer/Cargo.lock
generated
@ -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",
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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> {
|
||||
self.command_state_reset()?;
|
||||
self.command_memory_write(FIRMWARE_ADDRESS, data)?;
|
||||
let status = self.command_firmware_update(FIRMWARE_ADDRESS, data.len())?;
|
||||
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.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,
|
||||
|
@ -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
46
web/bom.html
Normal 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>
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user