diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 53b2ace..48c7887 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,6 +11,8 @@ jobs: - sim_alu - sim_inst_immediate_decode - sim_load_store + - sim_csr + - sim_mtimer # sim_cpu is not a testbench, but a target for RISCOF testing, so it # is not included here uses: ./.github/workflows/simulate.yml @@ -21,19 +23,29 @@ jobs: strategy: matrix: target: - - sim_memory - sim_top uses: ./.github/workflows/simulate.yml with: project: crush_example target: ${{ matrix.target }} + verilog-sim-crush-example-freertos-cpu: + uses: ./.github/workflows/simulate.yml + with: + project: crush_example_freertos + target: sim_cpu + verilog-sim-crush-example-freertos-top: + uses: ./.github/workflows/simulate.yml + with: + project: crush_example_freertos + target: sim_top + timeout-minutes: 10 verilog-lint: runs-on: ubuntu-22.04 container: image: barabas5532/crush-ci:5 strategy: matrix: - project: [crush, crush_example] + project: [crush, crush_example, crush_example_freertos] steps: - uses: actions/checkout@v4 with: @@ -77,6 +89,9 @@ jobs: runs-on: ubuntu-22.04 container: image: barabas5532/crush-ci:5 + strategy: + matrix: + project: [crush_example, crush_example_freertos] steps: - uses: actions/checkout@v4 with: @@ -94,24 +109,23 @@ jobs: timeout-minutes: 1 run: | . script/init.sh - fusesoc --verbose run crush_example + fusesoc --verbose run ${{ matrix.project }} firmware: runs-on: ubuntu-22.04 + strategy: + matrix: + path: + - crush_example/fw + - crush_example_freertos/fw/spi_bootloader + - crush_example_freertos/fw/app container: image: barabas5532/crush-ci:5 defaults: run: - working-directory: crush_example/fw + working-directory: ${{ matrix.path }} steps: - uses: actions/checkout@v4 - name: Configure run: cmake -B build -G Ninja -DCMAKE_TOOLCHAIN_FILE=TC-crush.cmake - name: Build run: cmake --build build - - uses: actions/upload-artifact@v4 - with: - name: firmware-elf - path: | - fw/build/crush-blinky - fw/build/crush-blinky.bin - fw/build/crush-blinky.data diff --git a/.github/workflows/simulate.yml b/.github/workflows/simulate.yml index 95d9a2b..6261e6a 100644 --- a/.github/workflows/simulate.yml +++ b/.github/workflows/simulate.yml @@ -9,6 +9,10 @@ on: target: required: true type: string + timeout-minutes: + default: 1 + required: false + type: number jobs: simulate: @@ -29,7 +33,7 @@ jobs: # also use the venv. echo PATH=$PATH >> $GITHUB_ENV - name: Run simulation - timeout-minutes: 1 + timeout-minutes: ${{ inputs.timeout-minutes }} run: | . script/init.sh fusesoc run --target ${{ inputs.target }} --resolve-env-vars-early ${{ inputs.project }} diff --git a/.gitignore b/.gitignore index 9d812a3..406d9cf 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build fusesoc.conf +fusesoc_libraries diff --git a/README.md b/README.md index ebcdbd4..87561b4 100644 --- a/README.md +++ b/README.md @@ -24,3 +24,64 @@ Goals: | [verible](https://github.com/chipsalliance/verible) | Standard LSP linter that can integrate with most text editors. | | [FuseSoC](https://github.com/olofk/fusesoc) | Build tool that simplifies running the testbenches and synthesis tools. | | [RISCOF, a RISC-V Architectural Test Framework](https://github.com/riscv-software-src/riscof) | The design passes all tests provided by RISCOF. See the `tools/compliance` folder. | + +## Demo SoCs + +### Basic Configuration (module top) + +#### Boot process + +All firmware executes directly from configurable block RAM. There is no support +for booting from flash. The block RAM stores both the executable code and the +system RAM. + +#### Vectors + +| Vector | Address | +|--------|-------------| +| Reset | 0x1000_0000 | + + +#### Memory Map + +| Address | Size (bytes) | Description | +|-------------|--------------|-------------| +| 0x1000_0000 | 8192 | Block RAM | +| 0x4000_0000 | | GPIO | + +### RTOS configuration (module top_freertos) + +#### Boot process + +The first stage bootloader stored in block RAM copies program data from flash to +RAM, then jumps to the "Boot entry" vector at the top of RAM (0x1000_0000). +After the bootloader completes, the application runs from SPRAM and the flash is +not used any more. + +#### Vectors + +| Vector | Address | +|----------------------|-------------| +| Reset | 0x0000_0000 | +| Bootloader app entry | 0x1000_0000 | +| Interrupt | 0x1000_0100 | + +#### Memory Map + +| Address | Size (bytes) | Description | +|-------------|--------------|----------------| +| 0x0000_0000 | 1024 | Boot block RAM | +| 0x1000_0000 | 65536 | SPRAM | +| 0x3000_0000 | | mtimer | +| 0x4000_0000 | | GPIO | +| 0x5000_0000 | | SPI | + +## References + +The SPI flash bootloader is based on the following open source libraries: + +https://github.com/no2fpga/no2bootloader + +https://github.com/chipsalliance/VeeRwolf + +https://github.com/olofk/simple_spi diff --git a/crush/crush.core b/crush/crush.core index 9425cb2..7e0d856 100644 --- a/crush/crush.core +++ b/crush/crush.core @@ -11,6 +11,7 @@ filesets: - rtl/inst_decode_registers.v - rtl/inst_immediate_decode.v - rtl/memory_infer.v: {file_type: systemVerilogSource} + - rtl/mtimer.v - rtl/params.vh: {is_include_file: true} - rtl/program_counter.v - rtl/registers.v @@ -20,19 +21,19 @@ filesets: files: - sim/inst_immediate_decode_tb.v file_type: systemVerilogSource - depend: [crush_support] + depend: [crush_testing] sim_alu: files: - sim/alu_tb.v file_type: systemVerilogSource - depend: [crush_support] + depend: [crush_testing] sim_load_store: files: - sim/load_store_tb.v file_type: systemVerilogSource - depend: [crush_support] + depend: [crush_testing] sim_cpu: files: @@ -40,6 +41,18 @@ filesets: - sim/cpu_tb.v file_type: systemVerilogSource + sim_csr: + files: + - sim/csr_tb.v + file_type: systemVerilogSource + depend: [crush_testing] + + sim_mtimer: + files: + - sim/mtimer_tb.v + file_type: systemVerilogSource + depend: [crush_testing] + verilator_waiver: files: - ../data/verilator_waiver.vlt @@ -55,6 +68,8 @@ targets: iverilog_options: - "-g2012" - "-gassertions" + parameters: + - MACHINE_MODE lint: default_tool : verilator @@ -102,3 +117,24 @@ targets: toplevel: cpu_tb default_tool: icarus + sim_csr: + <<: *default + filesets_append: + - sim_csr + toplevel: csr_tb + default_tool: icarus + parameters: + - MACHINE_MODE=true + + sim_mtimer: + <<: *default + filesets_append: + - sim_mtimer + toplevel: mtimer_tb + default_tool: icarus + +parameters: + MACHINE_MODE: + datatype : bool + description: Enables machine privilege mode features + paramtype : vlogdefine diff --git a/crush/rtl/alu.v b/crush/rtl/alu.v index cde9234..943f98a 100644 --- a/crush/rtl/alu.v +++ b/crush/rtl/alu.v @@ -21,6 +21,10 @@ module alu ( wire [31:0] B_immediate; wire [31:0] U_immediate; wire [31:0] J_immediate; + // False positive, because only used in machine mode + // verilator lint_off UNUSEDSIGNAL + wire [31:0] CSR_immediate; + // verilator lint_on UNUSEDSIGNAL inst_immediate_decode immediate_decode ( .inst(instruction), @@ -28,7 +32,8 @@ module alu ( .S_immediate(S_immediate), .B_immediate(B_immediate), .U_immediate(U_immediate), - .J_immediate(J_immediate) + .J_immediate(J_immediate), + .CSR_immediate(CSR_immediate) ); wire [6:0] opcode = instruction[6:0]; @@ -78,6 +83,17 @@ module alu ( OPCODE_STORE: out = op_a + S_immediate; OPCODE_JAL: out = pc + J_immediate; OPCODE_JALR: out = (op_a + I_immediate) & ~1; +`ifdef MACHINE_MODE + OPCODE_SYSTEM: case(funct3) + FUNCT3_CSRRW: out = op_a; + FUNCT3_CSRRWI: out = CSR_immediate; + FUNCT3_CSRRC: out = op_a & ~op_b; + FUNCT3_CSRRCI: out = op_a & ~CSR_immediate; + FUNCT3_CSRRS: out = op_a | op_b; + FUNCT3_CSRRSI: out = op_a | CSR_immediate; + default: ; + endcase +`endif default: ; endcase end diff --git a/crush/rtl/crush_cpu.v b/crush/rtl/crush_cpu.v index 1fe1d22..35d24cc 100644 --- a/crush/rtl/crush_cpu.v +++ b/crush/rtl/crush_cpu.v @@ -2,6 +2,10 @@ module crush_cpu #( parameter integer INITIAL_PC = 0 +`ifdef MACHINE_MODE + , + parameter integer TRAP_PC = 0 +`endif ) ( input wire clk_i, input wire[31:0] dat_i, @@ -15,6 +19,11 @@ module crush_cpu #( output reg[31:0] adr_o, output reg[3:0] sel_o, output reg we_o +`ifdef MACHINE_MODE + , + input wire timer_interrupt, + input wire external_interrupt +`endif ); `include "params.vh" @@ -39,6 +48,29 @@ reg[31:0] pc_value; wire[31:0] pc; wire[31:0] pc_inc; +`ifdef MACHINE_MODE +wire instruction_is_ecall = instruction == {{12'b0}, {5'b0}, {FUNCT3_PRIV}, {5'b0}, {OPCODE_SYSTEM}}; + +reg trap_taken; +reg [31:0] mcause_; + +reg [31:0] mcause; +reg [31:0] mepc; +reg [31:0] mie; +reg [31:0] mstatus; +wire [31:0] mtvec = TRAP_PC; + +reg [31:0] csr_read_value; + +wire mstatus_mie = mstatus[3]; + +wire mie_mtie = mie[7]; +wire mie_meie = mie[11]; + +wire timer_interrupt_enable = mstatus_mie && mie_mtie; +wire external_interrupt_enable = mstatus_mie && mie_meie; +`endif + program_counter #(.INITIAL_PC(INITIAL_PC)) program_counter( .reset(rst_i), .clk(clk_i), @@ -71,6 +103,9 @@ registers registers( assign r_address1 = instruction[19:15]; assign r_address2 = instruction[24:20]; assign w_address = instruction[11:7]; +`ifdef MACHINE_MODE +wire [11:0] csr_address = instruction[31:20]; +`endif reg[31:0] alu_op_a; reg[31:0] alu_op_b; @@ -129,6 +164,12 @@ always @(posedge(clk_i)) begin if(rst_i) begin state <= STATE_RESET; instruction <= 32'hxxxx_xxxx; +`ifdef MACHINE_MODE + mcause <= 0; + mepc <= 0; + mie <= 0; + mstatus <= 0; +`endif end else begin case(state) STATE_FETCH: @@ -136,17 +177,69 @@ always @(posedge(clk_i)) begin state <= STATE_REG_READ; instruction <= dat_i; end - STATE_REG_READ: state <= STATE_EXECUTE; + STATE_REG_READ: begin + state <= STATE_EXECUTE; +`ifdef MACHINE_MODE + if(opcode == OPCODE_SYSTEM && funct3 != FUNCT3_PRIV) begin + case(csr_address) + CSR_MSTATUS: csr_read_value <= mstatus; + CSR_MIE: csr_read_value <= mie; + CSR_MEPC: csr_read_value <= mepc; + CSR_MCAUSE: csr_read_value <= mcause; + CSR_MTVEC: csr_read_value <= mtvec; + default: ; + endcase + end +`endif + end STATE_EXECUTE: begin state <= STATE_MEMORY; state_change <= 0; end STATE_MEMORY: + begin if(ack_i | (!mem_r_en & !mem_w_en)) begin state <= STATE_REG_WRITE; read_data <= dat_i; end else state_change <= 0; - STATE_REG_WRITE: state <= STATE_FETCH; + +`ifdef MACHINE_MODE + if(trap_taken) begin + mcause <= mcause_; + mepc <= pc; + state <= STATE_FETCH; + + // MIE + mstatus[3] <= 0; + // MPIE + mstatus[7] <= 1; + end +`endif + end + STATE_REG_WRITE: begin + state <= STATE_FETCH; + +`ifdef MACHINE_MODE + if(opcode == OPCODE_SYSTEM) begin + if(w_address == 0 && + funct3 == FUNCT3_PRIV && + r_address1 == 0 && + instruction[31:20] == FUNCT12_MRET) begin + // MIE + mstatus[3] <= 1; + // MPIE + mstatus[7] <= 1; + end + else if (!instruction_is_ecall) case(csr_address) + CSR_MSTATUS: mstatus <= alu_out_r; + CSR_MIE: mie <= alu_out_r; + CSR_MEPC: mepc <= alu_out_r; + CSR_MCAUSE: mcause <= alu_out_r; + default: ; + endcase + end +`endif + end default: state <= STATE_FETCH; endcase end @@ -163,6 +256,18 @@ always @(*) begin OPCODE_JAL, OPCODE_JALR, OPCODE_LOAD: reg_w_en = 1; +`ifdef MACHINE_MODE + OPCODE_SYSTEM: + case(funct3) + FUNCT3_CSRRW, + FUNCT3_CSRRWI, + FUNCT3_CSRRC, + FUNCT3_CSRRCI, + FUNCT3_CSRRS, + FUNCT3_CSRRSI: reg_w_en = 1; + default: reg_w_en = 0; + endcase +`endif default: reg_w_en = 0; endcase end @@ -190,6 +295,11 @@ always @(*) begin pc_load = 0; pc_value = 32'hxxxx_xxxx; +`ifdef MACHINE_MODE + trap_taken = 0; + mcause_ = 32'hxxxx_xxxx; +`endif + stb_o = 0; cyc_o = 0; sel_o = 4'hx; @@ -216,6 +326,13 @@ always @(*) begin STATE_EXECUTE: begin alu_op_a = r_out1; alu_op_b = r_out2; + +`ifdef MACHINE_MODE + if((opcode == OPCODE_SYSTEM) && (funct3 != FUNCT3_CSRRW)) begin + alu_op_a = csr_read_value; + alu_op_b = r_out1; + end +`endif end STATE_MEMORY: begin if(mem_r_en) begin @@ -244,6 +361,38 @@ always @(*) begin default: sel_o = 4'bxxxx; endcase end + +`ifdef MACHINE_MODE + if((timer_interrupt && timer_interrupt_enable) + || (external_interrupt && external_interrupt_enable) + || instruction_is_ecall) begin + // Prevent memory writes if interrupted. This is the only side effect + // of the instruction, so this effectively interrupts the instruction, + // and it can be restarted after handling the interrupt. + stb_o = 0; + cyc_o = 0; + sel_o = 4'hx; + dat_o = 32'hxxxx_xxxx; + adr_o = 32'hxxxx_xxxx; + we_o = 1'hx; + + trap_taken = 1; + pc_value = mtvec; + pc_load = 1; + + if(instruction_is_ecall) begin + mcause_ = {1'b0, 31'd11}; + end + + if(timer_interrupt) begin + mcause_ = {1'b1, 31'd7}; + end + + if(external_interrupt) begin + mcause_ = {1'b1, 31'd11}; + end + end +`endif end STATE_REG_WRITE: begin w_enable = reg_w_en; @@ -263,6 +412,9 @@ always @(*) begin OPCODE_JALR: begin w_data = pc_inc; end +`ifdef MACHINE_MODE + OPCODE_SYSTEM: w_data = csr_read_value; +`endif default: w_data = alu_out_r; endcase @@ -295,6 +447,17 @@ always @(*) begin pc_value = 32'hxxxx_xxxx; end endcase + +`ifdef MACHINE_MODE + if(opcode == OPCODE_SYSTEM && + w_address == 0 && + funct3 == FUNCT3_PRIV && + r_address1 == 0 && + instruction[31:20] == FUNCT12_MRET) begin + pc_load = 1; + pc_value = mepc; + end +`endif end default: ; endcase diff --git a/crush/rtl/inst_immediate_decode.v b/crush/rtl/inst_immediate_decode.v index 94eba6d..b29d9d4 100644 --- a/crush/rtl/inst_immediate_decode.v +++ b/crush/rtl/inst_immediate_decode.v @@ -6,7 +6,8 @@ module inst_immediate_decode( output reg[31:0] S_immediate, output reg[31:0] B_immediate, output reg[31:0] U_immediate, - output reg[31:0] J_immediate + output reg[31:0] J_immediate, + output reg[31:0] CSR_immediate ); @@ -16,6 +17,7 @@ always @* begin B_immediate = { {20{inst[31]}}, inst[7], inst[30:25], inst[11:8], 1'b0}; U_immediate = { inst[31], inst[30:20], inst[19:12], 12'b0}; J_immediate = { {12{inst[31]}}, inst[19:12], inst[20], inst[30:25], inst[24:21], 1'b0}; + CSR_immediate = { 27'b0, inst[19:15]}; end endmodule diff --git a/crush/rtl/mtimer.v b/crush/rtl/mtimer.v new file mode 100644 index 0000000..56c078c --- /dev/null +++ b/crush/rtl/mtimer.v @@ -0,0 +1,78 @@ +`default_nettype none + +module mtimer #( + parameter integer BASE_ADDRESS = 0 +) ( + // wishbone + input wire clk_i, + input wire rst_i, + input wire stb_i, + input wire cyc_i, + input wire [31:0] adr_i, + input wire [3:0] sel_i, + input wire [31:0] dat_i, + output wire [31:0] dat_o, + input wire we_i, + output reg ack_o, + output reg err_o, + output reg rty_o, + // interrupt + output reg interrupt +); + // The number of 32-bit registers that can be addressed inside this + // peripheral + localparam SIZE = 4; + + wire [31:0] memory_address = (adr_i - BASE_ADDRESS) >> 2; + wire addressed = (adr_i >= BASE_ADDRESS) && (memory_address < SIZE); + + /* Implemented as registers to simplify the wishbone interface implementation. + * + * It would cleaner to define some kind of bidirectional alias so that we can + * read and write either the 32-bit register representation or the 64-bit + * counter representation, but it doesn't seem to be possible. We can at + * least read from the 64-bit representation below, but we must write to the + * 32-bit representation. + */ + reg [31:0] mem [4]; + + wire [63:0] mtime; + assign mtime = {mem[1], mem[0]}; + + wire [63:0] mtimecmp; + assign mtimecmp = {mem[3], mem[2]}; + + reg [31:0] data; + assign dat_o = ack_o ? data : 32'hzzzz_zzzz; + + always @(posedge clk_i) begin + ack_o <= 0; + err_o <= 0; + rty_o <= 0; + + if(rst_i) begin : reset + integer i; + for(i = 0; i < 4; i++) mem[i] <= 0; + interrupt <= 0; + end else begin + {mem[1], mem[0]} <= mtime + 1; + + // wishbone access overwrites counting behaviour + if (stb_i & cyc_i & !ack_o & addressed) begin + ack_o <= 1; + if(we_i) begin + if (sel_i[0]) mem[memory_address][7:0] <= dat_i[7:0]; + if (sel_i[1]) mem[memory_address][15:8] <= dat_i[15:8]; + if (sel_i[2]) mem[memory_address][23:16] <= dat_i[23:16]; + if (sel_i[3]) mem[memory_address][31:24] <= dat_i[31:24]; + end else begin + data <= mem[memory_address]; + end + end + + interrupt <= 1; + if(mtimecmp > mtime) interrupt <= 0; + end + end + +endmodule diff --git a/crush/rtl/params.vh b/crush/rtl/params.vh index cd522c6..47210c9 100644 --- a/crush/rtl/params.vh +++ b/crush/rtl/params.vh @@ -49,4 +49,19 @@ localparam FUNCT3_XOR = 3'b100; localparam FUNCT3_SRL_SRA = 3'b101; localparam FUNCT3_OR = 3'b110; localparam FUNCT3_AND = 3'b111; +localparam FUNCT3_CSRRW = 3'b001; +localparam FUNCT3_CSRRS = 3'b010; +localparam FUNCT3_CSRRC = 3'b011; +localparam FUNCT3_CSRRWI = 3'b101; +localparam FUNCT3_CSRRSI = 3'b110; +localparam FUNCT3_CSRRCI = 3'b111; +localparam FUNCT3_PRIV = 3'b000; + +localparam CSR_MSTATUS = 12'h300; +localparam CSR_MIE = 12'h304; +localparam CSR_MTVEC = 12'h305; +localparam CSR_MEPC = 12'h341; +localparam CSR_MCAUSE = 12'h342; + +localparam FUNCT12_MRET = 12'b001100000010; // verilator lint_on UNUSEDPARAM diff --git a/crush/sim/csr_tb.v b/crush/sim/csr_tb.v new file mode 100644 index 0000000..7a29251 --- /dev/null +++ b/crush/sim/csr_tb.v @@ -0,0 +1,267 @@ +/* Test bench for CSR instructions CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI */ + +/* Most of the implemented CSRs are not arbitrary read/write registers. Instead + * they are WARL etc. + * + * The most straight forward register to use for testing is the mepc, where + * every bit other than the last two are always readable and writable. + * It will also never be written by the system as long as software does not + * enable interrupts. + */ +`default_nettype none + +`include "fatal_assert.vh" + +module csr_tb; + +`include "params.vh" + +reg clk = 1; +reg reset = 1; +wire stb_o; +wire cyc_o; +wire[31:0] adr_o; +wire[3:0] sel_o; +wire[31:0] dat_i; +wire[31:0] dat_o; +wire we_o; +wire ack_i; +wire err_i = 0; +wire rty_i = 0; + +string test_case_name = ""; + +reg flash_ack_o = 0; +reg[31:0] flash_dat_o = 32'hzzzz_zzzz; + +crush_cpu #(.INITIAL_PC('h1000_0000), .TRAP_PC('h1234_5678)) cpu ( + .clk_i(clk), + .dat_i(dat_i), + .dat_o(dat_o), + .rst_i(reset), + .ack_i(ack_i), + .err_i(err_i), + .rty_i(rty_i), + .stb_o(stb_o), + .cyc_o(cyc_o), + .adr_o(adr_o), + .sel_o(sel_o), + .we_o(we_o) +); + +wire memory_ack_o; +memory_infer #(.BASE_ADDRESS('h2000_0000), .SIZE('h4000)) memory ( + .clk_i(clk), + .rst_i(reset), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i(we_o), + .ack_o(memory_ack_o), + .err_o(err_i), + .rty_o(rty_i) +); + +assign ack_i = flash_ack_o | memory_ack_o; +assign dat_i = flash_dat_o; +integer count = 0; + +always begin + #0.5 + clk <= !clk; + #0.5 + clk <= !clk; + count <= count + 1; +end + +task static reset_registers(); + integer i; + for (i = 0; i < 32; i++) begin + cpu.registers.memory[i] = 32'hxxxx_xxxx; + end +endtask + +task static test_case(input string a_test_case_name); + @(posedge clk) + reset = 1; + reset_registers; + + test_case_name = a_test_case_name; + + @(posedge clk) reset = 0; +endtask + +task static CSRRW(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] rs1); + // wait for wishbone instruction read + @(stb_o & cyc_o); + @(posedge clk); + flash_ack_o = 1; + flash_dat_o = {{csr}, {rs1}, {FUNCT3_CSRRW}, {rd}, {OPCODE_SYSTEM}}; + @(posedge clk); + flash_ack_o = 0; + flash_dat_o = 32'hzzzz_zzzz; + #0; +endtask + +task static CSRRS(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] rs1); + // wait for wishbone instruction read + @(stb_o & cyc_o); + @(posedge clk); + flash_ack_o = 1; + flash_dat_o = {{csr}, {rs1}, {FUNCT3_CSRRS}, {rd}, {OPCODE_SYSTEM}}; + @(posedge clk); + flash_ack_o = 0; + flash_dat_o = 32'hzzzz_zzzz; + #0; +endtask + +task static CSRRC(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] rs1); + // wait for wishbone instruction read + @(stb_o & cyc_o); + @(posedge clk); + flash_ack_o = 1; + flash_dat_o = {{csr}, {rs1}, {FUNCT3_CSRRC}, {rd}, {OPCODE_SYSTEM}}; + @(posedge clk); + flash_ack_o = 0; + flash_dat_o = 32'hzzzz_zzzz; + #0; +endtask + +task static CSRRWI(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] imm); + // wait for wishbone instruction read + @(stb_o & cyc_o); + @(posedge clk); + flash_ack_o = 1; + flash_dat_o = {{csr}, {imm}, {FUNCT3_CSRRWI}, {rd}, {OPCODE_SYSTEM}}; + @(posedge clk); + flash_ack_o = 0; + flash_dat_o = 32'hzzzz_zzzz; + #0; +endtask + +task static CSRRSI(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] imm); + // wait for wishbone instruction read + @(stb_o & cyc_o); + @(posedge clk); + flash_ack_o = 1; + flash_dat_o = {{csr}, {imm}, {FUNCT3_CSRRSI}, {rd}, {OPCODE_SYSTEM}}; + @(posedge clk); + flash_ack_o = 0; + flash_dat_o = 32'hzzzz_zzzz; + #0; +endtask + +task static CSRRCI(input reg[4:0] rd, input reg[11:0] csr, input reg[4:0] imm); + // wait for wishbone instruction read + @(stb_o & cyc_o); + @(posedge clk); + flash_ack_o = 1; + flash_dat_o = {{csr}, {imm}, {FUNCT3_CSRRCI}, {rd}, {OPCODE_SYSTEM}}; + @(posedge clk); + flash_ack_o = 0; + flash_dat_o = 32'hzzzz_zzzz; + #0; +endtask + +initial begin + $dumpfile("csr_tb.vcd"); + $dumpvars(0); + + test_case("CSRRW"); + + cpu.registers.memory[1] = 32'h0000_00A0; + cpu.registers.memory[2] = 32'h0000_00B0; + + CSRRW(1, CSR_MEPC, 2); + + #1; + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == 32'h0000_0000); + `fatal_assert (cpu.mepc == 32'h0000_00B0); + + CSRRW(1, CSR_MEPC, 2); + + #1; + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == 32'h0000_00B0); + `fatal_assert (cpu.mepc == 32'h0000_00B0); + #1; + + test_case("CSRRS"); + + cpu.mepc = 32'h1010_0000; + cpu.registers.memory[2] = 32'h1100_0000; + + CSRRS(1, CSR_MEPC, 2); + + #1; + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == 32'h1010_0000); + `fatal_assert (cpu.mepc == 32'h1110_0000); + #1; + + test_case("CSRRC"); + + cpu.mepc = 32'h1010_0000; + cpu.registers.memory[2] = 32'h1100_0000; + + CSRRC(1, CSR_MEPC, 2); + + #1; + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == 32'h1010_0000); + `fatal_assert (cpu.mepc == 32'h0010_0000); + #1; + + test_case("CSRRWI"); + + cpu.mepc = 32'h0000_0014; + + CSRRWI(1, CSR_MEPC, 5'h18); + + #1; + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == 32'h0000_0014); + `fatal_assert (cpu.mepc == 32'h0000_0018); + #1; + + test_case("CSRRSI"); + + cpu.mepc = 32'h0000_0014; + + CSRRSI(1, CSR_MEPC, 5'h18); + + #1; + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == 32'h0000_0014); + `fatal_assert (cpu.mepc == 32'h0000_001C); + #1; + + test_case("CSRRCI"); + + cpu.mepc = 32'h0000_0014; + + CSRRCI(1, CSR_MEPC, 5'h18); + + #1; + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == 32'h0000_0014); + `fatal_assert (cpu.mepc == 32'h0000_0004); + #1; + + test_case("read MTVEC"); + + CSRRW(1, CSR_MTVEC, 5'h0); + + #1; + @(cpu.state == cpu.STATE_FETCH); + `fatal_assert (cpu.registers.x1 == (32'h1234_5678)); + #1; + + $stop; +end + +endmodule diff --git a/crush/sim/inst_immediate_decode_tb.v b/crush/sim/inst_immediate_decode_tb.v index c17a25a..6ce45f3 100644 --- a/crush/sim/inst_immediate_decode_tb.v +++ b/crush/sim/inst_immediate_decode_tb.v @@ -10,6 +10,7 @@ wire[31:0] S_immediate; wire[31:0] B_immediate; wire[31:0] U_immediate; wire[31:0] J_immediate; +wire[31:0] CSR_immediate; inst_immediate_decode dut ( .inst(inst), @@ -17,7 +18,8 @@ inst_immediate_decode dut ( .S_immediate(S_immediate), .B_immediate(B_immediate), .U_immediate(U_immediate), - .J_immediate(J_immediate) + .J_immediate(J_immediate), + .CSR_immediate(CSR_immediate) ); initial begin diff --git a/crush_example/sim/memory_tb.v b/crush/sim/mtimer_tb.v similarity index 53% rename from crush_example/sim/memory_tb.v rename to crush/sim/mtimer_tb.v index 2d5bc4b..13dbbfb 100644 --- a/crush_example/sim/memory_tb.v +++ b/crush/sim/mtimer_tb.v @@ -1,10 +1,11 @@ + `default_nettype none `timescale 1s/1ms `include "fatal_assert.vh" -module memory_tb; +module mtimer_tb; reg clk = 1; reg reset = 1; @@ -19,7 +20,12 @@ wire ack_i; wire err_i; wire rty_i; -memory #(.BASE_ADDRESS(0)) dut ( +wire interrupt; + +localparam BASE_ADDRESS = 32'h100; + + +mtimer #(.BASE_ADDRESS(BASE_ADDRESS)) dut ( .clk_i(clk), .rst_i(reset), .stb_i(stb_o), @@ -31,33 +37,22 @@ memory #(.BASE_ADDRESS(0)) dut ( .we_i(we_o), .ack_o(ack_i), .err_o(err_i), - .rty_o(rty_i) + .rty_o(rty_i), + .interrupt(interrupt) ); always begin #0.5 clk = !clk; end -initial begin - $dumpfile("memory.vcd"); - $dumpvars; - - #0.1 - - #1 - reset = 1; - - #1 - reset = 0; - - #1 - // 32-bit write to 0 - // Based on Wishbone B4 3.2.3 Classic standard SINGLE WRITE Cycle +// 32-bit write +// Based on Wishbone B4 3.2.3 Classic standard SINGLE WRITE Cycle +task automatic write_register(input reg[31:0] register_address, input reg[31:0] data); // Clock edge 0 `fatal_assert(!ack_i); - adr_o = 32'b0; - dat_o = 32'h01234567; + adr_o = register_address; + dat_o = data; we_o = 1'b1; sel_o = 4'b1111; @@ -74,17 +69,34 @@ initial begin cyc_o = 0; #0 `fatal_assert(!ack_i); +endtask + + +initial begin + $dumpfile("mtimer.vcd"); + $dumpvars; + + #0.1 + + #1 + reset = 1; + + #1 + reset = 0; + + #5 + write_register(BASE_ADDRESS + 0, 0); adr_o = 32'hxxxxxxxx; dat_o = 32'hxxxxxxxx; sel_o = 4'hx; we_o = 1'bx; - #1 + #5 // 32-bit read from 0 // Based on Wishbone B4 3.2.1 Classic standard SINGLE READ Cycle `fatal_assert(!ack_i); - adr_o = 0; + adr_o = BASE_ADDRESS + 0; we_o = 0; sel_o = 4'b1111; cyc_o = 1; @@ -93,7 +105,8 @@ initial begin // Clock edge 0 #1 `fatal_assert(ack_i); - `fatal_assert(dat_i == 32'h01234567); + // The clock must have counted since we reset it earlier + `fatal_assert(dat_i > 32'h0); #1 // Clock edge 2 @@ -102,6 +115,25 @@ initial begin #0 `fatal_assert(!ack_i); + #5 + + // Set mtimecmp to a very large value to ensure interrupt doesn't trigger + // immediately + write_register(BASE_ADDRESS + 12, 1); + #0 `fatal_assert(!interrupt); + // mtime = 1000 + write_register(BASE_ADDRESS + 0, 1000); + // mtimecmp = 1010. Should interrupt in a few cycles + write_register(BASE_ADDRESS + 8, 1010); + write_register(BASE_ADDRESS + 12, 0); + + #10 + `fatal_assert(interrupt); + + // mtime = 1000. Should clear interrupt + write_register(BASE_ADDRESS + 0, 1000); + `fatal_assert(!interrupt); + #1 $stop; end diff --git a/crush_example/crush_example.core b/crush_example/crush_example.core index 45e83a8..2bcd49d 100644 --- a/crush_example/crush_example.core +++ b/crush_example/crush_example.core @@ -9,12 +9,9 @@ filesets: - fw/binary/crush-blinky.data: file_type: user copyto: fw.data - - rtl/memory.v - - rtl/memory_ice40_spram.v - rtl/top.v - - rtl/gpio.v file_type: verilogSource - depend: [crush] + depend: [crush, crush_util] pcf: files: @@ -26,13 +23,7 @@ filesets: # export YOSYS_DATDIR=$(yosys-config --datdir) - $YOSYS_DATDIR/ice40/cells_sim.v file_type: verilogSource - depend: [crush_support] - - sim_memory: - files: - - sim/memory_tb.v - file_type: systemVerilogSource - depend: [crush] + depend: [crush_testing] sim_top: files: @@ -64,6 +55,8 @@ targets: - "-gassertions" hooks: post_run: [iceprog_hint] + parameters: + - MACHINE_MODE=false lint: default_tool : verilator @@ -71,7 +64,6 @@ targets: - verilator_waiver - rtl - sim_top - - sim_memory - sim_common tools: verilator: @@ -82,23 +74,17 @@ targets: - "-DNO_ICE40_DEFAULT_ASSIGNMENTS" toplevel: top_tb - sim_memory: - <<: *default - filesets_append: - - sim_common - - sim_memory - toplevel: memory_tb - default_tool: icarus - sim_top: <<: *default filesets_append: - sim_top toplevel: top_tb default_tool: icarus + parameters: + - MACHINE_MODE=false scripts: iceprog_hint: cmd: - echo - - "Run 'iceprog ...' in the build folder to program the board" + - "Run 'iceprog build/crush_example_0.0.1/default-icestorm/crush_example_0.0.1.bin' to program the board." diff --git a/crush_example/rtl/memory.v b/crush_example/rtl/memory.v deleted file mode 100644 index 8fe9057..0000000 --- a/crush_example/rtl/memory.v +++ /dev/null @@ -1,49 +0,0 @@ -`default_nettype none - -module memory #( - parameter integer BASE_ADDRESS = 0 -) ( - input wire clk_i, - input wire rst_i, - input wire stb_i, - input wire cyc_i, - input wire [31:0] adr_i, - input wire [3:0] sel_i, - input wire [31:0] dat_i, - output reg [31:0] dat_o, - input wire we_i, - output reg ack_o, - output reg err_o, - output reg rty_o -); - localparam integer SIZE = 16384; - wire [31:0] memory_address = (adr_i - BASE_ADDRESS); - wire addressed = (adr_i >= BASE_ADDRESS) && (memory_address < SIZE); - wire [31:0] memory_data; - - memory_ice40_spram ram( - .clk(clk_i), - .rst(rst_i), - .wen(stb_i & cyc_i & we_i & addressed), - .wmask(sel_i), - .addr(memory_address[15:2]), - .wdata(dat_i), - .rdata(memory_data) - ); - - always @(*) begin - if (ack_o) dat_o = memory_data; - else dat_o = 32'hzzzz_zzzz; - end - - always @(posedge clk_i) begin - ack_o <= 0; - err_o <= 0; - rty_o <= 0; - - if (stb_i & cyc_i & !ack_o & addressed) begin - ack_o <= 1; - end - end - -endmodule diff --git a/crush_example_freertos/crush_example_freertos.core b/crush_example_freertos/crush_example_freertos.core new file mode 100644 index 0000000..6f4a911 --- /dev/null +++ b/crush_example_freertos/crush_example_freertos.core @@ -0,0 +1,127 @@ +CAPI=2: +# vim:syntax=yaml: + +name: ::crush_example_freertos:0.0.1 + +filesets: + rtl: + files: + - fw/spi_bootloader/binary/crush-boot.data: + file_type: user + copyto: boot.data + - rtl/memory_ice40_spram.v + - rtl/memory_ice40_spram_wb.v + - rtl/spi.v + - rtl/top.v + file_type: verilogSource + depend: [crush, crush_util, simple_spi] + + pcf: + files: + - data/icebreaker.pcf: {file_type: PCF} + + sim_common: + files: + # YOSYS_DATDIR must be defined in the calling environemnt. e.g.: + # export YOSYS_DATDIR=$(yosys-config --datdir) + - $YOSYS_DATDIR/ice40/cells_sim.v + file_type: verilogSource + depend: [crush_testing] + + sim_cpu: + files: + - sim/cpu_tb.v + file_type: systemVerilogSource + depend: [crush] + + sim_top: + files: + - sim/top_tb.v + - fw/app/binary/crush_freertos.data: + file_type: user + copyto: crush_freertos.data + - sim/s25fl128s.v + file_type: systemVerilogSource + depend: [crush] + + verilator_waiver: + files: + - ../data/verilator_waiver.vlt + file_type: vlt + +targets: + default: &default + filesets: + - rtl + - pcf + toplevel: top + default_tool: icestorm + tools: + icestorm: + nextpnr_options : [ "--up5k", "--package", "sg48" ] + # disable final deep-sleep SPI flash command after bitstream is loaded + icepack_options : [ "-s" ] + yosys_synth_options: + - "-dsp" + icarus: + timescale: "1s/100ms" + iverilog_options: + - "-g2012" + - "-gassertions" + hooks: + post_run: + - iceprog_hint + - iceprog_app_hint + parameters: + - MACHINE_MODE=true + + lint: + default_tool : verilator + filesets: + - verilator_waiver + - rtl + # Can't lint because verilator fails on flash simulator: + # https://github.com/verilator/verilator/issues/5767 + # - sim_top + - sim_cpu + - sim_common + tools: + verilator: + mode : lint-only + verilator_options: + - "-Wall -timing" + # Disable default values in yosys's simulation modules. + - "-DNO_ICE40_DEFAULT_ASSIGNMENTS" + toplevel: cpu_tb + parameters: + - MACHINE_MODE=true + + sim_cpu: + <<: *default + filesets_append: + - sim_common + - sim_cpu + toplevel: cpu_tb + default_tool: icarus + parameters: + - MACHINE_MODE=true + + sim_top: + <<: *default + filesets_append: + - sim_common + - sim_top + toplevel: top_tb + default_tool: icarus + parameters: + - MACHINE_MODE=true + +scripts: + iceprog_hint: + cmd: + - echo + - "Run 'iceprog build/crush_example_freertos_0.0.1/default-icestorm/crush_example_freertos_0.0.1.bin' to program the board." + iceprog_app_hint: + cmd: + - echo + - "Run 'iceprog -o 0x20000 crush_example_freertos/fw/app/binary/crush_freertos.bin' to load firmware to flash." diff --git a/crush_example_freertos/data/icebreaker.pcf b/crush_example_freertos/data/icebreaker.pcf new file mode 100644 index 0000000..429bf54 --- /dev/null +++ b/crush_example_freertos/data/icebreaker.pcf @@ -0,0 +1,68 @@ +# 12 MHz clock +set_io -nowarn CLK 35 +set_frequency CLK 12 + +# RS232 +set_io -nowarn RX 6 +set_io -nowarn TX 9 + +# LEDs and Button +set_io -nowarn BTN_N 10 +set_io -nowarn LEDR_N 11 +set_io -nowarn LEDG_N 37 + +# RGB LED Driver +set_io -nowarn LED_RED_N 39 +set_io -nowarn LED_GRN_N 40 +set_io -nowarn LED_BLU_N 41 +set_io -nowarn LED_RGB[0] 39 +set_io -nowarn LED_RGB[1] 40 +set_io -nowarn LED_RGB[2] 41 + +# SPI Flash +set_io -nowarn FLASH_SCK 15 +set_io -nowarn FLASH_SSB 16 +set_io -nowarn FLASH_IO0 14 +set_io -nowarn FLASH_IO1 17 +set_io -nowarn FLASH_IO2 12 +set_io -nowarn FLASH_IO3 13 + +# PMOD 1A +set_io -nowarn P1A1 4 +set_io -nowarn P1A2 2 +set_io -nowarn P1A3 47 +set_io -nowarn P1A4 45 +set_io -nowarn P1A7 3 +set_io -nowarn P1A8 48 +set_io -nowarn P1A9 46 +set_io -nowarn P1A10 44 + +# PMOD 1B +set_io -nowarn P1B1 43 +set_io -nowarn P1B2 38 +set_io -nowarn P1B3 34 +set_io -nowarn P1B4 31 +set_io -nowarn P1B7 42 +set_io -nowarn P1B8 36 +set_io -nowarn P1B9 32 +set_io -nowarn P1B10 28 + +# PMOD 2 +set_io -nowarn P2_1 27 +set_io -nowarn P2_2 25 +set_io -nowarn P2_3 21 +set_io -nowarn P2_4 19 +set_io -nowarn P2_7 26 +set_io -nowarn P2_8 23 +set_io -nowarn P2_9 20 +set_io -nowarn P2_10 18 + +# LEDs and Buttons (PMOD 2) +set_io -nowarn LED1 26 +set_io -nowarn LED2 27 +set_io -nowarn LED3 25 +set_io -nowarn LED4 23 +set_io -nowarn LED5 21 +set_io -nowarn BTN1 20 +set_io -nowarn BTN2 19 +set_io -nowarn BTN3 18 diff --git a/crush_example_freertos/fw/app/CMakeLists.txt b/crush_example_freertos/fw/app/CMakeLists.txt new file mode 100644 index 0000000..690a119 --- /dev/null +++ b/crush_example_freertos/fw/app/CMakeLists.txt @@ -0,0 +1,61 @@ +cmake_minimum_required(VERSION 3.15 FATAL_ERROR) + +project(crush_freertos C ASM) + +set(CMAKE_C_STANDARD 11) + +include(FetchContent) + +FetchContent_Declare( freertos_kernel + GIT_REPOSITORY https://github.com/FreeRTOS/FreeRTOS-Kernel.git + GIT_TAG V11.1.0 +) + +add_subdirectory(freertos_config) + +# no heap, only static allocation +# unset( FREERTOS_HEAP CACHE ) + +# Select the native compile PORT +set( FREERTOS_PORT "GCC_POSIX" CACHE STRING "" FORCE) + +# Select the cross-compile PORT +if (CMAKE_CROSSCOMPILING) + # We don't have a sifive CLINT, but that define seems to be unused anyway, + # and the MTIME define is required for FreeRTOS to automatically use the + # mtime for system tick. + set(FREERTOS_RISCV_EXTENSION "RISCV_MTIME_CLINT_no_extensions" CACHE STRING "" FORCE) + set(FREERTOS_PORT "GCC_RISC_V_GENERIC" CACHE STRING "" FORCE) +endif() + +FetchContent_MakeAvailable(freertos_kernel) + + +add_executable(${PROJECT_NAME} + src/main.c + src/hal.c + src/start.S + src/start.c +) + +target_link_options(${PROJECT_NAME} PRIVATE -T${CMAKE_CURRENT_SOURCE_DIR}/crush.ld) +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/crush.ld) + +target_link_libraries(${PROJECT_NAME} PRIVATE freertos_kernel) + +# Since we use -nostdlib, we must link to libgcc manually +target_link_libraries(${PROJECT_NAME} PRIVATE gcc) + +string(REPLACE "-gcc" "-objcopy" objcopy_name ${CMAKE_C_COMPILER}) +find_program(objcopy_program ${objcopy_name} REQUIRED) +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${objcopy_program} -O binary -j .text -j .data -j .bss -j .stack ${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/binary/${PROJECT_NAME}.bin + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + +# Output is loaded to flash at offset 0x20_000. the adjust-vma makes sure it +# will be loaded into the simulation at the correct address. +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${objcopy_program} -O verilog --adjust-vma -0x0ffe0000 --verilog-data-width 1 ${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/binary/${PROJECT_NAME}.data + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) diff --git a/crush_example_freertos/fw/app/TC-crush.cmake b/crush_example_freertos/fw/app/TC-crush.cmake new file mode 100644 index 0000000..ac22b3a --- /dev/null +++ b/crush_example_freertos/fw/app/TC-crush.cmake @@ -0,0 +1,17 @@ +# https://www.vinnie.work/blog/2020-11-17-cmake-eval + +set(CMAKE_SYSTEM_NAME Generic) + +find_program(COMPILER_PATH + NAMES + # ubuntu and debian + riscv32-unknown-elf-gcc + riscv64-unknown-elf-gcc + # arch linux + riscv64-elf-gcc + REQUIRED) +get_filename_component(COMPILER_NAME ${COMPILER_PATH} NAME) +set(CMAKE_C_COMPILER ${COMPILER_NAME}) + +set(CMAKE_C_FLAGS "-nostartfiles -nostdlib -march=rv32i_zicsr -mabi=ilp32") +set(CMAKE_ASM_FLAGS "-march=rv32i_zicsr -mabi=ilp32") diff --git a/crush_example_freertos/fw/app/binary/crush_freertos.bin b/crush_example_freertos/fw/app/binary/crush_freertos.bin new file mode 100755 index 0000000..230ba8c Binary files /dev/null and b/crush_example_freertos/fw/app/binary/crush_freertos.bin differ diff --git a/crush_example_freertos/fw/app/binary/crush_freertos.data b/crush_example_freertos/fw/app/binary/crush_freertos.data new file mode 100755 index 0000000..5ab0bc5 --- /dev/null +++ b/crush_example_freertos/fw/app/binary/crush_freertos.data @@ -0,0 +1,1103 @@ +@00020000 +17 51 00 00 13 01 01 1B EF 00 C0 3B 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +13 01 41 F8 23 22 11 00 23 24 51 00 23 26 61 00 +23 28 71 00 23 2A 81 00 23 2C 91 00 23 2E A1 00 +23 20 B1 02 23 22 C1 02 23 24 D1 02 23 26 E1 02 +23 28 F1 02 23 2A 01 03 23 2C 11 03 23 2E 21 03 +23 20 31 05 23 22 41 05 23 24 51 05 23 26 61 05 +23 28 71 05 23 2A 81 05 23 2C 91 05 23 2E A1 05 +23 20 B1 07 23 22 C1 07 23 24 D1 07 23 26 E1 07 +23 28 F1 07 97 42 00 00 83 A2 C2 34 23 2A 51 06 +F3 22 00 30 23 2C 51 06 97 52 00 00 83 A2 C2 B0 +23 A0 22 00 73 25 20 34 F3 25 10 34 63 5A 05 00 +23 20 B1 00 17 41 00 00 03 21 41 31 6F 00 80 01 +93 85 45 00 23 20 B1 00 17 41 00 00 03 21 01 30 +6F 00 00 07 93 02 10 00 93 92 F2 01 13 83 72 00 +63 1C 65 04 17 55 00 00 03 25 85 BC 97 45 00 00 +83 A5 85 2E 13 07 F0 FF 03 A6 05 00 83 A6 45 00 +23 20 E5 00 23 22 D5 00 23 20 C5 00 97 42 00 00 +83 A2 82 2B 33 87 C2 00 33 33 C7 00 B3 83 66 00 +23 A0 E5 00 23 A2 75 00 EF 00 D0 41 63 06 05 02 +EF 00 D0 43 6F 00 40 02 EF 20 80 76 6F 00 C0 01 +93 02 B0 00 63 16 55 00 EF 00 50 42 6F 00 C0 00 +EF 20 00 74 6F 00 40 00 17 53 00 00 03 23 C3 A4 +03 21 03 00 83 22 01 00 73 90 12 34 83 22 81 07 +73 90 02 30 83 22 41 07 17 43 00 00 03 23 43 25 +23 20 53 00 83 20 41 00 83 22 81 00 03 23 C1 00 +83 23 01 01 03 24 41 01 83 24 81 01 03 25 C1 01 +83 25 01 02 03 26 41 02 83 26 81 02 03 27 C1 02 +83 27 01 03 03 28 41 03 83 28 81 03 03 29 C1 03 +83 29 01 04 03 2A 41 04 83 2A 81 04 03 2B C1 04 +83 2B 01 05 03 2C 41 05 83 2C 81 05 03 2D C1 05 +83 2D 01 06 03 2E 41 06 83 2E 81 06 03 2F C1 06 +83 2F 01 07 13 01 C1 07 73 00 20 30 00 00 00 00 +13 01 01 FF 23 22 91 00 23 26 11 00 23 24 81 00 +93 04 00 00 EF 00 40 07 93 C4 14 00 13 04 05 00 +93 85 04 00 13 05 00 00 EF 00 40 07 93 05 04 00 +13 05 10 00 EF 00 80 06 EF 00 80 04 6F F0 9F FD +37 48 00 10 93 07 88 4C B7 45 00 10 37 05 00 10 +13 01 01 FF 93 87 47 05 13 08 88 4C 93 85 C5 44 +13 07 40 00 93 06 00 00 13 06 00 08 13 05 05 2F +23 26 11 00 EF 00 40 5A EF 00 90 0E 6F 00 00 00 +13 05 40 06 6F 00 D0 05 B7 07 00 40 03 A5 07 00 +13 55 85 00 13 75 15 00 67 80 00 00 93 07 10 00 +B3 97 A7 00 63 8C 05 00 B7 06 00 40 03 A7 06 00 +B3 67 F7 00 23 A0 F6 00 67 80 00 00 37 07 00 40 +83 26 07 00 93 C7 F7 FF B3 F7 D7 00 23 20 F7 00 +67 80 00 00 13 01 01 FF 37 45 00 10 B7 57 00 10 +23 26 11 00 13 07 85 4C 93 87 87 DA 63 70 F7 02 +13 86 F7 FF 33 06 E6 40 13 76 C6 FF 13 06 46 00 +13 05 85 4C 93 05 00 00 EF 30 D0 79 EF F0 5F F3 +6F 00 00 00 37 47 00 10 13 07 C7 71 93 06 10 00 +6F 00 80 00 73 00 00 00 83 27 07 00 E3 EC F6 FE +6F 00 00 00 13 01 01 FE 23 2A 91 00 B7 56 00 10 +B7 54 00 10 37 57 00 10 B7 57 00 10 23 28 21 01 +23 26 31 01 03 A9 46 C8 23 24 41 01 83 29 07 C9 +03 AA C7 C8 83 A7 44 C9 23 2C 81 00 13 04 05 00 +13 85 47 00 23 2E 11 00 EF 20 D0 2C 83 A7 44 C9 +33 04 89 00 83 A5 44 C9 23 A2 87 00 63 76 24 03 +03 24 81 01 83 20 C1 01 83 24 41 01 03 29 01 01 +83 29 C1 00 13 05 0A 00 03 2A 81 00 93 85 45 00 +13 01 01 02 6F 20 10 24 13 85 09 00 93 85 45 00 +EF 20 50 23 B7 57 00 10 03 A7 87 C6 63 74 E4 00 +23 A4 87 C6 83 20 C1 01 03 24 81 01 83 24 41 01 +03 29 01 01 83 29 C1 00 03 2A 81 00 13 01 01 02 +67 80 00 00 B7 57 00 10 83 A8 47 C8 93 88 18 00 +23 A2 17 C9 63 86 08 12 B7 52 00 10 83 A7 82 C6 +13 0E 00 00 63 EC F8 1C 37 55 00 10 83 27 05 C9 +83 A7 07 00 63 80 07 1C 13 01 01 FF 23 26 81 00 +B7 5E 00 10 37 4F 00 10 B7 5F 00 10 6F 00 80 0A +03 28 06 00 03 A7 87 02 23 AA 07 00 13 08 F8 FF +23 20 06 01 63 06 07 02 03 A8 C7 01 03 A6 07 02 +03 23 47 00 23 24 C8 00 23 22 06 01 63 0E 73 0A +03 26 07 00 23 A4 07 02 13 06 F6 FF 23 20 C7 00 +03 A7 C7 02 03 A8 0E C8 13 16 27 00 33 06 E6 00 +13 16 26 00 B3 86 C6 00 63 74 E8 00 23 A0 EE C8 +03 A8 46 00 03 A6 06 00 03 A4 4F C9 03 23 88 00 +23 A4 07 01 83 23 05 C9 23 A6 67 00 23 22 B3 00 +23 24 B8 00 23 AA D7 00 93 07 16 00 23 A0 F6 00 +83 26 C4 02 83 A7 03 00 33 B7 E6 00 33 6E EE 00 +63 84 07 0A 83 27 05 C9 93 06 CF 71 83 A7 C7 00 +83 A7 C7 00 03 A7 47 00 93 85 47 00 93 83 87 01 +63 E6 E8 0A 03 A6 47 01 03 A8 87 00 03 A7 C7 00 +03 23 46 00 23 24 E8 00 23 22 07 01 E3 12 B3 F2 +23 22 E6 00 6F F0 DF F1 23 22 C7 00 6F F0 5F F4 +B7 57 00 10 03 A7 07 C9 03 27 07 00 63 06 07 00 +73 70 04 30 6F 00 00 00 37 57 00 10 03 A6 07 C9 +83 25 C7 C8 B7 56 00 10 23 A8 B7 C8 23 26 C7 C8 +03 A7 06 C7 13 07 17 00 23 A8 E6 C6 03 A7 07 C9 +03 27 07 00 63 1C 07 04 B7 52 00 10 93 07 F0 FF +23 A4 F2 C6 6F F0 9F E8 93 07 F0 FF 23 A4 F2 C6 +B7 57 00 10 03 A5 47 C7 03 24 C1 00 33 35 A0 00 +33 65 C5 01 13 01 01 01 67 80 00 00 23 A4 E2 C6 +B7 57 00 10 03 A5 47 C7 03 24 C1 00 33 35 A0 00 +33 65 C5 01 13 01 01 01 67 80 00 00 83 A7 07 C9 +B7 52 00 10 83 A7 C7 00 83 A7 07 00 23 A4 F2 C6 +6F F0 DF E2 93 07 F0 FF 23 A4 F2 C6 B7 57 00 10 +03 A5 47 C7 33 35 A0 00 33 65 C5 01 67 80 00 00 +13 01 01 FE 23 2C 81 00 37 54 00 10 83 27 44 C6 +23 2E 11 00 93 87 F7 FF 23 22 F4 C6 83 27 44 C6 +63 96 07 12 B7 57 00 10 83 A7 87 C8 63 80 07 12 +37 48 00 10 13 08 C8 71 83 27 48 06 23 2A 91 00 +23 28 21 01 23 26 31 01 B7 54 00 10 63 8C 07 14 +37 53 00 10 37 5E 00 10 B7 54 00 10 93 0E 10 00 +6F 00 00 0A 83 26 07 00 23 A4 07 02 93 86 F6 FF +23 20 D7 00 03 A6 47 01 83 A6 87 00 03 A7 C7 00 +83 25 46 00 83 28 03 C8 23 A4 E6 00 23 22 D7 00 +13 85 47 00 63 82 A5 0E 83 A6 C7 02 83 25 06 00 +13 97 26 00 93 85 F5 FF 33 07 D7 00 13 17 27 00 +23 20 B6 00 33 07 E8 00 63 F4 D8 00 23 20 D3 C8 +83 25 47 00 03 2F 4E C9 03 26 07 00 83 A8 85 00 +03 2F CF 02 23 A4 B7 00 23 A6 17 01 23 A2 A8 00 +23 A4 A5 00 23 AA E7 00 93 07 16 00 23 20 F7 00 +63 74 DF 00 23 AA D4 C7 83 27 48 06 63 82 07 08 +83 27 08 07 83 A7 C7 00 03 A7 87 02 03 A6 C7 01 +83 A6 07 02 03 25 47 00 93 85 87 01 23 24 D6 00 +23 A2 C6 00 E3 10 B5 F4 23 22 D7 00 6F F0 9F F3 +03 2A 81 00 23 AC 09 C6 83 A7 44 C7 63 96 07 0A +83 24 41 01 03 29 01 01 83 29 C1 00 13 05 00 00 +37 47 00 10 83 27 07 4C 93 87 F7 FF 23 20 F7 4C +63 94 07 00 73 60 04 30 83 20 C1 01 03 24 81 01 +13 01 01 02 67 80 00 00 23 22 E6 00 6F F0 DF F1 +B7 57 00 10 03 A7 07 C9 03 27 07 00 63 0E 07 06 +03 A7 07 C9 B7 57 00 10 03 27 C7 00 03 27 07 00 +23 A4 E7 C6 B7 59 00 10 03 A9 89 C7 E3 06 09 F8 +23 24 41 01 13 0A 10 00 6F 00 80 01 EF F0 9F C3 +63 04 05 00 23 AA 44 C7 13 09 F9 FF E3 02 09 F6 +83 27 44 C6 E3 84 07 FE 83 A7 89 C7 93 87 17 00 +23 AC F9 C6 6F F0 5F FE B7 57 00 10 83 A7 47 C9 +73 00 00 00 13 05 10 00 83 24 41 01 03 29 01 01 +83 29 C1 00 6F F0 DF F4 B7 57 00 10 13 07 F0 FF +23 A4 E7 C6 6F F0 1F F9 63 84 07 04 13 01 01 FB +23 22 91 04 23 26 11 04 93 04 08 00 63 06 08 02 +23 2E 31 03 93 89 07 00 93 07 40 05 23 2E F1 00 +23 20 21 05 13 09 06 00 03 26 C1 01 63 0E F6 00 +73 70 04 30 6F 00 00 00 73 70 04 30 6F 00 00 00 +73 70 04 30 6F 00 00 00 83 27 C1 01 23 24 81 04 +23 2C 41 03 13 84 05 00 13 0A 05 00 93 05 00 00 +13 05 08 00 23 26 E1 00 23 24 D1 00 EF 30 90 21 +23 A8 34 03 83 26 81 00 03 27 C1 00 63 06 04 02 +93 05 04 00 13 05 04 01 13 86 44 03 83 C7 05 00 +93 85 15 00 23 00 F6 00 63 86 07 00 13 06 16 00 +E3 16 B5 FE A3 81 04 04 93 07 40 00 63 F6 E7 00 +73 70 04 30 6F 00 00 00 23 2A 51 03 93 8A 44 00 +23 A6 E4 02 23 A2 E4 04 13 85 0A 00 23 26 D1 00 +23 24 E1 00 EF 20 C0 4C 13 85 84 01 EF 20 40 4C +03 27 81 00 83 26 C1 00 13 16 29 00 93 05 50 00 +13 06 C6 FF 33 87 E5 40 33 86 C9 00 13 75 06 FF +23 A8 94 00 23 A2 94 02 13 86 06 00 93 05 0A 00 +23 AC E4 00 EF 10 D0 65 23 A0 A4 00 73 70 04 30 +B7 57 00 10 83 A6 87 C8 37 4A 00 10 03 27 0A 4C +93 86 16 00 23 A4 D7 C8 B7 59 00 10 83 A6 49 C9 +13 06 17 00 23 20 CA 4C 63 80 06 0E 37 56 00 10 +83 26 C6 C7 83 A7 C4 02 63 8A 06 0A 37 44 00 10 +13 04 C4 71 37 55 00 10 83 26 C5 C6 B7 55 00 10 +03 A8 05 C8 93 86 16 00 23 26 D5 C6 63 74 F8 00 +23 A0 F5 C8 93 96 27 00 B3 87 F6 00 93 97 27 00 +33 04 F4 00 83 26 44 00 83 27 04 00 23 20 EA 4C +83 A5 86 00 23 A4 D4 00 93 87 17 00 23 A6 B4 00 +23 A2 55 01 23 A4 56 01 23 AA 84 00 23 20 F4 00 +63 14 07 00 73 60 04 30 83 27 C6 C7 63 8C 07 00 +03 A7 49 C9 83 A7 C4 02 03 27 C7 02 63 74 F7 00 +73 00 00 00 03 24 81 04 83 20 C1 04 03 29 01 04 +83 29 C1 03 03 2A 81 03 83 2A 41 03 13 85 04 00 +83 24 41 04 13 01 01 05 67 80 00 00 83 A6 49 C9 +37 44 00 10 83 A6 C6 02 63 E4 D7 00 23 AA 99 C8 +13 04 C4 71 6F F0 1F F4 23 AA 99 C8 83 A6 87 C8 +93 07 10 00 63 8C F6 00 37 44 00 10 83 A7 C4 02 +13 04 C4 71 37 56 00 10 6F F0 DF F1 37 49 00 10 +13 04 C9 71 23 26 71 03 23 28 61 03 13 09 C9 71 +93 0B 44 06 13 05 09 00 13 09 49 01 EF 20 40 31 +E3 9A 2B FF 13 0B 84 07 13 05 0B 00 EF 20 40 30 +13 09 C4 08 13 05 09 00 EF 20 80 2F 13 85 0B 00 +EF 20 00 2F 03 27 0A 4C B7 57 00 10 23 A8 67 C9 +B7 57 00 10 23 A6 27 C9 03 2B 01 03 83 A7 C4 02 +83 2B C1 02 13 07 F7 FF 37 56 00 10 6F F0 9F EA +63 16 05 00 73 00 00 00 67 80 00 00 13 01 01 FF +23 24 81 00 37 54 00 10 83 27 44 C6 23 26 11 00 +93 87 17 00 23 22 F4 C6 03 27 44 C6 93 07 10 00 +63 06 F7 00 73 70 04 30 6F 00 00 00 EF F0 9F 81 +73 70 04 30 37 47 00 10 83 27 07 4C 83 26 44 C6 +93 87 17 00 23 20 F7 4C 63 96 06 00 73 70 04 30 +6F 00 00 00 EF F0 DF AB 63 14 05 00 73 00 00 00 +83 20 C1 00 03 24 81 00 13 01 01 01 67 80 00 00 +B7 47 00 10 13 01 01 FE 93 87 C7 71 B7 48 4C 45 +37 05 00 10 13 88 07 0A 93 88 98 44 93 87 47 0F +13 07 00 00 93 06 00 00 13 06 00 08 93 05 01 00 +13 05 45 40 23 2E 11 00 23 20 11 01 23 02 01 00 +EF F0 9F C7 EF 10 40 73 93 07 10 00 63 0A F5 00 +93 07 F0 FF 63 18 F5 02 73 70 04 30 6F 00 00 00 +73 70 04 30 B7 57 00 10 13 07 F0 FF 23 A4 E7 C6 +B7 57 00 10 23 AE A7 C6 B7 57 00 10 23 A2 07 C8 +EF 10 90 36 83 20 C1 01 B7 47 00 10 83 A7 47 48 +13 01 01 02 67 80 00 00 73 70 04 30 B7 57 00 10 +23 AE 07 C6 6F 10 90 38 37 57 00 10 83 27 47 C6 +93 87 17 00 23 22 F7 C6 67 80 00 00 73 70 04 30 +37 47 00 10 83 27 07 4C B7 56 00 10 83 A6 46 C6 +93 87 17 00 23 20 F7 4C 63 96 06 00 73 70 04 30 +6F 00 00 00 6F F0 DF 9B B7 57 00 10 03 A5 47 C8 +67 80 00 00 B7 57 00 10 03 A5 47 C8 67 80 00 00 +B7 57 00 10 03 A5 87 C8 67 80 00 00 63 06 05 00 +13 05 45 03 67 80 00 00 B7 57 00 10 03 A5 47 C9 +E3 18 05 FE 73 70 04 30 6F 00 00 00 93 07 05 00 +63 84 05 02 63 0E 06 00 63 04 05 02 03 A7 07 03 +13 05 10 00 23 A0 E5 00 23 20 F6 00 67 80 00 00 +73 70 04 30 6F 00 00 00 73 70 04 30 6F 00 00 00 +B7 57 00 10 83 A7 47 C9 13 05 10 00 03 A7 07 03 +23 A0 E5 00 23 20 F6 00 67 80 00 00 B7 57 00 10 +03 A7 47 C6 63 06 07 00 73 70 04 30 6F 00 00 00 +03 A7 47 C6 13 07 17 00 23 A2 E7 C6 73 70 04 30 +37 56 00 10 83 26 86 C7 37 47 00 10 83 25 07 4C +B3 86 A6 00 23 2C D6 C6 63 94 05 00 73 60 04 30 +73 70 04 30 83 26 07 4C 03 A6 47 C6 93 87 16 00 +23 20 F7 4C 63 16 06 00 73 70 04 30 6F 00 00 00 +6F F0 1F 8C B7 57 00 10 83 A7 47 C6 63 94 07 00 +6F F0 4F EA 37 57 00 10 83 27 87 C7 13 05 00 00 +93 87 17 00 23 2C F7 C6 67 80 00 00 B7 57 00 10 +83 A7 47 C6 63 8A 07 00 B7 57 00 10 13 07 10 00 +23 AA E7 C6 67 80 00 00 B7 57 00 10 23 AA 07 C6 +B7 55 00 10 03 A7 05 C8 37 46 00 10 13 06 C6 71 +93 16 27 00 B3 87 E6 00 93 97 27 00 B3 07 F6 00 +03 A5 07 00 63 06 05 04 B3 87 E6 00 93 97 27 00 +B3 06 F6 00 03 A5 46 00 93 87 87 00 33 06 F6 00 +83 27 45 00 23 A2 F6 00 63 80 C7 04 83 A6 C7 00 +B7 57 00 10 23 AA D7 C8 23 A0 E5 C8 83 A7 47 C9 +67 80 00 00 83 A6 07 00 13 07 F7 FF 63 9A 06 00 +93 87 C7 FE E3 18 07 FE 73 70 04 30 6F 00 00 00 +93 16 27 00 6F F0 5F FA 83 A7 C6 00 23 A2 F6 00 +6F F0 DF FB 63 0C 05 02 13 01 01 FF B7 57 00 10 +23 24 81 00 13 84 05 00 83 A5 47 C9 23 26 11 00 +93 85 85 01 EF 10 10 7B 13 05 04 00 03 24 81 00 +83 20 C1 00 13 01 01 01 6F F0 CF CD 73 70 04 30 +6F 00 00 00 93 07 05 00 63 08 05 06 37 57 00 10 +03 27 47 C6 63 16 07 00 73 70 04 30 6F 00 00 00 +83 26 45 00 37 57 00 10 03 2E 47 C9 03 23 47 C9 +03 A8 86 00 83 28 47 C9 03 25 47 C9 23 2C BE 00 +83 25 47 C9 23 2E D3 00 23 A0 08 03 13 05 85 01 +83 28 47 C9 03 A7 07 00 93 85 85 01 23 22 A8 00 +23 A4 B6 00 23 A4 F8 02 13 07 17 00 13 05 06 00 +23 A0 E7 00 6F F0 0F C6 73 70 04 30 6F 00 00 00 +93 07 05 00 13 85 05 00 63 8C 07 04 83 A6 47 00 +37 57 00 10 03 2E 47 C9 83 A8 86 00 03 23 47 C9 +03 28 47 C9 83 25 47 C9 23 2E DE 00 23 20 13 03 +13 08 88 01 03 23 47 C9 03 A7 07 00 93 85 85 01 +23 A2 08 01 23 A4 B6 00 23 24 F3 02 13 07 17 00 +23 A0 E7 00 63 04 06 00 13 05 F0 FF 6F F0 8F BF +73 70 04 30 6F 00 00 00 83 27 C5 00 83 A7 C7 00 +63 82 07 12 03 A7 87 02 03 A6 C7 01 83 A6 07 02 +03 25 47 00 93 85 87 01 23 24 D6 00 23 A2 C6 00 +63 0E B5 0E 83 26 07 00 37 56 00 10 03 26 46 C6 +93 86 F6 FF 23 A4 07 02 23 20 D7 00 83 A6 C7 02 +63 0E 06 04 37 47 00 10 13 07 C7 71 03 25 87 06 +03 26 47 06 93 08 47 06 03 28 85 00 23 AE A7 00 +13 06 16 00 23 A0 07 03 23 22 B8 00 23 24 B5 00 +23 22 C7 06 23 A4 17 03 B7 57 00 10 83 A7 47 C9 +13 05 00 00 83 A7 C7 02 63 F8 D7 00 B7 57 00 10 +13 05 10 00 23 AA A7 C6 67 80 00 00 03 A7 47 01 +83 A5 87 00 03 A6 C7 00 03 28 47 00 13 85 47 00 +23 A4 C5 00 23 22 B6 00 63 0A A8 06 03 26 07 00 +B7 55 00 10 03 A8 05 C8 13 06 F6 FF 23 20 C7 00 +63 74 D8 00 23 A0 D5 C8 13 96 26 00 33 06 D6 00 +37 47 00 10 13 16 26 00 13 07 C7 71 33 07 C7 00 +83 25 47 00 03 26 07 00 03 A8 85 00 23 A4 B7 00 +13 06 16 00 23 A6 07 01 23 22 A8 00 23 A4 A5 00 +23 AA E7 00 23 20 C7 00 6F F0 1F F6 23 22 D7 00 +6F F0 5F F0 73 70 04 30 6F 00 00 00 23 22 C7 00 +6F F0 DF F8 B7 57 00 10 83 A7 47 C6 63 96 07 00 +73 70 04 30 6F 00 00 00 83 27 C5 00 23 20 B5 00 +63 88 07 0C 83 26 05 01 03 26 45 00 03 27 85 00 +83 A5 46 00 23 24 E6 00 23 22 C7 00 63 82 A5 0C +03 A6 06 00 23 28 05 00 03 A7 47 01 03 A5 87 00 +83 A5 C7 00 13 06 F6 FF 23 A0 C6 00 83 26 47 00 +23 24 B5 00 23 A2 A5 00 13 85 47 00 63 86 A6 08 +83 26 07 00 B7 55 00 10 03 A6 C7 02 03 A8 05 C8 +93 86 F6 FF 23 20 D7 00 63 74 C8 00 23 A0 C5 C8 +93 16 26 00 B3 86 C6 00 37 47 00 10 93 96 26 00 +13 07 C7 71 33 07 D7 00 83 25 47 00 B7 56 00 10 +83 A8 46 C9 03 A8 85 00 83 26 07 00 23 A4 B7 00 +23 A6 07 01 23 22 A8 00 23 A4 A5 00 83 A5 C8 02 +23 AA E7 00 93 87 16 00 23 20 F7 00 63 F8 C5 00 +B7 57 00 10 13 07 10 00 23 AA E7 C6 67 80 00 00 +73 70 04 30 6F 00 00 00 23 22 B7 00 6F F0 5F F7 +23 A2 E6 00 6F F0 DF F3 63 0C 05 02 73 70 04 30 +B7 57 00 10 03 A6 07 C7 37 47 00 10 B7 56 00 10 +83 27 07 4C 83 A6 46 C8 23 20 C5 00 23 20 F7 4C +23 22 D5 00 63 94 07 00 73 60 04 30 67 80 00 00 +73 70 04 30 6F 00 00 00 37 57 00 10 B7 57 00 10 +03 27 07 C7 83 A7 47 C8 23 20 E5 00 23 22 F5 00 +67 80 00 00 63 06 05 08 63 88 05 04 73 70 04 30 +37 47 00 10 83 27 07 4C B7 58 00 10 37 53 00 10 +03 A8 48 C8 03 2E 05 00 83 26 03 C7 13 86 17 00 +23 20 C7 4C 03 26 45 00 63 04 DE 02 63 62 C8 02 +23 A0 05 00 13 05 10 00 23 20 F7 4C 63 94 07 00 +73 60 04 30 67 80 00 00 73 70 04 30 6F 00 00 00 +83 A6 05 00 33 0E C8 40 E3 7C DE FC 03 23 03 C7 +B3 86 06 41 03 A8 48 C8 B3 86 C6 00 23 A0 D5 00 +23 20 65 00 23 22 05 01 13 05 00 00 6F F0 DF FB +73 70 04 30 6F 00 00 00 B7 57 00 10 13 07 10 00 +23 AA E7 C6 67 80 00 00 B7 57 00 10 03 A5 47 C9 +67 80 00 00 63 18 05 00 B7 57 00 10 03 A5 47 C9 +67 80 00 00 13 05 00 00 67 80 00 00 B7 57 00 10 +83 A7 C7 C7 13 05 10 00 63 8A 07 00 B7 57 00 10 +03 A5 47 C6 13 35 15 00 13 15 15 00 67 80 00 00 +63 08 05 0A 13 01 01 FE 23 2A 91 00 B7 54 00 10 +83 A7 44 C9 03 27 C5 02 23 2C 81 00 83 A7 C7 02 +23 2E 11 00 13 04 05 00 63 72 F7 06 03 A6 44 C9 +93 17 27 00 23 28 21 01 83 25 C6 02 B3 87 E7 00 +93 06 50 00 37 49 00 10 03 26 45 01 33 87 B6 40 +93 97 27 00 13 09 C9 71 23 2C E5 00 B3 07 F9 00 +63 0C F6 04 83 A7 44 C9 83 A7 C7 02 23 26 F5 02 +83 20 C1 01 03 24 81 01 03 29 01 01 83 24 41 01 +13 05 10 00 13 01 01 02 67 80 00 00 83 A7 44 C9 +03 25 45 04 83 20 C1 01 83 A7 C7 02 03 24 81 01 +83 24 41 01 33 35 F5 00 13 01 01 02 67 80 00 00 +13 05 00 00 67 80 00 00 23 26 31 01 93 09 45 00 +13 85 09 00 EF 10 10 2B 03 A7 44 C9 B7 57 00 10 +83 A6 07 C8 03 27 C7 02 23 26 E4 02 63 F4 E6 00 +23 A0 E7 C8 93 17 27 00 B3 87 E7 00 93 97 27 00 +33 09 F9 00 03 27 49 00 83 27 09 00 83 26 87 00 +23 24 E4 00 93 87 17 00 23 26 D4 00 23 A2 36 01 +23 24 37 01 23 2A 24 01 83 29 C1 00 23 20 F9 00 +6F F0 1F F5 63 02 05 06 B7 57 00 10 83 A7 47 C9 +13 01 01 FF 23 24 81 00 23 26 11 00 13 04 05 00 +63 86 A7 00 73 70 04 30 6F 00 00 00 83 A7 87 04 +63 88 07 02 83 26 C5 02 03 27 45 04 93 87 F7 FF +23 24 F5 04 63 84 E6 00 63 84 07 02 13 05 00 00 +83 20 C1 00 03 24 81 00 13 01 01 01 67 80 00 00 +73 70 04 30 6F 00 00 00 13 05 00 00 67 80 00 00 +23 22 91 00 93 04 45 00 13 85 04 00 EF 10 90 1D +83 27 44 04 B7 56 00 10 13 07 50 00 03 A6 06 C8 +33 07 F7 40 23 26 F4 02 23 2C E4 00 63 74 F6 00 +23 A0 F6 C8 13 97 27 00 33 07 F7 00 B7 47 00 10 +13 17 27 00 93 87 C7 71 B3 87 E7 00 83 A6 47 00 +03 A7 07 00 13 05 10 00 03 A6 86 00 23 24 D4 00 +33 07 A7 00 23 26 C4 00 23 22 96 00 23 A4 96 00 +23 2A F4 00 83 24 41 00 23 A0 E7 00 6F F0 5F F6 +63 0E 05 0E 83 27 85 04 13 01 01 FF 23 24 81 00 +23 26 11 00 13 04 05 00 63 96 07 00 73 70 04 30 +6F 00 00 00 03 27 45 04 63 62 B7 02 83 26 C4 02 +63 86 E6 00 13 06 10 00 63 8E C7 00 83 20 C1 00 +03 24 81 00 13 01 01 01 67 80 00 00 13 87 05 00 +6F F0 DF FD B7 57 00 10 83 A7 47 C9 63 82 87 0A +93 97 26 00 B3 86 D7 00 13 06 50 00 B7 47 00 10 +83 25 44 01 33 06 E6 40 93 96 26 00 93 87 C7 71 +23 26 E4 02 23 2C C4 00 33 87 D7 00 E3 98 E5 FA +23 22 91 00 93 04 44 00 13 85 04 00 EF 10 90 0C +37 57 00 10 83 26 C4 02 03 26 07 C8 B7 47 00 10 +93 87 C7 71 63 74 D6 00 23 20 D7 C8 13 97 26 00 +33 07 D7 00 13 17 27 00 B3 87 E7 00 83 A6 47 00 +03 A7 07 00 03 A6 86 00 23 24 D4 00 13 07 17 00 +23 26 C4 00 23 22 96 00 23 A4 96 00 23 2A F4 00 +83 24 41 00 23 A0 E7 00 6F F0 5F F4 67 80 00 00 +73 70 04 30 6F 00 00 00 B7 57 00 10 03 A6 47 C9 +83 A6 47 C9 03 A7 47 C9 93 07 50 00 83 A6 C6 02 +03 25 86 01 B3 87 D7 40 23 2C F7 00 67 80 00 00 +B7 57 00 10 03 A5 47 C9 63 08 05 00 83 27 85 04 +93 87 17 00 23 24 F5 04 67 80 00 00 63 06 05 00 +73 70 04 30 6F 00 00 00 13 01 01 FE 23 28 21 01 +37 59 00 10 83 27 49 C6 23 2C 81 00 23 2E 11 00 +93 87 17 00 23 2A 91 00 23 26 31 01 23 24 41 01 +13 84 05 00 23 22 F9 C6 73 70 04 30 B7 59 00 10 +03 A7 49 C9 B7 44 00 10 83 A7 04 4C 03 27 C7 04 +63 16 07 02 03 A7 49 C9 93 06 10 00 23 08 D7 04 +63 0E 06 00 63 94 07 00 73 60 04 30 13 05 06 00 +EF E0 5F C9 13 0A 10 00 6F 00 C0 00 63 84 07 02 +13 0A 00 00 73 70 04 30 83 A7 04 4C 03 27 49 C6 +93 87 17 00 23 A0 F4 4C 63 1A 07 00 73 70 04 30 +6F 00 00 00 73 60 04 30 6F F0 9F FD EF E0 5F F2 +63 1A 0A 04 73 70 04 30 03 A7 49 C9 83 A7 04 4C +03 25 C7 04 63 08 05 00 03 A7 49 C9 63 02 04 04 +23 26 07 04 03 A7 49 C9 23 08 07 04 63 94 07 00 +73 60 04 30 83 20 C1 01 03 24 81 01 83 24 41 01 +03 29 01 01 83 29 C1 00 03 2A 81 00 13 01 01 02 +67 80 00 00 E3 18 05 FA 73 00 00 00 6F F0 9F FA +93 06 F5 FF 23 26 D7 04 6F F0 DF FB 63 06 05 00 +73 70 04 30 6F 00 00 00 13 01 01 FE 23 24 41 01 +37 5A 00 10 83 27 4A C6 23 28 21 01 23 26 31 01 +93 87 17 00 23 2E 11 00 23 2C 81 00 23 2A 91 00 +23 22 51 01 93 09 06 00 13 89 06 00 23 22 FA C6 +73 70 04 30 B7 54 00 10 83 A6 44 C9 37 44 00 10 +93 07 20 00 03 C6 06 05 83 26 04 4C 63 00 F6 04 +03 A6 44 C9 93 C5 F5 FF 13 05 10 00 83 27 C6 04 +B3 F7 F5 00 23 26 F6 04 83 A7 44 C9 23 88 A7 04 +63 0E 07 00 63 94 06 00 73 60 04 30 13 05 07 00 +EF E0 5F B5 93 0A 10 00 6F 00 C0 00 63 84 06 02 +93 0A 00 00 73 70 04 30 83 27 04 4C 03 27 4A C6 +93 87 17 00 23 20 F4 4C 63 1A 07 00 73 70 04 30 +6F 00 00 00 73 60 04 30 6F F0 9F FD EF E0 5F DE +63 90 0A 08 73 70 04 30 03 27 04 4C 63 08 09 00 +83 A7 44 C9 83 A7 C7 04 23 20 F9 00 83 A6 44 C9 +93 07 20 00 13 05 00 00 83 C6 06 05 63 9E F6 00 +83 A6 44 C9 93 C7 F9 FF 13 05 10 00 03 A6 C6 04 +B3 F7 C7 00 23 A6 F6 04 83 A7 44 C9 23 20 E4 4C +23 88 07 04 63 14 07 00 73 60 04 30 83 20 C1 01 +03 24 81 01 83 24 41 01 03 29 01 01 83 29 C1 00 +03 2A 81 00 83 2A 41 00 13 01 01 02 67 80 00 00 +E3 12 05 F8 73 00 00 00 6F F0 DF F7 63 86 05 00 +73 70 04 30 6F 00 00 00 63 0E 05 06 73 70 04 30 +37 48 00 10 83 25 08 4C 93 87 15 00 23 20 F8 4C +63 06 07 00 83 27 C5 04 23 20 F7 00 03 47 05 05 +93 07 20 00 23 08 F5 04 93 07 40 00 13 77 F7 0F +63 EE D7 0E B7 47 00 10 93 96 26 00 93 87 C7 45 +B3 87 F6 00 83 A7 07 00 67 80 07 00 93 07 20 00 +63 08 F7 0E 23 26 C5 04 93 07 10 00 63 00 F7 02 +13 05 10 00 23 20 B8 4C 63 94 05 00 73 60 04 30 +67 80 00 00 73 70 04 30 6F 00 00 00 83 27 45 01 +83 26 85 00 03 27 C5 00 03 A6 47 00 93 08 45 00 +23 A4 E6 00 23 22 D7 00 63 0A 16 0D 03 A7 07 00 +37 56 00 10 83 26 C5 02 03 23 06 C8 13 07 F7 FF +23 A0 E7 00 63 74 D3 00 23 20 D6 C8 13 97 26 00 +33 07 D7 00 B7 47 00 10 13 17 27 00 93 87 C7 71 +B3 87 E7 00 03 A6 47 00 03 A7 07 00 03 2E 85 02 +03 23 86 00 23 24 C5 00 13 07 17 00 23 26 65 00 +23 22 13 01 23 24 16 01 23 2A F5 00 23 A0 E7 00 +63 04 0E 04 73 70 04 30 6F 00 00 00 83 27 C5 04 +93 87 17 00 23 26 F5 04 6F F0 1F F4 83 27 C5 04 +B3 E7 C7 00 23 26 F5 04 6F F0 1F F3 B7 57 00 10 +83 A7 47 C8 E3 82 07 F2 73 70 04 30 6F 00 00 00 +13 05 00 00 6F F0 1F F2 B7 57 00 10 83 A7 47 C9 +83 A7 C7 02 E3 F6 D7 F0 73 00 00 00 83 25 08 4C +13 05 10 00 93 85 F5 FF 6F F0 DF EF 23 A2 E7 00 +6F F0 DF F2 63 04 05 06 63 90 05 04 63 06 07 00 +83 25 C5 04 23 20 B7 00 83 45 05 05 13 07 20 00 +23 08 E5 04 13 07 40 00 93 F5 F5 0F 63 6C D7 06 +37 47 00 10 93 96 26 00 13 07 07 47 33 87 E6 00 +03 27 07 00 67 00 07 00 73 70 04 30 6F 00 00 00 +13 07 20 00 63 82 E5 06 23 26 C5 04 13 07 10 00 +63 8A E5 00 13 05 10 00 67 80 00 00 73 70 04 30 +6F 00 00 00 03 27 85 02 63 04 07 04 73 70 04 30 +6F 00 00 00 03 27 C5 04 13 07 17 00 23 26 E5 04 +6F F0 DF FC 03 27 C5 04 33 67 C7 00 23 26 E5 04 +6F F0 DF FB 37 57 00 10 03 27 47 C8 E3 08 07 FA +73 70 04 30 6F 00 00 00 13 05 00 00 67 80 00 00 +37 57 00 10 03 27 47 C6 83 26 C5 02 63 16 07 0A +03 27 45 01 83 25 85 00 03 26 C5 00 83 28 47 00 +13 08 45 00 23 A4 C5 00 23 22 B6 00 63 84 08 0D +03 26 07 00 B7 55 00 10 83 A8 05 C8 13 06 F6 FF +23 20 C7 00 63 F4 D8 00 23 A0 D5 C8 13 96 26 00 +33 06 D6 00 37 47 00 10 13 16 26 00 13 07 C7 71 +33 07 C7 00 83 25 47 00 03 26 07 00 83 A8 85 00 +23 24 B5 00 13 06 16 00 23 26 15 01 23 A2 08 01 +23 A4 05 01 23 2A E5 00 23 20 C7 00 37 57 00 10 +03 27 47 C9 03 27 C7 02 E3 76 D7 F0 63 86 07 00 +13 07 10 00 23 A0 E7 00 B7 57 00 10 13 07 10 00 +23 AA E7 C6 6F F0 1F EF 37 47 00 10 13 07 C7 71 +83 25 87 06 03 26 47 06 13 08 85 01 83 A8 85 00 +23 2E B5 00 13 06 16 00 23 20 15 03 23 A2 08 01 +23 A4 05 01 93 08 47 06 23 22 C7 06 23 24 15 03 +6F F0 DF F9 23 22 C7 00 6F F0 9F F3 63 0A 05 02 +63 86 05 00 73 70 04 30 6F 00 00 00 93 07 20 00 +83 46 05 05 23 08 F5 04 83 27 C5 04 13 07 10 00 +B3 87 E7 00 23 26 F5 04 63 88 E6 00 67 80 00 00 +73 70 04 30 6F 00 00 00 83 27 85 02 63 86 07 00 +73 70 04 30 6F 00 00 00 B7 57 00 10 83 A7 47 C6 +03 27 C5 02 63 96 07 0A 83 27 45 01 83 25 85 00 +83 26 C5 00 83 A8 47 00 13 08 45 00 23 A4 D5 00 +23 A2 B6 00 63 84 08 0D 83 A6 07 00 B7 55 00 10 +83 A8 05 C8 93 86 F6 FF 23 A0 D7 00 63 F4 E8 00 +23 A0 E5 C8 93 16 27 00 B3 86 E6 00 B7 47 00 10 +93 96 26 00 93 87 C7 71 B3 87 D7 00 83 A5 47 00 +83 A6 07 00 83 A8 85 00 23 24 B5 00 93 86 16 00 +23 26 15 01 23 A2 08 01 23 A4 05 01 23 2A F5 00 +23 A0 D7 00 B7 57 00 10 83 A7 47 C9 83 A7 C7 02 +E3 F6 E7 F4 63 06 06 00 93 07 10 00 23 20 F6 00 +B7 57 00 10 13 07 10 00 23 AA E7 C6 67 80 00 00 +B7 47 00 10 93 87 C7 71 83 A5 87 06 83 A6 47 06 +13 08 85 01 83 A8 85 00 23 2E B5 00 93 86 16 00 +23 20 15 03 23 A2 08 01 23 A4 05 01 93 88 47 06 +23 A2 D7 06 23 24 15 03 6F F0 DF F9 23 A2 D7 00 +6F F0 9F F3 93 07 05 00 63 86 05 00 73 70 04 30 +6F 00 00 00 63 0E 05 02 73 70 04 30 03 C6 07 05 +37 47 00 10 93 06 20 00 03 27 07 4C 13 05 00 00 +63 08 D6 00 63 14 07 00 73 60 04 30 67 80 00 00 +23 88 07 04 13 05 10 00 E3 1A 07 FE 6F F0 DF FE +B7 57 00 10 83 A7 47 C9 73 70 04 30 03 C6 07 05 +37 47 00 10 93 06 20 00 03 27 07 4C 13 05 00 00 +E3 12 D6 FC 6F F0 DF FC 13 07 05 00 63 86 05 00 +73 70 04 30 6F 00 00 00 63 08 05 02 73 70 04 30 +03 25 C7 04 83 27 C7 04 B7 46 00 10 13 46 F6 FF +83 A6 06 4C B3 77 F6 00 23 26 F7 04 63 94 06 00 +73 60 04 30 67 80 00 00 B7 57 00 10 03 A7 47 C9 +6F F0 DF FC B7 47 00 10 93 87 C7 71 13 87 07 0A +23 20 E5 00 93 87 47 0F 23 A0 F5 00 93 07 00 08 +23 20 F6 00 67 80 00 00 B7 47 00 10 93 87 C7 71 +13 87 47 2F 23 20 E5 00 93 87 87 34 23 A0 F5 00 +93 07 00 08 23 20 F6 00 67 80 00 00 B7 57 00 10 +23 AA 07 C8 B7 57 00 10 23 A4 07 C8 B7 57 00 10 +23 A2 07 C8 B7 57 00 10 23 A0 07 C8 B7 57 00 10 +23 AE 07 C6 B7 57 00 10 23 AC 07 C6 B7 57 00 10 +23 AA 07 C6 B7 57 00 10 23 A8 07 C6 B7 57 00 10 +23 A4 07 C6 37 57 00 10 B7 57 00 10 23 26 07 C6 +23 A2 07 C6 67 80 00 00 13 01 01 FE 23 2E 11 00 +23 2C 81 00 23 2A 91 00 73 70 04 30 37 44 00 10 +83 27 04 4C B7 54 00 10 03 A7 84 D8 93 86 17 00 +23 20 D4 4C 63 02 07 02 23 20 F4 4C 63 94 07 00 +73 60 04 30 83 20 C1 01 03 24 81 01 83 24 41 01 +13 01 01 02 67 80 00 00 23 28 21 01 37 59 00 10 +13 05 89 C9 13 09 89 C9 23 26 31 01 EF 00 50 6A +93 09 49 01 13 85 09 00 EF 00 90 69 B7 57 00 10 +37 58 00 10 93 06 89 02 13 06 09 07 13 07 00 00 +93 05 C0 00 13 05 A0 00 23 A6 37 D9 23 28 28 D9 +EF 10 40 33 83 27 04 4C 03 29 01 01 83 29 C1 00 +23 A4 A4 D8 93 87 F7 FF 6F F0 1F F8 13 01 01 FE +23 24 41 01 37 5A 00 10 83 27 0A D9 23 2C 81 00 +23 22 51 01 83 A7 C7 00 23 2A 91 00 93 04 05 00 +03 A4 C7 00 23 26 31 01 23 2E 11 00 93 0A 44 00 +13 85 0A 00 93 89 05 00 EF 00 D0 6B 83 47 44 02 +13 F7 47 00 63 1A 07 02 93 F7 E7 FF 23 02 F4 02 +83 27 04 02 13 05 04 00 03 24 81 01 83 20 C1 01 +83 24 41 01 83 29 C1 00 03 2A 81 00 83 2A 41 00 +13 01 01 02 67 80 07 00 23 28 21 01 6F 00 40 01 +63 66 F7 04 83 27 04 02 93 04 09 00 E7 80 07 00 +83 27 84 01 23 28 84 00 13 05 04 00 33 89 F4 00 +23 22 24 01 33 87 99 40 B3 36 99 00 E3 FA 29 FD +63 F4 99 00 E3 88 06 FC 03 25 0A D9 93 85 0A 00 +EF 00 50 5E 03 29 01 01 6F F0 9F F8 B7 57 00 10 +03 A5 C7 D8 93 85 0A 00 EF 00 D0 5C 03 29 01 01 +6F F0 1F F7 13 01 01 FC 23 22 51 03 B7 4A 00 10 +23 2C 81 02 23 2A 91 02 23 26 31 03 23 24 41 03 +23 20 61 03 23 2E 11 02 23 28 21 03 23 2E 71 01 +23 2C 81 01 93 8A 8A 48 B7 54 00 10 B7 59 00 10 +37 5A 00 10 37 54 00 10 13 0B 90 00 83 A7 04 D9 +83 AB 07 00 63 94 0B 1E EF E0 1F B8 EF E0 DF BB +83 A7 09 D8 13 09 05 00 63 62 F5 0A 83 27 CA D8 +23 A0 A9 D8 03 A6 07 00 13 36 16 00 03 25 84 D8 +B3 85 2B 41 EF 20 80 11 EF E0 5F B6 63 14 05 00 +73 00 00 00 23 22 01 00 23 24 01 00 23 26 01 00 +03 25 84 D8 13 06 00 00 93 05 41 00 EF 10 C0 71 +E3 0E 05 F8 83 27 41 00 E3 C4 07 FE 03 29 C1 00 +83 27 49 01 63 86 07 00 13 05 49 00 EF 00 90 54 +EF E0 9F B4 83 A7 09 D8 93 0B 05 00 63 62 F5 06 +83 27 41 00 23 A0 79 D9 E3 6C FB FA 93 97 27 00 +B3 87 FA 00 83 A7 07 00 67 80 07 00 83 A7 C7 00 +93 05 F0 FF 03 A5 07 00 EF F0 5F E1 83 A7 04 D9 +03 A7 07 00 E3 14 07 FE 03 27 CA D8 23 A0 29 D9 +23 26 FA D8 23 A8 E4 D8 EF E0 5F AC 6F F0 9F F6 +83 A7 C7 00 93 05 F0 FF 03 A5 07 00 EF F0 1F DE +83 A7 04 D9 03 A7 07 00 E3 14 07 FE 03 27 CA D8 +23 26 FA D8 23 A8 E4 D8 6F F0 9F F8 83 26 81 00 +03 46 49 02 03 27 89 01 23 28 29 01 93 65 16 00 +B3 87 E6 00 23 02 B9 02 23 22 F9 00 B3 B5 D7 00 +63 EC FB 0E B3 86 DB 40 63 E2 E6 0A 93 76 46 00 +63 94 06 04 13 76 E6 FF 23 02 C9 02 83 27 09 02 +13 05 09 00 E7 80 07 00 6F F0 9F EF 83 47 49 02 +93 F7 E7 FF 23 02 F9 02 6F F0 9F EE B3 87 FB 40 +63 E8 E7 0C 83 27 09 02 13 05 09 00 E7 80 07 00 +03 27 89 01 93 07 0C 00 33 8C E7 00 23 28 29 01 +23 22 89 01 B3 36 FC 00 E3 FA 8B FD 63 F4 FB 00 +E3 8A 06 FC 03 A5 04 D9 93 05 49 00 EF 00 90 3C +6F F0 DF F9 03 47 49 02 83 27 81 00 13 67 17 00 +23 02 E9 02 23 2C F9 00 63 84 07 08 B3 87 77 01 +23 22 F9 00 23 28 29 01 63 EC FB 04 03 25 CA D8 +93 05 49 00 EF 00 10 39 6F F0 9F E6 83 A7 C7 00 +83 AB 07 00 EF E0 5F 99 EF E0 1F 9D 83 A7 09 D8 +13 09 05 00 E3 6C F5 EA 23 A0 A9 D8 13 06 00 00 +E3 6E 75 E1 EF E0 9F 98 93 05 09 00 13 85 0B 00 +EF F0 DF CA 6F F0 1F E2 63 F4 DB 00 E3 88 05 F0 +03 A5 04 D9 93 05 49 00 EF 00 D0 33 6F F0 5F E1 +03 25 CA D8 93 05 49 00 EF 00 D0 32 6F F0 1F F0 +73 70 04 30 6F 00 00 00 13 01 01 FE 23 2E 11 00 +EF F0 9F BB B7 57 00 10 83 A7 87 D8 63 80 07 06 +13 06 C1 00 93 05 81 00 13 05 41 00 23 22 01 00 +23 24 01 00 EF F0 5F B1 83 27 81 00 03 28 41 00 +03 26 C1 00 B7 45 00 10 37 25 00 10 93 85 45 45 +13 05 45 12 13 07 40 00 93 06 00 00 EF E0 CF CE +B7 57 00 10 23 A2 A7 D8 63 0A 05 00 83 20 C1 01 +13 05 10 00 13 01 01 02 67 80 00 00 73 70 04 30 +6F 00 00 00 13 01 01 FC 13 08 80 02 23 26 01 03 +83 28 C1 02 23 2E 11 02 63 86 08 01 73 70 04 30 +6F 00 00 00 03 28 C1 02 63 8C 07 00 13 08 20 00 +23 82 07 03 63 9A 05 00 73 70 04 30 6F 00 00 00 +73 70 04 30 6F 00 00 00 23 28 C1 00 23 2E F1 00 +23 2C E1 00 23 2A D1 00 23 26 B1 00 23 24 A1 00 +EF F0 9F AE 83 27 C1 01 03 25 81 00 83 25 C1 00 +83 26 41 01 03 27 81 01 23 A0 A7 00 23 AC B7 00 +23 AE D7 00 23 A0 E7 02 13 85 47 00 23 24 F1 00 +EF 00 10 1E 03 26 01 01 83 27 81 00 63 08 06 00 +03 C7 47 02 13 67 47 00 23 82 E7 02 83 20 C1 03 +13 85 07 00 13 01 01 04 67 80 00 00 63 06 05 04 +13 01 01 FD 23 24 81 02 37 54 00 10 83 27 84 D8 +23 26 11 02 63 80 07 02 23 2A B1 00 23 2C C1 00 +23 2E A1 00 93 07 50 00 63 D4 B7 02 73 70 04 30 +6F 00 00 00 13 05 00 00 83 20 C1 02 03 24 81 02 +13 01 01 03 67 80 00 00 73 70 04 30 6F 00 00 00 +23 26 E1 00 EF E0 9F E4 93 06 20 00 83 27 84 D8 +03 27 C1 00 63 04 D5 02 93 05 41 01 13 85 07 00 +93 06 00 00 13 06 00 00 EF 00 90 6A 83 20 C1 02 +03 24 81 02 13 01 01 03 67 80 00 00 13 06 07 00 +13 85 07 00 93 06 00 00 93 05 41 01 EF 00 50 68 +6F F0 9F F9 63 0E 05 02 B7 57 00 10 83 A7 87 D8 +63 84 07 02 13 01 01 FE 23 2E 11 00 23 22 B1 00 +23 24 C1 00 23 26 A1 00 13 07 50 00 63 4E B7 00 +73 70 04 30 6F 00 00 00 13 05 00 00 67 80 00 00 +73 70 04 30 6F 00 00 00 13 86 06 00 93 05 41 00 +13 85 07 00 93 06 00 00 EF 10 80 0E 83 20 C1 01 +13 01 01 02 67 80 00 00 B7 57 00 10 03 A5 47 D8 +63 04 05 00 67 80 00 00 73 70 04 30 6F 00 00 00 +63 06 05 00 03 25 85 01 67 80 00 00 73 70 04 30 +6F 00 00 00 63 08 05 02 73 70 04 30 03 47 45 02 +B7 47 00 10 83 A6 07 4C 93 77 B7 0F 63 84 05 00 +93 67 47 00 23 02 F5 02 63 94 06 00 73 60 04 30 +67 80 00 00 73 70 04 30 6F 00 00 00 63 04 05 02 +73 70 04 30 B7 47 00 10 03 25 45 02 83 A7 07 4C +13 55 25 00 13 75 15 00 63 94 07 00 73 60 04 30 +67 80 00 00 73 70 04 30 6F 00 00 00 63 04 05 02 +73 70 04 30 B7 47 00 10 03 25 45 02 83 A7 07 4C +13 55 25 00 13 75 15 00 63 94 07 00 73 60 04 30 +67 80 00 00 73 70 04 30 6F 00 00 00 63 06 05 00 +03 25 45 00 67 80 00 00 73 70 04 30 6F 00 00 00 +93 07 05 00 63 80 05 02 03 47 45 02 13 05 00 00 +13 77 27 00 63 06 07 00 23 A0 F5 00 13 05 10 00 +67 80 00 00 73 70 04 30 6F 00 00 00 63 06 05 00 +03 25 05 00 67 80 00 00 73 70 04 30 6F 00 00 00 +63 02 05 02 73 70 04 30 B7 47 00 10 03 45 45 02 +83 A7 07 4C 13 75 15 00 63 94 07 00 73 60 04 30 +67 80 00 00 73 70 04 30 6F 00 00 00 63 00 05 02 +73 70 04 30 B7 47 00 10 83 A7 07 4C 03 25 C5 01 +63 94 07 00 73 60 04 30 67 80 00 00 73 70 04 30 +6F 00 00 00 63 00 05 02 73 70 04 30 B7 47 00 10 +83 A7 07 4C 23 2E B5 00 63 94 07 00 73 60 04 30 +67 80 00 00 73 70 04 30 6F 00 00 00 37 57 00 10 +B7 57 00 10 23 24 07 D8 23 A2 07 D8 67 80 00 00 +13 01 01 FF F3 27 40 F1 23 26 F1 00 03 25 C1 00 +B7 07 00 06 93 87 17 00 33 05 F5 00 13 15 35 00 +37 57 00 10 B7 07 00 30 23 2E A7 D8 93 87 47 00 +B7 05 00 30 83 A6 07 00 03 A6 05 00 03 A7 07 00 +E3 1A D7 FE B7 D6 01 00 93 86 06 4C B7 B7 03 00 +B3 06 D6 00 93 87 07 98 B3 B5 C6 00 B3 07 F6 00 +23 20 D5 00 B3 88 E5 00 33 B6 C7 00 23 22 15 01 +33 06 E6 00 37 57 00 10 23 22 C7 DA 23 20 F7 DA +13 01 01 01 67 80 00 00 B7 57 00 10 93 87 07 1B +93 F7 F7 00 63 86 07 00 73 70 04 30 6F 00 00 00 +13 01 01 FF 23 26 11 00 EF F0 9F F5 B7 17 00 00 +93 87 07 88 73 A0 47 30 EF 00 80 07 83 20 C1 00 +13 05 00 00 13 01 01 01 67 80 00 00 6F 00 00 00 +F3 22 00 30 93 F2 72 FF 13 03 80 18 13 13 43 00 +B3 E2 62 00 13 05 C5 FF 23 20 55 00 13 05 C5 FF +23 20 05 00 13 05 85 FA 23 20 C5 00 13 05 85 FE +97 22 00 00 83 A2 82 4E 23 20 55 00 93 02 00 00 +63 8A 02 00 13 05 C5 FF 23 20 05 00 93 82 F2 FF +6F F0 1F FF 13 05 C5 FF 23 20 B5 00 67 80 00 00 +17 21 00 00 03 21 41 3B 03 21 01 00 83 20 01 00 +83 23 01 01 03 24 41 01 83 24 81 01 03 25 C1 01 +83 25 01 02 03 26 41 02 83 26 81 02 03 27 C1 02 +83 27 01 03 03 28 41 03 83 28 81 03 03 29 C1 03 +83 29 01 04 03 2A 41 04 83 2A 81 04 03 2B C1 04 +83 2B 01 05 03 2C 41 05 83 2C 81 05 03 2D C1 05 +83 2D 01 06 03 2E 41 06 83 2E 81 06 03 2F C1 06 +83 2F 01 07 83 22 41 07 17 23 00 00 03 23 43 B6 +23 20 53 00 83 22 81 07 93 82 82 00 73 90 02 30 +83 22 81 00 03 23 C1 00 13 01 C1 07 67 80 00 00 +F3 22 20 34 73 23 10 34 F3 23 00 30 6F 00 00 00 +F3 22 20 34 73 23 10 34 F3 23 00 30 6F 00 00 00 +13 01 41 F8 23 22 11 00 23 24 51 00 23 26 61 00 +23 28 71 00 23 2A 81 00 23 2C 91 00 23 2E A1 00 +23 20 B1 02 23 22 C1 02 23 24 D1 02 23 26 E1 02 +23 28 F1 02 23 2A 01 03 23 2C 11 03 23 2E 21 03 +23 20 31 05 23 22 41 05 23 24 51 05 23 26 61 05 +23 28 71 05 23 2A 81 05 23 2C 91 05 23 2E A1 05 +23 20 B1 07 23 22 C1 07 23 24 D1 07 23 26 E1 07 +23 28 F1 07 97 22 00 00 83 A2 C2 AA 23 2A 51 06 +F3 22 00 30 23 2C 51 06 97 22 00 00 83 A2 C2 26 +23 A0 22 00 73 25 20 34 F3 25 10 34 93 85 45 00 +23 20 B1 00 17 21 00 00 03 21 41 A7 93 02 B0 00 +63 16 55 0A EF E0 8F C0 17 23 00 00 03 23 C3 23 +03 21 03 00 83 22 01 00 73 90 12 34 83 22 81 07 +73 90 02 30 83 22 41 07 17 23 00 00 03 23 43 A4 +23 20 53 00 83 20 41 00 83 22 81 00 03 23 C1 00 +83 23 01 01 03 24 41 01 83 24 81 01 03 25 C1 01 +83 25 01 02 03 26 41 02 83 26 81 02 03 27 C1 02 +83 27 01 03 03 28 41 03 83 28 81 03 03 29 C1 03 +83 29 01 04 03 2A 41 04 83 2A 81 04 03 2B C1 04 +83 2B 01 05 03 2C 41 05 83 2C 81 05 03 2D C1 05 +83 2D 01 06 03 2E 41 06 83 2E 81 06 03 2F C1 06 +83 2F 01 07 13 01 C1 07 73 00 20 30 EF F0 5F E8 +17 23 00 00 03 23 43 19 03 21 03 00 83 22 01 00 +73 90 12 34 83 22 81 07 73 90 02 30 83 22 41 07 +17 23 00 00 03 23 C3 99 23 20 53 00 83 20 41 00 +83 22 81 00 03 23 C1 00 83 23 01 01 03 24 41 01 +83 24 81 01 03 25 C1 01 83 25 01 02 03 26 41 02 +83 26 81 02 03 27 C1 02 83 27 01 03 03 28 41 03 +83 28 81 03 03 29 C1 03 83 29 01 04 03 2A 41 04 +83 2A 81 04 03 2B C1 04 83 2B 01 05 03 2C 41 05 +83 2C 81 05 03 2D C1 05 83 2D 01 06 03 2E 41 06 +83 2E 81 06 03 2F C1 06 83 2F 01 07 13 01 C1 07 +73 00 20 30 13 01 41 F8 23 22 11 00 23 24 51 00 +23 26 61 00 23 28 71 00 23 2A 81 00 23 2C 91 00 +23 2E A1 00 23 20 B1 02 23 22 C1 02 23 24 D1 02 +23 26 E1 02 23 28 F1 02 23 2A 01 03 23 2C 11 03 +23 2E 21 03 23 20 31 05 23 22 41 05 23 24 51 05 +23 26 61 05 23 28 71 05 23 2A 81 05 23 2C 91 05 +23 2E A1 05 23 20 B1 07 23 22 C1 07 23 24 D1 07 +23 26 E1 07 23 28 F1 07 97 22 00 00 83 A2 82 8A +23 2A 51 06 F3 22 00 30 23 2C 51 06 97 22 00 00 +83 A2 82 06 23 A0 22 00 73 25 20 34 F3 25 10 34 +23 20 B1 00 17 21 00 00 03 21 41 87 EF F0 5F D4 +17 23 00 00 03 23 43 04 03 21 03 00 83 22 01 00 +73 90 12 34 83 22 81 07 73 90 02 30 83 22 41 07 +17 23 00 00 03 23 C3 84 23 20 53 00 83 20 41 00 +83 22 81 00 03 23 C1 00 83 23 01 01 03 24 41 01 +83 24 81 01 03 25 C1 01 83 25 01 02 03 26 41 02 +83 26 81 02 03 27 C1 02 83 27 01 03 03 28 41 03 +83 28 81 03 03 29 C1 03 83 29 01 04 03 2A 41 04 +83 2A 81 04 03 2B C1 04 83 2B 01 05 03 2C 41 05 +83 2C 81 05 03 2D C1 05 83 2D 01 06 03 2E 41 06 +83 2E 81 06 03 2F C1 06 83 2F 01 07 13 01 C1 07 +73 00 20 30 13 01 41 F8 23 22 11 00 23 24 51 00 +23 26 61 00 23 28 71 00 23 2A 81 00 23 2C 91 00 +23 2E A1 00 23 20 B1 02 23 22 C1 02 23 24 D1 02 +23 26 E1 02 23 28 F1 02 23 2A 01 03 23 2C 11 03 +23 2E 21 03 23 20 31 05 23 22 41 05 23 24 51 05 +23 26 61 05 23 28 71 05 23 2A 81 05 23 2C 91 05 +23 2E A1 05 23 20 B1 07 23 22 C1 07 23 24 D1 07 +23 26 E1 07 23 28 F1 07 97 12 00 00 83 A2 82 75 +23 2A 51 06 F3 22 00 30 23 2C 51 06 97 22 00 00 +83 A2 82 F1 23 A0 22 00 73 25 20 34 F3 25 10 34 +23 20 B1 00 17 11 00 00 03 21 41 72 17 25 00 00 +03 25 05 00 97 15 00 00 83 A5 05 72 13 07 F0 FF +03 A6 05 00 83 A6 45 00 23 20 E5 00 23 22 D5 00 +23 20 C5 00 97 12 00 00 83 A2 02 6F 33 87 C2 00 +33 33 C7 00 B3 83 66 00 23 A0 E5 00 23 A2 75 00 +EF E0 4F 85 63 04 05 00 EF E0 4F 87 17 23 00 00 +03 23 83 EA 03 21 03 00 83 22 01 00 73 90 12 34 +83 22 81 07 73 90 02 30 83 22 41 07 17 13 00 00 +03 23 03 6B 23 20 53 00 83 20 41 00 83 22 81 00 +03 23 C1 00 83 23 01 01 03 24 41 01 83 24 81 01 +03 25 C1 01 83 25 01 02 03 26 41 02 83 26 81 02 +03 27 C1 02 83 27 01 03 03 28 41 03 83 28 81 03 +03 29 C1 03 83 29 01 04 03 2A 41 04 83 2A 81 04 +03 2B C1 04 83 2B 01 05 03 2C 41 05 83 2C 81 05 +03 2D C1 05 83 2D 01 06 03 2E 41 06 83 2E 81 06 +03 2F C1 06 83 2F 01 07 13 01 C1 07 73 00 20 30 +93 07 85 00 13 07 F0 FF 23 20 05 00 23 24 E5 00 +23 22 F5 00 23 26 F5 00 23 28 F5 00 67 80 00 00 +23 28 05 00 67 80 00 00 03 27 45 00 83 27 05 00 +83 26 87 00 23 A2 E5 00 93 87 17 00 23 A4 D5 00 +23 A2 B6 00 23 24 B7 00 23 A8 A5 00 23 20 F5 00 +67 80 00 00 03 A6 05 00 13 07 F0 FF 93 07 85 00 +63 0C E6 02 93 86 07 00 83 A7 47 00 03 A7 07 00 +E3 7A E6 FE 23 A2 F5 00 23 A4 B7 00 83 27 05 00 +23 A4 D5 00 23 A2 B6 00 23 A8 A5 00 93 87 17 00 +23 20 F5 00 67 80 00 00 83 26 05 01 83 A7 46 00 +6F F0 5F FD 03 27 05 01 83 26 45 00 83 27 85 00 +03 26 47 00 23 A4 F6 00 23 A2 D7 00 63 0C A6 00 +83 27 07 00 23 28 05 00 13 85 F7 FF 23 20 A7 00 +67 80 00 00 23 22 F7 00 83 27 07 00 23 28 05 00 +13 85 F7 FF 23 20 A7 00 67 80 00 00 13 01 01 FF +83 27 05 04 23 22 91 00 83 24 85 03 23 24 81 00 +23 26 11 00 13 04 05 00 63 96 07 02 83 27 05 00 +93 84 14 00 13 05 00 00 63 8C 07 0C 23 2C 94 02 +83 20 C1 00 03 24 81 00 83 24 41 00 13 01 01 01 +67 80 00 00 23 20 21 01 13 09 06 00 63 1A 06 04 +03 25 45 00 13 86 07 00 93 84 14 00 EF 10 40 39 +83 27 44 00 83 26 04 04 03 27 84 00 B3 87 D7 00 +23 22 F4 00 63 E6 E7 00 83 27 04 00 23 22 F4 00 +03 29 01 00 83 20 C1 00 23 2C 94 02 03 24 81 00 +83 24 41 00 13 05 00 00 13 01 01 01 67 80 00 00 +03 25 C5 00 13 86 07 00 EF 10 80 34 03 27 04 04 +83 27 C4 00 83 26 04 00 33 06 E0 40 B3 87 E7 40 +23 26 F4 00 63 F8 D7 00 83 27 84 00 B3 87 C7 00 +23 26 F4 00 93 07 20 00 63 0C F9 02 93 84 14 00 +03 29 01 00 83 20 C1 00 23 2C 94 02 03 24 81 00 +83 24 41 00 13 05 00 00 13 01 01 01 67 80 00 00 +03 25 84 00 EF E0 0F C6 23 24 04 00 6F F0 1F F2 +E3 98 04 F6 93 04 10 00 6F F0 9F F6 13 01 01 FE +23 2A 91 00 23 2E 11 00 23 2C 81 00 23 28 21 01 +23 26 31 01 93 04 05 00 73 70 04 30 37 49 00 10 +83 47 55 04 03 27 09 4C 13 94 87 01 93 07 17 00 +13 54 84 41 23 20 F9 4C 63 5A 80 04 93 09 45 02 +6F 00 80 01 93 07 F4 FF 13 94 87 01 13 F7 F7 0F +13 54 84 41 63 08 07 02 83 A7 44 02 13 85 09 00 +63 82 07 02 EF D0 5F F3 E3 0E 05 FC EF E0 CF A5 +93 07 F4 FF 13 94 87 01 13 F7 F7 0F 13 54 84 41 +E3 1C 07 FC 03 27 09 4C 13 07 F7 FF 93 07 F0 FF +23 20 E9 4C A3 82 F4 04 63 14 07 00 73 60 04 30 +73 70 04 30 83 C7 44 04 03 27 09 4C 13 94 87 01 +93 07 17 00 13 54 84 41 23 20 F9 4C 63 5A 80 04 +93 89 04 01 6F 00 80 01 93 07 F4 FF 13 94 87 01 +13 F7 F7 0F 13 54 84 41 63 08 07 02 83 A7 04 01 +13 85 09 00 63 82 07 02 EF D0 1F EB E3 0E 05 FC +EF E0 8F 9D 93 07 F4 FF 13 94 87 01 13 F7 F7 0F +13 54 84 41 E3 1C 07 FC 03 27 09 4C 13 07 F7 FF +93 07 F0 FF 23 20 E9 4C 23 82 F4 04 63 14 07 00 +73 60 04 30 83 20 C1 01 03 24 81 01 83 24 41 01 +03 29 01 01 83 29 C1 00 13 01 01 02 67 80 00 00 +63 0A 05 12 13 01 01 FE 23 2C 81 00 13 04 05 00 +03 25 C5 03 23 2E 11 00 23 2A 91 00 23 28 21 01 +23 26 31 01 23 24 41 01 23 22 51 01 63 00 05 10 +93 84 05 00 83 25 04 04 93 57 05 01 13 D7 05 01 +63 90 07 0A 13 09 07 00 93 09 05 00 63 10 07 0A +73 70 04 30 37 4A 00 10 03 29 0A 4C 83 29 04 04 +83 25 C4 03 83 2A 04 00 93 07 19 00 13 85 09 00 +23 20 FA 4C EF 10 80 0F B3 07 35 41 23 2C 04 02 +13 07 F0 FF B3 87 FA 00 33 85 AA 00 23 02 E4 04 +23 22 54 01 23 26 F4 00 23 24 A4 00 A3 02 E4 04 +63 9E 04 08 83 27 04 01 63 98 07 0A 23 20 2A 4D +63 14 09 00 73 60 04 30 83 20 C1 01 03 24 81 01 +83 24 41 01 03 29 01 01 83 29 C1 00 03 2A 81 00 +83 2A 41 00 13 05 10 00 13 01 01 02 67 80 00 00 +63 16 07 04 13 89 07 00 93 89 05 00 93 95 05 01 +13 15 05 01 93 D5 05 01 13 55 05 01 EF 10 00 07 +93 07 05 00 93 15 09 01 13 95 09 01 13 89 07 00 +93 D5 05 01 13 55 05 01 EF 10 40 05 13 59 09 01 +B3 07 25 01 93 D7 07 01 E3 84 07 F2 73 70 04 30 +6F 00 00 00 73 70 04 30 6F 00 00 00 13 05 04 01 +EF F0 1F B7 13 05 44 02 EF F0 9F B6 03 29 0A 4C +13 09 F9 FF 6F F0 9F F5 13 05 04 01 EF D0 DF CF +E3 06 05 FE 73 00 00 00 03 29 0A 4C 13 09 F9 FF +6F F0 DF F3 63 80 06 04 63 06 05 02 13 01 01 FD +23 26 11 02 63 0C 06 02 63 82 05 02 93 07 80 04 +23 2E F1 00 03 27 C1 01 63 02 F7 04 73 70 04 30 +6F 00 00 00 73 70 04 30 6F 00 00 00 73 70 04 30 +6F 00 00 00 73 70 04 30 6F 00 00 00 E3 98 05 FE +93 07 80 04 23 2E F1 00 03 27 C1 01 E3 18 F7 FC +83 27 C1 01 13 86 06 00 6F 00 80 00 83 27 C1 01 +23 AE A6 02 23 A0 B6 04 23 A0 C6 00 13 85 06 00 +93 05 10 00 23 26 D1 00 EF F0 9F E0 83 26 C1 00 +83 20 C1 02 13 85 06 00 13 01 01 03 67 80 00 00 +63 04 05 02 63 0E 06 00 63 86 05 00 83 27 05 00 +23 A0 F5 00 23 20 A6 00 13 05 10 00 67 80 00 00 +73 70 04 30 6F 00 00 00 73 70 04 30 6F 00 00 00 +13 01 01 FC 23 2E 11 02 23 26 C1 00 63 06 05 1A +23 2C 81 02 23 26 31 03 23 24 41 03 13 04 05 00 +13 8A 05 00 93 89 06 00 63 86 05 14 93 07 20 00 +63 9C F9 00 03 27 C4 03 93 07 10 00 63 06 F7 00 +73 70 04 30 6F 00 00 00 EF D0 5F F3 63 0A 05 16 +23 2A 91 02 73 70 04 30 B7 44 00 10 83 A7 04 4C +03 27 84 03 83 26 C4 03 13 86 17 00 23 A0 C4 4C +63 64 D7 16 13 07 20 00 63 80 E9 16 03 27 C1 00 +23 28 21 03 23 22 51 03 63 0E 07 0A 13 05 81 01 +EF D0 9F E0 93 0A 04 01 13 09 F0 FF 83 A7 04 4C +93 87 F7 FF 23 A0 F4 4C 63 94 07 00 73 60 04 30 +EF D0 9F 82 73 70 04 30 83 47 44 04 03 A7 04 4C +93 97 87 01 93 D7 87 41 63 94 27 01 23 02 04 04 +83 47 54 04 93 97 87 01 93 D7 87 41 63 84 27 0B +63 14 07 00 73 60 04 30 93 05 C1 00 13 05 81 01 +EF D0 5F DC 63 18 05 12 73 70 04 30 83 26 84 03 +03 27 C4 03 83 A7 04 4C 63 82 E6 08 63 94 07 00 +73 60 04 30 13 05 04 00 EF F0 5F B6 EF D0 0F FD +73 70 04 30 83 A7 04 4C 83 26 84 03 03 27 C4 03 +13 86 17 00 23 A0 C4 4C 63 EC E6 08 03 27 C1 00 +E3 1E 07 F4 23 A0 F4 4C 63 86 07 0E 03 29 01 03 +83 2A 41 02 13 05 00 00 03 24 81 03 83 20 C1 03 +83 24 41 03 83 29 C1 02 03 2A 81 02 13 01 01 04 +67 80 00 00 83 27 05 04 E3 8A 07 EA 73 70 04 30 +6F 00 00 00 A3 02 04 04 6F F0 9F F5 63 94 07 00 +73 60 04 30 83 25 C1 00 13 85 0A 00 EF D0 9F 95 +13 05 04 00 EF F0 9F AD EF D0 4F F4 E3 1A 05 F6 +73 00 00 00 6F F0 DF F6 73 70 04 30 6F 00 00 00 +83 27 C1 00 E3 86 07 E8 73 70 04 30 6F 00 00 00 +03 29 01 03 83 2A 41 02 13 86 09 00 93 05 0A 00 +13 05 04 00 EF F0 9F 97 83 27 44 02 63 92 07 02 +63 16 05 02 83 A7 04 4C 93 87 F7 FF 23 A0 F4 4C +63 94 07 00 73 60 04 30 13 05 10 00 6F F0 DF F4 +13 05 44 02 EF D0 5F A0 E3 0E 05 FC 73 00 00 00 +6F F0 5F FD 13 05 04 00 EF F0 5F A5 EF D0 0F EC +6F F0 DF F1 73 60 04 30 6F F0 5F F1 63 8E 05 06 +13 01 01 FE 93 07 80 04 23 26 F1 00 03 27 C1 00 +23 2E 11 00 23 2C 81 00 63 06 F7 00 73 70 04 30 +6F 00 00 00 13 84 05 00 83 27 C1 00 93 05 10 00 +23 2E B4 02 23 20 84 00 23 20 04 04 13 05 04 00 +EF F0 1F B4 13 05 04 00 23 24 04 00 23 20 04 00 +23 26 04 00 93 06 00 00 13 06 00 00 93 05 00 00 +EF F0 1F D6 83 20 C1 01 13 05 04 00 03 24 81 01 +13 01 01 02 67 80 00 00 73 70 04 30 6F 00 00 00 +63 08 05 06 13 01 01 FF 23 24 81 00 23 22 91 00 +23 26 11 00 13 04 05 00 93 04 06 00 63 88 05 02 +13 07 20 00 83 27 C4 03 63 8A E6 02 03 27 84 03 +13 05 00 00 63 68 F7 08 83 20 C1 00 03 24 81 00 +83 24 41 00 13 01 01 01 67 80 00 00 83 27 05 04 +E3 88 07 FC 73 70 04 30 6F 00 00 00 23 20 21 01 +13 07 10 00 63 8A E7 00 73 70 04 30 6F 00 00 00 +73 70 04 30 6F 00 00 00 83 27 84 03 03 49 54 04 +83 27 84 03 13 86 06 00 13 05 04 00 13 19 89 01 +EF F0 DF 80 13 59 89 41 93 07 F0 FF 63 18 F9 02 +83 27 44 02 63 9A 07 04 83 20 C1 00 03 24 81 00 +03 29 01 00 83 24 41 00 13 05 10 00 13 01 01 01 +67 80 00 00 23 20 21 01 6F F0 5F FB EF D0 4F DA +E3 7C A9 FC 93 07 F0 07 63 0C F9 00 93 07 19 00 +93 97 87 01 93 D7 87 41 A3 02 F4 04 6F F0 DF FB +73 70 04 30 6F 00 00 00 13 05 44 02 EF D0 DF 85 +E3 04 05 FA E3 82 04 FA 93 07 10 00 23 A0 F4 00 +6F F0 9F F9 63 0C 05 06 83 27 05 04 13 01 01 FE +23 2C 81 00 23 2E 11 00 13 04 05 00 63 9C 07 04 +83 27 05 00 63 8A 07 06 83 27 84 03 03 27 C4 03 +63 FA E7 04 23 2A 91 00 83 44 54 04 93 87 17 00 +23 2C F4 02 93 94 84 01 93 D4 84 41 93 07 F0 FF +63 9C F4 04 83 27 44 02 63 9A 07 06 83 20 C1 01 +03 24 81 01 83 24 41 01 13 05 10 00 13 01 01 02 +67 80 00 00 73 70 04 30 6F 00 00 00 73 70 04 30 +6F 00 00 00 83 20 C1 01 03 24 81 01 13 05 00 00 +13 01 01 02 67 80 00 00 83 27 85 00 E3 86 07 F8 +73 70 04 30 6F 00 00 00 EF D0 8F CB E3 F8 A4 FA +93 07 F0 07 63 8E F4 02 93 87 14 00 93 97 87 01 +93 D7 87 41 A3 02 F4 04 6F F0 5F F9 13 05 44 02 +23 26 B1 00 EF D0 4F F7 E3 02 05 F8 83 25 C1 00 +E3 8E 05 F6 93 07 10 00 23 A0 F5 00 6F F0 1F F7 +73 70 04 30 6F 00 00 00 13 01 01 FC 23 2E 11 02 +23 26 C1 00 63 0C 05 20 23 2C 81 02 23 24 41 03 +13 04 05 00 13 8A 05 00 63 84 05 12 EF D0 1F A9 +63 0C 05 12 23 2A 91 02 23 26 31 03 73 70 04 30 +B7 44 00 10 83 A7 04 4C 83 29 84 03 13 87 17 00 +23 A0 E4 4C 63 9A 09 14 03 27 C1 00 23 28 21 03 +63 02 07 0C 13 05 81 01 EF D0 1F 97 13 09 F0 FF +83 A7 04 4C 93 87 F7 FF 23 A0 F4 4C 63 94 07 00 +73 60 04 30 EF D0 4F B9 73 70 04 30 83 47 44 04 +03 A7 04 4C 93 97 87 01 93 D7 87 41 63 94 27 01 +23 02 04 04 83 47 54 04 93 97 87 01 93 D7 87 41 +63 88 27 0B 63 14 07 00 73 60 04 30 93 05 C1 00 +13 05 81 01 EF D0 1F 93 63 18 05 12 73 70 04 30 +83 27 84 03 03 A7 04 4C 63 90 07 0A 63 14 07 00 +73 60 04 30 83 25 C1 00 13 05 44 02 EF D0 8F D4 +13 05 04 00 EF F0 8F EC EF D0 4F B3 63 14 05 00 +73 00 00 00 73 70 04 30 83 A7 04 4C 83 29 84 03 +13 87 17 00 23 A0 E4 4C 63 96 09 08 03 27 C1 00 +E3 18 07 F4 23 A0 F4 4C 63 8E 07 0E 03 29 01 03 +13 05 00 00 03 24 81 03 83 20 C1 03 83 24 41 03 +83 29 C1 02 03 2A 81 02 13 01 01 04 67 80 00 00 +83 27 05 04 E3 8C 07 EC 73 70 04 30 6F 00 00 00 +A3 02 04 04 6F F0 1F F5 83 27 C1 00 E3 84 07 EC +73 70 04 30 6F 00 00 00 63 14 07 00 73 60 04 30 +13 05 04 00 EF F0 8F E3 EF D0 4F AA 73 70 04 30 +83 A7 04 4C 83 29 84 03 13 87 17 00 23 A0 E4 4C +E3 8E 09 F6 03 29 01 03 03 26 04 04 63 00 06 02 +83 25 C4 00 83 27 84 00 B3 85 C5 00 23 26 B4 00 +63 F4 F5 08 13 05 0A 00 EF 00 90 0C 83 27 04 01 +93 89 F9 FF 23 2C 34 03 63 9E 07 04 83 A7 04 4C +93 87 F7 FF 23 A0 F4 4C 63 94 07 00 73 60 04 30 +13 05 10 00 6F F0 1F F4 13 05 04 00 EF F0 0F DC +EF D0 CF A2 73 70 04 30 83 27 84 03 03 A7 04 4C +63 88 07 00 E3 18 07 EE 73 60 04 30 6F F0 9F EE +E3 16 07 F0 73 60 04 30 6F F0 5F F0 73 70 04 30 +6F 00 00 00 13 05 04 01 EF D0 0F D2 E3 00 05 FA +73 00 00 00 6F F0 9F F9 83 25 04 00 23 26 B4 00 +6F F0 5F F7 13 01 01 FC 23 2E 11 02 23 26 B1 00 +63 0A 05 14 83 27 05 04 23 2C 81 02 13 04 05 00 +63 86 07 00 73 70 04 30 6F 00 00 00 EF D0 1F 84 +63 02 05 14 23 2A 91 02 73 70 04 30 B7 44 00 10 +03 A7 04 4C 83 27 84 03 93 06 17 00 23 A0 D4 4C +63 96 07 20 83 27 C1 00 23 28 21 03 23 26 31 03 +23 24 41 03 63 8A 07 0C 13 05 81 01 EF D0 CF F1 +93 09 44 02 13 0A 00 00 13 09 F0 FF 83 A7 04 4C +93 87 F7 FF 23 A0 F4 4C 63 94 07 00 73 60 04 30 +EF D0 8F 93 73 70 04 30 83 47 44 04 03 A7 04 4C +93 97 87 01 93 D7 87 41 63 94 27 01 23 02 04 04 +83 47 54 04 93 97 87 01 93 D7 87 41 63 88 27 0B +63 14 07 00 73 60 04 30 93 05 C1 00 13 05 81 01 +EF D0 4F ED 63 14 05 0C 73 70 04 30 83 27 84 03 +03 A7 04 4C 63 90 07 0A 63 14 07 00 73 60 04 30 +83 27 04 00 63 84 07 12 83 25 C1 00 13 85 09 00 +EF D0 4F AE 13 05 04 00 EF F0 4F C6 EF D0 0F 8D +63 14 05 00 73 00 00 00 73 70 04 30 03 A7 04 4C +83 27 84 03 93 06 17 00 23 A0 D4 4C 63 92 07 12 +83 27 C1 00 E3 94 07 F4 23 A0 E4 4C 63 08 07 0C +03 29 01 03 83 29 C1 02 03 2A 81 02 13 05 00 00 +03 24 81 03 83 20 C1 03 83 24 41 03 13 01 01 04 +67 80 00 00 73 70 04 30 6F 00 00 00 A3 02 04 04 +6F F0 1F F5 83 27 C1 00 E3 8E 07 EA 73 70 04 30 +6F 00 00 00 63 14 07 00 73 60 04 30 13 05 04 00 +EF F0 CF BD EF D0 8F 84 6F F0 1F F8 13 05 04 00 +EF F0 CF BC EF D0 8F 83 73 70 04 30 83 27 84 03 +03 A7 04 4C 63 88 07 00 E3 10 07 F6 73 60 04 30 +6F F0 9F F5 63 08 07 04 E3 0C 0A F6 73 70 04 30 +83 A7 04 4C 83 25 44 02 93 87 17 00 23 A0 F4 4C +63 8A 05 00 83 27 04 03 93 05 50 00 83 A7 07 00 +B3 85 F5 40 03 25 84 00 EF D0 9F 8A 83 A7 04 4C +93 87 F7 FF 23 A0 F4 4C E3 9C 07 F2 73 60 04 30 +6F F0 1F F3 73 60 04 30 6F F0 1F FB 73 70 04 30 +83 A7 04 4C 03 25 84 00 93 87 17 00 23 A0 F4 4C +EF D0 0F E6 83 A7 04 4C 13 0A 05 00 93 87 F7 FF +23 A0 F4 4C E3 9A 07 EA 73 60 04 30 6F F0 DF EA +03 29 01 03 83 29 C1 02 03 2A 81 02 03 27 04 00 +93 87 F7 FF 23 2C F4 02 63 0E 07 02 83 27 04 01 +63 90 07 02 83 A7 04 4C 93 87 F7 FF 23 A0 F4 4C +63 94 07 00 73 60 04 30 13 05 10 00 6F F0 5F EC +13 05 04 01 EF D0 4F A7 E3 0E 05 FC 73 00 00 00 +6F F0 5F FD EF D0 DF 92 23 24 A4 00 6F F0 1F FC +13 01 01 FC 23 2E 11 02 23 2C 81 02 23 2A 91 02 +23 28 21 03 23 26 31 03 23 26 C1 00 63 0C 05 1E +13 04 05 00 93 89 05 00 63 8C 05 10 EF D0 0F D9 +63 04 05 12 73 70 04 30 B7 44 00 10 83 A7 04 4C +03 27 84 03 93 86 17 00 23 A0 D4 4C 63 14 07 14 +03 27 C1 00 63 02 07 0C 13 05 81 01 EF D0 CF C7 +13 09 F0 FF 83 A7 04 4C 93 87 F7 FF 23 A0 F4 4C +63 94 07 00 73 60 04 30 EF C0 1F EA 73 70 04 30 +83 47 44 04 03 A7 04 4C 93 97 87 01 93 D7 87 41 +63 94 27 01 23 02 04 04 83 47 54 04 93 97 87 01 +93 D7 87 41 63 86 27 0B 63 14 07 00 73 60 04 30 +93 05 C1 00 13 05 81 01 EF D0 CF C3 63 12 05 12 +73 70 04 30 83 27 84 03 03 A7 04 4C 63 9E 07 08 +63 14 07 00 73 60 04 30 83 25 C1 00 13 05 44 02 +EF D0 4F 85 13 05 04 00 EF F0 4F 9D EF C0 1F E4 +63 14 05 00 73 00 00 00 73 70 04 30 83 A7 04 4C +03 27 84 03 93 86 17 00 23 A0 D4 4C 63 14 07 08 +03 27 C1 00 E3 18 07 F4 23 A0 F4 4C 63 88 07 0E +13 05 00 00 83 20 C1 03 03 24 81 03 83 24 41 03 +03 29 01 03 83 29 C1 02 13 01 01 04 67 80 00 00 +83 27 05 04 E3 84 07 EE 73 70 04 30 6F 00 00 00 +A3 02 04 04 6F F0 5F F5 83 27 C1 00 E3 8C 07 EC +73 70 04 30 6F 00 00 00 63 14 07 00 73 60 04 30 +13 05 04 00 EF F0 8F 94 EF C0 5F DB 73 70 04 30 +83 A7 04 4C 03 27 84 03 93 86 17 00 23 A0 D4 4C +E3 00 07 F8 03 26 04 04 03 29 C4 00 63 0E 06 00 +83 27 84 00 B3 05 C9 00 23 26 B4 00 63 F2 F5 08 +13 85 09 00 EF 00 C0 3D 83 27 44 02 23 26 24 01 +63 9E 07 04 83 A7 04 4C 93 87 F7 FF 23 A0 F4 4C +63 94 07 00 73 60 04 30 13 05 10 00 6F F0 9F F4 +13 05 04 00 EF F0 8F 8D EF C0 5F D4 73 70 04 30 +83 27 84 03 03 A7 04 4C 63 88 07 00 E3 1E 07 EE +73 60 04 30 6F F0 5F EF E3 1C 07 F0 73 60 04 30 +6F F0 1F F1 73 70 04 30 6F 00 00 00 13 05 44 02 +EF D0 8F 83 E3 00 05 FA 73 00 00 00 6F F0 9F F9 +83 25 04 00 23 26 B4 00 6F F0 9F F7 63 02 05 06 +13 01 01 FE 23 2C 81 00 23 2A 91 00 23 2E 11 00 +23 28 21 01 13 04 05 00 93 87 05 00 93 04 06 00 +63 84 05 02 03 29 85 03 13 05 00 00 63 12 09 04 +83 20 C1 01 03 24 81 01 83 24 41 01 03 29 01 01 +13 01 01 02 67 80 00 00 83 27 05 04 63 9E 07 00 +03 29 85 03 63 1A 09 0C 13 05 00 00 6F F0 5F FD +73 70 04 30 6F 00 00 00 73 70 04 30 6F 00 00 00 +23 26 31 01 83 49 44 04 03 26 04 04 93 99 89 01 +93 D9 89 41 63 00 06 02 83 25 C4 00 03 27 84 00 +B3 85 C5 00 23 26 B4 00 63 F4 E5 06 13 85 07 00 +EF 00 00 2B 13 09 F9 FF 23 2C 24 03 93 07 F0 FF +63 96 F9 02 83 27 04 01 63 9A 07 04 83 20 C1 01 +03 24 81 01 83 29 C1 00 83 24 41 01 03 29 01 01 +13 05 10 00 13 01 01 02 67 80 00 00 EF C0 5F C5 +E3 FE A9 FC 93 07 F0 07 63 8A F9 04 93 87 19 00 +93 97 87 01 93 D7 87 41 23 02 F4 04 6F F0 1F FC +83 25 04 00 23 26 B4 00 6F F0 5F F9 13 05 04 01 +EF C0 9F F0 E3 04 05 FA E3 82 04 FA 93 07 10 00 +23 A0 F4 00 6F F0 9F F9 23 26 31 01 83 49 44 04 +93 99 89 01 93 D9 89 41 6F F0 DF F6 73 70 04 30 +6F 00 00 00 63 06 05 04 13 01 01 FF 23 24 81 00 +23 26 11 00 03 26 05 04 13 04 05 00 93 87 05 00 +63 82 05 02 63 02 06 02 03 27 85 03 13 05 00 00 +63 18 07 02 83 20 C1 00 03 24 81 00 13 01 01 01 +67 80 00 00 63 1A 06 00 73 70 04 30 6F 00 00 00 +73 70 04 30 6F 00 00 00 73 70 04 30 6F 00 00 00 +23 22 91 00 83 24 C4 00 03 27 84 00 B3 85 C4 00 +23 26 B4 00 63 E6 E5 00 83 25 04 00 23 26 B4 00 +13 85 07 00 EF 00 C0 18 13 05 10 00 23 26 94 00 +83 24 41 00 6F F0 1F FA 63 00 05 02 73 70 04 30 +B7 47 00 10 83 A7 07 4C 03 25 85 03 63 94 07 00 +73 60 04 30 67 80 00 00 73 70 04 30 6F 00 00 00 +63 04 05 02 73 70 04 30 B7 47 00 10 03 27 85 03 +83 A7 07 4C 03 25 C5 03 33 05 E5 40 63 94 07 00 +73 60 04 30 67 80 00 00 73 70 04 30 6F 00 00 00 +63 06 05 00 03 25 85 03 67 80 00 00 73 70 04 30 +6F 00 00 00 63 04 05 00 67 80 00 00 73 70 04 30 +6F 00 00 00 03 25 05 04 67 80 00 00 03 25 C5 03 +67 80 00 00 63 08 05 00 03 25 85 03 13 35 15 00 +67 80 00 00 73 70 04 30 6F 00 00 00 63 0C 05 00 +83 27 85 03 03 25 C5 03 33 05 F5 40 13 35 15 00 +67 80 00 00 73 70 04 30 6F 00 00 00 13 01 01 FF +23 24 81 00 23 26 11 00 13 04 05 00 73 70 04 30 +83 47 45 04 37 47 00 10 93 06 F0 FF 93 97 87 01 +93 D7 87 41 03 27 07 4C 63 94 D7 00 23 02 05 04 +83 47 54 04 93 06 F0 FF 93 97 87 01 93 D7 87 41 +63 84 D7 02 63 14 07 00 73 60 04 30 83 27 84 03 +63 80 07 02 13 05 04 00 03 24 81 00 83 20 C1 00 +13 01 01 01 6F E0 9F D7 A3 02 04 04 6F F0 9F FD +13 05 44 02 EF C0 DF C9 13 05 04 00 03 24 81 00 +83 20 C1 00 13 01 01 01 6F E0 5F D5 13 06 05 00 +13 05 00 00 93 F6 15 00 63 84 06 00 33 05 C5 00 +93 D5 15 00 13 16 16 00 E3 96 05 FE 67 80 00 00 +63 00 06 02 33 86 C5 00 93 07 05 00 03 C7 05 00 +93 85 15 00 93 87 17 00 A3 8F E7 FE E3 98 C5 FE +67 80 00 00 93 F5 F5 0F 93 07 05 00 33 07 A6 00 +63 08 06 00 23 80 B7 00 93 87 17 00 E3 9C E7 FE +67 80 00 00 63 06 06 02 33 06 C5 00 6F 00 80 00 +63 00 C5 02 83 47 05 00 03 C7 05 00 13 05 15 00 +93 85 15 00 E3 86 E7 FE 33 85 E7 40 67 80 00 00 +13 05 00 00 67 80 00 00 63 04 B5 00 63 14 06 00 +67 80 00 00 63 72 B5 02 33 86 C5 00 93 07 05 00 +03 C7 05 00 93 85 15 00 93 87 17 00 A3 8F E7 FE +E3 98 C5 FE 67 80 00 00 13 06 F6 FF B3 87 C5 00 +03 C7 07 00 B3 07 C5 00 23 80 E7 00 E3 02 06 FC +13 06 F6 FF B3 87 C5 00 03 C7 07 00 B3 07 C5 00 +23 80 E7 00 E3 1A 06 FC 67 80 00 00 65 78 61 6D +70 6C 65 00 54 6D 72 20 53 76 63 00 08 1A 00 10 +CC 1A 00 10 BC 1A 00 10 04 1A 00 10 FC 19 00 10 +7C 1B 00 10 B4 1B 00 10 A4 1B 00 10 78 1B 00 10 +70 1B 00 10 04 00 00 00 C0 21 00 10 7C 22 00 10 +7C 22 00 10 CC 22 00 10 24 23 00 10 CC 22 00 10 +7C 22 00 10 7C 22 00 10 CC 22 00 10 24 23 00 10 +08 00 00 30 C0 D4 01 00 B0 51 00 10 +@000244BC +C0 44 00 10 AA AA AA AA A0 4D 00 10 diff --git a/crush_example_freertos/fw/app/crush.ld b/crush_example_freertos/fw/app/crush.ld new file mode 100644 index 0000000..e7ed8aa --- /dev/null +++ b/crush_example_freertos/fw/app/crush.ld @@ -0,0 +1,50 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(start) + +MEMORY +{ + ram (rwx): ORIGIN = 0x10000000, LENGTH = 0x10000 +} + +SECTIONS +{ + .text : { + . = ALIGN(4); + KEEP(*(.start)) + . = 0x100; + KEEP(*(.text.freertos_risc_v_trap_handler)) + *(.text .text.*) + *(.rodata .rodata* .srodata .srodata.*) + . = ALIGN(4); + } > ram + + .data : { + . = ALIGN(4); + __data_start = .; + *(.data .data.* .sdata .sdata.*); + . = ALIGN(4); + __data_end = .; + } > ram + + .bss (NOLOAD) : { + . = ALIGN(4); + bss_start = .; + *(.bss .bss.* .sbss .sbss.*) + *(COMMON) + . = ALIGN(4); + bss_end = .; + } > ram + + /* Calling conventions require 16 byte aligned stack pointer + * https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc + * + * This is initially the entry point stack, then is reused as the FreeRTOS + * interrupt stack when the scheduler starts. + */ + .stack : ALIGN(16) { + . = 1K; /* stack size */ + stack_start = .; + __freertos_irq_stack_top = .; + } > ram +} + diff --git a/crush_example_freertos/fw/app/freertos_config/CMakeLists.txt b/crush_example_freertos/fw/app/freertos_config/CMakeLists.txt new file mode 100644 index 0000000..316e474 --- /dev/null +++ b/crush_example_freertos/fw/app/freertos_config/CMakeLists.txt @@ -0,0 +1,20 @@ +add_library(freertos_config STATIC) + +target_include_directories(freertos_config SYSTEM INTERFACE include) +target_include_directories(freertos_config PRIVATE include) + +target_compile_definitions(freertos_config PUBLIC projCOVERAGE_TEST=0) + +target_sources(freertos_config PRIVATE string.c) + +# When compiling our memset implementation, this optimisation inserts a +# recursive call. +# +# Disable it for this module only. We want other places to call this memset, so +# that we can optimise the implementation once here and get the speed benefits +# everywhere else. +# +# https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-ftree-loop-distribute-patterns +# +# https://stackoverflow.com/a/33818680/15158846 +target_compile_options(freertos_config PRIVATE "-fno-tree-loop-distribute-patterns") diff --git a/crush_example_freertos/fw/app/freertos_config/include/FreeRTOSConfig.h b/crush_example_freertos/fw/app/freertos_config/include/FreeRTOSConfig.h new file mode 100644 index 0000000..3fcb807 --- /dev/null +++ b/crush_example_freertos/fw/app/freertos_config/include/FreeRTOSConfig.h @@ -0,0 +1,99 @@ +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#define configCPU_CLOCK_HZ ( ( unsigned long ) 12000000 ) + +#define configTICK_RATE_HZ 100 +#define configUSE_PREEMPTION 1 +#define configUSE_TIME_SLICING 0 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_TICKLESS_IDLE 0 +#define configMAX_PRIORITIES 5 +#define configMINIMAL_STACK_SIZE 128 +#define configMAX_TASK_NAME_LEN 16 +#define configTICK_TYPE_WIDTH_IN_BITS TICK_TYPE_WIDTH_64_BITS +#define configIDLE_SHOULD_YIELD 1 +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configENABLE_BACKWARD_COMPATIBILITY 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#define configUSE_MINI_LIST_ITEM 1 +#define configSTACK_DEPTH_TYPE size_t +#define configMESSAGE_BUFFER_LENGTH_TYPE size_t +#define configHEAP_CLEAR_MEMORY_ON_FREE 1 +#define configSTATS_BUFFER_MAX_LENGTH 0xFFFF +#define configUSE_NEWLIB_REENTRANT 0 + +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE +#define configTIMER_QUEUE_LENGTH 10 + +#define configUSE_EVENT_GROUPS 0 + +#define configUSE_STREAM_BUFFERS 0 + +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configKERNEL_PROVIDED_STATIC_MEMORY 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 0 +#define configTOTAL_HEAP_SIZE 4096 +#define configAPPLICATION_ALLOCATED_HEAP 0 +#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0 +#define configENABLE_HEAP_PROTECTOR 0 + +#define configKERNEL_INTERRUPT_PRIORITY 0 +#define configMAX_SYSCALL_INTERRUPT_PRIORITY 0 +#define configMAX_API_CALL_INTERRUPT_PRIORITY 0 + +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 +#define configUSE_SB_COMPLETED_CALLBACK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 + +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_TRACE_FACILITY 0 +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 1 + +#define configASSERT( x ) \ + if( ( x ) == 0 ) \ + { \ + taskDISABLE_INTERRUPTS(); \ + for( ; ; ) \ + ; \ + } + +#define configUSE_TASK_NOTIFICATIONS 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 0 +#define configUSE_COUNTING_SEMAPHORES 0 +#define configUSE_QUEUE_SETS 0 +#define configUSE_APPLICATION_TASK_TAG 0 + +#define INCLUDE_vTaskPrioritySet 0 +#define INCLUDE_uxTaskPriorityGet 0 +#define INCLUDE_vTaskDelete 0 +#define INCLUDE_vTaskSuspend 0 +#define INCLUDE_xResumeFromISR 0 +#define INCLUDE_vTaskDelayUntil 0 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 0 +// Must be on for the FreeRTOS bunded CMake script to work, as it always adds +// stream_buffers.c, and that file requires this to be on. +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_eTaskGetState 0 +#define INCLUDE_xEventGroupSetBitFromISR 0 +#define INCLUDE_xTimerPendFunctionCall 0 +#define INCLUDE_xTaskAbortDelay 0 +#define INCLUDE_xTaskGetHandle 0 +#define INCLUDE_xTaskResumeFromISR 0 + +#define configMTIME_BASE_ADDRESS 0x30000000 +#define configMTIMECMP_BASE_ADDRESS 0x30000008 + +#endif /* FREERTOS_CONFIG_H */ diff --git a/crush_example_freertos/fw/app/freertos_config/include/stdint.h b/crush_example_freertos/fw/app/freertos_config/include/stdint.h new file mode 100644 index 0000000..8133e2f --- /dev/null +++ b/crush_example_freertos/fw/app/freertos_config/include/stdint.h @@ -0,0 +1,28 @@ +#pragma once + +#ifdef __INT8_TYPE__ +typedef __INT8_TYPE__ int8_t; +#endif +#ifdef __INT16_TYPE__ +typedef __INT16_TYPE__ int16_t; +#endif +#ifdef __INT32_TYPE__ +typedef __INT32_TYPE__ int32_t; +#endif +#ifdef __INT64_TYPE__ +typedef __INT64_TYPE__ int64_t; +#endif +#ifdef __UINT8_TYPE__ +typedef __UINT8_TYPE__ uint8_t; +#endif +#ifdef __UINT16_TYPE__ +typedef __UINT16_TYPE__ uint16_t; +#endif +#ifdef __UINT32_TYPE__ +typedef __UINT32_TYPE__ uint32_t; +#endif +#ifdef __UINT64_TYPE__ +typedef __UINT64_TYPE__ uint64_t; +#endif + +#define SIZE_MAX __SIZE_MAX__ diff --git a/crush_example_freertos/fw/app/freertos_config/include/stdlib.h b/crush_example_freertos/fw/app/freertos_config/include/stdlib.h new file mode 100644 index 0000000..e69de29 diff --git a/crush_example_freertos/fw/app/freertos_config/include/string.h b/crush_example_freertos/fw/app/freertos_config/include/string.h new file mode 100644 index 0000000..d1eacbb --- /dev/null +++ b/crush_example_freertos/fw/app/freertos_config/include/string.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +/* The FreeRTOS GCC RISC-V port depends on some functions from string.h. We + * don't use a stdlib, so must manually implement the functions that are used. + */ + +void* memcpy( void *restrict dest, const void *restrict src, size_t count ); +void *memset( void *dest, int ch, size_t count ); diff --git a/crush_example_freertos/fw/app/freertos_config/string.c b/crush_example_freertos/fw/app/freertos_config/string.c new file mode 100644 index 0000000..cbc3b97 --- /dev/null +++ b/crush_example_freertos/fw/app/freertos_config/string.c @@ -0,0 +1,66 @@ +#include + +/* When using -nostdlib with GCC, it may still generate calls to memcmp, + * memset, memcpy and memmove. These usually come from the standard C library, + * but we don't have one. Define the functions here so that the app can still + * link. + * + * memcpy and memset are also used by FreeRTOS implementation. + */ + +void* memcpy( void *restrict a_dest, const void *restrict a_src, size_t count ) { + char *dest = a_dest; + const char *src = a_src; + + for(size_t i = 0; i < count; i++) { + dest[i] = src[i]; + } + + return dest; +} + +void *memset( void *a_dest, int ch, size_t count ) { + char *dest = a_dest; + + for(size_t i = 0; i < count; i++) { + dest[i] = ch; + } + + return dest; +} + +int memcmp( const void* a_lhs, const void* a_rhs, size_t count ) { + const unsigned char *lhs = a_lhs; + const unsigned char *rhs = a_rhs; + + for(int i = 0; i < count; i++) { + const unsigned char l = lhs[i]; + const unsigned char r = rhs[i]; + + if(l != r) + { + return (int)l - (int)r; + } + } + + return 0; +} + +void *memmove(void *a_dest, const void *a_src, size_t count) { + unsigned char *dest = a_dest; + const unsigned char *src = a_src; + + if (dest == src || count == 0) { + // nothing to copy + } else if (dest < src) { + for (size_t i = 0; i < count; i++) { + dest[i] = src[i]; + } + } else { + for (size_t i = count; i > 0; i--) { + dest[i - 1] = src[i - 1]; + } + } + + return a_dest; +} diff --git a/crush_example_freertos/fw/app/src/hal.c b/crush_example_freertos/fw/app/src/hal.c new file mode 100644 index 0000000..b2269fc --- /dev/null +++ b/crush_example_freertos/fw/app/src/hal.c @@ -0,0 +1,30 @@ +#include "hal.h" +#include "FreeRTOS.h" +#include "task.h" + +void delay() +{ + vTaskDelay(pdMS_TO_TICKS(1000)); +} + +#define GPIO_BASE_ADDRESS ((int *)0x40000000) +#define BIT_MASK(n) (1 << (n)) + +bool get_button(void) +{ + volatile int *gpio = GPIO_BASE_ADDRESS; + return *gpio & BIT_MASK(8); +} + +void set_led_on(int index, bool led_on) +{ + volatile int *gpio = GPIO_BASE_ADDRESS; + if(led_on) + { + *gpio |= BIT_MASK(index); + } + else + { + *gpio &= ~BIT_MASK(index); + } +} diff --git a/crush_example_freertos/fw/app/src/hal.h b/crush_example_freertos/fw/app/src/hal.h new file mode 100644 index 0000000..1f989d2 --- /dev/null +++ b/crush_example_freertos/fw/app/src/hal.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +bool get_button(void); +void set_led_on(int index, bool led_on); + +void delay(); diff --git a/crush_example_freertos/fw/app/src/main.c b/crush_example_freertos/fw/app/src/main.c new file mode 100644 index 0000000..70015ec --- /dev/null +++ b/crush_example_freertos/fw/app/src/main.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include + +#include + +#include "hal.h" + +static void task( void * parameters ); + +void main( void ) +{ + static StaticTask_t exampleTaskTCB; + static StackType_t exampleTaskStack[ configMINIMAL_STACK_SIZE ]; + + ( void ) xTaskCreateStatic( task, + "example", + configMINIMAL_STACK_SIZE, + NULL, + configMAX_PRIORITIES - 1U, + &( exampleTaskStack[ 0 ] ), + &( exampleTaskTCB ) ); + + /* Start the scheduler. */ + vTaskStartScheduler(); + + for( ; ; ) + { + /* Should not reach here. */ + } +} + +void task(void *parameters) +{ + bool blinky_led_on = false; + for(;;) + { + blinky_led_on = !blinky_led_on; + + bool is_pressed = get_button(); + + set_led_on(0, blinky_led_on); + set_led_on(1, is_pressed); + delay(); + } +} diff --git a/crush_example_freertos/fw/app/src/start.S b/crush_example_freertos/fw/app/src/start.S new file mode 100644 index 0000000..b463235 --- /dev/null +++ b/crush_example_freertos/fw/app/src/start.S @@ -0,0 +1,7 @@ +.section .start +.global start +start: + // Load stack_start defined by the linker file to the stack pointer + la sp, stack_start + // Call c_start to do the rest of the initialisation + call c_start \ No newline at end of file diff --git a/crush_example_freertos/fw/app/src/start.c b/crush_example_freertos/fw/app/src/start.c new file mode 100644 index 0000000..f09ac88 --- /dev/null +++ b/crush_example_freertos/fw/app/src/start.c @@ -0,0 +1,40 @@ +/** + * \file Start-up code for hardware and C runtime initialisation. + */ + +/** + * \defgroup linker Symbols exported by the linker script + * @{ + */ + +/** The start of the region in RAM to be zero initialised */ +extern int bss_start[0]; +/** The end of the region in RAM to be zero initialised */ +extern int bss_end[0]; + +/** + * @} + */ + +int main(void); + +/** + * The entry point into the C application. + * + * It is called from assembly startup code in start.S, which is in turn placed + * at the initial PC using the linker script. + */ +void c_start(void) +{ + for(int *i = bss_start; i < bss_end; i++) + { + *i = 0; + } + + main(); + + // The assembly start code does not expect us to return, really main should + // not return either + for(;;) + ; +} diff --git a/crush_example_freertos/fw/spi_bootloader/CMakeLists.txt b/crush_example_freertos/fw/spi_bootloader/CMakeLists.txt new file mode 100644 index 0000000..cd66fa0 --- /dev/null +++ b/crush_example_freertos/fw/spi_bootloader/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.24 FATAL_ERROR) + +project(crush-boot C ASM) + +add_executable(crush-boot) +target_sources(crush-boot PRIVATE boot.S) + +target_link_options(crush-boot PRIVATE -T${CMAKE_CURRENT_SOURCE_DIR}/crush-boot.ld) +set_target_properties(crush-boot PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/crush-boot.ld) + +string(REPLACE "-gcc" "-objcopy" objcopy_name ${CMAKE_C_COMPILER}) +find_program(objcopy_program ${objcopy_name} REQUIRED) +add_custom_command(TARGET crush-boot POST_BUILD + COMMAND ${objcopy_program} --verilog-data-width 4 -O verilog crush-boot ${CMAKE_CURRENT_LIST_DIR}/binary/crush-boot.data + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) diff --git a/crush_example_freertos/fw/spi_bootloader/TC-crush.cmake b/crush_example_freertos/fw/spi_bootloader/TC-crush.cmake new file mode 100644 index 0000000..dd3584b --- /dev/null +++ b/crush_example_freertos/fw/spi_bootloader/TC-crush.cmake @@ -0,0 +1,17 @@ +# https://www.vinnie.work/blog/2020-11-17-cmake-eval + +set(CMAKE_SYSTEM_NAME Generic) + +find_program(COMPILER_PATH + NAMES + # ubuntu and debian + riscv32-unknown-elf-gcc + riscv64-unknown-elf-gcc + # arch linux + riscv64-elf-gcc + REQUIRED) +get_filename_component(COMPILER_NAME ${COMPILER_PATH} NAME) +set(CMAKE_C_COMPILER ${COMPILER_NAME}) + +set(CMAKE_C_FLAGS "-nostartfiles -nostdlib -march=rv32i -mabi=ilp32") +set(CMAKE_ASM_FLAGS "-nostartfiles -nostdlib -march=rv32i -mabi=ilp32") diff --git a/crush_example_freertos/fw/spi_bootloader/binary/crush-boot.data b/crush_example_freertos/fw/spi_bootloader/binary/crush-boot.data new file mode 100755 index 0000000..38fc1e7 --- /dev/null +++ b/crush_example_freertos/fw/spi_bootloader/binary/crush-boot.data @@ -0,0 +1,9 @@ +@00000000 +500001B7 00018823 04100313 00618023 +00100313 00618823 20300513 02C000EF +00010437 100004B7 10000937 00000A13 +018000EF 01448333 00B32023 004A0A13 +FE8A48E3 00090067 00400293 00A18423 +0041C303 00137313 FE031CE3 0085D593 +0081C303 01831313 0065E5B3 00855513 +FFF28293 FC029CE3 00008067 diff --git a/crush_example_freertos/fw/spi_bootloader/boot.S b/crush_example_freertos/fw/spi_bootloader/boot.S new file mode 100644 index 0000000..62d3fe2 --- /dev/null +++ b/crush_example_freertos/fw/spi_bootloader/boot.S @@ -0,0 +1,117 @@ +/* + * boot.S + * + * SPI boot code + */ + +#ifndef APP_FLASH_ADDR +#define APP_FLASH_ADDR 0x20000 +#endif + +#ifndef APP_SRAM_ADDR +#define APP_SRAM_ADDR 0x10000000 +#endif + +#ifndef APP_SIZE +#define APP_SIZE 0x10000 +#endif + +#define SPI_SPSR_RX_CHECK 0x01 /* Check bit 0 is cleared, fifo !empty*/ + + /* Registers used + ra link register + t1 temp register + t2 temp register + s0 Image size + s1 Load address + s2 Reset vector + gp SPI master base address + a3 get_rx_data return value + t3 temp register + */ + + .equ SPI_BASE, 0x50000000 + .equ SPI_SPCR, 4 * 0x00 + .equ SPI_SPSR, 4 * 0x01 + .equ SPI_SPDR, 4 * 0x02 + .equ SPI_SPER, 4 * 0x03 + .equ SPI_SPSS, 4 * 0x04 + + .section .text.start + .global _start +_start: + /* Load SPI base address to gp */ + li gp, SPI_BASE + +spi_init: + /* Clear slave selects */ + sb zero, SPI_SPSS(gp) + + /* Set clock divider to 4 (arbitrarily chosen value) + and enable controller */ + addi t1, zero, 0x40 | 0x01 + sb t1, SPI_SPCR(gp) + + /* Set appropriate slave select */ + addi t1, zero, 1 + sb t1, SPI_SPSS(gp) + + /* Set command to READ at APP_FLASH_ADDR */ + li a0, ((APP_FLASH_ADDR & 0xFF) <<24) | ((APP_FLASH_ADDR & 0xFF00) << 8) | ((APP_FLASH_ADDR & 0xFF0000) >> 8) | 0x3 + jal spi_xfer + +read_header: + /* Load image size to s0 */ + li s0, APP_SIZE + + /* Load RAM base address to s1 */ + li s1, APP_SRAM_ADDR + + /* Load reset vector to s2 */ + li s2, APP_SRAM_ADDR + + /* Clear number of copied bytes */ + addi s4, zero, 0 +copy_to_ram: + jal spi_xfer + + /* Set memory store address */ + add t1, s1, s4 + + /* Write word to RAM */ + sw a1, 0(t1) + + /* Increase counter */ + addi s4, s4, 4 + + /* Check if file is completely copied */ + bgt s0, s4, copy_to_ram + + /* Jump to entry point */ +goto_reset: + jr s2 + +spi_xfer: + /* Loop four times */ + addi t0, zero, 4 + +spi_xfer_loop: + /* Send data in a0[7:0] */ + sb a0, SPI_SPDR(gp) + +spi_xfer_poll: + /* Wait for data in RX FIFO */ + lbu t1, SPI_SPSR(gp) + andi t1, t1, SPI_SPSR_RX_CHECK + bnez t1, spi_xfer_poll + + srli a1, a1, 8 + lbu t1, SPI_SPDR(gp) + slli t1, t1, 24 + or a1, a1, t1 + + srli a0, a0, 8 + addi t0, t0, -1 + bnez t0, spi_xfer_loop + + ret diff --git a/crush_example_freertos/fw/spi_bootloader/crush-boot.ld b/crush_example_freertos/fw/spi_bootloader/crush-boot.ld new file mode 100644 index 0000000..62e4537 --- /dev/null +++ b/crush_example_freertos/fw/spi_bootloader/crush-boot.ld @@ -0,0 +1,17 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(_start) + +MEMORY +{ + rom (rx): ORIGIN = 0x00000000, LENGTH = 256 +} + +SECTIONS +{ + .rom : { + . = ALIGN(4); + KEEP(*(.text.start)) + *(.text .text.*) + } > rom +} + diff --git a/crush_example/rtl/memory_ice40_spram.v b/crush_example_freertos/rtl/memory_ice40_spram.v similarity index 89% rename from crush_example/rtl/memory_ice40_spram.v rename to crush_example_freertos/rtl/memory_ice40_spram.v index eeb1b73..dcd6a89 100644 --- a/crush_example/rtl/memory_ice40_spram.v +++ b/crush_example_freertos/rtl/memory_ice40_spram.v @@ -3,6 +3,7 @@ module memory_ice40_spram ( input wire clk, input wire rst, + input wire chip_select, input wire wen, input wire[3:0] wmask, input wire[13:0] addr, @@ -15,7 +16,7 @@ module memory_ice40_spram ( .ADDRESS(addr), .MASKWREN({{2{wmask[3]}}, {2{wmask[2]}}}), .WREN(wen), - .CHIPSELECT(1'b1), + .CHIPSELECT(chip_select), .CLOCK(clk), .STANDBY(1'b0), .SLEEP(1'b0), @@ -28,7 +29,7 @@ module memory_ice40_spram ( .ADDRESS(addr), .MASKWREN({{2{wmask[1]}}, {2{wmask[0]}}}), .WREN(wen), - .CHIPSELECT(1'b1), + .CHIPSELECT(chip_select), .CLOCK(clk), .STANDBY(1'b0), .SLEEP(1'b0), diff --git a/crush_example_freertos/rtl/memory_ice40_spram_wb.v b/crush_example_freertos/rtl/memory_ice40_spram_wb.v new file mode 100644 index 0000000..641d470 --- /dev/null +++ b/crush_example_freertos/rtl/memory_ice40_spram_wb.v @@ -0,0 +1,51 @@ +`default_nettype none + +/* 32-bit * 16K word (64KByte) memory */ +module memory_ice40_spram_wb #( + parameter integer BASE_ADDRESS = 0 +) ( + input wire clk_i, + input wire rst_i, + input wire stb_i, + input wire cyc_i, + input wire [31:0] adr_i, + input wire [3:0] sel_i, + input wire [31:0] dat_i, + output wire [31:0] dat_o, + input wire we_i, + output reg ack_o, + output reg err_o, + output reg rty_o +); + + localparam SIZE = 65536; + + reg [31:0] data; + assign dat_o = ack_o ? data : 32'hzzzz_zzzz; + + wire addressed = (adr_i >= BASE_ADDRESS) & (adr_i < BASE_ADDRESS + SIZE); + + wire [13:0] memory_address = (adr_i - BASE_ADDRESS) >> 2; + +memory_ice40_spram memory( + .clk(clk_i), + .rst(rst_i), + .chip_select(stb_i & cyc_i & !ack_o & addressed), + .wen(we_i), + .wmask(sel_i), + .addr(memory_address), + .wdata(dat_i), + .rdata(data)); + + always @(posedge clk_i) begin + ack_o <= 0; + err_o <= 0; + rty_o <= 0; + + if (stb_i & cyc_i & !ack_o & addressed) begin + ack_o <= 1; + end + end + + +endmodule diff --git a/crush_example_freertos/rtl/spi.v b/crush_example_freertos/rtl/spi.v new file mode 100644 index 0000000..5c58ef3 --- /dev/null +++ b/crush_example_freertos/rtl/spi.v @@ -0,0 +1,60 @@ +`default_nettype none + +module spi #( + parameter integer BASE_ADDRESS=0 +) ( + input wire clk_i, + // verilator lint_off UNUSEDSIGNAL + input wire rst_i, + // verilator lint_on UNUSEDSIGNAL + input wire stb_i, + input wire cyc_i, + input wire [31:0] adr_i, + input wire [3:0] sel_i, + input wire [31:0] dat_i, + output wire [31:0] dat_o, + input wire we_i, + output reg ack_o, + output reg err_o, + output reg rty_o, + // Flash SPI interface + inout wire flash_clk, + inout wire flash_miso, + inout wire flash_mosi, + output wire flash_cs_n +); + reg[7:0] spi_dat_o; + wire [31:0] data = {24'h0, spi_dat_o}; + + assign dat_o = ack_o ? data : 32'hzzzz_zzzz; + + wire addressed = (adr_i >= BASE_ADDRESS) & (adr_i < BASE_ADDRESS + 4 * 32'h10); + wire[31:0] address = adr_i - BASE_ADDRESS; + + simple_spi spi ( + // Wishbone + .clk_i (clk_i), + .rst_i (rst_i), + .adr_i (address[9-:8]), + .dat_i (dat_i[7:0]), + .we_i (we_i), + .cyc_i (addressed & cyc_i), + .stb_i (addressed & stb_i), + .dat_o (spi_dat_o), + .ack_o (ack_o), + // SPI flash chip + .sck_o (flash_clk), + .ss_o (flash_cs_n), + .mosi_o (flash_mosi), + .miso_i (flash_miso), + // Interrupt output is ignored. The CPU is programmed to send commands + // slow enough that we will not overflow the FIFOs. + // verilator lint_off PINCONNECTEMPTY + .inta_o () + // verilator lint_on PINCONNECTEMPTY + ); + + assign err_o = 0; + assign rty_o = 0; + +endmodule diff --git a/crush_example_freertos/rtl/top.v b/crush_example_freertos/rtl/top.v new file mode 100644 index 0000000..1594822 --- /dev/null +++ b/crush_example_freertos/rtl/top.v @@ -0,0 +1,156 @@ +`default_nettype none + +module top ( + input wire CLK, + input wire BTN_N, + input wire BTN1, + output wire LED1, + output wire LED2, + inout wire FLASH_SCK, + inout wire FLASH_SSB, + inout wire FLASH_IO0, + inout wire FLASH_IO1 +); + +wire rst_i = !BTN_N; +wire clk = CLK; + +wire stb_o; +wire cyc_o; +wire[31:0] adr_o; +wire[3:0] sel_o; +wire[31:0] dat_i; +wire[31:0] dat_o; +wire we_o; +wire ack_i; +wire err_i; +wire rty_i; + +wire timer_interrupt; + +crush_cpu #(.INITIAL_PC('h0000_0000), .TRAP_PC('h1000_0100)) cpu ( + .clk_i(clk), + .dat_i(dat_i), + .dat_o(dat_o), + .rst_i(rst_i), + .ack_i(ack_i), + .err_i(err_i), + .rty_i(rty_i), + .stb_o(stb_o), + .cyc_o(cyc_o), + .adr_o(adr_o), + .sel_o(sel_o), + .we_o(we_o), + .timer_interrupt(timer_interrupt), + .external_interrupt(1'b0) +); + +wire boot_rom_ack_o; +wire boot_rom_rty_o; +wire boot_rom_err_o; + memory_infer #( + .BASE_ADDRESS('h0000_0000), + .SIZE(256), + .READMEMH_FILE("boot.data") + ) boot_rom ( + .clk_i(clk), + .rst_i(rst_i), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i (we_o), + .ack_o(boot_rom_ack_o), + .err_o(boot_rom_err_o), + .rty_o(boot_rom_rty_o) + ); + +wire ram_ack_o; +wire ram_rty_o; +wire ram_err_o; + memory_ice40_spram_wb #( + .BASE_ADDRESS('h1000_0000) + ) ram ( + .clk_i(clk), + .rst_i(rst_i), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i (we_o), + .ack_o(ram_ack_o), + .err_o(ram_err_o), + .rty_o(ram_rty_o) + ); + +wire mtimer_ack_o; +wire mtimer_err_o; +wire mtimer_rty_o; +mtimer #(.BASE_ADDRESS('h3000_0000)) mtimer ( + .clk_i(clk), + .rst_i(rst_i), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i(we_o), + .ack_o(mtimer_ack_o), + .err_o(mtimer_err_o), + .rty_o(mtimer_rty_o), + .interrupt(timer_interrupt) +); + +wire gpio_ack_o; +wire gpio_rty_o; +wire gpio_err_o; +wire [5:0] unused; +gpio #(.BASE_ADDRESS('h4000_0000)) gpio ( + .clk_i(clk), + .rst_i(rst_i), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i(we_o), + .ack_o(gpio_ack_o), + .err_o(gpio_err_o), + .rty_o(gpio_rty_o), + .pin_input({{7{1'b0}}, BTN1}), + .pin_output({unused, LED2, LED1}) +); + +wire spi_ack_o; +wire spi_rty_o; +wire spi_err_o; +spi #(.BASE_ADDRESS('h5000_0000)) spi ( + .clk_i(clk), + .rst_i(rst_i), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i(we_o), + .ack_o(spi_ack_o), + .err_o(spi_err_o), + .rty_o(spi_rty_o), + .flash_clk(FLASH_SCK), + .flash_miso(FLASH_IO1), + .flash_mosi(FLASH_IO0), + .flash_cs_n(FLASH_SSB) +); + +assign ack_i = boot_rom_ack_o | ram_ack_o | mtimer_ack_o | gpio_ack_o | spi_ack_o; +assign err_i = boot_rom_err_o | ram_err_o | mtimer_err_o | gpio_err_o | spi_err_o; +assign rty_i = boot_rom_rty_o | ram_rty_o | mtimer_rty_o | gpio_rty_o | spi_rty_o; + +endmodule diff --git a/crush_example_freertos/sim/cpu_tb.v b/crush_example_freertos/sim/cpu_tb.v new file mode 100644 index 0000000..25cef2f --- /dev/null +++ b/crush_example_freertos/sim/cpu_tb.v @@ -0,0 +1,158 @@ +/* This file implements a test that simulates the CPU configured with interrupts. + * + * It is capable of running the FreeRTOS demo app. + * + * The initial configuration of the simulation is equivalent to the SoC after it + * has been booted from flash by the boot ROM. The simulation skips the loading, + * and starts up with the program already stored in memory. + */ + +`default_nettype none + +`timescale 1ns/1ps + +module cpu_tb; + +`include "params.vh" + +reg clk = 1; +reg reset = 1; +wire stb_o; +wire cyc_o; +wire[31:0] adr_o; +wire[3:0] sel_o; +wire[31:0] dat_i; +wire[31:0] dat_o; +wire we_o; +wire ack_i; +wire err_i; +wire rty_i; + +wire timer_interrupt; + +crush_cpu #(.INITIAL_PC('h1000_0000), .TRAP_PC('h1000_0100)) dut ( + .clk_i(clk), + .dat_i(dat_i), + .dat_o(dat_o), + .rst_i(reset), + .ack_i(ack_i), + .err_i(err_i), + .rty_i(rty_i), + .stb_o(stb_o), + .cyc_o(cyc_o), + .adr_o(adr_o), + .sel_o(sel_o), + .we_o(we_o), + .timer_interrupt(timer_interrupt), + .external_interrupt(1'b0) +); + +wire ram_ack_o; +wire ram_err_o; +wire ram_rty_o; +memory_infer #(.BASE_ADDRESS('h1000_0000), .SIZE('h1_0000)) ram ( + .clk_i(clk), + .rst_i(reset), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i(we_o), + .ack_o(ram_ack_o), + .err_o(ram_err_o), + .rty_o(ram_rty_o) +); + +initial begin + string binary_path; + if($value$plusargs("BINARY_PATH=%s", binary_path)) begin + integer file; + integer length; + + $display("Reading ram contents from %s", binary_path); + + file = $fopen(binary_path, "rb"); + length = $fread(ram.mem, file); + $fclose(file); + + $display("Read %0d bytes", length); + end else begin + $error("The BINARY_PATH plus arg must be set"); + $stop; + end +end + +wire mtimer_ack_o; +wire mtimer_err_o; +wire mtimer_rty_o; +mtimer #(.BASE_ADDRESS('h3000_0000)) mtimer ( + .clk_i(clk), + .rst_i(reset), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i(we_o), + .ack_o(mtimer_ack_o), + .err_o(mtimer_err_o), + .rty_o(mtimer_rty_o), + .interrupt(timer_interrupt) +); + +wire gpio_ack_o; +wire gpio_rty_o; +wire gpio_err_o; +wire [5:0] unused; +reg btn = 0; +// verilator lint_off UNUSEDSIGNAL +// standin for GPIO going off the board +reg led1; +reg led2; +// verilator lint_on UNUSEDSIGNAL +gpio #(.BASE_ADDRESS('h4000_0000)) gpio ( + .clk_i(clk), + .rst_i(reset), + .stb_i(stb_o), + .cyc_i(cyc_o), + .adr_i(adr_o), + .sel_i(sel_o), + .dat_i(dat_o), + .dat_o(dat_i), + .we_i(we_o), + .ack_o(gpio_ack_o), + .err_o(gpio_err_o), + .rty_o(gpio_rty_o), + .pin_input({{7{1'b0}}, btn}), + .pin_output({unused, led2, led1}) +); + +assign ack_i = ram_ack_o | mtimer_ack_o | gpio_ack_o; +assign rty_i = ram_rty_o | mtimer_rty_o | gpio_rty_o; +assign err_i = ram_err_o | mtimer_err_o | gpio_err_o; + +always begin + #42 clk <= !clk; +end + +always begin + #100_000_000 btn <= !btn; +end + +initial begin + $dumpfile("cpu_freertos_tb.vcd"); + $dumpvars(0); + + #250 reset = 0; + #50; + + #300_000_000; + + $error("Stop was not called within 300 ms, stopping now"); + $fatal; +end + +endmodule diff --git a/crush_example_freertos/sim/s25fl128s.v b/crush_example_freertos/sim/s25fl128s.v new file mode 100644 index 0000000..3bb5113 --- /dev/null +++ b/crush_example_freertos/sim/s25fl128s.v @@ -0,0 +1,8077 @@ +/////////////////////////////////////////////////////////////////////////////// +// File name : s25fl128s.v +/////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2009-2019 Free Model Foundry; http://www.FreeModelFoundry.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// MODIFICATION HISTORY : +// +// version: | author: | mod date: | changes made: +// V1.0 V.Mancev 23 Nov 09 Initial +// R.Prokopovic +// V1.1 V.Mancev 24 Feb 10 addr_cnt for second read in +// high performance read continuous +// mode can change its value only +// when CSNeg = '0' +// V1.2 V.Mancev 23 Mar 10 During read operations read_out +// signal changes its value in +// shorter interval +// V1.3 V.Mancev 13 Apr 10 HOLD mode corrected +// Condition for PP operation +// corrected +// V1.4 V.Mancev 19 May 10 SRWD bit assignment is corrected +// Condition for WRR command in +// write_cycle _decode section is +// corrected +// Blocking assignments for signals +// WSTART and PSTART are replaced +// with nonblocking assignments +// Conditions in Page Program +// section are fixed +// V1.5 V.Mancev 26 May 10 Conditions in programming +// sections are fixed +// Timing control sections for +// Program and Erase operation are +// changed +// V1.6 V.Mancev 03 June 10 bus_cycle_state section for +// PGSP command is fixed +// V1.7 V.Mancev 29 July 10 During the QUAD mode HOLD# input +// is not monitored for its normal +// function +// V1.8 B.Colakovic 24 Aug 10 All redundant signals are removed +// from BusCycle process +// V1.9 V. Mancev 08 Oct 10 Latest datasheet aligned +// B.Colakovic +// R. Prokopovic +// V1.10 V. Mancev 01 Nov 10 Read Configuration register added +// B.Colakovic for any state. Hybrid configuration +// R. Prokopovic added +// V1.11 S.Petrovic 08 Apr 11 Corrected timing in always block +// that generates +// rising_edge_CSNeg_ipd +// V1.12 V. Mancev 11 May 11 Condition for CS# High Time +// (Program/Erase) is fixed +// V1.13 V. Mancev 01 July 11 Latest datasheet aligned +// V1.14 B.Colakovic 14 July 11 Optimization issue is fixed +// V1.15 V.Mancev 22 July 11 Timing check issue is fixed +// V1.16 V. Mancev 16 Nov 11 Time tHO is changed to 1 ns +// (customer's request) +// BRWR instruction is corrected +// V1.17 S.Petrovic 28 Aug 12 QPP Instruction is allowed on +// previously programmed page +// V1.18 S.Petrovic 30 Aug 12 Wrong code corrected +// V1.19 V. Mancev 13 Feb 13 Reverted restriction for QPP +// on programmed page and +// added clearing with sector erase +// V1.20 S.Petrovic 13 Nov 28 Corrected state transitions +// initiated by Power-Up and HW +// Reset in StateGen process +// V1.21 S.Petrovic 13 Dec 16 Corrected Read DLP. +// Corrected Autoboot reg decoding +// V1.22 M.Stojanovic 15 May 15 Ignored upper address bits for RD4 +// V1.23 M.Stojanovic 15 May 29 Ignored upper address bits for all +// commands in QUAD mode +// V1.24 M.Stojanovic 16 May 11 During QPP and QPP4 commands +// the same page must not be +// programmed more than once. However +// do not generate P_ERR if this +// occurs. +// V1.25 M.Dinic 19 Feb 12 Updated according rev *P +// B.Barac (QPP and QPP4 commands changed, +// ECCRD command added, +// LOCK bit removed) +// +/////////////////////////////////////////////////////////////////////////////// +// PART DESCRIPTION: +// +// Library: FLASH +// Technology: FLASH MEMORY +// Part: S25FL128S +// +// Description: 128 Megabit Serial Flash Memory +// +////////////////////////////////////////////////////////////////////////////// +// Comments : +// For correct simulation, simulator resolution should be set to 1 ps +// A device ordering (trim) option determines whether a feature is enabled +// or not, or provide relevant parameters: +// -15th character in TimingModel determines if enhanced high +// performance option is available +// (0,2,3,R,A,B,C,D) EHPLC +// (Y,Z,S,T,K,L) Security EHPLC +// (4,6,7,8,9,Q) HPLC +// -15th character in TimingModel determines if RESET# input +// is available +// (R,A,B,C,D,Q.6,7,K,L,S,T,M,N,U,V) RESET# is available +// (0,2,3,4,8,9,Y.Z.W,X) RESET# is tied to the inactive +// state,inside the package. +// -16th character in TimingModel determines Sector and Page Size: +// (0) Sector Size = 64 kB; Page Size = 256 bytes +// Hybrid Top/Bottom sector size architecture +// (1) Sector Size = 256 kB; Page Size = 512 bytes +// Uniform sector size architecture +////////////////////////////////////////////////////////////////////////////// +// Known Bugs: +// +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// MODULE DECLARATION // +////////////////////////////////////////////////////////////////////////////// +`timescale 1 ps/1 ps + +module s25fl128s + ( + // Data Inputs/Outputs + SI , + SO , + // Controls + SCK , + CSNeg , + RSTNeg , + WPNeg , + HOLDNeg + +); + +/////////////////////////////////////////////////////////////////////////////// +// Port / Part Pin Declarations +/////////////////////////////////////////////////////////////////////////////// + + inout SI ; + inout SO ; + + input SCK ; + input CSNeg ; + input RSTNeg ; + inout HOLDNeg ; + inout WPNeg ; + + // interconnect path delay signals + wire SCK_ipd ; + wire SI_ipd ; + wire SO_ipd ; + + wire SI_in ; + assign SI_in = SI_ipd ; + + wire SI_out ; + assign SI_out = SI ; + + wire SO_in ; + assign SO_in = SO_ipd ; + + wire SO_out ; + assign SO_out = SO ; + + wire CSNeg_ipd ; + wire HOLDNeg_ipd ; + wire WPNeg_ipd ; + wire RSTNeg_ipd ; + + wire HOLDNeg_in ; + //Internal pull-up + assign HOLDNeg_in = (HOLDNeg_ipd === 1'bx) ? 1'b1 : HOLDNeg_ipd; + + wire HOLDNeg_out ; + assign HOLDNeg_out = HOLDNeg ; + + wire WPNeg_in ; + //Internal pull-up + assign WPNeg_in = (WPNeg_ipd === 1'bx) ? 1'b1 : WPNeg_ipd; + + wire WPNeg_out ; + assign WPNeg_out = WPNeg ; + + wire RSTNeg_in ; + //Internal pull-up + assign RSTNeg_in = (RSTNeg_ipd === 1'bx) ? 1'b1 : RSTNeg_ipd; + + // internal delays + reg PP_in ; + reg PP_out ; + reg BP_in ; + reg BP_out ; + reg SE_in ; + reg SE_out ; + reg BE_in ; + reg BE_out ; + reg WRR_in ; + reg WRR_out ; + reg ERSSUSP_in ; + reg ERSSUSP_out ; + reg PRGSUSP_in ; + reg PRGSUSP_out ; + reg PU_in ; + reg PU_out ; + reg RST_in ; + reg RST_out ; + reg PPBERASE_in ; + reg PPBERASE_out; + reg PASSULCK_in ; + reg PASSULCK_out; + reg PASSACC_in ; + reg PASSACC_out; + + // event control registers + reg PRGSUSP_out_event; + reg ERSSUSP_out_event; + reg Reseted_event; + reg SCK_ipd_event; + reg next_state_event; + + reg rising_edge_PoweredUp = 1'b0; + reg rising_edge_Reseted = 1'b0; + reg rising_edge_PASSULCK_in = 1'b0; + reg rising_edge_RES_out = 1'b0; + reg rising_edge_PSTART = 1'b0; + reg rising_edge_WSTART = 1'b0; + reg rising_edge_ESTART = 1'b0; + reg rising_edge_RSTNeg = 1'b0; + reg rising_edge_RST = 1'b0; + reg falling_edge_RSTNeg = 1'b0; + reg falling_edge_RST = 1'b0; + reg rising_edge_RST_out = 1'b0; + reg rising_edge_CSNeg_ipd = 1'b0; + reg falling_edge_CSNeg_ipd = 1'b0; + reg rising_edge_SCK_ipd = 1'b0; + reg falling_edge_SCK_ipd = 1'b0; + + reg RST ; + + reg SOut_zd = 1'bZ ; + reg SOut_z = 1'bZ ; + + wire SI_z ; + wire SO_z ; + + reg SIOut_zd = 1'bZ ; + reg SIOut_z = 1'bZ ; + + reg WPNegOut_zd = 1'bZ ; + reg HOLDNegOut_zd = 1'bZ ; + + assign SI_z = SIOut_z; + assign SO_z = SOut_z; + + parameter UserPreload = 1; + parameter mem_file_name = "none";//"s25fl128s.mem"; + parameter otp_file_name = "s25fl128sOTP.mem";//"none"; + + parameter TimingModel = "DefaultTimingModel"; + + parameter PartID = "s25fl128s"; + parameter MaxData = 255; + parameter MemSize = 24'hFFFFFF; + parameter SecSize256 = 20'h3FFFF; + parameter SecSize64 = 16'hFFFF; + parameter SecSize4 = 12'hFFF; + parameter SecNum64 = 285; + parameter SecNum256 = 63; + parameter PageNum64 = 20'h1FFFF; + parameter PageNum256 = 16'h7FFF; + parameter AddrRANGE = 24'hFFFFFF; + parameter HiAddrBit = 31; + parameter OTPSize = 1023; + parameter OTPLoAddr = 12'h000; + parameter OTPHiAddr = 12'h3FF; + parameter BYTE = 8; + + // Manufacturer Identification + parameter Manuf_ID = 8'h01; + parameter DeviceID = 8'h17; + // Electronic Signature + parameter ESignature = 8'h17; + // Device ID + //Manufacturer Identification && Memory Type && Memory Capacity + parameter Jedec_ID = 8'h01; + parameter DeviceID1 = 8'h20; + parameter DeviceID2 = 8'h18; + parameter ExtendedBytes = 8'h4D; + parameter ExtendedID64 = 8'h01; + parameter ExtendedID256 = 8'h00; + parameter DieRev = 8'h03; + parameter MaskRev = 8'h00; + + integer PageSize; + integer PageNum; + integer SecSize; + integer b_act = 0; + + integer ASP_ProtSE = 0; + integer Sec_ProtSE = 0; + + integer EHP; //Enhanced High Performance Mode active + + integer BAR_ACC = 0; //Bank Register Access active + + //varaibles to resolve architecture used + reg [24*8-1:0] tmp_timing;//stores copy of TimingModel + reg [7:0] tmp_char1;//Define EHPLC or HPLC Mode + reg [7:0] tmp_char2;//stores "0" or "1" character defining sector/page size + integer found = 1'b0; + + // If speedsimulation is needed uncomment following line + + `define SPEEDSIM; + + // powerup + reg PoweredUp; + + // Memory Array Configuration + reg BottomBoot = 1'b0; + reg TopBoot = 1'b0; + reg UniformSec = 1'b0; + + // FSM control signals + reg PDONE ; + reg PSTART ; + reg PGSUSP ; + reg PGRES ; + + reg TSU ; + + reg RES_TO_SUSP_MIN_TIME; + reg RES_TO_SUSP_TYP_TIME; + + reg WDONE ; + reg WSTART ; + + reg EDONE ; + reg ESTART ; + reg ESUSP ; + reg ERES ; + reg ERS_SUSP_PG_SUSP_ACT; + + reg Reseted ; + + reg PARAM_REGION = 1'b0; + + // Lock Bit is enabled for customer programming + reg WRLOCKENABLE = 1'b1; + // Flag that mark if ASP Register is allready programmed + reg ASPOTPFLAG = 1'b0; + + //Flag for Password unlock command + reg PASS_UNLOCKED = 1'b0; + reg [63:0] PASS_TEMP = 64'hFFFFFFFFFFFFFFFF; + + reg QUADRD = 1'b0; + reg INITIAL_CONFIG = 1'b0; + reg CHECK_FREQ = 1'b0; + + // Programming buffer + integer WByte[0:511]; + // CFI array + integer CFI_array[8'h00:8'h50]; + // OTP Memory Array + integer OTPMem[OTPLoAddr:OTPHiAddr]; + // Flash Memory Array + integer Mem[0:AddrRANGE]; + + // Registers + // VDLR Register + reg[7:0] VDLR_reg = 8'h00; + reg[7:0] VDLR_reg_in = 8'h00; + // NVDLR Register + reg[7:0] NVDLR_reg = 8'h00; + reg[7:0] NVDLR_reg_in = 8'h00; + reg start_dlp = 1'b0; + + // Status Register 1 + reg[7:0] Status_reg1 = 8'h00; + reg[7:0] Status_reg1_in = 8'h00; + + wire SRWD ; + wire P_ERR; + wire E_ERR; + wire [2:0]BP; + wire WEL; + wire WIP; + assign SRWD = Status_reg1[7]; + assign P_ERR = Status_reg1[6]; + assign E_ERR = Status_reg1[5]; + assign BP = Status_reg1[4:2]; + assign WEL = Status_reg1[1]; + assign WIP = Status_reg1[0]; + + // Status Register 2 + reg[7:0] Status_reg2 = 8'h00; + reg[7:0] Status_reg2_in = 8'h00; + + wire ES ; + wire PS ; + assign ES = Status_reg2[1]; + assign PS = Status_reg2[0]; + + // Configuration Register 1 + reg[7:0] Config_reg1 = 8'h00; + reg[7:0] Config_reg1_in = 8'h00; + + wire LC1 ; + wire LC0 ; + wire TBPROT ; +// wire LOCK ; + wire BPNV ; + wire TBPARM ; + wire QUAD ; + wire FREEZE ; + assign LC1 = Config_reg1[7]; + assign LC0 = Config_reg1[6]; + assign TBPROT = Config_reg1[5]; +// assign LOCK = Config_reg1[4]; + assign BPNV = Config_reg1[3]; + assign TBPARM = Config_reg1[2]; + assign QUAD = Config_reg1[1]; + assign FREEZE = Config_reg1[0]; + + // Autoboot Register + reg[31:0] AutoBoot_reg = 32'h00000000; + reg[31:0] AutoBoot_reg_in = 32'h00000000; + + wire ABE; + assign ABE = AutoBoot_reg[0]; + + // Bank Address Register + reg [7:0] Bank_Addr_reg = 8'h00; + reg [7:0] Bank_Addr_reg_in = 8'h00; + + wire EXTADD; + assign EXTADD = Bank_Addr_reg[7]; + + // ECC Status Register + reg[7:0] ECCSR = 8'h00; + + wire EECC; + wire EECCD; + wire ECCDI; + + assign EECC = ECCSR[2]; + assign EECCD = ECCSR[1]; + assign ECCDI = ECCSR[0]; + + // ASP Register + reg[15:0] ASP_reg ; + reg[15:0] ASP_reg_in; + + wire RPME ; + wire PPBOTP ; + wire PWDMLB ; + wire PSTMLB ; + assign RPME = ASP_reg[5]; + assign PPBOTP = ASP_reg[3]; + assign PWDMLB = ASP_reg[2]; + assign PSTMLB = ASP_reg[1]; + + // Password register + reg[63:0] Password_reg = 64'hFFFFFFFFFFFFFFFF; + reg[63:0] Password_reg_in = 64'hFFFFFFFFFFFFFFFF; + + // PPB Lock Register + reg[7:0] PPBL = 8'h00; + reg[7:0] PPBL_in = 8'h00; + + wire PPB_LOCK ; + assign PPB_LOCK = PPBL[0]; + + // PPB Access Register + reg[7:0] PPBAR = 8'hFF; + reg[7:0] PPBAR_in = 8'hFF; + + reg[SecNum64:0] PPB_bits = {286{1'b1}}; + + // DYB Access Register + reg[7:0] DYBAR = 8'hFF; + reg[7:0] DYBAR_in = 8'hFF; + + reg[SecNum64:0] DYB_bits = {286{1'b1}}; + + //The Lock Protection Registers for OTP Memory space + reg[7:0] LOCK_BYTE1; + reg[7:0] LOCK_BYTE2; + reg[7:0] LOCK_BYTE3; + reg[7:0] LOCK_BYTE4; + + // Command Register + reg write; + reg cfg_write; + reg read_out; + reg dual = 1'b0; + reg rd_fast = 1'b1; + reg rd_slow = 1'b0; + reg ddr = 1'b0; + reg ddr80 = 1'b0; + reg ddr_fast = 1'b0; + reg hold_mode = 1'b0; + reg any_read = 1'b0; + reg quad_pg = 1'b0; + + wire rd ; + wire fast_rd ; + wire ddrd ; + wire fast_ddr ; + wire ddrd80 ; + + wire quadpg ; + assign quadpg = quad_pg; + + wire RD_EQU_1; + assign RD_EQU_1 = any_read; + + wire RD_EQU_0; + assign RD_EQU_0 = ~any_read; + + reg change_TBPARM = 0; + + reg change_BP = 0; + reg [2:0] BP_bits = 3'b0; + + reg DOUBLE = 1'b0; //Double Data Rate (DDR) flag + + reg RdPswdProtMode = 1'b0;//Read Password Protection Mode Active flag + reg RdPswdProtEnable = 1'b0;//Read Password Protection Mode Support flag + + integer Byte_number = 0; + + reg oe = 1'b0; + reg oe_z = 1'b0; + + reg [647:0] CFI_array_tmp ; + reg [7:0] CFI_tmp; + + integer start_delay; + reg start_autoboot; + integer ABSD; + + reg change_addr ; + integer Address = 0; + integer SectorSuspend = 0; + + //Sector and subsector addresses + integer SA = 0; + + // Sector is protect if Sec_Prot(SecNum) = '1' + reg [SecNum64:0] Sec_Prot = {286{1'b0}}; + + // timing check violation + reg Viol = 1'b0; + + integer WOTPByte; + integer AddrLo; + integer AddrHi; + + reg[7:0] old_bit, new_bit; + integer old_int, new_int; + reg[63:0] old_pass; + reg[63:0] new_pass; + integer wr_cnt; + integer cnt; + + integer read_cnt = 0; + integer byte_cnt = 1; + integer read_addr = 0; + integer read_addr_tmp = 0; + integer Sec_addr = 0; + integer SecAddr = 0; + integer Page_addr = 0; + integer pgm_page = 0; + + reg[7:0] data_out; + reg[647:0] ident_out; + + time SCK_cycle = 0; + time prev_SCK; + time start_ddr; + time out_time; + time SCK_SO_DDR; +/////////////////////////////////////////////////////////////////////////////// +//Interconnect Path Delay Section +/////////////////////////////////////////////////////////////////////////////// + buf (SCK_ipd, SCK); + buf (SI_ipd, SI); + + buf (SO_ipd, SO); + buf (CSNeg_ipd, CSNeg); + buf (HOLDNeg_ipd, HOLDNeg); + buf (WPNeg_ipd, WPNeg); + buf (RSTNeg_ipd, RSTNeg); + +/////////////////////////////////////////////////////////////////////////////// +// Propagation delay Section +/////////////////////////////////////////////////////////////////////////////// + nmos (SI, SI_z , 1); + + nmos (SO, SO_z , 1); + nmos (HOLDNeg, HOLDNegOut_zd , 1); + nmos (WPNeg, WPNegOut_zd , 1); + + wire deg_pin; + wire deg_sin; + wire deg_holdin; + wire deh_pin; + wire deh_sout; + wire deh_ddr_sout; + wire deh_holdin; + //VHDL VITAL CheckEnable equivalents + wire quad_rd; + assign quad_rd = deg_holdin && ~QUAD && (SIOut_z != 1'bz); + wire wr_prot; + assign wr_prot = SRWD && WEL && ~QUAD; + wire dual_rd; + assign dual_rd = dual ; + wire ddro; + assign ddro = ddr && ~ddr80 && ~dual ; + wire ddro80; + assign ddro80 = ddr && ddr80 && ~dual ; + wire ddr_rd; + assign ddr_rd = PoweredUp && ddr; + wire sdr_rd; + assign sdr_rd = PoweredUp && ~ddr; +specify + // tipd delays: interconnect path delays , mapped to input port delays. + // In Verilog is not necessary to declare any tipd_ delay variables, + // they can be taken from SDF file + // With all the other delays real delays would be taken from SDF file + + // tpd delays + specparam tpd_SCK_SO_normal =1; + specparam tpd_CSNeg_SO =1; + specparam tpd_HOLDNeg_SO =1; + specparam tpd_RSTNeg_SO =1; + //DDR operation values + specparam tpd_SCK_SO_DDR =1; + + //tsetup values: setup times + specparam tsetup_CSNeg_SCK =1; + specparam tsetup_SI_SCK_normal =1; + specparam tsetup_WPNeg_CSNeg =1; + specparam tsetup_HOLDNeg_SCK =1; + specparam tsetup_RSTNeg_CSNeg =1; + // DDR operation values + specparam tsetup_SI_SCK_DDR =1; + specparam tsetup_SI_SCK_DDR_fast =1; + specparam tsetup_CSNeg_SCK_DDR =1; + + //thold values: hold times + specparam thold_CSNeg_SCK =1; + specparam thold_SI_SCK_normal =1; + specparam thold_SO_SCK_normal =1; + specparam thold_WPNeg_CSNeg =1; + specparam thold_HOLDNeg_SCK =1; + specparam thold_CSNeg_RSTNeg =1; + // DDR operation values + specparam thold_SI_SCK_DDR =1; + specparam thold_SI_SCK_DDR_fast =1; + specparam thold_CSNeg_SCK_DDR =1; + + // tpw values: pulse width + specparam tpw_SCK_serial_posedge =1; + specparam tpw_SCK_dual_posedge =1; + specparam tpw_SCK_fast_posedge =1; + specparam tpw_SCK_quadpg_posedge =1; + specparam tpw_SCK_serial_negedge =1; + specparam tpw_SCK_dual_negedge =1; + specparam tpw_SCK_fast_negedge =1; + specparam tpw_SCK_quadpg_negedge =1; + specparam tpw_CSNeg_read_posedge =1; + specparam tpw_CSNeg_pgers_posedge =1; + specparam tpw_RSTNeg_negedge =1; + specparam tpw_RSTNeg_posedge =1; + // DDR operation values + specparam tpw_SCK_DDR_posedge =1; + specparam tpw_SCK_DDR_negedge =1; + specparam tpw_SCK_DDR80_posedge =1; + specparam tpw_SCK_DDR80_negedge =1; + + // tperiod min (calculated as 1/max freq) + specparam tperiod_SCK_serial_rd =1;// 50 MHz + specparam tperiod_SCK_fast_rd =1;//133 MHz + specparam tperiod_SCK_dual_rd =1;//104 MHz + specparam tperiod_SCK_quadpg =1;// 80 MHz + // DDR operation values + specparam tperiod_SCK_DDR_rd =1;// 66 MHz + specparam tperiod_SCK_DDR80_rd =1;// 80 MHz + + `ifdef SPEEDSIM + // Page Program Operation + specparam tdevice_PP_256 = 75e7;//tPP + // Page Program Operation + specparam tdevice_PP_512 = 75e7;//tPP + // Typical Byte Programming Time + specparam tdevice_BP = 4e8;//tBP + // Sector Erase Operation + specparam tdevice_SE64 = 650e7;//tSE + // Sector Erase Operation + specparam tdevice_SE256 = 1875e7;//tSE + // Bulk Erase Operation + specparam tdevice_BE = 165e9;//tBE + // WRR Cycle Time + specparam tdevice_WRR = 2e9;//tW + // Erase Suspend/Erase Resume Time + specparam tdevice_ERSSUSP = 40e6;//tESL + // Program Suspend/Program Resume Time + specparam tdevice_PRGSUSP = 40e6;// + // VCC (min) to CS# Low + specparam tdevice_PU = 3e8;//tPU + // PPB Erase Time + specparam tdevice_PPBERASE = 15e9;// + // Password Unlock Time + specparam tdevice_PASSULCK = 1e6;// + // Password Unlock to Password Unlock Time + specparam tdevice_PASSACC = 100e6; + // Data In Setup Max time + specparam tdevice_TSU = 300e3; + `else + // Page Program Operation + specparam tdevice_PP_256 = 75e7;//tPP + // Page Program Operation + specparam tdevice_PP_512 = 75e7;//tPP + // Typical Byte Programming Time + specparam tdevice_BP = 4e8;//tBP + // Sector Erase Operation + specparam tdevice_SE64 = 650e9;//tSE + // Sector Erase Operation + specparam tdevice_SE256 = 1875e9;//tSE + // Bulk Erase Operation + specparam tdevice_BE = 165e12;//tBE + // WRR Cycle Time + specparam tdevice_WRR = 2e11;//tW + // Erase Suspend/Erase Resume Time + specparam tdevice_ERSSUSP = 40e6;//tESL + // Program Suspend/Program Resume Time + specparam tdevice_PRGSUSP = 40e6;// + // VCC (min) to CS# Low + specparam tdevice_PU = 3e8;//tPU + // PPB Erase Time + specparam tdevice_PPBERASE = 15e9;// + // Password Unlock Time + specparam tdevice_PASSULCK = 1e6;// + // Password Unlock to Password Unlock Time + specparam tdevice_PASSACC = 100e6; + // Data In Setup Max time + specparam tdevice_TSU = 300e3; + `endif // SPEEDSIM + +/////////////////////////////////////////////////////////////////////////////// +// Input Port Delays don't require Verilog description +/////////////////////////////////////////////////////////////////////////////// +// Path delays // +/////////////////////////////////////////////////////////////////////////////// + if (~ddr) (SCK => SO) = tpd_SCK_SO_normal; + if (ddr || rd_fast) (SCK => SO) = tpd_SCK_SO_DDR; + + if (~ddr && dual) (SCK => SI) = tpd_SCK_SO_normal; + if ( ddr && dual) (SCK => SI) = tpd_SCK_SO_DDR; + + if (~ddr && QUAD)(SCK => HOLDNeg) = tpd_SCK_SO_normal; + if ( ddr && QUAD)(SCK => HOLDNeg) = tpd_SCK_SO_DDR; + if (~ddr && QUAD)(SCK => WPNeg) = tpd_SCK_SO_normal; + if ( ddr && QUAD)(SCK => WPNeg) = tpd_SCK_SO_DDR; + + if (CSNeg) (CSNeg => SO) = tpd_CSNeg_SO; + if (CSNeg && dual) (CSNeg => SI) = tpd_CSNeg_SO; + + if (CSNeg && QUAD) (CSNeg => HOLDNeg) = tpd_CSNeg_SO; + if (CSNeg && QUAD) (CSNeg => WPNeg) = tpd_CSNeg_SO; + + if (~QUAD) (HOLDNeg => SO) = tpd_HOLDNeg_SO; + if (~QUAD && dual) (HOLDNeg => SI) = tpd_HOLDNeg_SO; + + (RSTNeg => SO) = tpd_RSTNeg_SO; +/////////////////////////////////////////////////////////////////////////////// +// Timing Violation // +/////////////////////////////////////////////////////////////////////////////// + $setup ( CSNeg , posedge SCK &&& sdr_rd, + tsetup_CSNeg_SCK, Viol); + $setup ( CSNeg , posedge SCK &&& ddr_rd, + tsetup_CSNeg_SCK_DDR, Viol); + $setup ( SI , posedge SCK &&& deg_sin, + tsetup_SI_SCK_normal, Viol); + $setup ( WPNeg , negedge CSNeg &&& wr_prot, + tsetup_WPNeg_CSNeg, Viol); + $setup ( HOLDNeg , posedge SCK &&& quad_rd, + tsetup_HOLDNeg_SCK, Viol); + $setup ( SI , posedge SCK &&& ddro, + tsetup_SI_SCK_DDR, Viol); + $setup ( SI , negedge SCK &&& ddro, + tsetup_SI_SCK_DDR, Viol); + $setup ( SI , posedge SCK &&& ddro80, + tsetup_SI_SCK_DDR, Viol); + $setup ( SI , negedge SCK &&& ddro80, + tsetup_SI_SCK_DDR, Viol); + + $setup ( RSTNeg , negedge CSNeg, + tsetup_RSTNeg_CSNeg, Viol); + + $hold ( posedge SCK &&& sdr_rd , CSNeg, + thold_CSNeg_SCK, Viol); + $hold ( posedge SCK &&& ddr_rd , CSNeg, + thold_CSNeg_SCK_DDR, Viol); + $hold ( posedge SCK &&& deg_sin , SI , + thold_SI_SCK_normal, Viol); + $hold ( negedge SCK &&& deh_sout , SO , + thold_SO_SCK_normal, Viol); + $hold ( negedge SCK &&& deh_ddr_sout , SO , + thold_SO_SCK_normal, Viol); + $hold ( posedge SCK &&& deh_ddr_sout , SO , + thold_SO_SCK_normal, Viol); + $hold ( posedge CSNeg &&& wr_prot , WPNeg , + thold_WPNeg_CSNeg, Viol); + $hold ( posedge SCK &&& quad_rd , HOLDNeg , + thold_HOLDNeg_SCK, Viol); + $hold ( posedge SCK &&& ddro , SI, + thold_SI_SCK_DDR, Viol); + $hold ( negedge SCK &&& ddro , SI, + thold_SI_SCK_DDR, Viol); + $hold ( posedge SCK &&& ddro80 , SI, + thold_SI_SCK_DDR, Viol); + $hold ( negedge SCK &&& ddro80 , SI, + thold_SI_SCK_DDR, Viol); + + $hold ( negedge RSTNeg , CSNeg, + thold_CSNeg_RSTNeg, Viol); + + $width ( posedge SCK &&& rd , tpw_SCK_serial_posedge); + $width ( negedge SCK &&& rd , tpw_SCK_serial_negedge); + $width ( posedge SCK &&& dual_rd , tpw_SCK_dual_posedge); + $width ( negedge SCK &&& dual_rd , tpw_SCK_dual_negedge); + $width ( posedge SCK &&& fast_rd , tpw_SCK_fast_posedge); + $width ( negedge SCK &&& fast_rd , tpw_SCK_fast_negedge); + $width ( posedge SCK &&& ddrd , tpw_SCK_DDR_posedge); + $width ( negedge SCK &&& ddrd , tpw_SCK_DDR_negedge); + $width ( posedge SCK &&& ddrd80 , tpw_SCK_DDR80_posedge); + $width ( negedge SCK &&& ddrd80 , tpw_SCK_DDR80_negedge); + $width ( posedge SCK &&& quadpg , tpw_SCK_quadpg_posedge); + $width ( negedge SCK &&& quadpg , tpw_SCK_quadpg_negedge); + + $width ( posedge CSNeg &&& RD_EQU_1, tpw_CSNeg_read_posedge); + $width ( posedge CSNeg &&& RD_EQU_0, tpw_CSNeg_pgers_posedge); + $width ( negedge RSTNeg , tpw_RSTNeg_negedge); + $width ( posedge RSTNeg , tpw_RSTNeg_posedge); + + $period ( posedge SCK &&& rd , tperiod_SCK_serial_rd); + $period ( posedge SCK &&& fast_rd , tperiod_SCK_fast_rd); + $period ( posedge SCK &&& dual_rd , tperiod_SCK_dual_rd); + $period ( posedge SCK &&& quadpg , tperiod_SCK_quadpg); + $period ( posedge SCK &&& ddrd , tperiod_SCK_DDR_rd); + $period ( posedge SCK &&& ddrd80 , tperiod_SCK_DDR80_rd); + +endspecify + +/////////////////////////////////////////////////////////////////////////////// +// Main Behavior Block // +/////////////////////////////////////////////////////////////////////////////// +// FSM states + parameter IDLE = 5'd0; + parameter RESET_STATE = 5'd1; + parameter AUTOBOOT = 5'd2; + parameter WRITE_SR = 5'd3; + parameter PAGE_PG = 5'd4; + parameter OTP_PG = 5'd5; + parameter PG_SUSP = 5'd6; + parameter SECTOR_ERS = 5'd7; + parameter BULK_ERS = 5'd8; + parameter ERS_SUSP = 5'd9; + parameter ERS_SUSP_PG = 5'd10; + parameter ERS_SUSP_PG_SUSP= 5'd11; + parameter PASS_PG = 5'd12; + parameter PASS_UNLOCK = 5'd13; + parameter PPB_PG = 5'd14; + parameter PPB_ERS = 5'd15; + parameter AUTOBOOT_PG = 5'd16; + parameter ASP_PG = 5'd17; + parameter PLB_PG = 5'd18; + parameter DYB_PG = 5'd19; + parameter NVDLR_PG = 5'd20; + + reg [4:0] current_state; + reg [4:0] next_state; + +// Instruction type + parameter NONE = 7'd0; + parameter WRR = 7'd1; + parameter PP = 7'd2; + parameter READ = 7'd3; + parameter WRDI = 7'd4; + parameter RDSR = 7'd5; + parameter WREN = 7'd6; + parameter RDSR2 = 7'd7; + parameter FSTRD = 7'd8; + parameter FSTRD4 = 7'd9; + parameter DDRFR = 7'd10; + parameter DDRFR4 = 7'd11; + parameter PP4 = 7'd12; + parameter RD4 = 7'd13; + parameter ABRD = 7'd14; + parameter ABWR = 7'd15; + parameter BRRD = 7'd16; + parameter BRWR = 7'd17; + parameter P4E = 7'd19; + parameter P4E4 = 7'd20; + parameter ASPRD = 7'd21; + parameter ASPP = 7'd22; + parameter CLSR = 7'd23; + parameter QPP = 7'd24; + parameter QPP4 = 7'd25; + parameter RDCR = 7'd26; + parameter DOR = 7'd27; + parameter DOR4 = 7'd28; + parameter DLPRD = 7'd29; + parameter OTPP = 7'd30; + parameter PNVDLR = 7'd31; + parameter OTPR = 7'd32; + parameter WVDLR = 7'd33; + parameter BE = 7'd34; + parameter QOR = 7'd35; + parameter QOR4 = 7'd36; + parameter ERSP = 7'd37; + parameter ERRS = 7'd38; + parameter PGSP = 7'd39; + parameter PGRS = 7'd40; + parameter REMS = 7'd41; + parameter RDID = 7'd42; + parameter MPM = 7'd43; + parameter PLBWR = 7'd44; + parameter PLBRD = 7'd45; + parameter RES = 7'd46; + parameter DIOR = 7'd47; + parameter DIOR4 = 7'd48; + parameter DDRDIOR = 7'd49; + parameter DDRDIOR4 = 7'd50; + parameter SE = 7'd51; + parameter SE4 = 7'd52; + parameter DYBRD = 7'd53; + parameter DYBWR = 7'd54; + parameter PPBRD = 7'd55; + parameter PPBP = 7'd56; + parameter PPBERS = 7'd57; + parameter PASSRD = 7'd58; + parameter PASSP = 7'd59; + parameter PASSU = 7'd60; + parameter QIOR = 7'd61; + parameter QIOR4 = 7'd62; + parameter DDRQIOR = 7'd63; + parameter DDRQIOR4 = 7'd64; + parameter RESET = 7'd65; + parameter MBR = 7'd66; + parameter BRAC = 7'd67; + parameter ECCRD = 7'd68; + + reg [6:0] Instruct; + +//Bus cycle state + parameter STAND_BY = 3'd0; + parameter OPCODE_BYTE = 3'd1; + parameter ADDRESS_BYTES = 3'd2; + parameter DUMMY_BYTES = 3'd3; + parameter MODE_BYTE = 3'd4; + parameter DATA_BYTES = 3'd5; + + reg [2:0] bus_cycle_state; + + reg deq_pin; + always @(SO_in, SO_z) + begin + if (SO_in==SO_z) + deq_pin=1'b0; + else + deq_pin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_pin = deq_pin; + assign deh_pin = (deq_pin == 1'b0) && (SO_z != 1'bz); + reg deq_sin; + always @(SI_in, SIOut_z) + begin + if (SI_in==SIOut_z) + deq_sin=1'b0; + else + deq_sin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_sin=deq_sin + && (ddr == 1'b0) && (Instruct !== DDRFR) + && (Instruct !== DDRFR4) && (Instruct !== DDRDIOR) + && (Instruct !== DDRDIOR4) && (Instruct !== DDRQIOR) + && (Instruct !== DDRQIOR4) && (SIOut_z != 1'bz); + reg deq_sout; + always @(SO_out, SIOut_z) + begin + if (SO_out==SIOut_z) + deq_sout=1'b0; + else + deq_sout=1'b1; + end + // check when data is generated from model + assign deh_sout= (deq_sout == 1'b0) + && (ddr == 1'b0) && (SOut_z != 1'bz); + assign deh_ddr_sout= (deq_sout == 1'b0) + && (ddr == 1'b1) && (SOut_z != 1'bz); + + reg deq_holdin; + always @(HOLDNeg_ipd, HOLDNegOut_zd) + begin + if (HOLDNeg_ipd==HOLDNegOut_zd) + deq_holdin=1'b0; + else + deq_holdin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // this occasion + assign deg_holdin=deq_holdin; + assign deh_holdin=(deq_holdin == 1'b0) && (HOLDNegOut_zd != 1'bz); + + //Power Up time; + initial + begin + PoweredUp = 1'b0; + #tdevice_PU PoweredUp = 1'b1; + end + + initial + begin : Init + write = 1'b0; + cfg_write = 1'b0; + read_out = 1'b0; + Address = 0; + change_addr = 1'b0; + cnt = 0; + RST = 1'b0; + RST_in = 1'b0; + RST_out = 1'b1; + PDONE = 1'b1; + PSTART = 1'b0; + PGSUSP = 1'b0; + PGRES = 1'b0; + PRGSUSP_in = 1'b0; + ERSSUSP_in = 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b0; + RES_TO_SUSP_TYP_TIME = 1'b0; + + EDONE = 1'b1; + ESTART = 1'b0; + ESUSP = 1'b0; + ERES = 1'b0; + + WDONE = 1'b1; + WSTART = 1'b0; + + Reseted = 1'b0; + + Instruct = NONE; + bus_cycle_state = STAND_BY; + current_state = RESET_STATE; + next_state = RESET_STATE; + end + + // initialize memory and load preload files if any + initial + begin: InitMemory + integer i; + + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = MaxData; + end + + if ((UserPreload) && !(mem_file_name == "none")) + begin + // Memory Preload + //s25fl128s.mem, memory preload file + // @aaaaaa - stands for address + // dd -
is byte to be written at Mem(aaaaaa++) + // (aaaaaa is incremented at every load) + $readmemh(mem_file_name,Mem); + end + + for (i=OTPLoAddr;i<=OTPHiAddr;i=i+1) + begin + OTPMem[i] = MaxData; + end + + if (UserPreload && !(otp_file_name == "none")) + begin + //s25fl128s_otp memory file + // / - comment + // @aaaaaa - stands for address within last defined + // sector + // dd -
is byte to be written at OTPMem(aaa++) + // (aa is incremented at every load) + // only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + $readmemh(otp_file_name,OTPMem); + end + + LOCK_BYTE1[7:0] = OTPMem[16]; + LOCK_BYTE2[7:0] = OTPMem[17]; + LOCK_BYTE3[7:0] = OTPMem[18]; + LOCK_BYTE4[7:0] = OTPMem[19]; + end + + // initialize memory and load preload files if any + initial + begin: InitTimingModel + integer i; + integer j; + //UNIFORM OR HYBRID arch model is used + //assumptions: + //1. TimingModel has format as S25FL128SXXXXXXXX_X_XXpF + //it is important that 16-th character from first one is "0" or "1" + //2. TimingModel does not have more then 24 characters + tmp_timing = TimingModel;//copy of TimingModel + + i = 23; + while ((i >= 0) && (found != 1'b1))//search for first non null character + begin //i keeps position of first non null character + j = 7; + while ((j >= 0) && (found != 1'b1)) + begin + if (tmp_timing[i*8+j] != 1'd0) + found = 1'b1; + else + j = j-1; + end + i = i - 1; + end + i = i +1; + if (found)//if non null character is found + begin + for (j=0;j<=7;j=j+1) + begin + //EHPLC/HPLC character is 15 + tmp_char1[j] = TimingModel[(i-14)*8+j]; + //256B/512B Page character is 16 + tmp_char2[j] = TimingModel[(i-15)*8+j]; + end + end + if (tmp_char1 == "0" || tmp_char1 == "2" || tmp_char1 == "3" || + tmp_char1 == "R" || tmp_char1 == "A" || tmp_char1 == "B" || + tmp_char1 == "C" || tmp_char1 == "D" || tmp_char1 == "Y" || + tmp_char1 == "Z" || tmp_char1 == "S" || tmp_char1 == "T" || + tmp_char1 == "K" || tmp_char1 == "L") + begin + EHP = 1; + if(tmp_char1 == "Z" || tmp_char1 == "S" || tmp_char1 == "T" || + tmp_char1 == "K" || tmp_char1 == "L" || tmp_char1 == "Y") + begin + RdPswdProtEnable = 1; + end + end + else if (tmp_char1 == "4" || tmp_char1 == "6" || tmp_char1 == "7" || + tmp_char1 == "8" || tmp_char1 == "9" || tmp_char1 == "Q") + begin + EHP = 0; + end + + if (tmp_char1 == "0" || tmp_char1 == "2" || tmp_char1 == "3" || + tmp_char1 == "R" || tmp_char1 == "A" || tmp_char1 == "B" || + tmp_char1 == "C" || tmp_char1 == "D" || tmp_char1 == "4" || + tmp_char1 == "6" || tmp_char1 == "7" || tmp_char1 == "8" || + tmp_char1 == "9" || tmp_char1 == "Q") + begin + ASP_reg = 16'hFE7F; + ASP_reg_in = 16'hFE7F; + end + else if (tmp_char1 == "Y" || tmp_char1 == "Z" || tmp_char1 == "S" || + tmp_char1 == "T" || tmp_char1 == "K" || tmp_char1 == "L") + begin + ASP_reg = 16'hFE4F; + ASP_reg_in = 16'hFE4F; + end + + if (tmp_char2 == "0") + begin + PageSize = 255; + PageNum = PageNum64; + SecSize = SecSize64; + end + else if (tmp_char2 == "1") + begin + PageSize = 511; + PageNum = PageNum256; + SecSize = SecSize256; + end + end + + //CFI + initial + begin: InitCFI + integer i; + integer j; + /////////////////////////////////////////////////////////////////////// + // ID-CFI array data + /////////////////////////////////////////////////////////////////////// + // Manufacturer and Device ID + CFI_array[8'h00] = Jedec_ID; + CFI_array[8'h01] = DeviceID1; + CFI_array[8'h02] = DeviceID2; + CFI_array[8'h03] = 8'h00; + if (tmp_char2 == "0") + // Uniform 64kB sectors + CFI_array[8'h04] = ExtendedID64; + else if (tmp_char2 == "1") + // Uniform 256kB sectors + CFI_array[8'h04] = ExtendedID256; + CFI_array[8'h05] = 8'h80; + CFI_array[8'h06] = 8'h00; + CFI_array[8'h07] = 8'h00; + CFI_array[8'h08] = 8'h00; + CFI_array[8'h09] = 8'h00; + CFI_array[8'h0A] = 8'h00; + CFI_array[8'h0B] = 8'h00; + CFI_array[8'h0C] = 8'h00; + CFI_array[8'h0D] = 8'h00; + CFI_array[8'h0E] = 8'h00; + CFI_array[8'h0F] = 8'h00; + // CFI Query Identification String + CFI_array[8'h10] = 8'h51; + CFI_array[8'h11] = 8'h52; + CFI_array[8'h12] = 8'h59; + CFI_array[8'h13] = 8'h02; + CFI_array[8'h14] = 8'h00; + CFI_array[8'h15] = 8'h40; + CFI_array[8'h16] = 8'h00; + CFI_array[8'h17] = 8'h53; + CFI_array[8'h18] = 8'h46; + CFI_array[8'h19] = 8'h51; + CFI_array[8'h1A] = 8'h00; + //CFI system interface string + CFI_array[8'h1B] = 8'h27; + CFI_array[8'h1C] = 8'h36; + CFI_array[8'h1D] = 8'h00; + CFI_array[8'h1E] = 8'h00; + CFI_array[8'h1F] = 8'h06; + if (tmp_char2 == "0") + begin + // 64kB sector and 256B page + CFI_array[8'h20] = 8'h08; + CFI_array[8'h21] = 8'h08; + end + else if (tmp_char2 == "1") + begin + // 256kB sector and 512B page + CFI_array[8'h20] = 8'h09; + CFI_array[8'h21] = 8'h09; + end + CFI_array[8'h22] = 8'h0F; + CFI_array[8'h23] = 8'h02; + CFI_array[8'h24] = 8'h02; + CFI_array[8'h25] = 8'h03; + CFI_array[8'h26] = 8'h03; + // Device Geometry Definition(Uniform Sector Devices) + CFI_array[8'h27] = 8'h18; + CFI_array[8'h28] = 8'h02; + CFI_array[8'h29] = 8'h01; + + if (tmp_char2 == "0") + // 64kB sectors + CFI_array[8'h2A] = 8'h08; + else if (tmp_char2 == "1") + CFI_array[8'h2A] = 8'h09; + + CFI_array[8'h2B] = 8'h00; + if (tmp_char2 == "1") + begin + CFI_array[8'h2C] = 8'h01; + CFI_array[8'h2D] = 8'h3F; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h00; + CFI_array[8'h30] = 8'h04; + CFI_array[8'h31] = 8'hFF; + CFI_array[8'h32] = 8'hFF; + CFI_array[8'h33] = 8'hFF; + CFI_array[8'h34] = 8'hFF; + end + else + begin + CFI_array[8'h2C] = 8'h02; + if (TBPARM) + begin + // 4KB physical sectors at top + CFI_array[8'h2D] = 8'hFD; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h00; + CFI_array[8'h30] = 8'h01; + CFI_array[8'h31] = 8'h1F; + CFI_array[8'h32] = 8'h00; + CFI_array[8'h33] = 8'h10; + CFI_array[8'h34] = 8'h00; + end + else + begin + // 4KB physical sectors at bottom + CFI_array[8'h2D] = 8'h1F; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h10; + CFI_array[8'h30] = 8'h00; + CFI_array[8'h31] = 8'hFD; + CFI_array[8'h32] = 8'h00; + CFI_array[8'h33] = 8'h00; + CFI_array[8'h34] = 8'h01; + end + end + CFI_array[8'h35] = 8'hFF; + CFI_array[8'h36] = 8'hFF; + CFI_array[8'h37] = 8'hFF; + CFI_array[8'h38] = 8'hFF; + CFI_array[8'h39] = 8'hFF; + CFI_array[8'h3A] = 8'hFF; + CFI_array[8'h3B] = 8'hFF; + CFI_array[8'h3C] = 8'hFF; + CFI_array[8'h3D] = 8'hFF; + CFI_array[8'h3E] = 8'hFF; + CFI_array[8'h3F] = 8'hFF; + // CFI Primary Vendor-Specific Extended Query + CFI_array[8'h40] = 8'h50; + CFI_array[8'h41] = 8'h52; + CFI_array[8'h42] = 8'h49; + CFI_array[8'h43] = 8'h31; + CFI_array[8'h44] = 8'h33; + CFI_array[8'h45] = 8'h21; + CFI_array[8'h46] = 8'h02; + CFI_array[8'h47] = 8'h01; + CFI_array[8'h48] = 8'h00; + CFI_array[8'h49] = 8'h08; + CFI_array[8'h4A] = 8'h00; + CFI_array[8'h4B] = 8'h01; + CFI_array[8'h4C] = 8'h00; + CFI_array[8'h4D] = 8'h00; + CFI_array[8'h4E] = 8'h00; + CFI_array[8'h4F] = 8'h07; + CFI_array[8'h50] = 8'h01; + + begin + for(i=80;i>=0;i=i-1) + begin + CFI_tmp = CFI_array[8'h00-i+80]; + for(j=7;j>=0;j=j-1) + begin + CFI_array_tmp[8*i+j] = CFI_tmp[j]; + end + end + end + + end + + always @(next_state_event or PoweredUp or RST or RST_out or + RSTNeg_in or rising_edge_RSTNeg or falling_edge_RST) + begin: StateTransition + if (PoweredUp) + begin + if ((RSTNeg_in == 1'b1) && (RST_out == 1'b1)) + current_state = #(1000) next_state; + else if ((~RSTNeg_in || rising_edge_RSTNeg) && falling_edge_RST) + begin + // no state transition while RESET# low + current_state = RESET_STATE; + RST_in = 1'b1; + #1000 RST_in = 1'b0; + end + end + end + + always @(posedge RST_in) + begin:Threset + RST_out = 1'b0; + #(35000000-200000) RST_out = 1'b1; + end + + always @(negedge CSNeg_ipd) + begin:CheckCEOnPowerUP + if (~PoweredUp) + $display ("Device is selected during Power Up"); + end + + /////////////////////////////////////////////////////////////////////////// + //// Internal Delays + /////////////////////////////////////////////////////////////////////////// + + always @(posedge PRGSUSP_in) + begin:PRGSuspend + PRGSUSP_out = 1'b0; + #tdevice_PRGSUSP PRGSUSP_out = 1'b1; + end + + always @(posedge PPBERASE_in) + begin:PPBErs + PPBERASE_out = 1'b0; + #tdevice_PPBERASE PPBERASE_out = 1'b1; + end + + always @(posedge ERSSUSP_in) + begin:ERSSuspend + ERSSUSP_out = 1'b0; + #tdevice_ERSSUSP ERSSUSP_out = 1'b1; + end + + always @(posedge PASSULCK_in) + begin:PASSULock + PASSULCK_out = 1'b0; + #tdevice_PASSULCK PASSULCK_out = 1'b1; + end + + always @(posedge PASSACC_in) + begin:PASSAcc + PASSACC_out = 1'b0; + #tdevice_PASSACC PASSACC_out = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// write cycle decode +/////////////////////////////////////////////////////////////////////////////// + integer opcode_cnt = 0; + integer addr_cnt = 0; + integer mode_cnt = 0; + integer dummy_cnt = 0; + integer data_cnt = 0; + integer bit_cnt = 0; + + reg [4095:0] Data_in = 4096'b0; + reg [7:0] opcode; + reg [7:0] opcode_in; + reg [7:0] opcode_tmp; + reg [31:0] addr_bytes; + reg [31:0] hiaddr_bytes; + reg [31:0] Address_in; + reg [7:0] mode_bytes; + reg [7:0] mode_in; + integer Latency_code; + integer quad_data_in [0:1023]; + reg [3:0] quad_nybble = 4'b0; + reg [3:0] Quad_slv; + reg [7:0] Byte_slv; + + always @(rising_edge_CSNeg_ipd or falling_edge_CSNeg_ipd or + rising_edge_SCK_ipd or falling_edge_SCK_ipd or + current_state) + begin: Buscycle + integer i; + integer j; + integer k; + time CLK_PER; + time LAST_CLK; + + if (current_state == RESET_STATE) + bus_cycle_state = STAND_BY; + else + begin + if (falling_edge_CSNeg_ipd) + begin + if (bus_cycle_state==STAND_BY) + begin + Instruct = NONE; + write = 1'b1; + cfg_write = 0; + opcode_cnt = 0; + addr_cnt = 0; + mode_cnt = 0; + dummy_cnt = 0; + data_cnt = 0; + opcode_tmp = 0; + start_dlp = 0; + DOUBLE = 1'b0; + QUADRD = 1'b0; + CLK_PER = 1'b0; + LAST_CLK = 1'b0; + if (current_state == AUTOBOOT) + begin + bus_cycle_state = DATA_BYTES; + end + else + begin + bus_cycle_state = OPCODE_BYTE; + end + end + end + + if (rising_edge_SCK_ipd) // Instructions, addresses or data present + begin // at SI are latched on the rising edge of SCK + + CLK_PER = $time - LAST_CLK; + LAST_CLK = $time; + if (CHECK_FREQ) + begin + if ((CLK_PER < 20000 && Latency_code == 3) || + (CLK_PER < 12500 && Latency_code == 0) || + (CLK_PER < 11100 && Latency_code == 1) || + (CLK_PER < 9600 && Latency_code == 2)) + begin + $display ("More wait states are required for"); + $display ("this clock frequency value"); + end + if (Instruct == DDRFR || Instruct == DDRFR4 || Instruct == DDRDIOR || + Instruct == DDRDIOR4 || Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + if (CLK_PER < 12500) + begin + ddr80 = 1'b1; + end + else + begin + ddr80 = 1'b0; + end + end + CHECK_FREQ = 0; + end + + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + OPCODE_BYTE: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + opcode_in[opcode_cnt] = SI_in; + opcode_cnt = opcode_cnt + 1; + Latency_code = Config_reg1[7:6]; + if (opcode_cnt == BYTE) + begin + for(i=7;i>=0;i=i-1) + begin + opcode[i] = opcode_in[7-i]; + end + case (opcode) + 8'b00000110 : // 06h + begin + Instruct = WREN; + bus_cycle_state = DATA_BYTES; + end + 8'b00000100 : // 04h + begin + Instruct = WRDI; + bus_cycle_state = DATA_BYTES; + end + 8'b00000001 : // 01h + begin + Instruct = WRR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000011 : // 03h + begin + Instruct = READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00010011 : // 13h + begin + Instruct = RD4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01001011 : // 4Bh + begin + Instruct = OTPR; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00000101 : // 05h + begin + Instruct = RDSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000111 : // 07h + begin + Instruct = RDSR2; + bus_cycle_state = DATA_BYTES; + end + 8'b00110101 : // 35h + begin + Instruct = RDCR; + bus_cycle_state = DATA_BYTES; + end + 8'b10010000 : // 90h + begin + Instruct = REMS; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10011111 : // 9Fh + begin + Instruct = RDID; + bus_cycle_state = DATA_BYTES; + end + 8'b10101011 : // ABh + begin + Instruct = RES; + bus_cycle_state = DUMMY_BYTES; + end + 8'b00001011 : // 0Bh + begin + Instruct = FSTRD; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001100 : // 0Ch + begin + Instruct = FSTRD4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001101 : // 0Dh + begin + Instruct = DDRFR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00001110 : // 0Eh + begin + Instruct = DDRFR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00111011 : // 3Bh + begin + Instruct = DOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00111100 : // 3Ch + begin + Instruct = DOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111011 : // BBh + begin + Instruct = DIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111100 : // BCh + begin + Instruct = DIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111101 : // BDh + begin + Instruct = DDRDIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b10111110 : // BEh + begin + Instruct = DDRDIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b01101011 : // 6Bh + begin + Instruct = QOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b01101100 : // 6Ch + begin + Instruct = QOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101011 : // EBh + begin + Instruct = QIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101100 : // ECh + begin + Instruct = QIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101101 : // EDh + begin + Instruct = DDRQIOR; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b11101110 : // EEh + begin + Instruct = DDRQIOR4; + bus_cycle_state = ADDRESS_BYTES; + CHECK_FREQ = 1'b1; + end + 8'b00000010 : // 02h + begin + Instruct = PP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00010010 : // 12h + begin + Instruct = PP4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00110010: // 32h + begin + Instruct = QPP; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b00111000: // 38h + begin + Instruct = QPP; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b00110100 : // 34h + begin + Instruct = QPP4; + bus_cycle_state = ADDRESS_BYTES; + quad_pg = 1'b1; + end + 8'b01000010 : // 42h + begin + Instruct = OTPP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10000101 : // 85h + begin + Instruct = PGSP; + bus_cycle_state = DATA_BYTES; + end + 8'b10001010 : // 8Ah + begin + Instruct = PGRS; + bus_cycle_state = DATA_BYTES; + end + 8'b11000111 : // C7h + begin + Instruct = BE; + bus_cycle_state = DATA_BYTES; + end + 8'b01100000 : // 60h + begin + Instruct = BE; + bus_cycle_state = DATA_BYTES; + end + 8'b11011000 : // D8h + begin + Instruct = SE; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11011100 : // DCh + begin + Instruct = SE4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01110101 : // 75h + begin + Instruct = ERSP; + bus_cycle_state = DATA_BYTES; + end + 8'b01111010 : // 7Ah + begin + Instruct = ERRS; + bus_cycle_state = DATA_BYTES; + end + 8'b00010100 : // 14h + begin + Instruct = ABRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00010101 : // 15h + begin + Instruct = ABWR; + bus_cycle_state = DATA_BYTES; + end + 8'b00010110 : // 16h + begin + Instruct = BRRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00010111 : // 17h + begin + Instruct = BRWR; + bus_cycle_state = DATA_BYTES; + end + 8'b00101011 : // 2Bh + begin + Instruct = ASPRD; + bus_cycle_state = DATA_BYTES; + end + 8'b00101111 : // 2Fh + begin + Instruct = ASPP; + bus_cycle_state = DATA_BYTES; + end + 8'b11100000 : // E0h + begin + Instruct = DYBRD; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100001 : // E1h + begin + Instruct = DYBWR; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100010 : // E2h + begin + Instruct = PPBRD; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100011 : // E3h + begin + Instruct = PPBP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11100100 : // E4h + begin + Instruct = PPBERS; + bus_cycle_state = DATA_BYTES; + end + 8'b10100110 : // A6h + begin + Instruct = PLBWR; + bus_cycle_state = DATA_BYTES; + end + 8'b10100111 : // A7h + begin + Instruct = PLBRD; + bus_cycle_state = DATA_BYTES; + end + 8'b11100111 : // E7h + begin + Instruct = PASSRD; + bus_cycle_state = DATA_BYTES; + end + 8'b11101000 : // E8h + begin + Instruct = PASSP; + bus_cycle_state = DATA_BYTES; + end + 8'b11101001 : // E9h + begin + Instruct = PASSU; + bus_cycle_state = DATA_BYTES; + end + 8'b11110000 : // F0h + begin + Instruct = RESET; + bus_cycle_state = DATA_BYTES; + end + 8'b00110000 : // 30h + begin + Instruct = CLSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00100000 : // 20h + begin + Instruct = P4E; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00100001 : // 21h + begin + Instruct = P4E4; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01000001 : // 41h + begin + Instruct = DLPRD; + bus_cycle_state = DATA_BYTES; + end + 8'b01000011 : // 43h + begin + Instruct = PNVDLR; + bus_cycle_state = DATA_BYTES; + end + 8'b01001010 : // 4Ah + begin + Instruct = WVDLR; + bus_cycle_state = DATA_BYTES; + end + 8'b10111001 : // B9h + begin + Instruct = BRAC; + bus_cycle_state = DATA_BYTES; + end + 8'b11111111 : // FFh + begin + Instruct = MBR; + bus_cycle_state = MODE_BYTE; + end + 8'b00011000 : // 18h + begin + Instruct = ECCRD; + bus_cycle_state = ADDRESS_BYTES; + end + endcase + end + end + end //end of OPCODE BYTE + + ADDRESS_BYTES : + begin + if ((Instruct == DDRFR) || (Instruct == DDRFR4) || + (Instruct == DDRDIOR) || (Instruct == DDRDIOR4) || + (Instruct == DDRQIOR) || (Instruct == DDRQIOR4)) + DOUBLE = 1'b1; + else + DOUBLE = 1'b0; + if ((Instruct == QOR) || (Instruct == QOR4) || + (Instruct == QIOR) || (Instruct == QIOR4) || + (Instruct == DDRQIOR) || (Instruct == DDRQIOR4)) + QUADRD = 1'b1; + else + QUADRD = 1'b0; + if (DOUBLE == 1'b0) + begin + if (((((Instruct == FSTRD) && (~EXTADD)) || + ((Instruct == DOR) && (~EXTADD)) || + (Instruct == OTPR)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct == QOR) && QUAD && (~EXTADD))) + begin + //Instruction + 3 Bytes Address + Dummy Byte + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes ; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (Instruct==FSTRD || Instruct==DOR || + Instruct == QOR) + begin + if (Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (Instruct==ECCRD) + begin + //Instruction + 4 Bytes Address + Dummy Byte + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE) + begin + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + //High order address bits are ignored + Address = {hiaddr_bytes[31:4],4'b0000}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((((Instruct==FSTRD4) || + (Instruct==DOR4) || + ((Instruct==FSTRD) && EXTADD) || + ((Instruct==DOR) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct==QOR4) && QUAD) || + ((Instruct==QOR) && QUAD && EXTADD)) + begin + //Instruction + 4 Bytes Address + Dummy Byte + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE) + begin + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + //High order address bits are ignored + Address = {8'b00000000,hiaddr_bytes[23:0]}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + begin + bus_cycle_state = DUMMY_BYTES; + end + end + end + else if ((Instruct==DIOR) && (~EXTADD) && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + //DUAL I/O High Performance Read(3 Bytes Addr) + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt + 1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/2) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i]=Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (((Instruct==DIOR4) || + ((Instruct==DIOR) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin //DUAL I/O High Performance Read(4Bytes Addr) + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt + 1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE/2) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = {8'b00000000,addr_bytes[23:0]}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct == QIOR) && (~EXTADD)) + begin + //QUAD I/O High Performance Read (3Bytes Address) + if (QUAD) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE/4) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + bus_cycle_state = STAND_BY; + end + else if ((Instruct==QIOR4) || ((Instruct==QIOR) + && EXTADD)) + begin + //QUAD I/O High Performance Read (4Bytes Addr) + if (QUAD) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt +1; + if (addr_cnt == 4*BYTE/4) + begin + addr_cnt =0; + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + //High order address bits are ignored + Address = {8'b00000000,hiaddr_bytes[23:0]}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else + bus_cycle_state = STAND_BY; + end + else if ((((Instruct==RD4) || (Instruct==PP4) || + (Instruct==SE4) ||(Instruct==PPBRD) || + (Instruct==DYBRD) ||(Instruct==DYBWR) || + (Instruct==PPBP) || (Instruct==P4E4) || + ((Instruct==READ) && EXTADD) || + ((Instruct==PP) && EXTADD) || + ((Instruct==P4E) && EXTADD) || + ((Instruct==SE) && EXTADD)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + (QUAD && (Instruct==QPP4 || + ((Instruct==QPP) && EXTADD)))) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 4*BYTE) + begin + for(i=31;i>=0;i=i-1) + begin + hiaddr_bytes[31-i] = Address_in[i]; + end + //High order address bits are ignored + Address = {8'b00000000,hiaddr_bytes[23:0]}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DATA_BYTES; + end + end + else if (((HOLDNeg_in && ~QUAD) || QUAD) && + (~EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DATA_BYTES; + end + end + end + else + begin + if ((Instruct==DDRFR) && (~EXTADD)) + //Fast DDR Read Mode + begin + Address_in[addr_cnt] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRFR4) || + ((Instruct==DDRFR) && EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct == DDRDIOR) && (~EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1]= SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRDIOR4) || + ((Instruct==DDRDIOR) && EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1] = SI_in; + if ((addr_cnt/2) <= 16) + begin + opcode_tmp[addr_cnt/2] = SI_in; + end + addr_cnt = addr_cnt + 1; + read_cnt = 0; + end + else if ((Instruct==DDRQIOR) && (~EXTADD) && QUAD) + begin //Quad I/O DDR Read Mode + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + opcode_tmp[addr_cnt/2] = SI_in; + addr_cnt = addr_cnt +1; + read_cnt = 0; + end + else if (QUAD && ((Instruct==DDRQIOR4) || + ((Instruct==DDRQIOR) && EXTADD))) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + opcode_tmp[addr_cnt/2] = SI_in; + addr_cnt = addr_cnt +1; + read_cnt = 0; + end + end + end + + MODE_BYTE : + begin + if (((Instruct==DIOR) || (Instruct == DIOR4)) + && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + mode_in[2*mode_cnt] = SO_in; + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + if (Latency_code == 0 || Latency_code == 3) + bus_cycle_state = DATA_BYTES; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if (((Instruct==QIOR) || (Instruct == QIOR4)) + && QUAD) + begin + mode_in[4*mode_cnt] = HOLDNeg_in; + mode_in[4*mode_cnt+1] = WPNeg_in; + mode_in[4*mode_cnt+2] = SO_in; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct == DDRFR) || (Instruct == DDRFR4)) + mode_in[2*mode_cnt] = SI_in; + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + mode_in[4*mode_cnt] = SO_in; + mode_in[4*mode_cnt+1] = SI_in; + end + else if (((Instruct==DDRQIOR) || (Instruct == DDRQIOR4)) + && QUAD) + begin + mode_in[0] = HOLDNeg_in; + mode_in[1] = WPNeg_in; + mode_in[2] = SO_in; + mode_in[3] = SI_in; + end + dummy_cnt = 0; + end + + DUMMY_BYTES : + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, start_dlp); + if (DOUBLE == 1'b1 && (hold_mode==0) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + if ((((Instruct==FSTRD) || (Instruct==FSTRD4) || + (Instruct==DOR) || (Instruct==DOR4) || + (Instruct==OTPR)) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + (((Instruct==QOR)||(Instruct==QOR4)) && QUAD)) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE) + begin + bus_cycle_state = DATA_BYTES; + end + end + + else if ((Instruct==DDRFR) || (Instruct==DDRFR4)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 3) && (dummy_cnt==1)) || + ((Latency_code == 0) && (dummy_cnt==2)) || + ((Latency_code == 1) && (dummy_cnt==4)) || + ((Latency_code == 2) && (dummy_cnt==5))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==5)) || + ((Latency_code == 1) && (dummy_cnt==6)) || + ((Latency_code == 2) && (dummy_cnt==7))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + else if (Instruct==RES) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == 3*BYTE) + bus_cycle_state = DATA_BYTES; + end + else if (Instruct==ECCRD) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE) + bus_cycle_state = DATA_BYTES; + end + else if ((Instruct == DIOR) || (Instruct == DIOR4) + && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 1) && (dummy_cnt==1)) || + ((Latency_code == 2) && (dummy_cnt==2))) + bus_cycle_state = DATA_BYTES; + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==5)) || + ((Latency_code == 2) && (dummy_cnt==6))) + bus_cycle_state = DATA_BYTES; + end + end + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + dummy_cnt = dummy_cnt + 1; + if (EHP) + begin + if (((Latency_code == 3) && (dummy_cnt==2)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==5)) || + ((Latency_code == 2) && (dummy_cnt==6))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else + begin + if (((Latency_code == 3) && (dummy_cnt==4)) || + ((Latency_code == 0) && (dummy_cnt==6)) || + ((Latency_code == 1) && (dummy_cnt==7)) || + ((Latency_code == 2) && (dummy_cnt==8))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + else if (((Instruct == QIOR) || (Instruct == QIOR4)) + && QUAD) + begin + dummy_cnt = dummy_cnt + 1; + if (((Latency_code == 3) && (dummy_cnt==1)) || + ((Latency_code == 0) && (dummy_cnt==4)) || + ((Latency_code == 1) && (dummy_cnt==4)) || + ((Latency_code == 2) && (dummy_cnt==5))) + begin + bus_cycle_state = DATA_BYTES; + end + end + else if (((Instruct==DDRQIOR) || (Instruct==DDRQIOR4)) + && QUAD) + begin + dummy_cnt = dummy_cnt + 1; + + if (((Latency_code == 3) && (dummy_cnt==3)) || + ((Latency_code == 0) && (dummy_cnt==6)) || + ((Latency_code == 1) && (dummy_cnt==7)) || + ((Latency_code == 2) && (dummy_cnt==8))) + begin + bus_cycle_state = DATA_BYTES; + end + end + end + + DATA_BYTES : + begin + + if (DOUBLE == 1'b1 && (hold_mode==0)) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + + if ((QUAD) && ((Instruct==QPP) || (Instruct == QPP4))) + begin + quad_nybble = {HOLDNeg_in, WPNeg_in, SO_in, SI_in}; + if (data_cnt > ((PageSize+1)*2-1)) + begin + //In case of quad mode and QPP, + //if more than 512 bytes are sent to the device + for(i=0;i<=(PageSize*2-1);i=i+1) + begin + quad_data_in[i] = quad_data_in[i+1]; + end + quad_data_in[(PageSize+1)*2-1] = quad_nybble; + data_cnt = data_cnt +1; + end + else + begin + if (quad_nybble !== 4'bZZZZ) + begin + quad_data_in[data_cnt] = quad_nybble; + end + data_cnt = data_cnt +1; + end + end + else if ((~QUADRD) && ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + if (data_cnt > ((PageSize+1)*8-1)) + begin + //In case of serial mode and PP, + //if more than PageSize are sent to the device + //previously latched data are discarded and last + //256/512 data bytes are guaranteed to be programmed + //correctly within the same page. + if (bit_cnt == 0) + begin + for(i=0;i<=(PageSize*BYTE-1);i=i+1) + begin + Data_in[i] = Data_in[i+8]; + end + end + Data_in[PageSize*BYTE + bit_cnt] = SI_in; + bit_cnt = bit_cnt + 1; + if (bit_cnt == 8) + begin + bit_cnt = 0; + end + data_cnt = data_cnt + 1; + end + else + begin + Data_in[data_cnt] = SI_in; + data_cnt = data_cnt + 1; + bit_cnt = 0; + end + end + end + endcase + end + end + + if (falling_edge_SCK_ipd) + begin + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + ADDRESS_BYTES : + begin + if (DOUBLE == 1'b1) + begin + if ((Instruct==DDRFR) && (~EXTADD)) + //Fast DDR Read Mode + begin + Address_in[addr_cnt] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct==DDRFR4) || + ((Instruct==DDRFR) && EXTADD)) + begin + Address_in[addr_cnt] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = {8'b00000000,addr_bytes[23:0]}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + else if ((Instruct == DDRDIOR) && (~EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1]= SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE/2) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + bus_cycle_state = DUMMY_BYTES; + end + end + else if ((Instruct==DDRDIOR4) || + ((Instruct==DDRDIOR) && EXTADD)) + begin //Dual I/O DDR Read Mode + Address_in[2*addr_cnt] = SO_in; + Address_in[2*addr_cnt+1] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE/2) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = {8'b00000000,addr_bytes[23:0]}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + if (EHP) + bus_cycle_state = MODE_BYTE; + else + begin + bus_cycle_state = DUMMY_BYTES; + if (DOUBLE == 1'b1 && (hold_mode==0) + && VDLR_reg != 8'b00000000) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + else if ((Instruct==DDRQIOR) && (~EXTADD) && QUAD) + begin //Quad I/O DDR Read Mode + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 3*BYTE/4) + begin + addr_cnt = 0; + for(i=23;i>=0;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + addr_bytes[31:24] = 8'b00000000; + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + else if (QUAD && ((Instruct==DDRQIOR4) || + ((Instruct==DDRQIOR) && EXTADD))) + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SO_in; + Address_in[4*addr_cnt+3] = SI_in; + if (addr_cnt != 0) + begin + addr_cnt = addr_cnt + 1; + end + read_cnt = 0; + if (addr_cnt == 4*BYTE/4) + begin + addr_cnt = 0; + for(i=31;i>=0;i=i-1) + begin + addr_bytes[31-i] = Address_in[i]; + end + Address = {8'b00000000,addr_bytes[23:0]}; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + end + end + + MODE_BYTE : + begin + if ((Instruct == DDRFR) || (Instruct == DDRFR4)) + begin + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, start_dlp); + if (DOUBLE == 1'b1 && (hold_mode==0) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4)) + begin + mode_in[4*mode_cnt+2] = SO_in; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, start_dlp); + if (DOUBLE == 1'b1 && (hold_mode==0) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + else if ((Instruct==DDRQIOR) || (Instruct==DDRQIOR4)) + begin + mode_in[4] = HOLDNeg_in; + mode_in[5] = WPNeg_in; + mode_in[6] = SO_in; + mode_in[7] = SI_in; + for(i=7;i>=0;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, start_dlp); + if (DOUBLE == 1'b1 && (hold_mode==0) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + + DATA_BYTES: + begin + if (hold_mode==0) + begin + if (DOUBLE == 1'b1 ) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + + end + else + begin + if ((Instruct==READ) || (Instruct==RD4) || + (Instruct==FSTRD)|| (Instruct==FSTRD4)|| + (Instruct==RDSR) || (Instruct==RDSR2) || + (Instruct==RDCR) || (Instruct==OTPR) || + (Instruct==DOR) || (Instruct==DOR4) || + (Instruct==DIOR)|| (Instruct==DIOR4)|| + (Instruct==ABRD) || (Instruct==BRRD) || + (Instruct==ASPRD)|| (Instruct==DYBRD) || + (Instruct==PPBRD)|| (Instruct == ECCRD) || + (Instruct==PASSRD)|| (Instruct==RDID)|| + (Instruct==RES) || (Instruct==REMS) || + (Instruct==PLBRD)|| (Instruct==DLPRD) || + (current_state == AUTOBOOT && + start_delay == 0) || + (((Instruct==QOR) || (Instruct==QIOR) || + (Instruct==QOR4) || + (Instruct==QIOR4)) && QUAD)) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + end + + DUMMY_BYTES: + begin + if (hold_mode==0) + begin + Return_DLP(Instruct, EHP, Latency_code, + dummy_cnt, start_dlp); + + if (DOUBLE == 1'b1 && VDLR_reg != 8'b00000000 && + start_dlp) + begin + read_out = 1'b1; + #10 read_out = 1'b0; + end + end + end + + endcase + end + end + + if (rising_edge_CSNeg_ipd) + begin + if (bus_cycle_state != DATA_BYTES) + begin + if (bus_cycle_state == ADDRESS_BYTES && opcode_tmp == 8'hFF) + begin + Instruct = MBR; + end + bus_cycle_state = STAND_BY; + end + else + begin + if (bus_cycle_state == DATA_BYTES) + begin + if (((mode_bytes[7:4] == 4'b1010) && + (Instruct==DIOR || Instruct==DIOR4 || + Instruct==QIOR || Instruct==QIOR4)) || + ((mode_bytes[7:4] == ~mode_bytes[3:0]) && + (Instruct == DDRFR || Instruct == DDRFR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4))) + bus_cycle_state = ADDRESS_BYTES; + else + bus_cycle_state = STAND_BY; + + case (Instruct) + WREN, + WRDI, + BE, + SE, + SE4, + P4E, + P4E4, + CLSR, + BRAC, + RESET, + PPBERS, + PPBP, + PLBWR, + PGSP, + PGRS, + ERSP, + ERRS: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 0) + write = 1'b0; + end + end + + WRR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + //If CS# is driven high after eight + //cycle,only the Status Register is + //written to. + begin + write = 1'b0; + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + end + end + else if (data_cnt == 16) + //After the 16th cycle both the + //Status and Configuration Registers + //are written to. + begin + write = 1'b0; + cfg_write = 1'b1; + for(i=0;i<=7;i=i+1) + begin + Status_reg1_in[i]= + Data_in[7-i]; + Config_reg1_in[i]= + Data_in[15-i]; + end + end + end + end + + PP, + PP4, + OTPP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt > 0) + begin + if ((data_cnt % 8) == 0) + begin + write = 1'b0; + for(i=0;i<=PageSize;i=i+1) + begin + for(j=7;j>=0;j=j-1) + begin + if ((Data_in[(i*8)+(7-j)]) + !== 1'bX) + begin + Byte_slv[j] = + Data_in[(i*8)+(7-j)]; + end + end + WByte[i] = Byte_slv; + end + + if (data_cnt > (PageSize+1)*BYTE) + Byte_number = PageSize; + else + Byte_number = + ((data_cnt/8) - 1); + end + end + end + end + + QPP, + QPP4: + begin + if (data_cnt >0) + begin + if ((data_cnt % 2) == 0) + begin + write = 1'b0; + quad_pg = 1'b0; + for(i=0;i<=PageSize;i=i+1) + begin + for(j=1;j>=0;j=j-1) + begin + Quad_slv = + quad_data_in[(i*2)+(1-j)]; + if (j==1) + Byte_slv[7:4] = Quad_slv; + else if (j==0) + Byte_slv[3:0] = Quad_slv; + end + WByte[i] = Byte_slv; + end + if (data_cnt > (PageSize+1)*2) + Byte_number = PageSize; + else + Byte_number = ((data_cnt/2)-1); + end + end + end + + ABWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 32) + begin + write = 1'b0; + for(j=0;j<=31;j=j+1) + begin + AutoBoot_reg_in[j] = Data_in[31-j]; + end + end + end + end + + BRWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + Bank_Addr_reg_in[j] = Data_in[7-j]; + end + end + end + end + + ASPP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 16) + begin + write = 1'b0; + for(j=0;j<=15;j=j+1) + begin + ASP_reg_in[j] = Data_in[15-j]; + end + end + end + end + + DYBWR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + DYBAR_in[j] = Data_in[7-j]; + end + end + end + end + + PNVDLR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + NVDLR_reg_in[j] = Data_in[7-j]; + end + end + end + end + + WVDLR: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 1'b0; + for(j=0;j<=7;j=j+1) + begin + VDLR_reg_in[j] = Data_in[7-j]; + end + end + end + end + + PASSP: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 64) + begin + write = 1'b0; + for(j=1;j<=8;j=j+1) + begin + for(k=1;k<=8;k=k+1) + begin + Password_reg_in[j*8-k] = + Data_in[8*(j-1)+k-1]; + end + end + end + end + end + + PASSU: + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 64) + begin + write = 1'b0; + for(j=1;j<=8;j=j+1) + begin + for(k=1;k<=8;k=k+1) + begin + PASS_TEMP[j*8-k] = + Data_in[8*(j-1)+k-1]; + end + end + end + end + end + endcase + end + end + end + end + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Page Program +/////////////////////////////////////////////////////////////////////////////// + time pob; + time elapsed_pgm; + time elapsed_tsu; + time start_pgm; + time start_tsu; + time duration_pgm; + time duration_tsu; + event pdone_event; + + always @(rising_edge_PSTART) + begin + if ((Instruct == PP) || (Instruct == PP4) || (Instruct == OTPP) || + (Instruct == QPP) || (Instruct == QPP4)) + if (PageSize == 255) + begin + pob = tdevice_PP_256; + end + else + begin + pob = tdevice_PP_512; + end + else + pob = tdevice_BP; + if ((rising_edge_PSTART) && PDONE) + begin + elapsed_pgm = 0; + duration_pgm = pob; + PDONE = 1'b0; + ->pdone_event; + start_pgm = $time; + end + end + + always @(posedge PGSUSP) + begin + if (PGSUSP && (~PDONE)) + begin + disable pdone_process; + elapsed_pgm = $time - start_pgm; + duration_pgm = pob - elapsed_pgm; + PDONE = 1'b0; + end + end + + always @(posedge PGRES) + begin + start_pgm = $time; + ->pdone_event; + end + + always @(pdone_event) + begin:pdone_process + PDONE = 1'b0; + #duration_pgm PDONE = 1'b1; + end + + always @(SI) + begin + if ((Instruct == PGSP) || (Instruct == PGRS) || + (Instruct == ERSP) || (Instruct == ERRS)) + begin + start_tsu = $time; + end + end + + always @(posedge SCK) + begin + if ((Instruct == PGSP) || (Instruct == PGRS) || + (Instruct == ERSP) || (Instruct == ERRS)) + begin + elapsed_tsu = $time - start_tsu; + duration_tsu = tdevice_TSU - elapsed_tsu; + if (duration_tsu > 0) + begin + TSU = 1'b0; + end + else + begin + TSU = 1'b1; + $display("Warning at", $time); + $display("tSU max time violation"); + end + end + end +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Write Status Register +/////////////////////////////////////////////////////////////////////////////// + time wob; + always @(posedge WSTART) + begin:wdone_process + wob = tdevice_WRR; + if (WSTART && WDONE) + begin + WDONE = 1'b0; + #wob WDONE = 1'b1; + end + end + +/////////////////////////////////////////////////////////////////////////////// +// Reset Timing +/////////////////////////////////////////////////////////////////////////////// + + time startlo; + time starthi; + time durationlo; + time durationhi; + + always @(negedge RSTNeg_in or Instruct) + begin + if (~RSTNeg_in) + begin + RST = 1'b1; + #200000 RST = 1'b0; // 200 ns + end + else if (Instruct == RESET) + begin + Reseted = 1'b0; + #10000 Reseted = 1'b1; // 10 ns + end + end + + always @(RST_in or rising_edge_Reseted) // Reset done,program terminated + begin + if ((RST_in && ~RST) || (rising_edge_Reseted)) + disable pdone_process; + disable edone_process; + disable wdone_process; + PDONE = 1'b1; + EDONE = 1'b1; + WDONE = 1'b1; + end + +/////////////////////////////////////////////////////////////////////////////// +// Timing control for the Bulk Erase +/////////////////////////////////////////////////////////////////////////////// + time seo; + time beo; + event edone_event; + time elapsed_ers; + time start_ers; + time duration_ers; + + always @(rising_edge_ESTART) + begin + if (UniformSec) + begin + seo = tdevice_SE256; + end + else + begin + seo = tdevice_SE64; + end + beo = tdevice_BE; + if ((rising_edge_ESTART) && EDONE) + begin + if (Instruct == BE) + begin + duration_ers = beo; + end + else + begin + duration_ers = seo; + end + elapsed_ers = 0; + EDONE = 1'b0; + ->edone_event; + start_ers = $time; + end + end + + always @(posedge ESUSP) + begin + if (ESUSP && (~EDONE)) + begin + disable edone_process; + elapsed_ers = $time - start_ers; + duration_ers = seo - elapsed_ers; + EDONE = 1'b0; + end + end + + always @(posedge ERES) + begin + if (ERES && (~EDONE)) + begin + start_ers = $time; + ->edone_event; + end + end + + always @(edone_event) + begin : edone_process + EDONE = 1'b0; + #duration_ers EDONE = 1'b1; + end + + /////////////////////////////////////////////////////////////////// + // Process for clock frequency determination + /////////////////////////////////////////////////////////////////// + always @(posedge SCK_ipd) + begin : clock_period + if (SCK_ipd) + begin + SCK_cycle = $time - prev_SCK; + prev_SCK = $time; + end + end + +// ///////////////////////////////////////////////////////////////////////// +// // Main Behavior Process +// // combinational process for next state generation +// ///////////////////////////////////////////////////////////////////////// + + reg rising_edge_PDONE = 1'b0; + reg rising_edge_EDONE = 1'b0; + reg rising_edge_WDONE = 1'b0; + reg falling_edge_write = 1'b0; + reg falling_edge_PPBERASE_in = 1'b0; + reg falling_edge_PASSULCK_in = 1'b0; + + integer i; + integer j; + + always @(rising_edge_PoweredUp or falling_edge_write or + falling_edge_RSTNeg or rising_edge_PDONE or rising_edge_WDONE or + rising_edge_EDONE or ERSSUSP_out_event or rising_edge_RSTNeg or + PRGSUSP_out_event or rising_edge_CSNeg_ipd or rising_edge_RST_out + or falling_edge_PPBERASE_in or falling_edge_PASSULCK_in or RST_out) + begin: StateGen1 + + integer sect; + + if (rising_edge_PoweredUp && RSTNeg_in && RST_out) + begin + if (ABE == 1 && RPME !== 0 ) + begin + next_state = AUTOBOOT; + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9], 9'b0}; + start_delay = AutoBoot_reg[8:1]; + start_autoboot = 0; + ABSD = AutoBoot_reg[8:1]; + end + else + next_state = IDLE; + end + else if (PoweredUp) + begin + if (RST_out == 1'b0) + next_state = current_state; + else if (falling_edge_write && Instruct == RESET) + begin + if (ABE == 1 && RPME !== 0) + begin + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9], 9'b0}; + start_delay = AutoBoot_reg[8:1]; + ABSD = AutoBoot_reg[8:1]; + start_autoboot = 0; + next_state = AUTOBOOT; + end + else + next_state = IDLE; + end + else + begin + case (current_state) + RESET_STATE : + begin + if ((rising_edge_RST_out && RSTNeg_in) || + (rising_edge_RSTNeg && RST_out)) + begin + if (ABE == 1 && RPME!== 0) + begin + next_state = AUTOBOOT; + read_cnt = 0; + byte_cnt = 1; + read_addr = {AutoBoot_reg[31:9],9'b0}; + start_delay = AutoBoot_reg[8:1]; + start_autoboot = 0; + ABSD = AutoBoot_reg[8:1]; + end + else + next_state = IDLE; + end + end + + IDLE : + begin + if (falling_edge_write && RdPswdProtMode == 0) + begin + if (Instruct == WRR && WEL == 1 && BAR_ACC == 0 + && (((~(SRWD == 1 && ~WPNeg_in))&& ~QUAD) || QUAD)) + // can not execute if HPM is entered or + // if WEL bit is zero + if (((TBPROT==1 && Config_reg1_in[5]==1'b0) || + (TBPARM==1 && Config_reg1_in[2]==1'b0) || + (BPNV ==1 && Config_reg1_in[3]==1'b0)) && + cfg_write) + begin + $display ("WARNING: Changing value of "); + $display ("Configuration Register OTP "); + $display ("bit from 1 to 0 is not"); + $display ("allowed!!!"); + end + else + begin + next_state = WRITE_SR; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("RFU bits are not allowed!!!"); + end + end + else if ((Instruct == PP || Instruct == QPP || + Instruct == PP4 || Instruct == QPP4) && + WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (Sec_Prot[sect]== 0 && PPB_bits[sect]== 1 && + DYB_bits[sect]== 1) + begin + next_state = PAGE_PG; + end + end + else if (Instruct==OTPP && WEL==1 && FREEZE==0) + begin + if (((((Address>=16'h0010 && Address<=16'h0013) + ||(Address>=16'h0020 && Address<=16'h00FF)) + && LOCK_BYTE1[Address/32] == 1) || + ((Address>=16'h0100 && Address<=16'h01FF) + && LOCK_BYTE2[(Address-16'h0100)/32]==1) || + ((Address>=16'h0200 && Address<=16'h02FF) + && LOCK_BYTE3[(Address-16'h0200)/32]==1) || + ((Address>=16'h0300 && Address<=16'h03FF) + && LOCK_BYTE4[(Address-16'h0300)/32] == 1)) + && (Address + Byte_number <= OTPHiAddr)) + next_state = OTP_PG; + end + else if ((Instruct == SE || Instruct == SE4) + && WEL == 1) + begin + ReturnSectorID(sect,Address); + if (UniformSec || (TopBoot && sect < 254) || + (BottomBoot && sect > 31)) + begin + if (Sec_Prot[sect]== 0 && PPB_bits[sect]== 1 + && DYB_bits[sect]== 1) + next_state = SECTOR_ERS; + end + else if ((TopBoot && sect >= 254) || + (BottomBoot && sect <= 31)) + begin + if (Sec_ProtSE == 32 && ASP_ProtSE == 32) + //Sector erase command is applied to a + //64 KB range that includes 4 KB sectors. + next_state = SECTOR_ERS; + end + end + else if ((Instruct == P4E || Instruct == P4E4) + && WEL == 1) + begin + if (UniformSec || (TopBoot && sect < 254) || + (BottomBoot && sect > 31)) + begin + $display("The instruction is applied to"); + $display("a sector that is larger than"); + $display("4 KB."); + $display("Instruction is ignored!!!"); + end + else + begin + if (Sec_Prot[sect]== 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + next_state = SECTOR_ERS; + end + end + else if (Instruct == BE && WEL == 1 && + (Status_reg1[4]== 0 && Status_reg1[3]== 0 && + Status_reg1[2]== 0)) + next_state = BULK_ERS; + else if (Instruct == ABWR && WEL == 1) + //Autoboot Register Write Command + next_state = AUTOBOOT_PG; + else if (Instruct == BRWR) + //Bank Register Write Command + next_state = IDLE; + else if (Instruct == ASPP && WEL == 1) + begin + //ASP Register Program Command + if (~(ASPOTPFLAG)) + next_state = ASP_PG; + end + else if (Instruct == PLBWR && WEL == 1 && + RdPswdProtEnable == 0) + next_state = PLB_PG; + else if (Instruct == PASSP && WEL == 1) + begin + if (~(PWDMLB== 0 && PSTMLB== 1)) + next_state = PASS_PG; + end + else if (Instruct == PASSU && WEL && ~WIP) + next_state = PASS_UNLOCK; + else if (Instruct == PPBP && WEL == 1) + next_state <= PPB_PG; + else if (Instruct == PPBERS && WEL && PPBOTP) + next_state <= PPB_ERS; + else if (Instruct == DYBWR && WEL == 1) + next_state = DYB_PG; + else if (Instruct == PNVDLR && WEL == 1) + next_state = NVDLR_PG; + else + next_state = IDLE; + end + if (falling_edge_write && RdPswdProtMode == 1 && ~WIP) + begin + if (Instruct == PASSU) + next_state = PASS_UNLOCK; + end + end + + AUTOBOOT : + begin + if (rising_edge_CSNeg_ipd) + next_state = IDLE; + end + + WRITE_SR : + begin + if (rising_edge_WDONE) + next_state = IDLE; + end + + PAGE_PG : + begin + if (PRGSUSP_out_event && PRGSUSP_out == 1) + next_state = PG_SUSP; + else if (rising_edge_PDONE) + next_state = IDLE; + end + + PG_SUSP : + begin + if (falling_edge_write) + begin + if (Instruct == BRWR) + //Bank Register Write Command + next_state = PG_SUSP; + else if (Instruct == PGRS) + next_state = PAGE_PG; + end + end + + OTP_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + BULK_ERS : + begin + if (rising_edge_EDONE) + next_state = IDLE; + end + + SECTOR_ERS : + begin + if (ERSSUSP_out_event && ERSSUSP_out == 1) + next_state = ERS_SUSP; + else if (rising_edge_EDONE) + next_state = IDLE; + end + + ERS_SUSP : + begin + if (falling_edge_write) + begin + if ((Instruct == PP || Instruct == QPP || + Instruct == PP4 || Instruct == QPP4) && + WEL == 1) + begin + if ((PARAM_REGION && + SectorSuspend != Address/(SecSize+1)) || + (~PARAM_REGION && SectorSuspend != + Address/(SecSize+1)+30*b_act)) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (PPB_bits[sect]== 1 && + DYB_bits[sect]== 1) + begin + next_state = ERS_SUSP_PG; + end + end + end + else if (Instruct == BRWR) + begin + //Bank Register Write Command + next_state = ERS_SUSP; + end + else if (Instruct == DYBWR && WEL == 1) + next_state = DYB_PG; + else if (Instruct == ERRS) + next_state = SECTOR_ERS; + end + end + + ERS_SUSP_PG : + begin + if (rising_edge_PDONE) + next_state = ERS_SUSP; + else if (PRGSUSP_out_event && PRGSUSP_out == 1) + next_state = ERS_SUSP_PG_SUSP; + end + + ERS_SUSP_PG_SUSP : + begin + if (rising_edge_PDONE) + next_state = ERS_SUSP; + if (falling_edge_write) + begin + if (Instruct == BRWR) + begin + next_state = ERS_SUSP_PG_SUSP; + end + else if (Instruct == PGRS) + begin + next_state = ERS_SUSP_PG; + end + end + end + + PASS_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PASS_UNLOCK : + begin + if (falling_edge_PASSULCK_in) + next_state = IDLE; + end + + PPB_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PPB_ERS : + begin + if (falling_edge_PPBERASE_in) + next_state = IDLE; + end + + AUTOBOOT_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + PLB_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + DYB_PG : + begin + if (rising_edge_PDONE) + if (ES) + next_state = ERS_SUSP; + else + next_state = IDLE; + end + + ASP_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + NVDLR_PG : + begin + if (rising_edge_PDONE) + next_state = IDLE; + end + + endcase + end + end + end + + /////////////////////////////////////////////////////////////////////////// + //FSM Output generation and general functionality + /////////////////////////////////////////////////////////////////////////// + reg rising_edge_read_out = 1'b0; + reg Instruct_event = 1'b0; + reg change_addr_event = 1'b0; + reg current_state_event = 1'b0; + reg rising_edge_DP_out = 1'b0; + + integer WData [0:511]; + integer WOTPData; + integer Addr; + integer Addr_tmp; + + always @(Instruct_event) + begin + read_cnt = 0; + byte_cnt = 1; + rd_fast = 1'b1; + dual = 1'b0; + rd_slow = 1'b0; + any_read = 1'b0; + end + + always @(rising_edge_read_out) + begin + if (rising_edge_read_out == 1'b1) + begin + if (PoweredUp == 1'b1) + begin + oe_z = 1'b1; + #1000 oe_z = 1'b0; + oe = 1'b1; + #1000 oe = 1'b0; + end + end + end + + always @(change_addr_event) + begin + if (change_addr_event) + begin + read_addr = Address; + end + end + + always @(posedge PASSACC_out) + begin + Status_reg1[0] = 1'b0; //WIP + PASSACC_in = 1'b0; + end + + always @(Instruct or posedge start_autoboot or oe or current_state_event or + falling_edge_write or posedge PDONE or posedge WDONE or oe_z or + posedge EDONE or ERSSUSP_out or rising_edge_Reseted or + rising_edge_PoweredUp or rising_edge_CSNeg_ipd or PRGSUSP_out or + Address) + begin: Functionality + integer i,j; + integer sect; + + if (rising_edge_PoweredUp) + begin + //the default condition after power-up + //The Bank Address Register is loaded to all zeroes + Bank_Addr_reg = 8'h0; + //The Configuration Register FREEZE bit is cleared. + Config_reg1[0] = 0; + //The WEL bit is cleared. + Status_reg1[1] = 0; + //When BPNV is set to '1'. the BP2-0 bits in Status Register are + //volatile and will be reset binary 111 after power-on reset + if (BPNV == 1 && FREEZE == 0 ) //&& LOCK == 0 + begin + Status_reg1[4] = 1'b0;// BP2 + Status_reg1[3] = 1'b0;// BP1 + Status_reg1[2] = 1'b0;// BP0 + BP_bits = {Status_reg1[4],Status_reg1[3],Status_reg1[2]}; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + + //As shipped from the factory, all devices default ASP to the + //Persistent Protection mode, with all sectors unprotected, + //when power is applied. The device programmer or host system must + //then choose which sector protection method to use. + //For Persistent Protection mode, PPBLOCK defaults to "1" + PPBL[0] = 1'b1; + + //All the DYB power-up in the unprotected state + DYB_bits = {286{1'b1}}; + end + + if (Instruct == RESET) + begin + //EXTADD is cleared to “0” + Bank_Addr_reg[7] = 1'b0; + //P_ERR bit is cleared + Status_reg1[6] = 1'b0; + //E_ERR bit is cleared + Status_reg1[5] = 1'b0; + //The WEL bit is cleared. + Status_reg1[1] = 1'b0; + //The WIP bit is cleared. + Status_reg1[0] = 1'b0; + //The ES bit is cleared. + Status_reg2[1] = 1'b0; + //The PS bit is cleared. + Status_reg2[0] = 1'b0; + //When BPNV is set to '1'. the BP2-0 bits in Status + //Register are volatile and will be reseted after + //reset command + if (BPNV == 1 && FREEZE == 0) //&& LOCK== 0 + begin + Status_reg1[4] = 1'b1; + Status_reg1[3] = 1'b1; + Status_reg1[2] = 1'b1; + + BP_bits = {Status_reg1[4],Status_reg1[3], + Status_reg1[2]}; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + end + + case (current_state) + IDLE : + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + ASP_ProtSE = 0; + Sec_ProtSE = 0; + + if (BottomBoot) + begin + for (j=31;j>=0;j=j-1) + begin + if (PPB_bits[j] == 1 && DYB_bits[j] == 1) + begin + ASP_ProtSE = ASP_ProtSE + 1; + end + if (Sec_Prot[j] == 0) + begin + Sec_ProtSE = Sec_ProtSE + 1; + end + end + end + else if (TopBoot) + begin + for (j=285;j>=254;j=j-1) + begin + if (PPB_bits[j] == 1 && DYB_bits[j] == 1) + begin + ASP_ProtSE = ASP_ProtSE + 1; + end + if (Sec_Prot[j] == 0) + begin + Sec_ProtSE = Sec_ProtSE + 1; + end + end + end + + if (falling_edge_write && RdPswdProtMode == 1) + begin + if(Instruct == PASSU) + begin + if (~WIP) + begin + PASSULCK_in = 1; + Status_reg1[0] = 1'b1; //WIP + end + else + begin + $display ("The PASSU command cannot be accepted"); + $display (" any faster than once every 100us"); + end + end + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + end + + if (falling_edge_write && RdPswdProtMode == 0) + begin + read_cnt = 0; + byte_cnt = 1; + if (Instruct == WREN) + Status_reg1[1] = 1'b1; + else if (Instruct == WRDI) + Status_reg1[1] = 0; + else if ((Instruct == WRR) && WEL == 1 && WDONE == 1 && + BAR_ACC == 0) + begin + if (((~(SRWD == 1 && ~WPNeg_in))&& ~QUAD) || QUAD) + begin + if (((TBPROT==1 && Config_reg1_in[5]==1'b0) || + (TBPARM==1 && Config_reg1_in[2]==1'b0) || + (BPNV ==1 && Config_reg1_in[3]==1'b0)) && + cfg_write) + begin + // P_ERR bit is set to 1 + Status_reg1[6] = 1'b1; + end + else + begin + // can not execute if Hardware Protection Mode + // is entered or if WEL bit is zero + WSTART = 1'b1; + WSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + end + else + Status_reg1[1] = 0; + end + else if ((Instruct == PP || Instruct == PP4) && WEL ==1 && + PDONE == 1 ) + begin + ReturnSectorID(sect,Address); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within a protected main memory sector + Status_reg1[6] = 1'b1; //P_ERR + Status_reg1[1] = 1'b0; //WEL + end + end + else if ((Instruct == QPP || Instruct == QPP4) && WEL ==1 && + PDONE == 1 ) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within a protected main memory sector + Status_reg1[6] = 1'b1; //P_ERR + Status_reg1[1] = 1'b0; //WEL + end + end + else if (Instruct == OTPP && WEL == 1) + begin + // As long as the FREEZE bit remains cleared to a logic + // '0' the OTP address space is programmable. + if (FREEZE == 0) + begin + if (((((Address>= 16'h0010 && Address<= 16'h0013) || + (Address >= 16'h0020 && Address <= 16'h00FF)) + && LOCK_BYTE1[Address/32] == 1) || + ((Address >= 16'h0100 && Address <= 16'h01FF) + && LOCK_BYTE2[(Address-16'h0100)/32] == 1) || + ((Address >= 16'h0200 && Address <= 16'h02FF) + && LOCK_BYTE3[(Address-16'h0200)/32] == 1) || + ((Address >= 16'h0300 && Address <= 16'h03FF) + && LOCK_BYTE4[(Address-16'h0300)/32] == 1)) && + (Address + Byte_number <= OTPHiAddr)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else if ((Address < 8'h10 || (Address > 8'h13 && + Address < 8'h20) || Address > 12'h3FF )) + begin + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + if (Address < 8'h20) + begin + $display ("Given address is "); + $display ("in reserved address range"); + end + else if (Address > 12'h3FF) + begin + $display ("Given address is "); + $display ("out of OTP address range"); + end + end + else + begin + //P_ERR bit will be set when the user attempts to + // to program within locked OTP region + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else + begin + //P_ERR bit will be set when the user attempts to + //to program within locked OTP region + Status_reg1[6] = 1'b1;//P_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else if ((Instruct == SE || Instruct == SE4) && WEL == 1) + begin + ReturnSectorID(sect,Address); + if (UniformSec || (TopBoot && sect < 254) || + (BottomBoot && sect > 31)) + begin + SectorSuspend = sect; + PARAM_REGION = 0; + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + Addr = Address; + end + else + begin + //E_ERR bit will be set when the user attempts to + //erase an individual protected main memory sector + Status_reg1[5] = 1'b1;//E_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + else if ((TopBoot && sect >= 254) || + (BottomBoot && sect <= 31)) + begin + if (Sec_ProtSE == 32 && ASP_ProtSE == 32) + //Sector erase command is applied to a 64 KB range + //that includes 4 KB sectors + begin + if (TopBoot) + begin + SectorSuspend = 254 + (285 - sect)/16; + end + else + begin + SectorSuspend = sect/16; + end + PARAM_REGION = 1; + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + Addr = Address; + end + else + begin + //E_ERR bit will be set when the user attempts to + //erase an individual protected main memory sector + Status_reg1[5] = 1'b1;//E_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + end + else if ((Instruct == P4E || Instruct == P4E4) && WEL == 1) + begin + ReturnSectorID(sect,Address); + if (UniformSec || (TopBoot && sect < 254) || + (BottomBoot && sect > 31)) + begin + Status_reg1[1] = 1'b0;//WEL + end + else + begin + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + //A P4E instruction applied to a sector + //that has been Write Protected through the + //Block Protect Bits or ASP will not be + //executed and will set the E_ERR status + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + Addr = Address; + end + else + begin + //E_ERR bit will be set when the user attempts to + //erase an individual protected main memory sector + Status_reg1[5] = 1'b1;//E_ERR + Status_reg1[1] = 1'b0;//WEL + end + end + end + else if (Instruct == BE && WEL == 1) + begin + if (Status_reg1[4]== 0 && Status_reg1[3]== 0 && + Status_reg1[2]== 0) + begin + ESTART = 1'b1; + ESTART <= #5 1'b0; + ESUSP = 0; + ERES = 0; + INITIAL_CONFIG = 1; + Status_reg1[0] = 1'b1; + end + else + begin + //The Bulk Erase command will not set E_ERR if a + //protected sector is found during the command + //execution. + Status_reg1[1] = 1'b0;//WEL + end + end + else if (Instruct == PASSP && WEL == 1) + begin + if (~(PWDMLB== 0 && PSTMLB== 1)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else + begin + $display ("Password programming is not allowed"); + $display (" in Password Protection Mode."); + end + end + else if (Instruct == PASSU && WEL) + begin + if (~WIP) + begin + PASSULCK_in = 1; + Status_reg1[0] = 1'b1; //WIP + end + else + begin + $display ("The PASSU command cannot be accepted"); + $display (" any faster than once every 100us"); + end + end + else if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + end + else if (Instruct == ASPP && WEL == 1) + begin + if (~(ASPOTPFLAG)) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + $display ("Once the Protection Mode is selected,"); + $display ("no further changes to the ASP "); + $display ("register is allowed."); + end + end + else if (Instruct == ABWR && WEL == 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PPBP && WEL == 1) + begin + ReturnSectorID(sect,Address); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PPBERS && WEL == 1) + begin + if (PPBOTP) + begin + PPBERASE_in = 1'b1; + Status_reg1[0] = 1'b1; + end + else + begin + Status_reg1[5] = 1'b1; + end + end + else if (Instruct == PLBWR && WEL == 1 && + RdPswdProtEnable == 0) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == DYBWR && WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == PNVDLR && WEL == 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == WVDLR && WEL == 1) + begin + VDLR_reg = VDLR_reg_in; + Status_reg1[1] = 1'b0; + end + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4 || + Instruct == RES || + (Instruct == DLPRD && RdPswdProtMode == 0)) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4 || + ((Instruct == DDRQIOR || Instruct == DDRQIOR4) + && QUAD)) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + ((Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + && QUAD)) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + else if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == ECCRD) + begin + //Read ECC Register + SOut_zd = ECCSR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if ((Instruct == DDRFR || Instruct == DDRFR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) is enabled + // Optional DLP + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + + end + else + begin + read_addr_tmp = read_addr; + SecAddr = read_addr/(SecSize+1) ; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + begin + read_addr = read_addr_tmp; + end + if (Mem[read_addr] !== -1) + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + end + else + begin + SOut_zd = 8'bx; + end + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((Instruct == DDRDIOR || Instruct == DDRDIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 0; + end + end + else + begin + read_addr_tmp = read_addr; + SecAddr = read_addr/(SecSize+1) ; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + read_addr = read_addr_tmp; + + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if ((Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + && QUAD) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) is enabled + // Optional DLP + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd = data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + read_addr_tmp = read_addr; + SecAddr = read_addr/(SecSize+1) ; + Sec_addr = read_addr - SecAddr*(SecSize+1); + SecAddr = ReturnSectorIDRdPswdMd(TBPROT); + read_addr = Sec_addr + SecAddr*(SecSize+1); + if (RdPswdProtMode == 0) + read_addr = read_addr_tmp; + + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == OTPR) + begin + if(read_addr>=OTPLoAddr && read_addr<=OTPHiAddr + && RdPswdProtMode == 0) + begin + //Read OTP Memory array + rd_fast = 1'b1; + rd_slow = 1'b0; + data_out[7:0] = OTPMem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else if ((read_addr > OTPHiAddr)||(RdPswdProtMode==1)) + begin + //OTP Read operation will not wrap to the + //starting address after the OTP address is at + //its maximum or Read Password Protection Mode + //is selected instead, the data beyond the + //maximum OTP address will be undefined. + SOut_zd = 1'bX; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (Instruct == REMS) + begin + //Read Manufacturer and Device ID + if (read_addr % 2 == 0) + begin + data_out[7:0] = Manuf_ID; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else + begin + data_out[7:0] = DeviceID; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = 0; + end + end + end + else if (Instruct == RDID) + begin + ident_out = CFI_array_tmp; + if(read_cnt < 648) + begin + SOut_zd = ident_out[647-read_cnt]; + read_cnt = read_cnt + 1; + end + else + begin + //Continued shifting of output beyond the end of + //the defined ID-CFI address space will + //provide undefined data. + SOut_zd = 1'bX; + end + end + else if (Instruct == RES) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + data_out = ESignature; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DLPRD && RdPswdProtMode == 0) + begin + //Read DLP + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = VDLR_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == ABRD && RdPswdProtMode == 0) + begin + //Read AutoBoot register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = AutoBoot_reg_in[31-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 32) + read_cnt = 0; + end + else if (Instruct == BRRD && RdPswdProtMode == 0) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == ASPRD && RdPswdProtMode == 0) + begin + //Read ASP Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = ASP_reg[15-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 16) + read_cnt = 0; + end + else if (Instruct == PASSRD && RdPswdProtMode == 0) + begin + //Read Password Register + if (~(PWDMLB == 0 && PSTMLB == 1)) + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = + Password_reg[(8*byte_cnt-1)-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + byte_cnt = byte_cnt + 1; + if (byte_cnt == 9) + byte_cnt = 1; + end + end + end + else if (Instruct == PLBRD) + begin + //Read PPB Lock Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = PPBL[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DYBRD) + begin + //Read DYB Access Register + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + DYBAR[7:0] = 8'bXXXXXXXX; + + if (RdPswdProtMode == 0) + begin + if (DYB_bits[sect] == 1) + DYBAR[7:0] = 8'hFF; + else + begin + DYBAR[7:0] = 8'h0; + end + end + SOut_zd = DYBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == PPBRD) + begin + //Read PPB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + PPBAR[7:0] = 8'bXXXXXXXX; + if (RdPswdProtMode == 0) + begin + if (PPB_bits[sect] == 1) + PPBAR[7:0] = 8'hFF; + else + begin + PPBAR[7:0] = 8'h0; + end + end + SOut_zd = PPBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + end + + AUTOBOOT: + begin + if (start_autoboot == 1) + begin + if (oe) + begin + any_read = 1'b1; + if (QUAD == 1) + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 104MHz + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 133MHz + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + end + else if (oe_z) + begin + if (QUAD == 1) + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 104MHz + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + end + else + begin + if (ABSD > 0) //If ABSD > 0, + begin //max SCK frequency is 133MHz + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + else // If ABSD = 0, max SCK frequency is 50 MHz + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + end + end + + WRITE_SR: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (WDONE == 1) + begin + Status_reg1[0] = 1'b0; //WIP + Status_reg1[1] = 1'b0; //WEL + //SRWD bit + Status_reg1[7] = Status_reg1_in[7]; //MSB first + +// if (LOCK == 0) +// begin + if (FREEZE == 0) + //The Freeze Bit, when set to 1, locks the current + //state of the BP2-0 bits in Status Register, + //the TBPROT and TBPARM bits in the Config Register + //As long as the FREEZE bit remains cleared to logic + //'0', the other bits of the Configuration register + //including FREEZE are writeable. + begin + Status_reg1[4] = Status_reg1_in[4];//BP2 + Status_reg1[3] = Status_reg1_in[3];//BP1 + Status_reg1[2] = Status_reg1_in[2];//BP0 + + BP_bits = {Status_reg1[4],Status_reg1[3], + Status_reg1[2]}; + if (TBPROT == 1'b0 && INITIAL_CONFIG == 1'b0) + begin + Config_reg1[5] = Config_reg1_in[5];//TBPROT + end + if (TBPARM == 1'b0 && INITIAL_CONFIG == 1'b0 && + tmp_char2 == "0") + begin + Config_reg1[2] = Config_reg1_in[2];//TBPARM + change_TBPARM = 1'b1; + #1000 change_TBPARM = 1'b0; + end + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end +// end + + Config_reg1[7] = Config_reg1_in[7];//LC1 + Config_reg1[6] = Config_reg1_in[6];//LC0 + Config_reg1[1] = Config_reg1_in[1];//QUAD + + if (FREEZE == 1'b0) + begin + Config_reg1[0] = Config_reg1_in[0];//FREEZE + end + +// if (WRLOCKENABLE== 1'b1 && LOCK == 1'b0) +// begin +// Config_reg1[4] = Config_reg1_in[4];//LOCK +// WRLOCKENABLE = 1'b0; +// end + if (BPNV == 1'b0) + begin + Config_reg1[3] = Config_reg1_in[3];//BPNV + end + end + end + + PAGE_PG : + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == PAGE_PG) + begin + if (~PDONE) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt = 0; + + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = Mem[Addr + i - cnt]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j]=1'b0; + end + new_int=new_bit; + end + WData[i]= new_int; + end + else + begin + WData[i] = -1; + end + + Mem[Addr + i - cnt] = - 1; + if ((Addr + i) == AddrHi) + begin + + Addr = AddrLo; + cnt = i + 1; + end + end + end + cnt = 0; + end + + if (PDONE) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + quad_pg = 0; + for (i=0;i<=wr_cnt;i=i+1) + begin + Mem[Addr_tmp + i - cnt] = WData[i]; + if ((Addr_tmp + i) == AddrHi) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + end + end + + if (Instruct) + begin + if (Instruct == PGSP && ~PRGSUSP_in) + begin + if (~RES_TO_SUSP_MIN_TIME) + begin + PGSUSP = 1'b1; + PGSUSP <= #5 1'b0; + PRGSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + else + begin + $display("Minimum for tPRS is not satisfied! ", + "PGSP command is ignored"); + end + end + end + end + + PG_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + + if (PRGSUSP_out && PRGSUSP_in) + begin + PRGSUSP_in = 1'b0; + //The RDY/BSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Program Suspend (PS) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[0] = 1'b1; + PDONE = 1'b1; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + //Read Array Operations + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if ((Instruct == DDRFR || Instruct == DDRFR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + + end + end + else + begin + SOut_zd = 8'bxxxxxxxx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if ((Instruct == DDRDIOR || Instruct == DDRDIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if (pgm_page != read_addr / (PageSize+1)) + begin + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) + // is enabled Optional DLP + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd= data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("RFU bits are not allowed!!!"); + end + end + else if (Instruct == PGRS) + begin + Status_reg2[0] = 1'b0; + Status_reg1[0] = 1'b1; + PGRES = 1'b1; + PGRES <= #5 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b1; + RES_TO_SUSP_MIN_TIME <= #60000 1'b0;//60 ns 3000000 ns = 3 us + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + ERS_SUSP_PG_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + + if (PRGSUSP_out && PRGSUSP_in) + begin + PRGSUSP_in = 1'b0; + //The RDY/BSY bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + //The Program Suspend (PS) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //program operation has been suspended. + Status_reg2[0] = 1'b1; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + //Read Array Operations + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if ((Instruct == DDRFR || Instruct == DDRFR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + + end + end + else + begin + SOut_zd = 8'bxxxxxxxx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if ((Instruct == DDRDIOR || Instruct == DDRDIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) + // is enabled Optional DLP + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((SectorSuspend != read_addr/(SecSize+1)) && + (pgm_page != read_addr / (PageSize+1))) + begin + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) + // is enabled Optional DLP + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd =data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("RFU bits are not allowed!!!"); + end + end + else if (Instruct == PGRS) + begin + Status_reg2[0] = 1'b0; + Status_reg1[0] = 1'b1; + PGRES = 1'b1; + PGRES <= #5 1'b0; + RES_TO_SUSP_MIN_TIME = 1'b1; + RES_TO_SUSP_MIN_TIME <= #60000 1'b0;//60 ns + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + OTP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == OTP_PG) + begin + if (~PDONE) + begin + if (Address + wr_cnt <= OTPHiAddr) + begin + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = OTPMem[Addr + i]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j] = 1'b0; + end + new_int = new_bit; + end + WData[i] = new_int; + end + else + begin + WData[i] = -1; + end + OTPMem[Addr + i] = -1; + end + end + else + begin + $display ("Programming will reach over "); + $display ("address limit of OTP array"); + end + end + end + + if (PDONE) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=0;i<=wr_cnt;i=i+1) + begin + OTPMem[Addr + i] = WData[i]; + end + LOCK_BYTE1 = OTPMem[16]; + LOCK_BYTE2 = OTPMem[17]; + LOCK_BYTE3 = OTPMem[18]; + LOCK_BYTE4 = OTPMem[19]; + end + end + + SECTOR_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == SECTOR_ERS) + begin + if (~EDONE) + begin + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = -1; + end + end + end + + if (EDONE == 1) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = MaxData; + + pgm_page = i / (PageSize+1); + end + end + else if (Instruct == ERSP && ~ERSSUSP_in) + begin + ESUSP = 1'b1; + ESUSP <= #5 1'b0; + ERSSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + end + + BULK_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == BULK_ERS) + begin + if (~EDONE) + begin + for (i=0;i<=AddrRANGE;i=i+1) + begin + ReturnSectorID(sect,i); + if (PPB_bits[sect] == 1 && DYB_bits[sect] == 1) + begin + Mem[i] = -1; + end + end + end + end + + if (EDONE == 1) + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + for (i=0;i<=AddrRANGE;i=i+1) + begin + ReturnSectorID(sect,i); + if (PPB_bits[sect] == 1 && DYB_bits[sect] == 1) + begin + Mem[i] = MaxData; + + pgm_page = i / (PageSize+1); + end + end + end + end + + ERS_SUSP: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (ERSSUSP_out == 1) + begin + ERSSUSP_in = 0; + //The Erase Suspend (ES) bit in the Status Register will + //be set to the logical “1” state to indicate that the + //erase operation has been suspended. + Status_reg2[1] = 1'b1; + //The WIP bit in the Status Register will indicate that + //the device is ready for another operation. + Status_reg1[0] = 1'b0; + end + + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == DYBRD) + begin + //Read DYB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (DYB_bits[sect] == 1) + DYBAR[7:0] = 8'hFF; + else + begin + DYBAR[7:0] = 8'h0; + end + SOut_zd = DYBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == BRRD) + begin + //Read Bank Address Register + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + SOut_zd = Bank_Addr_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == PPBRD) + begin + //Read PPB Access Register + ReturnSectorID(sect,Address); + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + PPBAR[7:0] = 8'bXXXXXXXX; + if (RdPswdProtMode == 0) + begin + if (PPB_bits[sect] == 1) + PPBAR[7:0] = 8'hFF; + else + begin + PPBAR[7:0] = 8'h0; + end + end + SOut_zd = PPBAR[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == RD4 || + Instruct == FSTRD || Instruct == FSTRD4 || + Instruct == DDRFR || Instruct == DDRFR4 ) + begin + //Read Memory array + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + if ((PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)+30*b_act)) + begin + if ((Instruct == DDRFR || Instruct == DDRFR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) + // is enabled Optional DLP + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == DDRDIOR || Instruct == DDRDIOR4 ) + begin + //Read Memory array + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)+30*b_act)) + begin + if ((Instruct == DDRDIOR || Instruct == DDRDIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) + // is enabled Optional DLP + data_out[7:0] = VDLR_reg; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else if (Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4 || + Instruct == DDRQIOR || Instruct == DDRQIOR4 ) + begin + //Read Memory array + if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + if ((PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != read_addr/(SecSize+1)+30*b_act)) + begin + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) && + (VDLR_reg != 8'b00000000) && start_dlp) + begin + // Data Learning Pattern (DLP) + // is enabled Optional DLP + data_out[7:0] = VDLR_reg; + HOLDNegOut_zd= data_out[7-read_cnt]; + WPNegOut_zd = data_out[7-read_cnt]; + SOut_zd = data_out[7-read_cnt]; + SIOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + start_dlp = 1'b0; + end + end + else + begin + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + else + begin + HOLDNegOut_zd = 1'bx; + WPNegOut_zd = 1'bx; + SOut_zd = 1'bx; + SIOut_zd = 1'bx; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + end + end + else if (oe_z) + begin + if (Instruct == READ || Instruct == RD4) + begin + rd_fast = 1'b0; + rd_slow = 1'b1; + dual = 1'b0; + ddr = 1'b0; + end + else if (Instruct == DDRFR || Instruct == DDRFR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b1; + end + else if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else if (Instruct == DOR || Instruct == DOR4 || + Instruct == DIOR || Instruct == DIOR4 || + Instruct == QOR || Instruct == QOR4 || + Instruct == QIOR || Instruct == QIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b0; + end + else if (Instruct == DDRQIOR || Instruct == DDRQIOR4) + begin + rd_fast = 1'b0; + rd_slow = 1'b0; + dual = 1'b1; + ddr = 1'b1; + end + else + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + end + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (falling_edge_write) + begin + if ((Instruct == PP || Instruct == PP4) && WEL == 1) + begin + if ((PARAM_REGION && + SectorSuspend != Address/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != Address/(SecSize+1)+30*b_act)) + begin + ReturnSectorID(sect,Address); + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else if ((Instruct == QPP || Instruct == QPP4) && WEL == 1) + begin + if ((PARAM_REGION && + SectorSuspend != Address/(SecSize+1)) || + (~PARAM_REGION && + SectorSuspend != Address/(SecSize+1)+30*b_act)) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + + if (Sec_Prot[sect] == 0 && + PPB_bits[sect]== 1 && DYB_bits[sect]== 1) + begin + PSTART = 1'b1; + PSTART <= #5 1'b0; + PGSUSP = 0; + PGRES = 0; + Status_reg1[0] = 1'b1; + SA = sect; + Addr = Address; + Addr_tmp= Address; + wr_cnt = Byte_number; + for (i=wr_cnt;i>=0;i=i-1) + begin + if (Viol != 0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else + begin + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; + end + end + else if (Instruct == WREN) + Status_reg1[1] = 1'b1; + else if (Instruct == CLSR) + begin + //The Clear Status Register Command resets bit SR1[5] + //(Erase Fail Flag) and bit SR1[6] (Program Fail Flag) + Status_reg1[5] = 0; + Status_reg1[6] = 0; + end + else if (Instruct == BRWR) + begin + Bank_Addr_reg[7] = Bank_Addr_reg_in[7]; + end + else if (Instruct == WRR && BAR_ACC == 1) + begin + // Write to the lower address bits of the BAR + if (P_ERR == 0 && E_ERR == 0) + begin + $display ("WARNING: Changing values of "); + $display ("Bank Address Register"); + $display ("RFU bits are not allowed!!!"); + end + end + else if (Instruct == DYBWR && WEL == 1) + begin + ReturnSectorID(sect,Address); + pgm_page = Address / (PageSize+1); + PSTART = 1'b1; + PSTART <= #5 1'b0; + Status_reg1[0] = 1'b1; + end + else if (Instruct == ERRS) + begin + Status_reg2[1] = 1'b0; + Status_reg1[0] = 1'b1; + if (BottomBoot) + begin + if (PARAM_REGION) + begin + Addr = SectorSuspend*(SecSize+1); + end + else + begin + Addr = (SectorSuspend-30)*(SecSize+1); + end + end + else + begin + Addr = SectorSuspend*(SecSize+1); + end + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + ERES = 1'b1; + ERES <= #5 1'b0; + RES_TO_SUSP_TYP_TIME = 1'b1; + RES_TO_SUSP_TYP_TIME <= #100000000 1'b0;//100us + end + + if (Instruct == BRAC && P_ERR == 0 && E_ERR == 0 && + RdPswdProtMode == 0) + begin + BAR_ACC = 1; + end + else + begin + BAR_ACC = 0; + end + end + end + + ERS_SUSP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if(current_state_event && current_state == ERS_SUSP_PG) + begin + if (~PDONE) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt = 0; + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = Mem[Addr + i - cnt]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j] = 1'b0; + end + new_int = new_bit; + end + WData[i] = new_int; + end + else + begin + WData[i] = -1; + end + + if ((Addr + i) == AddrHi) + begin + Addr = AddrLo; + cnt = i + 1; + end + end + end + cnt =0; + end + + if(PDONE == 1) + begin + Status_reg1[0] = 1'b0;//WIP + Status_reg1[1] = 1'b0;//WEL + for (i=0;i<=wr_cnt;i=i+1) + begin + Mem[Addr_tmp + i - cnt] = WData[i]; + if ((Addr_tmp + i) == AddrHi ) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + end + end + + if (Instruct) + begin + if (Instruct == PGSP && ~PRGSUSP_in) + begin + if (~RES_TO_SUSP_MIN_TIME) + begin + PGSUSP = 1'b1; + PGSUSP <= #5 1'b0; + PRGSUSP_in = 1'b1; + if (RES_TO_SUSP_TYP_TIME) + begin + $display("Typical periods are needed for ", + "Program to progress to completion"); + end + end + else + begin + $display("Minimum for tPRS is not satisfied! ", + "PGSP command is ignored"); + end + end + end + end + + PASS_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + new_pass = Password_reg_in; + old_pass = Password_reg; + for (i=0;i<=63;i=i+1) + begin + if (old_pass[j] == 0) + new_pass[j] = 0; + end + + if (PDONE == 1) + begin + Password_reg = new_pass; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + PASS_UNLOCK: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PASS_TEMP == Password_reg) + begin + PASS_UNLOCKED = 1'b1; + end + else + begin + PASS_UNLOCKED = 1'b0; + end + if (PASSULCK_out == 1'b1) + begin + if ((PASS_UNLOCKED == 1'b1) && (~PWDMLB)) + begin + PPBL[0] = 1'b1; + Status_reg1[0] = 1'b0; //WIP + end + else + begin + Status_reg1[6] = 1'b1; + $display ("Incorrect Password"); + PASSACC_in = 1'b1; + end + Status_reg1[1] = 1'b0; + PASSULCK_in = 1'b0; + end + end + + PPB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + if (PPB_LOCK !== 0) + begin + PPB_bits[sect]= 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + else + begin + Status_reg1[5] = 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + end + + PPB_ERS: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PPBERASE_out == 1'b1) + begin + if ((PPB_LOCK !== 0) && PPBOTP) + begin + PPB_bits = {286{1'b1}}; + end + else + begin + Status_reg1[5] = 1'b1; + end + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + PPBERASE_in = 1'b0; + end + end + + AUTOBOOT_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register 2 + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + for(i=0;i<=3;i=i+1) + for(j=0;j<=7;j=j+1) + AutoBoot_reg[i*8+j] = + AutoBoot_reg_in[(3-i)*8+j]; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + PLB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + PPBL[0] = 1'b0; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + DYB_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + DYBAR = DYBAR_in; + if (DYBAR == 8'hFF) + begin + DYB_bits[sect]= 1'b1; + end + else if (DYBAR == 8'h00) + begin + DYB_bits[sect]= 1'b0; + end + else + begin + Status_reg1[6] = 1'b1; + end + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + ASP_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + + if (RPME == 1'b0 && ASP_reg_in[5] == 1'b1) + begin + Status_reg1[6] = 1'b1; //P_ERR + $display("RPME bit is allready programmed"); + end + else + begin + ASP_reg[5] = ASP_reg_in[5];//RPME + end + + if (PPBOTP == 1'b0 && ASP_reg_in[3] == 1'b1) + begin + Status_reg1[6] = 1'b1; //P_ERR + $display("PPBOTP bit is allready programmed"); + end + else + begin + ASP_reg[3] = ASP_reg_in[3];//PPBOTP + end + + if (PWDMLB == 1'b1 && PSTMLB == 1'b1) + begin + if (ASP_reg_in[2] == 1'b0 && ASP_reg_in[1] == 1'b0) + begin + $display("ASPR[2:1] = 00 Illegal condition"); + Status_reg1[6] = 1'b1; //P_ERR + end + else + begin + if (ASP_reg_in[2]!==1'b1 || ASP_reg_in[1]!==1'b1) + begin + ASPOTPFLAG = 1'b1; + end + ASP_reg[2] = ASP_reg_in[2];//PWDMLB + ASP_reg[1] = ASP_reg_in[1];//PSTMLB + end + end + + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + end + + NVDLR_PG: + begin + rd_fast = 1'b1; + rd_slow = 1'b0; + dual = 1'b0; + ddr = 1'b0; + if (oe) + begin + any_read = 1'b1; + if (Instruct == RDSR) + begin + //Read Status Register 1 + SOut_zd = Status_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDSR2) + begin + //Read Status Register + SOut_zd = Status_reg2[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == RDCR) + begin + //Read Configuration Register 1 + SOut_zd = Config_reg1[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (oe_z) + begin + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + end + + if (PDONE) + begin + if (NVDLR_reg == 0) + begin + NVDLR_reg = NVDLR_reg_in; + VDLR_reg = NVDLR_reg_in; + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + end + else + begin + Status_reg1[0] = 1'b0; + Status_reg1[1] = 1'b0; + Status_reg1[6] = 1'b1; //P_ERR + $display("NVDLR bits allready programmed"); + end + end + end + + RESET_STATE: + begin + //the default condition hardware reset + //The Bank Address Register is loaded to all zeroes + Bank_Addr_reg = 8'h0; + if (BPNV && ~FREEZE) //&& ~LOCK + begin + Status_reg1[2] = 1'b1;// BP0 + Status_reg1[3] = 1'b1;// BP1 + Status_reg1[4] = 1'b1;// BP2 + BP_bits = 3'b111; + change_BP = 1'b1; + #1000 change_BP = 1'b0; + end + //Resets the volatile bits in the Status register 1 + Status_reg1[6] = 1'b0; + Status_reg1[5] = 1'b0; + Status_reg1[1] = 1'b0; + Status_reg1[0] = 1'b0; + //Resets the volatile bits in the Status register 2 + Status_reg2[1] = 1'b0; + Status_reg2[0] = 1'b0; + //Resets the volatile bits in the Configuration register 1 + Config_reg1[0] = 1'b0; + //On reset cycles the data pattern reverts back + //to what is in the NVDLR + VDLR_reg = NVDLR_reg; + start_dlp = 1'b0; + //Loads the Program Buffer with all ones + for(i=0;i<=511;i=i+1) + begin + WData[i] = MaxData; + end + if (~PWDMLB) + PPBL[0] = 1'b0; + else + PPBL[0] = 1'b1; + end + + endcase + + //Output Disable Control + if (CSNeg_ipd ) + begin + SOut_zd = 1'bZ; + SIOut_zd = 1'bZ; + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + end + end + + assign fast_rd = rd_fast; + assign rd = rd_slow; + assign ddrd = ddr && ~ddr80; + assign ddrd80 = ddr && ddr80; + assign fast_ddr = ddr_fast; + + always @(change_TBPARM, posedge PoweredUp) + begin + if (tmp_char2 == "0") + begin + if (TBPARM == 0) + begin + BottomBoot = 1; + b_act = 1; + end + else + begin + TopBoot = 1; + BottomBoot = 0; + b_act = 0; + end + end + else if (tmp_char2 == "1") + begin + UniformSec = 1; + end + end + + always @(posedge change_BP) + begin + case (Status_reg1[4:2]) + + 3'b000: + Sec_Prot[285:0] = {286{1'b0}}; + + 3'b001: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256:(SecNum256+1)*63/64] = 1'b1; + Sec_Prot[(SecNum256+1)*63/64-1 : 0] = {63{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/64-1 : 0] = 1'b1; + Sec_Prot[SecNum256 : (SecNum256+1)/64] = {63{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64:(SecNum64-29)*63/64] = {34{1'b1}}; + Sec_Prot[(SecNum64-29)*63/64-1 : 0] = {252{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/64-1 : 0] = {4{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/64] = {282{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64:(SecNum64-29)*63/64+30] = {4{1'b1}}; + Sec_Prot[(SecNum64-29)*63/64+29 : 0] = {282{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/64+29 : 0] = {34{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/64+30] = {252{1'b0}}; + end + end + end + + 3'b010: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*31/32] = {2{1'b1}}; + Sec_Prot[(SecNum256+1)*31/32-1 : 0] = {62{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/32-1 : 0] = {2{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/32] = {62{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*31/32] = {38{1'b1}}; + Sec_Prot[(SecNum64-29)*31/32-1 : 0] = {248{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/32-1 : 0] = {8{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/32] = {278{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64:(SecNum64-29)*31/32+30] = {8{1'b1}}; + Sec_Prot[(SecNum64-29)*31/32+29 : 0] = {278{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/32+29 : 0] = {38{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/32+30] = {248{1'b0}}; + end + end + end + + 3'b011: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*15/16] = 4'b1111; + Sec_Prot[(SecNum256+1)*15/16-1 : 0] = {60{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/16-1 : 0] = 4'b1111; + Sec_Prot[SecNum256 : (SecNum256+1)/16] = {60{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*15/16] = {46{1'b1}}; + Sec_Prot[(SecNum64-29)*15/16-1 : 0] = {240{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/16-1 : 0] = {16{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/16] = {270{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*15/16+30] ={16{1'b1}}; + Sec_Prot[(SecNum64-29)*15/16+29 : 0] = {270{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/16+29 : 0] ={46{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/16+30] = {240{1'b0}}; + end + end + end + + 3'b100: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*7/8] = {8{1'b1}}; + Sec_Prot[(SecNum256+1)*7/8-1 : 0] = {278{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/8-1 : 0] = {8{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/8] = {278{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*7/8] = {62{1'b1}}; + Sec_Prot[(SecNum64-29)*7/8-1 : 0] = {224{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/8-1 : 0] = {32{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/8] = {254{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*7/8+30] ={32{1'b1}}; + Sec_Prot[(SecNum64-29)*7/8+29 : 0] = {254{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/8+29 : 0] = {62{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/8+30] = {224{1'b0}}; + end + end + end + + 3'b101: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)*3/4] = {16{1'b1}}; + Sec_Prot[(SecNum256+1)*3/4-1 : 0] = {270{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/4-1 : 0] = {16{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/4] = {270{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*3/4] = {94{1'b1}}; + Sec_Prot[(SecNum64-29)*3/4-1 : 0] = {192{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/4-1 : 0] = {64{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/4] = {222{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)*3/4+30] = {64{1'b1}}; + Sec_Prot[(SecNum64-29)*3/4+29 : 0] = {222{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/4+29 : 0] = {94{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/4+30] = {192{1'b0}}; + end + end + end + + 3'b110: + begin + if (tmp_char2 == "1") + begin + if (~TBPROT) + begin + Sec_Prot[SecNum256 : (SecNum256+1)/2] = {32{1'b1}}; + Sec_Prot[(SecNum256+1)/2-1 : 0] = {32{1'b0}}; + end + else + begin + Sec_Prot[(SecNum256+1)/2-1 : 0] = {32{1'b1}}; + Sec_Prot[SecNum256 : (SecNum256+1)/2] = {32{1'b0}}; + end + end + else if (tmp_char2 == "0" && TBPARM == 1) + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)/2] = {158{1'b1}}; + Sec_Prot[(SecNum64-29)/2-1 : 0] = {128{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/2-1 : 0] = {128{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/2] = {158{1'b0}}; + end + end + else + begin + if (~TBPROT) + begin + Sec_Prot[SecNum64 : (SecNum64-29)/2+30] = {128{1'b1}}; + Sec_Prot[(SecNum64-29)/2+29 : 0] = {158{1'b0}}; + end + else + begin + Sec_Prot[(SecNum64-29)/2+29 : 0] = {158{1'b1}}; + Sec_Prot[SecNum64 : (SecNum64-29)/2+30] = {128{1'b0}}; + end + end + end + + 3'b111: + begin + Sec_Prot[SecNum64:0] = {286{1'b1}}; + end + endcase + end + + always @(SOut_zd or HOLDNeg_in or SIOut_zd) + begin + if (HOLDNeg_in == 0 && ~QUAD) + begin + hold_mode = 1'b1; + SIOut_z = 1'bZ; + SOut_z = 1'bZ; + end + else + begin + if (hold_mode == 1) + begin + SIOut_z <= #(tpd_HOLDNeg_SO) SIOut_zd; + SOut_z <= #(tpd_HOLDNeg_SO) SOut_zd; + hold_mode = #(tpd_HOLDNeg_SO) 1'b0; + end + else + begin + SIOut_z = SIOut_zd; + SOut_z = SOut_zd; + hold_mode = 1'b0; + end + end + end + + //////////////////////////////////////////////////////////////////////// + // autoboot control logic + //////////////////////////////////////////////////////////////////////// + always @(rising_edge_SCK_ipd or current_state_event) + begin + if(current_state == AUTOBOOT) + begin + if (rising_edge_SCK_ipd) + begin + if (start_delay > 0) + start_delay = start_delay - 1; + end + + if (start_delay == 0) + begin + start_autoboot = 1; + end + end + end + + //////////////////////////////////////////////////////////////////////// + // functions & tasks + //////////////////////////////////////////////////////////////////////// + // Procedure FDDR_DPL +task Return_DLP; + input integer Instruct; + input integer EHP; + input integer Latency_code; + input integer dummy_cnt; + inout start_dlp; + begin + if (Instruct == DDRFR || Instruct == DDRFR4) + begin + if (EHP) + begin + if (Latency_code == 1) + start_dlp = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 1) + start_dlp = 1'b1; + else if(Latency_code == 3 || Latency_code == 0) + begin + start_dlp = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is set during DPL mode"); + end + end + else + begin + + if (Latency_code == 3) + start_dlp = 1'b1; + else if (Latency_code == 0 && dummy_cnt >= 1) + start_dlp = 1'b1; + else if(Latency_code == 1 && dummy_cnt >= 2) + start_dlp = 1'b1; + else if(Latency_code == 2 && dummy_cnt >= 3) + start_dlp = 1'b1; + else + start_dlp = 1'b0; + end + end + if (Instruct == DDRDIOR || Instruct == DDRDIOR4) + begin + if (EHP) + begin + if (Latency_code == 1 && dummy_cnt >= 1) + start_dlp = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 2) + start_dlp = 1'b1; + else if( Latency_code == 3 || Latency_code == 0) + begin + start_dlp = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is set during DPL mode"); + end + else + start_dlp = 1'b0; + end + else + begin + if (Latency_code == 0 && dummy_cnt >= 2) + start_dlp = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + start_dlp = 1'b1; + else if(Latency_code == 2 && dummy_cnt >= 4) + start_dlp = 1'b1; + else + start_dlp = 1'b0; + end + end + if ((Instruct == DDRQIOR || Instruct == DDRQIOR4) && QUAD) + begin + if (EHP) + begin + if (Latency_code == 0 && dummy_cnt >= 2) + start_dlp = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + start_dlp = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 4) + start_dlp = 1'b1; + else if( Latency_code == 3) + begin + start_dlp = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is"); + $display("set during DPL mode"); + end + else + start_dlp = 1'b0; + + end + else + begin + if (Latency_code == 0 && dummy_cnt >= 2) + start_dlp = 1'b1; + else if (Latency_code == 1 && dummy_cnt >= 3) + start_dlp = 1'b1; + else if (Latency_code == 2 && dummy_cnt >= 4) + start_dlp = 1'b1; + else if( Latency_code == 3) + begin + start_dlp = 1'b0; + $display("Warning at", $time); + $display("Inappropriate latency is"); + $display("set during DPL mode"); + end + else + start_dlp = 1'b0; + end + end + end + endtask + + function integer ReturnSectorIDRdPswdMd; + input reg TBPROT; + begin + if(TBPROT == 0) + begin + ReturnSectorIDRdPswdMd = 0; + end + else + begin + if (UniformSec) + begin + ReturnSectorIDRdPswdMd = SecNum256; + end + else + begin + ReturnSectorIDRdPswdMd = 255; + end + end + end + endfunction + + // Procedure ADDRHILO_SEC + task ADDRHILO_SEC; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + if (tmp_char2 == "0") + begin + if (TBPARM == 0) + begin + if (Addr/(SecSize64+1) <= 1 && + (Instruct == P4E || Instruct == P4E4)) //4KB Sectors + begin + sector = Addr/(SecSize4+1); + AddrLOW = sector*(SecSize4+1); + AddrHIGH = sector*(SecSize4+1) + SecSize4; + end + else + begin + sector = Addr/(SecSize64+1); + AddrLOW = sector*(SecSize64+1); + AddrHIGH = sector*(SecSize64+1) + SecSize64; + end + end + else + begin + if (Addr/(SecSize64+1) >= 254 && + (Instruct == P4E || Instruct == P4E4)) //4KB Sectors + begin + sector = 254 + (Addr-(SecSize64+1)*254)/(SecSize4+1); + AddrLOW = 254*(SecSize64+1)+(sector-254)*(SecSize4+1); + AddrHIGH = 254*(SecSize64+1)+(sector-254)*(SecSize4+1) + + SecSize4; + end + else + begin + sector = Addr/(SecSize64+1); + AddrLOW = sector*(SecSize64+1); + AddrHIGH = sector*(SecSize64+1) + SecSize64; + end + end + end + else if (tmp_char2 == "1") + begin + sector = Addr/(SecSize256+1); + AddrLOW = sector*(SecSize256+1); + AddrHIGH = sector*(SecSize256+1) + SecSize256; + end + end + endtask + + // Procedure ADDRHILO_PG + task ADDRHILO_PG; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer page; + begin + page = Addr / (PageSize + 1); + AddrLOW = page * (PageSize + 1); + AddrHIGH = page * (PageSize + 1) + PageSize ; + end + endtask + + // Procedure ReturnSectorID + task ReturnSectorID; + inout sect; + input Address; + integer sect; + integer Address; + integer conv; + begin + if (tmp_char2 == "0") + begin + conv = Address / (SecSize64+1); + if (BottomBoot) + begin + if (conv <= 1) //4KB Sectors + begin + sect = Address/(SecSize4+1); + end + else + begin + sect = conv + 30; + end + end + else if (TopBoot) + begin + if (conv >= 254) //4KB Sectors + begin + sect = 254 + (Address-(SecSize64+1)*254)/(SecSize4+1); + end + else + begin + sect = conv; + end + end + end + else + begin + sect = Address/(SecSize256+1); + end + end + endtask + + always @(PPBL[0], ASP_reg) + begin + if (PPBL[0] == 0 && PWDMLB == 0 && RPME == 0 && RdPswdProtEnable) + begin + RdPswdProtMode = 1; + AutoBoot_reg[0] = 0;//AUTOBOOT is disabled when Read Password + end //Protection is enabled + else + begin + RdPswdProtMode = 0; + end + end + + /////////////////////////////////////////////////////////////////////////// + // edge controll processes + /////////////////////////////////////////////////////////////////////////// + + always @(posedge PoweredUp) + begin + rising_edge_PoweredUp = 1; + #1000 rising_edge_PoweredUp = 0; + end + + always @(posedge SCK_ipd) + begin + rising_edge_SCK_ipd = 1'b1; + #1000 rising_edge_SCK_ipd = 1'b0; + end + + always @(negedge SCK_ipd) + begin + falling_edge_SCK_ipd = 1'b1; + #1000 falling_edge_SCK_ipd = 1'b0; + end + + always @(posedge read_out) + begin + rising_edge_read_out = 1'b1; + #1000 rising_edge_read_out = 1'b0; + end + + always @(negedge write) + begin + falling_edge_write = 1; + #1000 falling_edge_write = 0; + end + + always @(posedge PRGSUSP_out) + begin + PRGSUSP_out_event = 1; + #1000 PRGSUSP_out_event = 0; + end + + always @(posedge ERSSUSP_out) + begin + ERSSUSP_out_event = 1; + #1000 ERSSUSP_out_event = 0; + end + + always @(posedge CSNeg_ipd) + begin + rising_edge_CSNeg_ipd = 1'b1; + #1000 rising_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge CSNeg_ipd) + begin + falling_edge_CSNeg_ipd = 1'b1; + #1000 falling_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge RSTNeg_in) + begin + falling_edge_RSTNeg = 1'b1; + #50000 falling_edge_RSTNeg = 1'b0; + end + + always @(posedge RSTNeg_in) + begin + rising_edge_RSTNeg = 1'b1; + #10000 rising_edge_RSTNeg = 1'b0; + end + + always @(negedge RST) + begin + falling_edge_RST = 1'b1; + #10000 falling_edge_RST = 1'b0; + end + + always @(posedge RST) + begin + rising_edge_RST = 1'b1; + #1000 rising_edge_RST = 1'b0; + end + + always @(posedge PDONE) + begin + rising_edge_PDONE = 1'b1; + #1000 rising_edge_PDONE = 1'b0; + end + + always @(posedge WDONE) + begin + rising_edge_WDONE = 1'b1; + #1000 rising_edge_WDONE = 1'b0; + end + + always @(posedge WSTART) + begin + rising_edge_WSTART = 1'b1; + #1000 rising_edge_WSTART = 1'b0; + end + + always @(posedge EDONE) + begin + rising_edge_EDONE = 1'b1; + #1000 rising_edge_EDONE = 1'b0; + end + + always @(posedge ESTART) + begin + rising_edge_ESTART = 1'b1; + #1000 rising_edge_ESTART = 1'b0; + end + + always @(posedge PSTART) + begin + rising_edge_PSTART = 1'b1; + #1000 rising_edge_PSTART = 1'b0; + end + + always @(posedge Reseted) + begin + rising_edge_Reseted = 1'b1; + #1000 rising_edge_Reseted = 1'b0; + end + + always @(negedge PASSULCK_in) + begin + falling_edge_PASSULCK_in = 1'b1; + #1000 falling_edge_PASSULCK_in = 1'b0; + end + + always @(negedge PPBERASE_in) + begin + falling_edge_PPBERASE_in = 1'b1; + #1000 falling_edge_PPBERASE_in = 1'b0; + end + + always @(Instruct) + begin + Instruct_event = 1'b1; + #1000 Instruct_event = 1'b0; + end + + always @(change_addr) + begin + change_addr_event = 1'b1; + #1000 change_addr_event = 1'b0; + end + + always @(next_state) + begin + next_state_event = 1'b1; + #1000 next_state_event = 1'b0; + end + + always @(current_state) + begin + current_state_event = 1'b1; + #1000 current_state_event = 1'b0; + end + + always @(posedge RST_out) + begin + rising_edge_RST_out = 1'b1; + #1000 rising_edge_RST_out = 1'b0; + end + +endmodule diff --git a/crush_example_freertos/sim/top_tb.v b/crush_example_freertos/sim/top_tb.v new file mode 100644 index 0000000..edc499e --- /dev/null +++ b/crush_example_freertos/sim/top_tb.v @@ -0,0 +1,68 @@ +/* This file implements a test that is able to execute programs stored on the + * host file system. + */ + +`default_nettype none + +`timescale 1ns/1ps + +module top_tb; + +reg clk; +reg btn_n; +reg btn1; +wire led1; +wire led2; +wire flash_sck; +wire flash_ssb; +wire flash_io0; +wire flash_io1; + +top dut( + .CLK(clk), + .BTN_N(btn_n), + .BTN1(btn1), + .LED1(led1), + .LED2(led2), + .FLASH_SCK(flash_sck), + .FLASH_SSB(flash_ssb), + .FLASH_IO0(flash_io0), + .FLASH_IO1(flash_io1) +); + +s25fl128s + #(.mem_file_name ("crush_freertos.data"), + .AddrRANGE (24'h2F_FFFF)) +flash + ( + .SCK (flash_sck), + .SI (flash_io0), + .CSNeg (flash_ssb), + .HOLDNeg (), //Internal pull-up + .WPNeg (), //Internal pull-up + .SO (flash_io1), + .RSTNeg (1'b1)); + +initial begin + btn_n = 0; + // Wait for flash to power up + #500_000 btn_n = 1; +end + +initial clk = 0; +always #80 clk <= !clk; + +initial btn1 = 0; +always #10_000_000 btn1 <= !btn1; + +initial begin + $dumpfile("top_freertos.vcd"); + $dumpvars(0); + + #(1_300_000_000) + + $display("finishing now"); + $finish; +end + +endmodule diff --git a/support/crush_support.core b/crush_testing/crush_testing.core similarity index 67% rename from support/crush_support.core rename to crush_testing/crush_testing.core index 1d27d0f..261a2cc 100644 --- a/support/crush_support.core +++ b/crush_testing/crush_testing.core @@ -1,7 +1,7 @@ CAPI=2: # vim:syntax=yaml: -name: ::crush_support:0.0.1 +name: ::crush_testing:0.0.1 filesets: sim_common: @@ -14,7 +14,3 @@ targets: default: &default filesets: - sim_common - tools: - icarus: - iverilog_options: - - "-gassertions" diff --git a/support/sim/fatal_assert.vh b/crush_testing/sim/fatal_assert.vh similarity index 100% rename from support/sim/fatal_assert.vh rename to crush_testing/sim/fatal_assert.vh diff --git a/crush_util/crush_util.core b/crush_util/crush_util.core new file mode 100644 index 0000000..0e3cc20 --- /dev/null +++ b/crush_util/crush_util.core @@ -0,0 +1,15 @@ +CAPI=2: +# vim:syntax=yaml: + +name: ::crush_util:0.0.1 + +filesets: + rtl: + files: + - rtl/gpio.v + file_type: verilogSource + +targets: + default: &default + filesets: + - rtl diff --git a/crush_example/rtl/gpio.v b/crush_util/rtl/gpio.v similarity index 100% rename from crush_example/rtl/gpio.v rename to crush_util/rtl/gpio.v diff --git a/data/verilator_waiver.vlt b/data/verilator_waiver.vlt index 32a5df7..aa6b488 100644 --- a/data/verilator_waiver.vlt +++ b/data/verilator_waiver.vlt @@ -30,5 +30,7 @@ lint_off -rule UNUSEDSIGNAL -file "*/sim/control.v" -match "Signal is not used: lint_off -rule UNUSEDSIGNAL -file "*/sim/control.v" -match "Signal is not used: 'we_i'" lint_off -file "*/yosys/ice40/cells_sim.v" +lint_off -file "*/simple_spi_top.v" lint_off -rule TIMESCALEMOD + diff --git a/doc/Implementation progress.ods b/doc/Implementation progress.ods index be8784d..851e911 100644 Binary files a/doc/Implementation progress.ods and b/doc/Implementation progress.ods differ diff --git a/requirements.txt b/requirements.txt index 857a2bd..ed9f0cc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.12 +# This file is autogenerated by pip-compile with Python 3.13 # by the following command: # # pip-compile @@ -84,8 +84,6 @@ ruamel-yaml==0.18.6 # via # riscv-config # riscv-isac -ruamel-yaml-clib==0.2.8 - # via ruamel-yaml simplesat==0.8.2 # via fusesoc six==1.16.0 diff --git a/script/init.sh b/script/init.sh index 467a5f1..54b711e 100755 --- a/script/init.sh +++ b/script/init.sh @@ -1,6 +1,12 @@ #!/usr/bin/env bash export YOSYS_DATDIR=$(yosys-config --datdir) + +rm -f fusesoc.conf +rm -rf fusesoc_libraries fusesoc library add --sync-type local crush crush fusesoc library add --sync-type local crush_example crush_example -fusesoc library add --sync-type local crush_support support +fusesoc library add --sync-type local crush_example_freertos crush_example_freertos +fusesoc library add --sync-type local crush_testing crush_testing +fusesoc library add --sync-type local crush_util crush_util +fusesoc library add fusesoc_cores https://github.com/fusesoc/fusesoc-cores diff --git a/simulate.yml b/simulate.yml deleted file mode 100644 index dc2f19f..0000000 --- a/simulate.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Simulate - -on: - workflow_call: - inputs: - project: - required: true - type: string - target: - required: true - type: string - -jobs: - simulate: - runs-on: ubuntu-22.04 - container: - image: barabas5532/crush-ci:4 - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - name: Set up python environment - run: | - python -m venv .venv - . .venv/bin/activate - python -m pip install -r requirements.txt - # Every step runs in its own shell. Activating the venv really just - # modifies the path. Persist the modified path, so that other steps - # also use the venv. - echo PATH=$PATH >> $GITHUB_ENV - - name: Run simulation - timeout-minutes: 1 - run: | - . script/init.sh - fusesoc run --target ${{ inputs.target }} --resolve-env-vars-early ${{ inputs.project }}