From 26f50b8528ef48d20de9fc741991052a2264249e Mon Sep 17 00:00:00 2001 From: YRabbit Date: Mon, 2 Sep 2024 19:12:14 +1000 Subject: [PATCH 1/2] Implement the UserFlash primitives. FLASH96K, FLASH64KZ, FLASH256K, and FLASH608K primitives are added. They have no fuses, but many wires. Examples of flash usage (erase, write and read) for Tangnano9k and Tangnano1k boards are given. Grug Huhler flash controller is used by agreement with the author. Signed-off-by: YRabbit --- apycula/chipdb.py | 117 +++++ apycula/gowin_pack.py | 16 +- examples/himbaechel/Makefile.himbaechel | 7 +- examples/himbaechel/dsp-alu54d.v | 2 +- examples/himbaechel/dsp-mult18x18.v | 2 +- examples/himbaechel/dsp-mult36x36.v | 2 +- examples/himbaechel/dsp-mult9x9.v | 2 +- examples/himbaechel/dsp-multaddalu18x18.v | 2 +- examples/himbaechel/dsp-multalu18x18.v | 2 +- examples/himbaechel/dsp-multalu36x18.v | 2 +- examples/himbaechel/dsp-padd18.v | 2 +- examples/himbaechel/dsp-padd9.v | 2 +- examples/himbaechel/femto-riscv-userflash.v | 446 ++++++++++++++++++ .../README.md | 0 .../alu54d.hex | 0 .../mult18x18.S | 2 +- .../mult18x18.hex | 0 .../mult36x36.S | 2 +- .../mult36x36.hex | 0 .../mult9x9.S | 2 +- .../mult9x9.hex | 0 .../multaddalu18x18.hex | 0 .../multalu18x18.hex | 0 .../multalu36x18.hex | 0 .../padd18.S | 2 +- .../padd18.hex | 0 .../padd9.S | 2 +- .../padd9.hex | 0 .../riscv-firmware/userflash-9k.hex | 384 +++++++++++++++ .../himbaechel/riscv-firmware/userflash.S | 192 ++++++++ examples/himbaechel/tangnano9k.cst | 2 - examples/himbaechel/uflash_controller.v | 283 +++++++++++ examples/himbaechel/userflash.v | 165 +++++++ 33 files changed, 1614 insertions(+), 26 deletions(-) create mode 100644 examples/himbaechel/femto-riscv-userflash.v rename examples/himbaechel/{riscv-dsp-firmware => riscv-firmware}/README.md (100%) rename examples/himbaechel/{riscv-dsp-firmware => riscv-firmware}/alu54d.hex (100%) rename examples/himbaechel/{riscv-dsp-firmware => riscv-firmware}/mult18x18.S (99%) rename examples/himbaechel/{riscv-dsp-firmware => riscv-firmware}/mult18x18.hex (100%) rename examples/himbaechel/{riscv-dsp-firmware => riscv-firmware}/mult36x36.S (99%) rename examples/himbaechel/{riscv-dsp-firmware => riscv-firmware}/mult36x36.hex (100%) rename examples/himbaechel/{riscv-dsp-firmware => riscv-firmware}/mult9x9.S (99%) rename examples/himbaechel/{riscv-dsp-firmware => riscv-firmware}/mult9x9.hex (100%) rename examples/himbaechel/{riscv-dsp-firmware => riscv-firmware}/multaddalu18x18.hex (100%) rename examples/himbaechel/{riscv-dsp-firmware => riscv-firmware}/multalu18x18.hex (100%) rename examples/himbaechel/{riscv-dsp-firmware => riscv-firmware}/multalu36x18.hex (100%) rename examples/himbaechel/{riscv-dsp-firmware => riscv-firmware}/padd18.S (99%) rename examples/himbaechel/{riscv-dsp-firmware => riscv-firmware}/padd18.hex (100%) rename examples/himbaechel/{riscv-dsp-firmware => riscv-firmware}/padd9.S (99%) rename examples/himbaechel/{riscv-dsp-firmware => riscv-firmware}/padd9.hex (100%) create mode 100644 examples/himbaechel/riscv-firmware/userflash-9k.hex create mode 100644 examples/himbaechel/riscv-firmware/userflash.S create mode 100644 examples/himbaechel/uflash_controller.v create mode 100644 examples/himbaechel/userflash.v diff --git a/apycula/chipdb.py b/apycula/chipdb.py index 570dea12..10982af2 100644 --- a/apycula/chipdb.py +++ b/apycula/chipdb.py @@ -1832,6 +1832,122 @@ def fse_create_bandgap(dev, device): dev.extra_func.setdefault((10, 18), {}).update( {'bandgap': {'wire': 'C1'}}) +def fse_create_userflash(dev, device, dat): + # dat[‘UfbIns’] and dat[‘UfbOuts’] judgement to describe the waste and waste UserFlash. + # The outputs are exactly 32 by the number of bits and they are always + # present, their positions correspond to bit indices - checked by + # selectively connecting the outputs to LEDs. + # The inputs depend on the Flash type - different types have different + # inputs, e.g. XY or RCP addressing is used etc. During experimental + # generation of images with input to button connection some inputs + # description could not be found in the table, such inputs will be + # specified here rigidly. + # Flash types (see UG295-1.4.3E_Gowin User Flash User Guide.pdf) + _flash_type = {'GW1N-1': 'FLASH96K', + 'GW1NZ-1': 'FLASH64KZ', + 'GW1N-4': 'FLASH256K', 'GW1NS-4': 'FLASH256K', + 'GW1N-9': 'FLASH608K', 'GW1N-9C': 'FLASH608K'} + if device not in _flash_type: + return + flash_type = _flash_type[device] + ins_type = 'XY' + if flash_type == 'FLASH96K': + ins_type = 'RC' + + # userflash has neither its own cell type nor fuses, so it is logical to make it extra func. + # use X0Y0 cell for convenience - a significant part of UserFlash pins are + # located there, it saves from creating unnecessary nodes + row, col = (0, 0) + dev.extra_func.setdefault((row, col), {}).update( + {'userflash': {'type': flash_type}}) + extra_func = dev.extra_func[(row, col)]['userflash'] + + + def make_port(r, c, wire, port, wire_type, pins): + if r == -1 or c == -1: + return + bel = Bel() + wire = wirenames[wire] + bel.portmap[port] = wire + if r - 1 != row or c - 1 != col : + create_port_wire(dev, row, col, r - row - 1, c - col - 1, bel, 'USERFLASH', port, wire, wire_type) + pins[port] = bel.portmap[port] + + # outputs + outs = extra_func.setdefault('outs', {}) + for i, desc in enumerate(dat.compat_dict['UfbOuts']): + port = f'DOUT{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'FLASH_OUT', outs) + + # inputs + ins = extra_func.setdefault('ins', {}) + # DIN first - we know there they are + for i, desc in enumerate(dat.compat_dict['UfbIns'][58:]): + port = f'DIN{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'FLASH_IN', ins) + + if ins_type == 'RC': + for i, desc in enumerate(dat.compat_dict['UfbIns'][21:27]): + port = f'RA{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'FLASH_IN', ins) + for i, desc in enumerate(dat.compat_dict['UfbIns'][27:33]): + port = f'CA{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'FLASH_IN', ins) + for i, desc in enumerate(dat.compat_dict['UfbIns'][33:39]): + port = f'PA{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'FLASH_IN', ins) + for i, desc in enumerate(dat.compat_dict['UfbIns'][39:43]): + port = f'MODE{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'FLASH_IN', ins) + for i, desc in enumerate(dat.compat_dict['UfbIns'][43:45]): + port = f'SEQ{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'FLASH_IN', ins) + for i, desc in enumerate(dat.compat_dict['UfbIns'][45:50]): + port = ['ACLK', 'PW', 'RESET', 'PE', 'OE'][i] + r, c, wire = desc + make_port(r, c, wire, port, 'FLASH_IN', ins) + for i, desc in enumerate(dat.compat_dict['UfbIns'][50:52]): + port = f'RMODE{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'FLASH_IN', ins) + for i, desc in enumerate(dat.compat_dict['UfbIns'][52:54]): + port = f'WMODE{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'FLASH_IN', ins) + for i, desc in enumerate(dat.compat_dict['UfbIns'][54:56]): + port = f'RBYTESEL{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'FLASH_IN', ins) + for i, desc in enumerate(dat.compat_dict['UfbIns'][56:58]): + port = f'WBYTESEL{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'FLASH_IN', ins) + else: + for i, desc in enumerate(dat.compat_dict['UfbIns'][:6]): + port = ['XE', 'YE', 'SE', 'PROG', 'ERASE', 'NVSTR'][i] + r, c, wire = desc + make_port(r, c, wire, port, 'FLASH_IN', ins) + for i, desc in enumerate(dat.compat_dict['UfbIns'][6:15]): + port = f'XADR{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'FLASH_IN', ins) + for i, desc in enumerate(dat.compat_dict['UfbIns'][15:21]): + port = f'YADR{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'FLASH_IN', ins) + + # XXX INUSEN - is observed to be connected to the VSS when USERFLASH is used + if flash_type != 'FLASH64KZ': + ins['INUSEN'] = 'C0' + + def fse_bram(fse, aux = False): bels = {} name = 'BSRAM' @@ -1970,6 +2086,7 @@ def from_fse(device, fse, dat: Datfile): fse_create_osc(dev, device, fse) fse_create_gsr(dev, device) fse_create_bandgap(dev, device) + fse_create_userflash(dev, device, dat) fse_create_logic2clk(dev, device, dat) disable_plls(dev, device) sync_extra_func(dev) diff --git a/apycula/gowin_pack.py b/apycula/gowin_pack.py index df1c0bdf..d81b73ed 100644 --- a/apycula/gowin_pack.py +++ b/apycula/gowin_pack.py @@ -185,7 +185,7 @@ def get_bits(init_data): def get_bels(data): later = [] if is_himbaechel: - belre = re.compile(r"X(\d+)Y(\d+)/(?:GSR|LUT|DFF|IOB|MUX|ALU|ODDR|OSC[ZFHWO]?|BUF[GS]|RAM16SDP4|RAM16SDP2|RAM16SDP1|PLL|IOLOGIC|CLKDIV2|CLKDIV|BSRAM|ALU|MULTALU18X18|MULTALU36X18|MULTADDALU18X18|MULT36X36|MULT18X18|MULT9X9|PADD18|PADD9|BANDGAP|DQCE|DCS)(\w*)") + belre = re.compile(r"X(\d+)Y(\d+)/(?:GSR|LUT|DFF|IOB|MUX|ALU|ODDR|OSC[ZFHWO]?|BUF[GS]|RAM16SDP4|RAM16SDP2|RAM16SDP1|PLL|IOLOGIC|CLKDIV2|CLKDIV|BSRAM|ALU|MULTALU18X18|MULTALU36X18|MULTADDALU18X18|MULT36X36|MULT18X18|MULT9X9|PADD18|PADD9|BANDGAP|DQCE|DCS|USERFLASH)(\w*)") else: belre = re.compile(r"R(\d+)C(\d+)_(?:GSR|SLICE|IOB|MUX2_LUT5|MUX2_LUT6|MUX2_LUT7|MUX2_LUT8|ODDR|OSC[ZFHWO]?|BUFS|RAMW|rPLL|PLLVR|IOLOGIC)(\w*)") @@ -1996,13 +1996,13 @@ def bin_str_to_dec(str_val): dec_num = int(bin_str[0], 2) return str(dec_num) return None - + _hclk_default_params ={"GSREN": "false", "DIV_MODE":"2"} def set_hclk_attrs(db, params, num, typ, cell_name): name_pattern = r'^_HCLK([0,1])_SECT([0,1])$' - params = dict(params or _hclk_default_params) + params = dict(params or _hclk_default_params) attrs = {} pattern_match = re.findall(name_pattern, num) if (not pattern_match): @@ -2013,21 +2013,21 @@ def set_hclk_attrs(db, params, num, typ, cell_name): if device in ["GW1N-1S","GW1N-2","GW1NR-2","GW1NS-4","GW1NS-4C","GW1NSR-4",\ "GW1NSR-4C","GW1NSER-4C","GW1N-9","GW1NR-9", "GW1N-9C","GW1NR-9C","GW1N-1P5"]: valid_div_modes.append("8") - + if (params["DIV_MODE"]) not in valid_div_modes: bin_match = bin_str_to_dec(params["DIV_MODE"]) if bin_match is None or bin_match not in valid_div_modes: raise Exception(f"Invalid DIV_MODE {bin_match or params['DIV_MODE']} for CLKDIV {cell_name} on device {device}") params["DIV_MODE"] = str(bin_match[0]) - + if (typ == "CLKDIV2"): attrs[f"BK{section_idx}MUX{hclk_idx}_OUTSEL"] = "DIV2" elif (typ == "CLKDIV"): - attrs[f"HCLKDIV{hclk_idx}_DIV"] = params["DIV_MODE"] + attrs[f"HCLKDIV{hclk_idx}_DIV"] = params["DIV_MODE"] if (section_idx == '1'): attrs[f"HCLKDCS{hclk_idx}_SEL"] = f"HCLKBK{section_idx}{hclk_idx}" - + fin_attrs = set() for attr, val in attrs.items(): if isinstance(val, str): @@ -2313,6 +2313,8 @@ def place(db, tilemap, bels, cst, args): pass elif typ == "BANDGAP": pass + elif typ.startswith("FLASH"): + pass elif typ.startswith('MUX2_'): pass elif typ == "BUFS": diff --git a/examples/himbaechel/Makefile.himbaechel b/examples/himbaechel/Makefile.himbaechel index 80925219..eef31be8 100644 --- a/examples/himbaechel/Makefile.himbaechel +++ b/examples/himbaechel/Makefile.himbaechel @@ -49,7 +49,7 @@ all: \ bsram-pROM-tangnano1k.fs bsram-SDPB-tangnano1k.fs bsram-DPB16-tangnano1k.fs \ bsram-SP-tangnano1k.fs bsram-pROMX9-tangnano1k.fs bsram-SDPX9B-tangnano1k.fs \ bsram-SPX9-tangnano1k.fs bsram-DPX9B18-tangnano1k.fs \ - dqce-tangnano1k.fs dcs-tangnano1k.fs \ + dqce-tangnano1k.fs dcs-tangnano1k.fs userflash-tangnano1k.fs \ \ blinky-tangnano4k.fs shift-tangnano4k.fs blinky-tbuf-tangnano4k.fs blinky-oddr-tangnano4k.fs \ blinky-osc-tangnano4k.fs tlvds-tangnano4k.fs elvds-tangnano4k.fs oddr-tlvds-tangnano4k.fs \ @@ -78,7 +78,7 @@ all: \ dsp-mult36x36-tangnano9k.fs dsp-padd9-tangnano9k.fs dsp-padd18-tangnano9k.fs \ dsp-mult9x9-tangnano9k.fs dsp-alu54d-tangnano9k.fs dsp-multalu18x18-tangnano9k.fs \ dsp-multalu36x18-tangnano9k.fs dsp-multaddalu18x18-tangnano9k.fs \ - dqce-tangnano9k.fs dcs-tangnano9k.fs \ + dqce-tangnano9k.fs dcs-tangnano9k.fs femto-riscv-userflash-tangnano9k.fs \ \ blinky-szfpga.fs shift-szfpga.fs blinky-tbuf-szfpga.fs blinky-oddr-szfpga.fs \ blinky-osc-szfpga.fs tlvds-szfpga.fs elvds-szfpga.fs oddr-tlvds-szfpga.fs \ @@ -314,6 +314,7 @@ bsram-%-tangnano1k-synth.json: pll/GW1NZ-1-dyn.vh %-image-rom.v %-video-ram.v %. %-pll-tangnano4k-synth.json: pll/GW1NS-4-dyn.vh %-pll-vr.v $(YOSYS) -D INV_BTN=0 -D LEDS_NR=6 -p "read_verilog $^; synth_gowin -json $@" + # ============================================================ # Tangnano9k (GW1N-9C) %-tangnano9k.fs: %-tangnano9k.json @@ -323,7 +324,7 @@ bsram-%-tangnano1k-synth.json: pll/GW1NZ-1-dyn.vh %-image-rom.v %-video-ram.v %. $(NEXTPNR) --json $< --write $@ --device GW1NR-LV9QN88PC6/I5 --vopt family=GW1N-9C --vopt cst=tangnano9k.cst %-tangnano9k-synth.json: %.v - $(YOSYS) -D LEDS_NR=6 -D OSC_TYPE_OSC -D INV_BTN=0 -D CPU_FREQ=27 -D BAUD_RATE=115200 -D NUM_HCLK=5 -p "read_verilog $^; synth_gowin -json $@" + $(YOSYS) -D LEDS_NR=6 -D OSC_TYPE_OSC -D INV_BTN=0 -D CPU_FREQ=27 -D BAUD_RATE=115200 -D NUM_HCLK=5 -D HAS_FLASH608K -p "read_verilog $^; synth_gowin -json $@" pll-nanolcd-tangnano9k-synth.json: pll/GW1N-9C-dyn.vh pll-nanolcd/TOP.v pll-nanolcd/VGAMod.v $(YOSYS) -D INV_BTN=0 -p "read_verilog $^; synth_gowin -json $@" diff --git a/examples/himbaechel/dsp-alu54d.v b/examples/himbaechel/dsp-alu54d.v index 3fa8b141..36cf2d21 100644 --- a/examples/himbaechel/dsp-alu54d.v +++ b/examples/himbaechel/dsp-alu54d.v @@ -96,6 +96,6 @@ ALU54D alu2( defparam alu2.ALU_RESET_MODE="SYNC"; endmodule -`define FIRMWARE "riscv-dsp-firmware/alu54d.hex" +`define FIRMWARE "riscv-firmware/alu54d.hex" `include "dsp-riscv.v" diff --git a/examples/himbaechel/dsp-mult18x18.v b/examples/himbaechel/dsp-mult18x18.v index 7b74a270..dc999c8a 100644 --- a/examples/himbaechel/dsp-mult18x18.v +++ b/examples/himbaechel/dsp-mult18x18.v @@ -143,6 +143,6 @@ defparam mult_4.SOA_REG=1'b0; defparam mult_4.MULT_RESET_MODE="SYNC"; endmodule -`define FIRMWARE "riscv-dsp-firmware/mult18x18.hex" +`define FIRMWARE "riscv-firmware/mult18x18.hex" `include "dsp-riscv.v" diff --git a/examples/himbaechel/dsp-mult36x36.v b/examples/himbaechel/dsp-mult36x36.v index 7181829f..f40693c7 100644 --- a/examples/himbaechel/dsp-mult36x36.v +++ b/examples/himbaechel/dsp-mult36x36.v @@ -49,6 +49,6 @@ module idsp(input wire clk, input wire reset, defparam mu_1.MULT_RESET_MODE="SYNC"; endmodule -`define FIRMWARE "riscv-dsp-firmware/mult36x36.hex" +`define FIRMWARE "riscv-firmware/mult36x36.hex" `include "dsp-riscv.v" diff --git a/examples/himbaechel/dsp-mult9x9.v b/examples/himbaechel/dsp-mult9x9.v index 3622f24f..678426c5 100644 --- a/examples/himbaechel/dsp-mult9x9.v +++ b/examples/himbaechel/dsp-mult9x9.v @@ -146,6 +146,6 @@ defparam mult_4.SOA_REG=1'b0; defparam mult_4.MULT_RESET_MODE="SYNC"; endmodule -`define FIRMWARE "riscv-dsp-firmware/mult9x9.hex" +`define FIRMWARE "riscv-firmware/mult9x9.hex" `include "dsp-riscv.v" diff --git a/examples/himbaechel/dsp-multaddalu18x18.v b/examples/himbaechel/dsp-multaddalu18x18.v index c0c15a13..106eb965 100644 --- a/examples/himbaechel/dsp-multaddalu18x18.v +++ b/examples/himbaechel/dsp-multaddalu18x18.v @@ -186,6 +186,6 @@ module idsp(input wire clk, input wire reset, defparam multaddalu_3.MULTADDALU18X18_MODE=2; endmodule -`define FIRMWARE "riscv-dsp-firmware/multaddalu18x18.hex" +`define FIRMWARE "riscv-firmware/multaddalu18x18.hex" `include "dsp-riscv.v" diff --git a/examples/himbaechel/dsp-multalu18x18.v b/examples/himbaechel/dsp-multalu18x18.v index b40e17fe..8684f0b9 100644 --- a/examples/himbaechel/dsp-multalu18x18.v +++ b/examples/himbaechel/dsp-multalu18x18.v @@ -177,6 +177,6 @@ module idsp(input wire clk, input wire reset, defparam multalu_4.MULTALU18X18_MODE=2; endmodule -`define FIRMWARE "riscv-dsp-firmware/multalu18x18.hex" +`define FIRMWARE "riscv-firmware/multalu18x18.hex" `include "dsp-riscv.v" diff --git a/examples/himbaechel/dsp-multalu36x18.v b/examples/himbaechel/dsp-multalu36x18.v index a7f29192..dc9b712b 100644 --- a/examples/himbaechel/dsp-multalu36x18.v +++ b/examples/himbaechel/dsp-multalu36x18.v @@ -152,6 +152,6 @@ module idsp(input wire clk, input wire reset, defparam multalu_4.MULTALU36X18_MODE=0; endmodule -`define FIRMWARE "riscv-dsp-firmware/multalu36x18.hex" +`define FIRMWARE "riscv-firmware/multalu36x18.hex" `include "dsp-riscv.v" diff --git a/examples/himbaechel/dsp-padd18.v b/examples/himbaechel/dsp-padd18.v index cd262702..03fee5b5 100644 --- a/examples/himbaechel/dsp-padd18.v +++ b/examples/himbaechel/dsp-padd18.v @@ -119,6 +119,6 @@ module idsp(input wire clk, input wire reset, defparam padd18_4.PADD_RESET_MODE="SYNC"; endmodule -`define FIRMWARE "riscv-dsp-firmware/padd18.hex" +`define FIRMWARE "riscv-firmware/padd18.hex" `include "dsp-riscv.v" diff --git a/examples/himbaechel/dsp-padd9.v b/examples/himbaechel/dsp-padd9.v index 1a99a45b..a7bce84f 100644 --- a/examples/himbaechel/dsp-padd9.v +++ b/examples/himbaechel/dsp-padd9.v @@ -121,6 +121,6 @@ module idsp(input wire clk, input wire reset, defparam padd_4.PADD_RESET_MODE="SYNC"; endmodule -`define FIRMWARE "riscv-dsp-firmware/padd9.hex" +`define FIRMWARE "riscv-firmware/padd9.hex" `include "dsp-riscv.v" diff --git a/examples/himbaechel/femto-riscv-userflash.v b/examples/himbaechel/femto-riscv-userflash.v new file mode 100644 index 00000000..f489dab9 --- /dev/null +++ b/examples/himbaechel/femto-riscv-userflash.v @@ -0,0 +1,446 @@ +/** + * Step 18: Creating a RISC-V processor + * Mandelbrot in the terminal + * + * Copyright (c) 2020, Bruno Levy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +`default_nettype none +`include "clockworks.v" +`include "emitter_uart.v" +`include "uflash_controller.v" + +module Memory ( + input clk, + input [31:0] mem_addr, // address to be read + output reg [31:0] mem_rdata, // data read from memory + input mem_rstrb, // goes high when processor wants to read + input [31:0] mem_wdata, // data to be written + input [3:0] mem_wmask // masks for writing the 4 bytes (1=write byte) +); + + reg [31:0] MEM [0:1535]; // 1536 4-bytes words = 6 Kb of RAM in total + + initial begin + $readmemh("riscv-firmware/userflash-9k.hex", MEM); + end + + localparam slow_bit=19; + + wire [29:0] word_addr = mem_addr[31:2]; + + always @(posedge clk) begin + if(mem_rstrb) begin + mem_rdata <= MEM[word_addr]; + end + if(mem_wmask[0]) MEM[word_addr][ 7:0 ] <= mem_wdata[ 7:0 ]; + if(mem_wmask[1]) MEM[word_addr][15:8 ] <= mem_wdata[15:8 ]; + if(mem_wmask[2]) MEM[word_addr][23:16] <= mem_wdata[23:16]; + if(mem_wmask[3]) MEM[word_addr][31:24] <= mem_wdata[31:24]; + end +endmodule + +module Processor ( + input clk, + input resetn, + output [31:0] mem_addr, + input [31:0] mem_rdata, + input wire mem_rready, + output mem_rstrb, + output [31:0] mem_wdata, + output [3:0] mem_wmask +); + + reg [31:0] PC=0; // program counter + reg [31:0] instr; // current instruction + + // See the table P. 105 in RISC-V manual + + // The 10 RISC-V instructions + wire isALUreg = (instr[6:0] == 7'b0110011); // rd <- rs1 OP rs2 + wire isALUimm = (instr[6:0] == 7'b0010011); // rd <- rs1 OP Iimm + wire isBranch = (instr[6:0] == 7'b1100011); // if(rs1 OP rs2) PC<-PC+Bimm + wire isJALR = (instr[6:0] == 7'b1100111); // rd <- PC+4; PC<-rs1+Iimm + wire isJAL = (instr[6:0] == 7'b1101111); // rd <- PC+4; PC<-PC+Jimm + wire isAUIPC = (instr[6:0] == 7'b0010111); // rd <- PC + Uimm + wire isLUI = (instr[6:0] == 7'b0110111); // rd <- Uimm + wire isLoad = (instr[6:0] == 7'b0000011); // rd <- mem[rs1+Iimm] + wire isStore = (instr[6:0] == 7'b0100011); // mem[rs1+Simm] <- rs2 + wire isSYSTEM = (instr[6:0] == 7'b1110011); // special + + // The 5 immediate formats + wire [31:0] Uimm={ instr[31], instr[30:12], {12{1'b0}}}; + wire [31:0] Iimm={{21{instr[31]}}, instr[30:20]}; + wire [31:0] Simm={{21{instr[31]}}, instr[30:25],instr[11:7]}; + wire [31:0] Bimm={{20{instr[31]}}, instr[7],instr[30:25],instr[11:8],1'b0}; + wire [31:0] Jimm={{12{instr[31]}}, instr[19:12],instr[20],instr[30:21],1'b0}; + + // Source and destination registers + wire [4:0] rs1Id = instr[19:15]; + wire [4:0] rs2Id = instr[24:20]; + wire [4:0] rdId = instr[11:7]; + + // function codes + wire [2:0] funct3 = instr[14:12]; + wire [6:0] funct7 = instr[31:25]; + + // The registers bank +`ifdef FORCE_BRAM + (* ram_style = "block" *) +`endif + reg [31:0] RegisterBank [0:31]; + reg [31:0] rs1; // value of source + reg [31:0] rs2; // registers. + wire [31:0] writeBackData; // data to be written to rd + wire writeBackEn; // asserted if data should be written to rd + + // The ALU + wire [31:0] aluIn1 = rs1; + wire [31:0] aluIn2 = isALUreg | isBranch ? rs2 : Iimm; + + wire [4:0] shamt = isALUreg ? rs2[4:0] : instr[24:20]; // shift amount + + // The adder is used by both arithmetic instructions and JALR. + wire [31:0] aluPlus = aluIn1 + aluIn2; + + // Use a single 33 bits subtract to do subtraction and all comparisons + // (trick borrowed from swapforth/J1) + wire [32:0] aluMinus = {1'b1, ~aluIn2} + {1'b0,aluIn1} + 33'b1; + wire LT = (aluIn1[31] ^ aluIn2[31]) ? aluIn1[31] : aluMinus[32]; + wire LTU = aluMinus[32]; + wire EQ = (aluMinus[31:0] == 0); + + // Flip a 32 bit word. Used by the shifter (a single shifter for + // left and right shifts, saves silicium !) + function [31:0] flip32; + input [31:0] x; + flip32 = {x[ 0], x[ 1], x[ 2], x[ 3], x[ 4], x[ 5], x[ 6], x[ 7], + x[ 8], x[ 9], x[10], x[11], x[12], x[13], x[14], x[15], + x[16], x[17], x[18], x[19], x[20], x[21], x[22], x[23], + x[24], x[25], x[26], x[27], x[28], x[29], x[30], x[31]}; + endfunction + + wire [31:0] shifter_in = (funct3 == 3'b001) ? flip32(aluIn1) : aluIn1; + + /* verilator lint_off WIDTH */ + wire [31:0] shifter = + $signed({instr[30] & aluIn1[31], shifter_in}) >>> aluIn2[4:0]; + /* verilator lint_on WIDTH */ + + wire [31:0] leftshift = flip32(shifter); + + + + // ADD/SUB/ADDI: + // funct7[5] is 1 for SUB and 0 for ADD. We need also to test instr[5] + // to make the difference with ADDI + // + // SRLI/SRAI/SRL/SRA: + // funct7[5] is 1 for arithmetic shift (SRA/SRAI) and + // 0 for logical shift (SRL/SRLI) + reg [31:0] aluOut; + always @(*) begin + case(funct3) + 3'b000: aluOut = (funct7[5] & instr[5]) ? aluMinus[31:0] : aluPlus; + 3'b001: aluOut = leftshift; + 3'b010: aluOut = {31'b0, LT}; + 3'b011: aluOut = {31'b0, LTU}; + 3'b100: aluOut = (aluIn1 ^ aluIn2); + 3'b101: aluOut = shifter; + 3'b110: aluOut = (aluIn1 | aluIn2); + 3'b111: aluOut = (aluIn1 & aluIn2); + endcase + end + + // The predicate for branch instructions + reg takeBranch; + always @(*) begin + case(funct3) + 3'b000: takeBranch = EQ; + 3'b001: takeBranch = !EQ; + 3'b100: takeBranch = LT; + 3'b101: takeBranch = !LT; + 3'b110: takeBranch = LTU; + 3'b111: takeBranch = !LTU; + default: takeBranch = 1'b0; + endcase + end + + + // Address computation + // An adder used to compute branch address, JAL address and AUIPC. + // branch->PC+Bimm AUIPC->PC+Uimm JAL->PC+Jimm + // Equivalent to PCplusImm = PC + (isJAL ? Jimm : isAUIPC ? Uimm : Bimm) + wire [31:0] PCplusImm = PC + ( instr[3] ? Jimm[31:0] : + instr[4] ? Uimm[31:0] : + Bimm[31:0] ); + wire [31:0] PCplus4 = PC+4; + + // register write back + assign writeBackData = (isJAL || isJALR) ? PCplus4 : + isLUI ? Uimm : + isAUIPC ? PCplusImm : + isLoad ? LOAD_data : + aluOut; + + wire [31:0] nextPC = ((isBranch && takeBranch) || isJAL) ? PCplusImm : + isJALR ? {aluPlus[31:1],1'b0} : + PCplus4; + + wire [31:0] loadstore_addr = rs1 + (isStore ? Simm : Iimm); + + // Load + // All memory accesses are aligned on 32 bits boundary. For this + // reason, we need some circuitry that does unaligned halfword + // and byte load/store, based on: + // - funct3[1:0]: 00->byte 01->halfword 10->word + // - mem_addr[1:0]: indicates which byte/halfword is accessed + + wire mem_byteAccess = funct3[1:0] == 2'b00; + wire mem_halfwordAccess = funct3[1:0] == 2'b01; + + + wire [15:0] LOAD_halfword = + loadstore_addr[1] ? mem_rdata[31:16] : mem_rdata[15:0]; + + wire [7:0] LOAD_byte = + loadstore_addr[0] ? LOAD_halfword[15:8] : LOAD_halfword[7:0]; + + // LOAD, in addition to funct3[1:0], LOAD depends on: + // - funct3[2] (instr[14]): 0->do sign expansion 1->no sign expansion + wire LOAD_sign = + !funct3[2] & (mem_byteAccess ? LOAD_byte[7] : LOAD_halfword[15]); + + wire [31:0] LOAD_data = + mem_byteAccess ? {{24{LOAD_sign}}, LOAD_byte} : + mem_halfwordAccess ? {{16{LOAD_sign}}, LOAD_halfword} : + mem_rdata ; + + // Store + // ------------------------------------------------------------------------ + + assign mem_wdata[ 7: 0] = rs2[7:0]; + assign mem_wdata[15: 8] = loadstore_addr[0] ? rs2[7:0] : rs2[15: 8]; + assign mem_wdata[23:16] = loadstore_addr[1] ? rs2[7:0] : rs2[23:16]; + assign mem_wdata[31:24] = loadstore_addr[0] ? rs2[7:0] : + loadstore_addr[1] ? rs2[15:8] : rs2[31:24]; + + // The memory write mask: + // 1111 if writing a word + // 0011 or 1100 if writing a halfword + // (depending on loadstore_addr[1]) + // 0001, 0010, 0100 or 1000 if writing a byte + // (depending on loadstore_addr[1:0]) + + wire [3:0] STORE_wmask = + mem_byteAccess ? + (loadstore_addr[1] ? + (loadstore_addr[0] ? 4'b1000 : 4'b0100) : + (loadstore_addr[0] ? 4'b0010 : 4'b0001) + ) : + mem_halfwordAccess ? + (loadstore_addr[1] ? 4'b1100 : 4'b0011) : + 4'b1111; + + // The state machine + localparam FETCH_INSTR = 0; + localparam WAIT_INSTR = 1; + localparam FETCH_REGS = 2; + localparam EXECUTE = 3; + localparam LOAD = 4; + localparam WAIT_DATA = 5; + localparam STORE = 6; + reg [2:0] state = FETCH_INSTR; + + always @(posedge clk) begin + if(!resetn) begin + PC <= 0; + state <= FETCH_INSTR; + end else begin + if(writeBackEn && rdId != 0) begin + RegisterBank[rdId] <= writeBackData; + end + case(state) + FETCH_INSTR: begin + state <= WAIT_INSTR; + end + WAIT_INSTR: begin + instr <= mem_rdata; + state <= FETCH_REGS; + end + FETCH_REGS: begin + rs1 <= RegisterBank[rs1Id]; + rs2 <= RegisterBank[rs2Id]; + state <= EXECUTE; + end + EXECUTE: begin + if(!isSYSTEM) begin + PC <= nextPC; + end + state <= isLoad ? LOAD : + isStore ? STORE : + FETCH_INSTR; + end + LOAD: begin + state <= WAIT_DATA; + end + WAIT_DATA: begin + if (mem_rready) begin + state <= FETCH_INSTR; + end + end + STORE: begin + state <= WAIT_DATA; + //state <= FETCH_INSTR; + end + endcase + end + end + + assign writeBackEn = (state==EXECUTE && !isBranch && !isStore) || + (state==WAIT_DATA) ; + + assign mem_addr = (state == WAIT_INSTR || state == FETCH_INSTR) ? + PC : loadstore_addr ; + assign mem_rstrb = (state == FETCH_INSTR || state == LOAD); + assign mem_wmask = {4{(state == STORE)}} & STORE_wmask; + +endmodule + + +module top ( + input clk_i, // system clock + input rst_i, // reset button + output [5:0] led, // system LEDs + input RXD, // UART receive + output TXD // UART transmit +); + + wire clk; + wire resetn; + + wire [31:0] mem_addr; + wire [31:0] mem_rdata; + wire mem_rready; + wire mem_rstrb; + wire [31:0] mem_wdata; + wire [3:0] mem_wmask; + + Processor CPU( + .clk(clk), + .resetn(resetn), + .mem_addr(mem_addr), + .mem_rdata(mem_rdata), + .mem_rready(mem_rready), + .mem_rstrb(mem_rstrb), + .mem_wdata(mem_wdata), + .mem_wmask(mem_wmask) + ); + + wire [31:0] RAM_rdata; + wire [29:0] mem_wordaddr = mem_addr[31:2]; + wire isUserFlash = mem_addr[23:22] == 2'b10; + wire isIO = mem_addr[23:22] == 2'b01; + wire isRAM = mem_addr[23:22] == 2'b00; + wire mem_wstrb = |mem_wmask; + + Memory RAM( + .clk(clk), + .mem_addr(mem_addr), + .mem_rdata(RAM_rdata), + .mem_rstrb(isRAM & mem_rstrb), + .mem_wdata(mem_wdata), + .mem_wmask({4{isRAM}}&mem_wmask) + ); + + // UserFlash + wire [31:0] UserFlash_rdata; + wire UserFlash_ready; + wire UserFlash_strob = isUserFlash & (mem_wstrb | mem_rstrb); + uflash UserFlash( + .reset_n(resetn), + .clk(clk), + .sel(UserFlash_strob), + .wstrb(mem_wmask), + .addr(mem_wordaddr[14:0]), + .data_i(mem_wdata), + .ready(UserFlash_ready), + .data_o(UserFlash_rdata) + ); + defparam UserFlash.CLK_FREQ=`CPU_FREQ*1000000; + + // Memory-mapped IO in IO page, 1-hot addressing in word address. + localparam IO_LEDS_bit = 0; // W five leds + localparam IO_UART_DAT_bit = 1; // W data to send (8 bits) + localparam IO_UART_CNTL_bit = 2; // R status. bit 9: busy sending + + always @(posedge clk) begin + if(isIO & mem_wstrb & mem_wordaddr[IO_LEDS_bit]) begin + led <= mem_wdata; + end + end + + wire uart_valid = isIO & mem_wstrb & mem_wordaddr[IO_UART_DAT_bit]; + wire uart_ready; + + corescore_emitter_uart #( + .clk_freq_hz(`CPU_FREQ*1000000), + .baud_rate(`BAUD_RATE) + ) UART( + .i_clk(clk), + .i_rst(!resetn), + .i_data(mem_wdata[7:0]), + .i_valid(uart_valid), + .o_ready(uart_ready), + .o_uart_tx(TXD) + ); + + wire [31:0] IO_rdata = + mem_wordaddr[IO_UART_CNTL_bit] ? { 22'b0, !uart_ready, 9'b0} + : 32'b0; + + assign mem_rdata = isRAM ? RAM_rdata : + isUserFlash ? UserFlash_rdata : + IO_rdata ; + assign mem_rready = isUserFlash ? UserFlash_ready : 1'b1; + + + // Gearbox and reset circuitry. + Clockworks #( + .SLOW(0) //Specifying a value other than zero here may result in + // nextpnr being unable to route the clock for some boards. BUGFIX is under development. + ) CW ( + .CLK(clk_i), + .RESET(rst_i), + .clk(clk), + .resetn(resetn) + ); + +endmodule + diff --git a/examples/himbaechel/riscv-dsp-firmware/README.md b/examples/himbaechel/riscv-firmware/README.md similarity index 100% rename from examples/himbaechel/riscv-dsp-firmware/README.md rename to examples/himbaechel/riscv-firmware/README.md diff --git a/examples/himbaechel/riscv-dsp-firmware/alu54d.hex b/examples/himbaechel/riscv-firmware/alu54d.hex similarity index 100% rename from examples/himbaechel/riscv-dsp-firmware/alu54d.hex rename to examples/himbaechel/riscv-firmware/alu54d.hex diff --git a/examples/himbaechel/riscv-dsp-firmware/mult18x18.S b/examples/himbaechel/riscv-firmware/mult18x18.S similarity index 99% rename from examples/himbaechel/riscv-dsp-firmware/mult18x18.S rename to examples/himbaechel/riscv-firmware/mult18x18.S index 731ffc97..409db11f 100644 --- a/examples/himbaechel/riscv-dsp-firmware/mult18x18.S +++ b/examples/himbaechel/riscv-firmware/mult18x18.S @@ -82,7 +82,7 @@ print_2_bytes: srli a0, a0, 8 call print_byte_hex - andi s0, s1, 0xff + andi a0, s1, 0xff call print_byte_hex lw s1, 0(sp) diff --git a/examples/himbaechel/riscv-dsp-firmware/mult18x18.hex b/examples/himbaechel/riscv-firmware/mult18x18.hex similarity index 100% rename from examples/himbaechel/riscv-dsp-firmware/mult18x18.hex rename to examples/himbaechel/riscv-firmware/mult18x18.hex diff --git a/examples/himbaechel/riscv-dsp-firmware/mult36x36.S b/examples/himbaechel/riscv-firmware/mult36x36.S similarity index 99% rename from examples/himbaechel/riscv-dsp-firmware/mult36x36.S rename to examples/himbaechel/riscv-firmware/mult36x36.S index 3b211ece..6a96c341 100644 --- a/examples/himbaechel/riscv-dsp-firmware/mult36x36.S +++ b/examples/himbaechel/riscv-firmware/mult36x36.S @@ -82,7 +82,7 @@ print_2_bytes: srli a0, a0, 8 call print_byte_hex - andi s0, s1, 0xff + andi a0, s1, 0xff call print_byte_hex lw s1, 0(sp) diff --git a/examples/himbaechel/riscv-dsp-firmware/mult36x36.hex b/examples/himbaechel/riscv-firmware/mult36x36.hex similarity index 100% rename from examples/himbaechel/riscv-dsp-firmware/mult36x36.hex rename to examples/himbaechel/riscv-firmware/mult36x36.hex diff --git a/examples/himbaechel/riscv-dsp-firmware/mult9x9.S b/examples/himbaechel/riscv-firmware/mult9x9.S similarity index 99% rename from examples/himbaechel/riscv-dsp-firmware/mult9x9.S rename to examples/himbaechel/riscv-firmware/mult9x9.S index 0aa4dbad..344d1dc8 100644 --- a/examples/himbaechel/riscv-dsp-firmware/mult9x9.S +++ b/examples/himbaechel/riscv-firmware/mult9x9.S @@ -82,7 +82,7 @@ print_2_bytes: srli a0, a0, 8 call print_byte_hex - andi s0, s1, 0xff + andi a0, s1, 0xff call print_byte_hex lw s1, 0(sp) diff --git a/examples/himbaechel/riscv-dsp-firmware/mult9x9.hex b/examples/himbaechel/riscv-firmware/mult9x9.hex similarity index 100% rename from examples/himbaechel/riscv-dsp-firmware/mult9x9.hex rename to examples/himbaechel/riscv-firmware/mult9x9.hex diff --git a/examples/himbaechel/riscv-dsp-firmware/multaddalu18x18.hex b/examples/himbaechel/riscv-firmware/multaddalu18x18.hex similarity index 100% rename from examples/himbaechel/riscv-dsp-firmware/multaddalu18x18.hex rename to examples/himbaechel/riscv-firmware/multaddalu18x18.hex diff --git a/examples/himbaechel/riscv-dsp-firmware/multalu18x18.hex b/examples/himbaechel/riscv-firmware/multalu18x18.hex similarity index 100% rename from examples/himbaechel/riscv-dsp-firmware/multalu18x18.hex rename to examples/himbaechel/riscv-firmware/multalu18x18.hex diff --git a/examples/himbaechel/riscv-dsp-firmware/multalu36x18.hex b/examples/himbaechel/riscv-firmware/multalu36x18.hex similarity index 100% rename from examples/himbaechel/riscv-dsp-firmware/multalu36x18.hex rename to examples/himbaechel/riscv-firmware/multalu36x18.hex diff --git a/examples/himbaechel/riscv-dsp-firmware/padd18.S b/examples/himbaechel/riscv-firmware/padd18.S similarity index 99% rename from examples/himbaechel/riscv-dsp-firmware/padd18.S rename to examples/himbaechel/riscv-firmware/padd18.S index 8ea7ef7c..4ffaf1cb 100644 --- a/examples/himbaechel/riscv-dsp-firmware/padd18.S +++ b/examples/himbaechel/riscv-firmware/padd18.S @@ -82,7 +82,7 @@ print_2_bytes: srli a0, a0, 8 call print_byte_hex - andi s0, s1, 0xff + andi a0, s1, 0xff call print_byte_hex lw s1, 0(sp) diff --git a/examples/himbaechel/riscv-dsp-firmware/padd18.hex b/examples/himbaechel/riscv-firmware/padd18.hex similarity index 100% rename from examples/himbaechel/riscv-dsp-firmware/padd18.hex rename to examples/himbaechel/riscv-firmware/padd18.hex diff --git a/examples/himbaechel/riscv-dsp-firmware/padd9.S b/examples/himbaechel/riscv-firmware/padd9.S similarity index 99% rename from examples/himbaechel/riscv-dsp-firmware/padd9.S rename to examples/himbaechel/riscv-firmware/padd9.S index 57432faa..b727d8d1 100644 --- a/examples/himbaechel/riscv-dsp-firmware/padd9.S +++ b/examples/himbaechel/riscv-firmware/padd9.S @@ -82,7 +82,7 @@ print_2_bytes: srli a0, a0, 8 call print_byte_hex - andi s0, s1, 0xff + andi a0, s1, 0xff call print_byte_hex lw s1, 0(sp) diff --git a/examples/himbaechel/riscv-dsp-firmware/padd9.hex b/examples/himbaechel/riscv-firmware/padd9.hex similarity index 100% rename from examples/himbaechel/riscv-dsp-firmware/padd9.hex rename to examples/himbaechel/riscv-firmware/padd9.hex diff --git a/examples/himbaechel/riscv-firmware/userflash-9k.hex b/examples/himbaechel/riscv-firmware/userflash-9k.hex new file mode 100644 index 00000000..a5ed1b9c --- /dev/null +++ b/examples/himbaechel/riscv-firmware/userflash-9k.hex @@ -0,0 +1,384 @@ +004001b7 00002137 80010113 00000097 +164080e7 00100073 00a1a423 20000293 +0101a303 00537333 fe031ce3 00008067 +ffc10113 00112023 00050393 0003c503 +00050a63 00000097 fd4080e7 00138393 +fedff06f 00012083 00410113 00008067 +ffc10113 00112023 00a00513 00000097 +fac080e7 00012083 00410113 00008067 +33323130 37363534 62613938 66656463 +ffc10113 00112023 00000f17 fe8f0f13 +00050e13 00455513 00af0eb3 000ec503 +00000097 f68080e7 00fe7513 00af0eb3 +000ec503 00000097 f54080e7 00012083 +00410113 00008067 ff810113 00112223 +00912023 00050493 00855513 00000097 +fa4080e7 0ff4f513 00000097 f98080e7 +00012483 00412083 00810113 00008067 +ff810113 00112223 00912023 00050493 +01055513 00000097 fb4080e7 000102b7 +fff28293 0054f533 00000097 fa0080e7 +00012483 00412083 00810113 00008067 +00dd9513 00adcdb3 011dd513 00adcdb3 +005d9513 00adcdb3 000d8513 00008067 +00800937 00000517 13850513 00000097 +eb4080e7 00000097 edc080e7 00000517 +19750513 00000097 e9c080e7 00000097 +ec4080e7 0000ddb7 afed8d93 00000993 +00013a37 01298b33 7ff9f313 00031a63 +00ab0023 02e00513 00000097 e50080e7 +20000a93 00000097 f7c080e7 00ab2023 +00498993 fffa8a93 01298b33 fe0a94e3 +fd4994e3 00000097 e6c080e7 00000517 +15650513 00000097 e2c080e7 00000097 +e54080e7 0000ddb7 afed8d93 00000993 +13000a13 00699513 00000097 ee8080e7 +00000517 19250513 00000097 df8080e7 +00000a93 04000b13 00000097 f08080e7 +00050313 00699293 015282b3 012282b3 +0002a283 02e00513 00628463 05800513 +00000097 da8080e7 00000097 da0080e7 +00000097 d98080e7 00000097 d90080e7 +004a8a93 fb6a9ae3 00000097 dc8080e7 +00198993 f94990e3 0000006f 63697041 +2e616c75 6d695320 20656c70 72657355 +73616c46 65742068 203a7473 73617245 +76652065 74797265 676e6968 7277202c +20657469 73702061 6f647565 6e61722d +206d6f64 626d756e 74207265 6165206f +61206863 65726464 202c7373 20646e61 +6e656874 61657220 74692064 63616220 +45002e6b 65736172 67617020 79622065 +67617020 6e612065 72772064 20657469 +646e6172 6e206d6f 65626d75 2e2e7372 +6552002e 74206461 65206568 7269746e +73552065 6c467265 2c687361 63616520 +2e272068 65722027 73657270 73746e65 +6d206120 68637461 74697720 68742068 +20342065 65747962 72772073 65747469 +65202c6e 20686361 20275827 72706572 +6e657365 61207374 69616620 6572756c +203a002e 00010000 00001941 73697200 +01007663 0000000f 33767205 70326932 +00000030 00100293 01329293 fff28293 +fe029ee3 00008067 00001941 73697200 +01007663 0000000f 33767205 70326932 +19410030 72000000 76637369 000f0100 +72050000 69323376 00307032 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 diff --git a/examples/himbaechel/riscv-firmware/userflash.S b/examples/himbaechel/riscv-firmware/userflash.S new file mode 100644 index 00000000..fa0cb0bf --- /dev/null +++ b/examples/himbaechel/riscv-firmware/userflash.S @@ -0,0 +1,192 @@ +.equ IO_BASE, 0x400000 +.equ IO_LEDS, 4 +.equ IO_UART_DAT, 8 +.equ IO_UART_CTRL, 16 +.equ USERFLASH_BASE, 0x800000 + +.section .text + +putc: + sw a0, IO_UART_DAT(gp) + li t0, 512 +0: + lw t1, IO_UART_CTRL(gp) + and t1, t1, t0 + bnez t1, 0b + ret + +puts: + addi sp, sp, -4 + sw ra, 0(sp) + mv t2, a0 +0: + lbu a0, 0(t2) + beqz a0, 1f + call putc + addi t2, t2, 1 + j 0b +1: + lw ra, 0(sp) + addi sp, sp, 4 + ret + +put_eol: + addi sp, sp, -4 + sw ra, 0(sp) + + li a0, 0xa + call putc + + lw ra, 0(sp) + addi sp, sp, 4 + ret + +hex: .ascii "0123456789abcdef" +print_byte_hex: + addi sp, sp, -4 + sw ra, 0(sp) + + la t5, hex + mv t3, a0 + + srli a0, a0, 4 + add t4, t5, a0 + lbu a0, 0(t4) + call putc + + andi a0, t3, 0xf + add t4, t5, a0 + lbu a0, 0(t4) + call putc + + lw ra, 0(sp) + addi sp, sp, 4 + ret + +print_2_bytes: + addi sp, sp, -8 + sw ra, 4(sp) + sw s1, 0(sp) + + mv s1, a0 + srli a0, a0, 8 + call print_byte_hex + + andi a0, s1, 0xff + call print_byte_hex + + lw s1, 0(sp) + lw ra, 4(sp) + addi sp, sp, 8 + ret + +print_4_bytes: + addi sp, sp, -8 + sw ra, 4(sp) + sw s1, 0(sp) + + mv s1, a0 + srli a0, a0, 16 + call print_2_bytes + + li t0, 0xffff + and a0, s1, t0 + call print_2_bytes + + lw s1, 0(sp) + lw ra, 4(sp) + addi sp, sp, 8 + ret + +.globl main +rnd: # xorshift rnd generator + slli a0, s11, 13 + xor s11, s11, a0 + srli a0, s11, 17 + xor s11, s11, a0 + slli a0, s11, 5 + xor s11, s11, a0 + mv a0, s11 + ret +main: + li s2, USERFLASH_BASE + la a0, hello_str + call puts + call put_eol + + # Erase/Write + la a0, erase_write_title + call puts + call put_eol + li s11, 0xcafe # init rnd + + mv s3, zero + li s4, 304*64*4 + add s6, s3, s2 +.L20: + andi t1, s3, 2047 # 2048 bytes per page + bnez t1, .L21 + sb a0, (s6) # writing byte erases page + li a0, '.' + call putc +.L21: + li s5, 512 # 2048/4 +.L22: + call rnd + sw a0, (s6) + add s3, s3, 4 + add s5, s5, -1 + add s6, s3, s2 + bnez s5, .L22 + bne s3, s4, .L20 + + call put_eol + + # Read back + la a0, read_title + call puts + call put_eol + li s11, 0xcafe # init rnd + mv s3, zero + li s4, 304 +.L1: + slli a0, s3, 6 + call print_4_bytes + la a0, colon_space + call puts + + mv s5, zero + li s6, 64 +.L0: + # read flash + call rnd + mv t1, a0 + slli t0, s3, 6 + add t0, t0, s5 + add t0, t0, s2 + lw t0, (t0) + li a0, '.' + beq t0, t1, .L2 + li a0, 'X' +.L2: + call putc + call putc + call putc + call putc + + add s5, s5, 4 + bne s5, s6, .L0 + + call put_eol + + add s3, s3, 1 + bne s3, s4, .L1 + + +.L10: + j .L10 + +hello_str: .asciz "Apicula. Simple UserFlash test: Erase everything, write a pseudo-random number to each address, and then read it back." +erase_write_title: .asciz "Erase page by page and write random numbers..." +read_title: .asciz "Read the entire UserFlash, each '.' represents a match with the 4 bytes written, each 'X' represents a failure." +colon_space: .asciz ": " diff --git a/examples/himbaechel/tangnano9k.cst b/examples/himbaechel/tangnano9k.cst index 6f5a33b7..a4a655f8 100644 --- a/examples/himbaechel/tangnano9k.cst +++ b/examples/himbaechel/tangnano9k.cst @@ -18,9 +18,7 @@ IO_LOC "LED_B" 13; // Use buildin USB-serial IO_LOC "TXD" 17; -IO_PORT "TXD" PULL_MODE=UP; IO_LOC "RXD" 18; -IO_PORT "RXD" PULL_MODE=UP; // fake IO_LOC "led[6]" 35; diff --git a/examples/himbaechel/uflash_controller.v b/examples/himbaechel/uflash_controller.v new file mode 100644 index 00000000..04446af7 --- /dev/null +++ b/examples/himbaechel/uflash_controller.v @@ -0,0 +1,283 @@ +/* Copyright 2024 Grug Huhler. License SPDX BSD-2-Clause. + + This module implements a controller for the user flash on the Tang + Nano 9K FPGA development board. The controller integrates with + the PicoRV32 mini-SoC bus scheme. It also instantiates the + actual flash. Note: the Tang Nano 20K does not contain user + flash. + + See document UG295 "Gowin User Flash". + + The Flash is 608 Kbits, 32-bits wide, organized into 304 rows of 64 + columns each. The erase page size is 2048 bytes, so there are + 38 pages that may be separately erased. + + This controller expects a system clock no more than 40 Mhz. The + actual clock frequency must be passed to the module via the + CLK_FREQ parameter. + + Leave at least 10 millisconds between a write and an erase and do + not write the same address twice without an erase between the writes. + The controller does not enforce these rules. + + Reads can be 8, 16, or 32 bits wide. Erasing is done on a page basis. + To erase a page, do an 8 bit write to a 32-bit aligned address in the + page. To program (write), do a 32-bit write to the address to be + programmed. +*/ + +module uflash #(parameter CLK_FREQ=5400000) +( + input wire reset_n, + input wire clk, + input wire sel, + input wire [3:0] wstrb, + input wire [14:0] addr, // word address, 9-bits row, 6 bits col + input wire [31:0] data_i, + output wire ready, + output wire [31:0] data_o +); + + // state machine states + localparam IDLE = 'd0; + localparam READ1 = 'd1; + localparam READ2 = 'd2; + localparam ERASE1 = 'd3; + localparam ERASE2 = 'd4; + localparam ERASE3 = 'd5; + localparam ERASE4 = 'd6; + localparam ERASE5 = 'd7; + localparam WRITE1 = 'd8; + localparam WRITE2 = 'd9; + localparam WRITE3 = 'd10; + localparam WRITE4 = 'd11; + localparam WRITE5 = 'd12; + localparam WRITE6 = 'd13; + localparam WRITE7 = 'd14; + localparam DONE = 'd15; + + // clocks required in state when > 1 + localparam E2_CLKS = $rtoi(CLK_FREQ * 6.0e-6) + 1; + localparam E3_CLKS = $rtoi(CLK_FREQ * 120.0e-3) + 1; + localparam E4_CLKS = $rtoi(CLK_FREQ * 6.0e-6) + 1; + localparam E5_CLKS = $rtoi(CLK_FREQ * 11.0e-6) + 1; + localparam W2_CLKS = $rtoi(CLK_FREQ * 6.0e-6) + 1; + localparam W3_CLKS = $rtoi(CLK_FREQ * 11.0e-6) + 1; + localparam W4_CLKS = $rtoi(CLK_FREQ * 16.0e-6) + 1; + localparam W6_CLKS = $rtoi(CLK_FREQ * 6.0e-6) + 1; + localparam W7_CLKS = $rtoi(CLK_FREQ * 11.0e-6) + 1; + + reg xe = 1'b0; + reg ye = 1'b0; + reg se = 1'b0; + reg erase = 1'b0; + reg nvstr = 1'b0; + reg prog = 1'b0; + reg [3:0] state = IDLE; + reg [23:0] cycle_count; + + assign ready = state == DONE; + + always @(posedge clk or negedge reset_n) + if (!reset_n) begin + state <= IDLE; + se <= 1'b0; + xe <= 1'b0; + ye <= 1'b0; + erase <= 1'b0; + nvstr <= 1'b0; + prog <= 1'b0; + cycle_count <= 'd0; + end + else + case (state) + IDLE: begin + if (sel) begin + if (wstrb == 'b0) begin + // Read + state <= READ1; + xe <= 1'b1; + ye <= 1'b1; + end + else if (&wstrb) begin + // Write + state <= WRITE1; + xe <= 1'b1; + end else if (wstrb == 'b1) begin + // Erase + ye <= 1'b0; + se <= 1'b0; + xe <= 1'b1; + erase <= 1'b0; + nvstr <= 1'b0; + state <= ERASE1; + end else begin + // Unsupported + state <= DONE; + end + end + else + state <= IDLE; + end + READ1: begin + se <= 1'b1; + state <= READ2; + end + READ2: begin + se <= 1'b0; + state <= DONE; + end + ERASE1: begin + state <= ERASE2; + cycle_count <= 'd0; + erase <= 1'b1; + end + ERASE2: begin + if (cycle_count < E2_CLKS) begin + state <= ERASE2; + cycle_count <= cycle_count + 1; + end + else begin + state <= ERASE3; + cycle_count <= 'd0; + nvstr <= 1'b1; + end + end + ERASE3: begin + if (cycle_count < E3_CLKS) begin + state <= ERASE3; + cycle_count <= cycle_count + 1; + end + else begin + state <= ERASE4; + cycle_count <= 'd0; + erase <= 1'b0; + end + end + ERASE4: begin + if (cycle_count < E4_CLKS) begin + state <= ERASE4; + cycle_count <= cycle_count + 1; + end + else begin + state <= ERASE5; + cycle_count <= 'd0; + nvstr <= 1'b0; + end + end + ERASE5: begin + if (cycle_count < E5_CLKS) begin + state <= ERASE5; + cycle_count <= cycle_count + 1; + end + else begin + state <= DONE; + cycle_count <= 'd0; + xe <= 1'b0; + end + end + WRITE1: begin + state <= WRITE2; + prog <= 1'b1; + end + WRITE2: begin + if (cycle_count < W2_CLKS) begin + state <= WRITE2; + cycle_count <= cycle_count + 1; + end + else begin + state <= WRITE3; + cycle_count <= 'd0; + nvstr <= 1'b1; + end + end + WRITE3: begin + if (cycle_count < W3_CLKS) begin + state <= WRITE3; + cycle_count <= cycle_count + 1; + end + else begin + state <= WRITE4; + cycle_count <= 'd0; + ye <= 1'b1; + end + end + WRITE4: begin + if (cycle_count < W4_CLKS) begin + state <= WRITE4; + cycle_count <= cycle_count + 1; + end + else begin + state <= WRITE5; + cycle_count <= 'd0; + ye <= 1'b0; + end + end + WRITE5: begin + state <= WRITE6; + prog <= 1'b0; + end + WRITE6: begin + if (cycle_count < W6_CLKS) begin + state <= WRITE6; + cycle_count <= cycle_count + 1; + end + else begin + state <= WRITE7; + cycle_count <= 'd0; + nvstr <= 1'b0; + end + end + WRITE7: begin + if (cycle_count < W7_CLKS) begin + state <= WRITE7; + cycle_count <= cycle_count + 1; + end + else begin + state <= DONE; + cycle_count <= 'd0; + xe <= 1'b0; + end + end + DONE: begin + state <= IDLE; + xe <= 1'b0; + ye <= 1'b0; + se <= 1'b0; + erase <= 1'b0; + nvstr <= 1'b0; + prog <= 1'b0; + end + endcase + +`ifdef HAS_FLASH608K + (* keep *) + FLASH608K uflash_hw0 ( + .DOUT(data_o), //output [31:0] dout + .XE(xe), //input xe + .YE(ye), //input ye + .SE(se), //input se + .PROG(prog), //input prog + .ERASE(erase), //input erase + .NVSTR(nvstr), //input nvstr + .XADR(addr[14:6]), //input [8:0] xadr + .YADR(addr[5:0]), //input [5:0] yadr + .DIN(data_i) //input [31:0] din + ); +`else + (* keep *) + FLASH64KZ uflash_hw0 ( + .DOUT(data_o), //output [31:0] dout + .XE(xe), //input xe + .YE(ye), //input ye + .SE(se), //input se + .PROG(prog), //input prog + .ERASE(erase), //input erase + .NVSTR(nvstr), //input nvstr + .XADR(addr[10:6]), //input [4:0] xadr + .YADR(addr[5:0]), //input [5:0] yadr + .DIN(data_i) //input [31:0] din + ); +`endif + +endmodule diff --git a/examples/himbaechel/userflash.v b/examples/himbaechel/userflash.v new file mode 100644 index 00000000..9ea97c2d --- /dev/null +++ b/examples/himbaechel/userflash.v @@ -0,0 +1,165 @@ +/* +* I tested performance by programming SRAM, programming in flash is left at your own risk. +* At startup, the UserFlash page is cleared, then the number 0xc001cafe is +* written, then this number is read back and displayed on the dual segment +* indicator (https://wiki.sipeed.com/hardware/en/tang/tang-PMOD/FPGA_PMOD.html#PMOD_DTx2) +* pinout: +* A - 9 A +* B - 10 F B +* C - 11 G +* D - 15 E C +* E - 16 D +* F - 17 +* G - 18 +* sel - 28 +*/ +`include "uflash_controller.v" +`default_nettype none +module top ( + input wire clk, + input wire rst_i, + input wire key_i, + output wire [2:0] led, + output wire [5:0] LCD_G +); + + wire [7:0] out; + assign led[2:0] = out[2:0]; + assign LCD_G[5:2] = out[7:3]; + + reg sel; + reg [3:0] w_strb; + wire [31:0] data_i; + wire ready; + wire [31:0] data_o; + + assign data_i = 32'hc001cafe; + + + uflash flash_ctl( + rst_i, + clk, + sel, + w_strb, + {9'h0, 6'h0}, //addr, + data_i, + ready, + data_o + ); + defparam flash_ctl.CLK_FREQ=27000000; + + reg [25:0] ctr_q; + wire [25:0] ctr_d; + + // ========= clock ============= + // Sequential code (flip-flop) + always @(posedge clk) begin + ctr_q <= ctr_d; + end + + // Combinational code (boolean logic) + assign ctr_d = ctr_q + 1'b1; + wire led_tick = ctr_q[10]; + // ============================ + + localparam ERASE = 3'h0; + localparam WAIT_ERASE_DONE = 3'h1; + localparam WRITE = 3'h2; + localparam WAIT_WRITE_DONE = 3'h3; + localparam READ = 3'h4; + localparam WAIT_READ_DONE = 3'h5; + localparam IDLE = 3'h6; + + // rotate bytes + reg [31:0] shift32; + reg [2:0] state; + always @(posedge clk or negedge rst_i) begin + if (!rst_i) begin + state <= ERASE; + sel <= 1'b1; + w_strb <= 4'b0001; + shift32 <= 32'h0; + end else begin + case (state) + ERASE: begin + state <= WAIT_ERASE_DONE; + sel <= 1'b0; + end + WAIT_ERASE_DONE: begin + if (ready) begin + state <= WRITE; + w_strb <= 4'b1111; + sel <= 1'b1; + end + end + WRITE: begin + state <= WAIT_WRITE_DONE; + sel <= 1'b0; + end + WAIT_WRITE_DONE: begin + if (ready) begin + state <= READ; + w_strb <= 4'b0000; + sel <= 1'b1; + end + end + READ: begin + state <= WAIT_READ_DONE; + sel <= 1'b0; + end + WAIT_READ_DONE: begin + if (ready) begin + state <= IDLE; + w_strb <= 4'b0000; + sel <= 1'b0; + shift32 <= data_o; + end + end + IDLE: begin + if (&ctr_q[24:0]) begin + shift32 <= {shift32[23:0], shift32[31:24]}; + end + end + endcase + end + end + + + // output + assign LCD_G[0] = led_tick; + + wire [6:0] seg[1:0]; + bin2segments left( + .halfbyte(shift32[31:28]), + .segments(seg[0]) + ); + + bin2segments right( + .halfbyte(shift32[27:24]), + .segments(seg[1]) + ); + assign out = ~seg[led_tick]; + +endmodule + +module bin2segments( + input wire [3:0] halfbyte, + output wire [6:0] segments +); + assign segments = halfbyte == 4'hf ? 7'b1110001 : + halfbyte == 4'he ? 7'b1111001 : + halfbyte == 4'hd ? 7'b1011111 : + halfbyte == 4'hc ? 7'b0111001 : + halfbyte == 4'hb ? 7'b1111100 : + halfbyte == 4'ha ? 7'b1110111 : + halfbyte == 4'h9 ? 7'b1101111 : + halfbyte == 4'h8 ? 7'b1111111 : + halfbyte == 4'h7 ? 7'b0000111 : + halfbyte == 4'h6 ? 7'b1111100 : + halfbyte == 4'h5 ? 7'b1101101 : + halfbyte == 4'h4 ? 7'b1100110 : + halfbyte == 4'h3 ? 7'b1001111 : + halfbyte == 4'h2 ? 7'b1011011 : + halfbyte == 4'h1 ? 7'b0000110 : 7'b0111111; +endmodule + From b758d37ba20211daa2be995f7ae3b51945fb9c1f Mon Sep 17 00:00:00 2001 From: YRabbit Date: Fri, 6 Sep 2024 18:58:14 +1000 Subject: [PATCH 2/2] Update chipdb.py --- apycula/chipdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apycula/chipdb.py b/apycula/chipdb.py index 10982af2..d6ee5e13 100644 --- a/apycula/chipdb.py +++ b/apycula/chipdb.py @@ -1833,7 +1833,7 @@ def fse_create_bandgap(dev, device): {'bandgap': {'wire': 'C1'}}) def fse_create_userflash(dev, device, dat): - # dat[‘UfbIns’] and dat[‘UfbOuts’] judgement to describe the waste and waste UserFlash. + # dat[‘UfbIns’] and dat[‘UfbOuts’]. # The outputs are exactly 32 by the number of bits and they are always # present, their positions correspond to bit indices - checked by # selectively connecting the outputs to LEDs.