From e195e09e0f0fa7734401acc9a4272420cae534ca Mon Sep 17 00:00:00 2001 From: YRabbit Date: Sat, 14 Sep 2024 12:18:59 +1000 Subject: [PATCH 1/5] Implement EMCU primitive In this PR we add the ARM Cortex M3 microcontroller integrated in the GW1NSR-4C chip that powers the Sipeed TangNano 4K. This primitive represents the microprocessor itself, but you need to add ROM (flash), RAM, and some I/O to it for proper operation. Luckily we have working flash, BSRAM and IOBUFs :) The examples will show how to use this EMCU in the simplest cases. Signed-off-by: YRabbit --- apycula/chipdb.py | 195 ++++++++++++++++++++++++++++++++++++++++ apycula/gowin_pack.py | 5 +- apycula/gowin_unpack.py | 3 +- 3 files changed, 201 insertions(+), 2 deletions(-) diff --git a/apycula/chipdb.py b/apycula/chipdb.py index 734c0352..47580a3f 100644 --- a/apycula/chipdb.py +++ b/apycula/chipdb.py @@ -2018,23 +2018,217 @@ def make_port(r, c, wire, port, wire_type, pins): r, c, wire = desc make_port(r, c, wire, port, 'FLASH_IN', ins) else: + # GW1NS-4 has a direct connection of Flash with the built-in Cortex-M3 + # and some wires during test compilations showed connections different + # from the table in the DAT file for i, desc in enumerate(dat.compat_dict['UfbIns'][:6]): port = ['XE', 'YE', 'SE', 'PROG', 'ERASE', 'NVSTR'][i] r, c, wire = desc + if device == 'GW1NS-4' and port in {'XE', 'YE', 'SE'}: + r, c, wire = {'XE':(15, 1, 28), 'YE': (15, 1, 0), 'SE':(14, 1, 31)}[port] 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 + if device == 'GW1NS-4' and i < 7: + r, c, wire = (14, 1, 3 + 4 * i) 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 + if device == 'GW1NS-4' and i < 6: + r, c, wire = (15, 1, 4 + 4 * i) 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_create_emcu(dev, device, dat): + # Mentions of the NS-2 series are excluded from the latest Gowin + # documentation so that only one chip remains with the ARM processor + if device != 'GW1NS-4': + return + + # The primitive pins are described in tables dat["EMcuIns"] and dat["EMcuOuts"] + # Since there is only one chip, there is no need to check for [-1, -1, -1] + # in the table and try to create obviously missing wires. + def make_port(r, c, wire, port, wire_type, pins): + 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, 'EMCU', port, wire, wire_type) + pins[port] = bel.portmap[port] + + # In (0, 0) is the CPU enabled/disabled flag, so place the CPU there + row, col = (0, 0) + dev.extra_func.setdefault((row, col), {}).update({'emcu': {}}) + extra_func = dev.extra_func[(row, col)]['emcu'] + + # outputs + outs = extra_func.setdefault('outs', {}) + single_wires = [('MTXHRESETN', 87), ('UART0TXDO', 32), ('UART1TXDO', 33), + ('UART0BAUDTICK', 34), ('UART1BAUDTICK', 35), ('INTMONITOR', 36), + ('SRAM0WREN0', 50), ('SRAM0WREN1', 51), ('SRAM0WREN2', 52), ('SRAM0WREN3', 53), + ('SRAM0CS', 86), ('TARGFLASH0HSEL', 88), ('TARGFLASH0HTRANS0', 118), ('TARGFLASH0HTRANS1', 119), + ('TARGEXP0HSEL', 127), ('TARGEXP0HTRANS0', 160), ('TARGEXP0HTRANS1', 161), + ('TARGEXP0HWRITE', 162), + ('TARGEXP0HSIZE0', 163), ('TARGEXP0HSIZE1', 164), ('TARGEXP0HSIZE2', 165), + ('TARGEXP0HBURST0', 166), ('TARGEXP0HBURST1', 167), ('TARGEXP0HBURST2', 168), + ('TARGEXP0HPROT0', 169), ('TARGEXP0HPROT1', 170), + ('TARGEXP0HPROT2', 171), ('TARGEXP0HPROT3', 172), + ('TARGEXP0MEMATTR0', 173), ('TARGEXP0MEMATTR1', 174), + ('TARGEXP0EXREQ', 175), + ('TARGEXP0HMASTER0', 176), ('TARGEXP0HMASTER1', 177), + ('TARGEXP0HMASTER2', 178), ('TARGEXP0HMASTER3', 179), + ('TARGEXP0HMASTLOCK', 212), ('TARGEXP0HREADYMUX', 213), + ('INITEXP0HREADY', 251), ('INITEXP0HRESP', 252), ('INITEXP0EXRESP', 253), + ('APBTARGEXP2PSEL', 257), ('APBTARGEXP2PENABLE', 258), ('APBTARGEXP2PWRITE', 271), + ('APBTARGEXP2PSTRB0', 304), ('APBTARGEXP2PSTRB1', 305), + ('APBTARGEXP2PSTRB2', 306), ('APBTARGEXP2PSTRB3', 307), + ('APBTARGEXP2PPROT0', 308), ('APBTARGEXP2PPROT1', 309), ('APBTARGEXP2PPROT2', 310), + ('DAPJTAGNSW', 313), + ('TPIUTRACEDATA0', 314), ('TPIUTRACEDATA1', 315), + ('TPIUTRACEDATA2', 316), ('TPIUTRACEDATA3', 317), + ] + for port, idx in single_wires: + r, c, wire = dat.compat_dict['EMcuOuts'][idx] + make_port(r, c, wire, port, 'EMCU_OUT', outs) + + # gpio out - 16 output wires + for i, desc in enumerate(dat.compat_dict['EMcuOuts'][0:16]): + port = f'IOEXPOUTPUTO{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_OUT', outs) + + # gpio outputenable - 16 output wires + for i, desc in enumerate(dat.compat_dict['EMcuOuts'][16:32]): + port = f'IOEXPOUTPUTENO{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_OUT', outs) + + # ram addr- 13 output wires + for i, desc in enumerate(dat.compat_dict['EMcuOuts'][37:50]): + port = f'SRAM0ADDR{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_OUT', outs) + + # ram data- 32 output wires + for i, desc in enumerate(dat.compat_dict['EMcuOuts'][54:86]): + port = f'SRAM0WDATA{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_OUT', outs) + + # flash addr- 29 output wires + for i, desc in enumerate(dat.compat_dict['EMcuOuts'][89:118]): + port = f'TARGFLASH0HADDR{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_OUT', outs) + + # 32 output wires, unknown purpose + for i, desc in enumerate(dat.compat_dict['EMcuOuts'][128:160]): + port = f'TARGEXP0HADDR{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_OUT', outs) + + # 32 output wires, unknown purpose + for i, desc in enumerate(dat.compat_dict['EMcuOuts'][180:212]): + port = f'TARGEXP0HWDATA{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_OUT', outs) + + # 32 output wires, unknown purpose + for i, desc in enumerate(dat.compat_dict['EMcuOuts'][219:251]): + port = f'INITEXP0HRDATA{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_OUT', outs) + + # 12 output wires, unknown purpose + for i, desc in enumerate(dat.compat_dict['EMcuOuts'][259:271]): + port = f'APBTARGEXP2PADDR{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_OUT', outs) + + # 32 output wires, unknown purpose + for i, desc in enumerate(dat.compat_dict['EMcuOuts'][272:304]): + port = f'APBTARGEXP2PWDATA{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_OUT', outs) + + # inputs + # funny thing - I have not been able to find ports PORESETN and SYSRESETN, they just + # don't connect to the button. There is a suspicion that implicit + # connection from GSR primitives is used, now it comes in handy. + ins = extra_func.setdefault('ins', {}) + clock_wires = [('FCLK', 0), ('RTCSRCCLK', 3)] + for port, idx in clock_wires: + r, c, wire = dat.compat_dict['EMcuIns'][idx] + make_port(r, c, wire, port, 'TILE_CLK', ins) + + single_wires = [('UART0RXDI', 20), ('UART1RXDI', 21), + ('TARGFLASH0HRESP', 89), ('TARGFLASH0HREADYOUT', 91), + ('TARGEXP0HRESP', 125), ('TARGEXP0HREADYOUT', 124), ('TARGEXP0EXRESP', 126), + ('TARGEXP0HRUSER0', 127), ('TARGEXP0HRUSER1', 128), ('TARGEXP0HRUSER2', 129), + ('INITEXP0HSEL', 130), ('INITEXP0HTRANS0', 163), ('INITEXP0HTRANS1', 164), + ('INITEXP0HWRITE', 165), ('INITEXP0HSIZE0', 166), ('INITEXP0HSIZE1', 167), ('INITEXP0HSIZE2', 168), + ('INITEXP0HBURST0', 169), ('INITEXP0HBURST1', 170), ('INITEXP0HBURST2', 171), + ('INITEXP0HPROT0', 172), ('INITEXP0HPROT1', 173), ('INITEXP0HPROT2', 174), ('INITEXP0HPROT3', 175), + ('INITEXP0MEMATTR0', 176), ('INITEXP0MEMATTR1', 177), ('INITEXP0EXREQ', 178), + ('INITEXP0HMASTER0', 179), ('INITEXP0HMASTER1', 180), + ('INITEXP0HMASTER2', 181), ('INITEXP0HMASTER3', 182), + ('INITEXP0HMASTLOCK', 215), ('INITEXP0HAUSER', 216), + ('INITEXP0HWUSER0', 217), ('INITEXP0HWUSER1', 218), + ('INITEXP0HWUSER2', 219), ('INITEXP0HWUSER3', 220), + ('APBTARGEXP2PREADY', 253), ('APBTARGEXP2PSLVERR', 254), + ('FLASHERR', 263), ('FLASHINT', 264), + ] + for port, idx in single_wires: + r, c, wire = dat.compat_dict['EMcuIns'][idx] + make_port(r, c, wire, port, 'EMCU_IN', ins) + + # gpio inout - 16 input wires + for i, desc in enumerate(dat.compat_dict['EMcuIns'][4:20]): + port = f'IOEXPINPUTI{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_IN', ins) + + # read from ram - 32 input wires + for i, desc in enumerate(dat.compat_dict['EMcuIns'][22:54]): + port = f'SRAM0RDATA{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_IN', ins) + + # 32 input wires, unknown purpose + for i, desc in enumerate(dat.compat_dict['EMcuIns'][92:124]): + port = f'TARGEXP0HRDATA{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_IN', ins) + + # 32 input wires, unknown purpose + for i, desc in enumerate(dat.compat_dict['EMcuIns'][131:163]): + port = f'INITEXP0HADDR{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_IN', ins) + + # 32 input wires, unknown purpose + for i, desc in enumerate(dat.compat_dict['EMcuIns'][183:215]): + port = f'INITEXP0HWDATA{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_IN', ins) + + # 32 input wires, unknown purpose + for i, desc in enumerate(dat.compat_dict['EMcuIns'][221:253]): + port = f'APBTARGEXP2PRDATA{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_IN', ins) + + # 5 input wires connected to GND, may be GPINT + for i, desc in enumerate(dat.compat_dict['EMcuIns'][265:270]): + port = f'GPINT{i}' + r, c, wire = desc + make_port(r, c, wire, port, 'EMCU_IN', ins) + def fse_bram(fse, aux = False): bels = {} @@ -2175,6 +2369,7 @@ def from_fse(device, fse, dat: Datfile): fse_create_gsr(dev, device) fse_create_bandgap(dev, device) fse_create_userflash(dev, device, dat) + fse_create_emcu(dev, device, dat) fse_create_logic2clk(dev, device, dat) fse_create_dhcen(dev, device, fse, dat) disable_plls(dev, device) diff --git a/apycula/gowin_pack.py b/apycula/gowin_pack.py index 05fd1b23..fbf9d5d0 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|USERFLASH|DHCEN)(\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|EMCU|DHCEN)(\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*)") @@ -2351,6 +2351,8 @@ def place(db, tilemap, bels, cst, args): pass elif typ.startswith("FLASH"): pass + elif typ.startswith("EMCU"): + pass elif typ.startswith('MUX2_'): pass elif typ == "BUFS": @@ -2886,6 +2888,7 @@ def main(): parser.add_argument('-o', '--output', default='pack.fs') parser.add_argument('-c', '--compress', action='store_true') parser.add_argument('-s', '--cst', default = None) + # XXX remove - nextpnr-himbaechel doesn't allow it parser.add_argument('--allow_pinless_io', action = 'store_true') parser.add_argument('--jtag_as_gpio', action = 'store_true') parser.add_argument('--sspi_as_gpio', action = 'store_true') diff --git a/apycula/gowin_unpack.py b/apycula/gowin_unpack.py index c62d1753..75f40be9 100644 --- a/apycula/gowin_unpack.py +++ b/apycula/gowin_unpack.py @@ -1074,7 +1074,8 @@ def tile2verilog(dbrow, dbcol, bels, pips, clock_pips, mod, cst, db): mod.primitives[name] = iob # constraints pos = chipdb.loc2pin_name(db, dbrow, dbcol) - bank = chipdb.loc2bank(db, dbrow, dbcol) + # XXX tangnano4k uses IOT30 not found in the package + #bank = chipdb.loc2bank(db, dbrow, dbcol) cst.ports[name] = f"{pos}{idx}" if kind[0:5] == 'TLVDS': cst.ports[name] = f"{pos}{idx},{pos}{chr(ord(idx) + 1)}" From fd3d8787c9360461b6ec1b969fabcbc9dd7ed594 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Sat, 14 Sep 2024 17:01:09 +1000 Subject: [PATCH 2/5] Add EMCU blinky example It shows the practical minimum of It shows the practical minimum of the components that need to be added to the EMCU primitive to get a working system. You can use more memory addressing lines thereby increasing its volume with the current 4K, as well as those who wish can make an APB bus to communicate with other devices. Firmware compilation is very difficult, but there is a good description: https://github.com/verilog-indeed/gowin_fpga_tutorials/tree/main/gowin_empu Signed-off-by: YRabbit --- examples/himbaechel/Makefile.himbaechel | 2 +- examples/himbaechel/emcu-blinky.v | 348 ++++++++++++++++++ .../emcu-firmware/blinky-main.c-src | 79 ++++ examples/himbaechel/emcu-firmware/blinky.bin | Bin 0 -> 3232 bytes examples/himbaechel/tangnano4k.cst | 3 + 5 files changed, 431 insertions(+), 1 deletion(-) create mode 100644 examples/himbaechel/emcu-blinky.v create mode 100755 examples/himbaechel/emcu-firmware/blinky-main.c-src create mode 100755 examples/himbaechel/emcu-firmware/blinky.bin diff --git a/examples/himbaechel/Makefile.himbaechel b/examples/himbaechel/Makefile.himbaechel index 13c03ad9..1d3c8a94 100644 --- a/examples/himbaechel/Makefile.himbaechel +++ b/examples/himbaechel/Makefile.himbaechel @@ -62,7 +62,7 @@ all: \ dsp-mult36x36-tangnano4k.fs dsp-padd9-tangnano4k.fs dsp-padd18-tangnano4k.fs \ dsp-mult9x9-tangnano4k.fs dsp-alu54d-tangnano4k.fs dsp-multalu18x18-tangnano4k.fs \ dsp-multalu36x18-tangnano4k.fs dsp-multaddalu18x18-tangnano4k.fs \ - dqce-tangnano4k.fs dcs-tangnano4k.fs \ + dqce-tangnano4k.fs dcs-tangnano4k.fs emcu-blinky-tangnano4k.fs \ \ blinky-tangnano9k.fs shift-tangnano9k.fs blinky-tbuf-tangnano9k.fs blinky-oddr-tangnano9k.fs \ blinky-clkdiv-tangnano9k.fs dvi-example-tangnano9k.fs\ diff --git a/examples/himbaechel/emcu-blinky.v b/examples/himbaechel/emcu-blinky.v new file mode 100644 index 00000000..fa8c2324 --- /dev/null +++ b/examples/himbaechel/emcu-blinky.v @@ -0,0 +1,348 @@ +`default_nettype none + +/* +* The LED on the board should blink. +* Attention: flashing is performed with firmware as follows: +* openFPGALoader -f -b tangnano4k --mcufw=emcu-firmware/blinky.bin emcu-blinky-tangnano4k.fs +*/ + +module top ( + input wire clk, + inout wire mode_led, + input wire RXD, + output wire TXD, + input wire rst_i); + + // dummy sinks + wire dummy_uart1_txd; + wire dummy_uart0_baudtick; + wire dummy_uart1_baudtick; + wire dummy_intmonitor; + wire dummy_targexp0_hsel; + wire [31:0] dummy_targexp0_haddr; + wire [1:0] dummy_targexp0_htrans; + wire dummy_targexp0_hwrite; + wire [2:0] dummy_targexp0_hsize; + wire [2:0] dummy_targexp0_hburst; + wire [3:0] dummy_targexp0_hprot; + wire [1:0] dummy_targexp0_memattr; + wire dummy_targexp0_exreq; + wire [3:0] dummy_targexp0_hmaster; + wire [31:0] dummy_targexp0_hwdata; + wire dummy_targexp0_hmastlock; + wire dummy_targexp0_hauser; + wire [3:0] dummy_targexp0_hwuser; + wire [31:0] dummy_initexp0_hrdata; + wire dummy_initexp0_hready; + wire dummy_initexp0_hresp; + wire dummy_initexp0_exresp; + wire [2:0] dummy_initexp0_hruser; + wire [3:0] dummy_apbtargexp2_pstrb; + wire [2:0] dummy_apbtargexp2_pprot; + wire dummy_apbtargexp2_psel; + wire dummy_apbtargexp2_penable; + wire [11:0] dummy_apbtargexp2_paddr; + wire dummy_apbtargexp2_pwrite; + wire [31:0] dummy_apbtargexp2_pwdata; + wire dummy_daptdo; + wire dummy_dapjtagnsw; + wire [3:0] dummy_tpiutracedata; + wire dummy_targexp0_hreadymux; + wire dummy_dapntdoen; + + // ROM 32k + wire [12:0] rom_addr; + wire [15:0] dummy_rom_addr; // flash is addressed by 4 bytes each, and there are also unused high bits of the address + wire targflash0_hsel; + wire [1:0] targflash0_htrans; + wire [2:0] dummy_targflash0_hsize; + wire [2:0] dummy_targflash0_hburst; + wire dummy_targflash0_hreadymux; + wire [31:0] rom_out; + wire targflash0_readyout; + + // SRAM 8k + wire [10:0] sram0_addr; + wire [1:0] dummy_sram0_addr; // high address bits + wire sram0_cs; + wire [3:0] sram0_wren; // byte write mask + wire [31:0] sram0_wdata; + wire [31:0] sram0_rdata; // all 32bit + wire [23:0] dummy_sram0_rdata_0; // for unused bits + wire [23:0] dummy_sram0_rdata_1; + wire [23:0] dummy_sram0_rdata_2; + wire [23:0] dummy_sram0_rdata_3; + + wire mtx_hreset_n; + + // The processor reset inputs are not explicitly brought out - Global Set Reset is used. + GSR gsr ( + .GSRI(rst_i) + ); + + wire GND = 1'b0; + wire VCC = 1'b1; + + // GPIO inout ports, 16 total but we need only one + wire [15:0] gpio_out; + wire [15:0] gpio_oen; // active low + wire [15:0] gpio_in; + + IOBUF led( + .O(gpio_in[0]), + .IO(mode_led), + .I(gpio_out[0]), + .OEN(~gpio_oen[0]) + ); + + EMCU cpu ( + .FCLK(clk), + .PORESETN(GND), // doesn't matter + .SYSRESETN(GND), // doesn't matter + .RTCSRCCLK(GND), // this is normal port but we haven't RTC in this example + .MTXHRESETN(mtx_hreset_n), + + .IOEXPOUTPUTO(gpio_out), + .IOEXPOUTPUTENO(gpio_oen), + .IOEXPINPUTI(gpio_in), + + .UART0RXDI(RXD), + .UART1RXDI(GND), + .UART0TXDO(TXD), + .UART1TXDO(dummy_uart1_txd), + .UART0BAUDTICK(dummy_uart0_baudtick), + .UART1BAUDTICK(dummy_uart1_baudtick), + + .INTMONITOR(dummy_intmonitor), + + .SRAM0ADDR({dummy_sram0_addr, sram0_addr}), + .SRAM0CS(sram0_cs), + .SRAM0WREN(sram0_wren), + .SRAM0WDATA(sram0_wdata), + .SRAM0RDATA(sram0_rdata), + + .TARGFLASH0HSEL(targflash0_hsel), + .TARGFLASH0HADDR({dummy_rom_addr[15:2], rom_addr, dummy_rom_addr[1:0]}), + .TARGFLASH0HTRANS(targflash0_htrans), + .TARGFLASH0HSIZE(dummy_targflash0_hsize), + .TARGFLASH0HBURST(dummy_targflash0_hburst), + .TARGFLASH0HREADYMUX(dummy_targflash0_hreadymux), + .TARGFLASH0HRDATA(rom_out), + .TARGFLASH0HRUSER({GND,GND,GND}), + .TARGFLASH0HRESP(GND), + .TARGFLASH0EXRESP(GND), + .TARGFLASH0HREADYOUT(targflash0_readyout), + + .TARGEXP0HSEL(dummy_targexp0_hsel), + .TARGEXP0HADDR(dummy_targexp0_haddr), + .TARGEXP0HTRANS(dummy_targexp0_htrans), + .TARGEXP0HWRITE(dummy_targexp0_hwrite), + .TARGEXP0HSIZE(dummy_targexp0_hsize), + .TARGEXP0HBURST(dummy_targexp0_hburst[2:0]), + .TARGEXP0HPROT(dummy_targexp0_hprot[3:0]), + .TARGEXP0MEMATTR(dummy_targexp0_memattr), + .TARGEXP0EXREQ(dummy_targexp0_exreq), + .TARGEXP0HMASTER(dummy_targexp0_hmaster), + .TARGEXP0HWDATA(dummy_targexp0_hwdata), + .TARGEXP0HMASTLOCK(dummy_targexp0_hmastlock), + .TARGEXP0HREADYMUX(dummy_targexp0_hreadymux), + .TARGEXP0HAUSER(dummy_targexp0_hauser), + .TARGEXP0HWUSER(dummy_targexp0_hwuser), + .INITEXP0HRDATA(dummy_initexp0_hrdata), + .INITEXP0HREADY(dummy_initexp0_hready), + .INITEXP0HRESP(dummy_initexp0_hresp), + .INITEXP0EXRESP(dummy_initexp0_exresp), + .INITEXP0HRUSER(dummy_initexp0_hruser), + .APBTARGEXP2PSTRB(dummy_apbtargexp2_pstrb), + .APBTARGEXP2PPROT(dummy_apbtargexp2_pprot), + .APBTARGEXP2PSEL(dummy_apbtargexp2_psel), + .APBTARGEXP2PENABLE(dummy_apbtargexp2_penable), + .APBTARGEXP2PADDR(dummy_apbtargexp2_paddr), + .APBTARGEXP2PWRITE(dummy_apbtargexp2_pwrite), + .APBTARGEXP2PWDATA(dummy_apbtargexp2_pwdata), + .DAPTDO(dummy_daptdo), + .DAPJTAGNSW(dummy_dapjtagnsw), + .DAPNTDOEN(dummy_dapntdoen), + .TPIUTRACEDATA(dummy_tpiutracedata), + .TARGEXP0HRDATA({32{GND}}), + .TARGEXP0HREADYOUT(GND), + .TARGEXP0HRESP(VCC), // XXX + .TARGEXP0EXRESP(GND), + .TARGEXP0HRUSER({GND,GND,GND}), + .INITEXP0HSEL(GND), + .INITEXP0HADDR({32{GND}}), + .INITEXP0HTRANS({GND,GND}), + .INITEXP0HWRITE(GND), + .INITEXP0HSIZE({GND,GND,GND}), + .INITEXP0HBURST({GND,GND,GND}), + .INITEXP0HPROT({GND,GND,GND,GND}), + .INITEXP0MEMATTR({GND,GND}), + .INITEXP0EXREQ(GND), + .INITEXP0HMASTER({GND,GND,GND,GND}), + .INITEXP0HWDATA({32{GND}}), + .INITEXP0HMASTLOCK(GND), + .INITEXP0HAUSER(GND), + .INITEXP0HWUSER({GND,GND,GND,GND}), + .APBTARGEXP2PRDATA({32{GND}}), + .APBTARGEXP2PREADY(GND), + .APBTARGEXP2PSLVERR(GND), + .DAPSWDITMS(GND), + .FLASHERR(GND), + .FLASHINT(GND) + ); + + // ROM + // To understand what the entrances and outputs of this primitive, I followed the description of the AMBA protocol. + // https://developer.arm.com/documentation/ihi0011/a/ or search for IHI0011a.pdf + // It was from there and by the names of the ports of the primitive that it + // became clear that RAM is connected directly without tricks, but for Flash + // it would be necessary to implement a whole client of this AHB Bus. + // My implementation is naive and bad, but it works. And by the way, I did + // not bother with another APB bus because for my purposes there was enough + // UART and GPIO :) + // + localparam ROM_IDLE = 2'b00; + localparam ROM_READ = 2'b01; + localparam ROM_OKEY = 2'b10; + reg [1:0] rom_state; + reg rom_sel; + reg [12:0] flash_in_addr; + + // AHB slave + always @(posedge clk) begin + if (!(rst_i & mtx_hreset_n)) begin + rom_state <= ROM_IDLE; + rom_sel <= 1'b0; + end else begin + case (rom_state) + ROM_IDLE: begin + if (targflash0_hsel & targflash0_htrans[1]) begin // NONSEQ/SEQ transfer + rom_state <= ROM_READ; + flash_in_addr <= rom_addr; + rom_sel <= 1'b1; + end + end + ROM_READ: begin + if (targflash0_hsel & targflash0_htrans[1]) begin // NONSEQ/SEQ transfer + rom_state <= ROM_OKEY; + rom_sel <= 1'b0; + end else begin + rom_state <= ROM_IDLE; + rom_sel <= 1'b0; + end + end + ROM_OKEY: begin + if (targflash0_hsel & targflash0_htrans[1]) begin // NONSEQ/SEQ transfer + rom_state <= ROM_IDLE; + rom_sel <= 1'b0; + end + end + endcase + end + end + assign targflash0_readyout = rom_state == ROM_IDLE; + + FLASH256K rom( + .DOUT(rom_out[31:0]), + .XADR(flash_in_addr[12:6]), + .YADR(flash_in_addr[5:0]), + .XE(rst_i), + .YE(rst_i), + .SE(rom_sel), + .ERASE(GND), + .PROG(GND), + .NVSTR(GND), + .DIN({32{GND}}) + ); + + // RAM 4 block of 2K + // Inferring will probably also work, but with primitives it is somehow easier for me. + SDPB ram_0 ( + .DO({dummy_sram0_rdata_0, sram0_rdata[7:0]}), + .DI({{24{GND}}, sram0_wdata[7:0]}), + .BLKSELA({GND, GND, sram0_cs}), + .BLKSELB({GND, GND, sram0_cs}), + .ADA({sram0_addr, GND,GND,GND}), + .ADB({sram0_addr, GND,GND,GND}), + .CLKA(clk), + .CLKB(clk), + .CEA(sram0_wren[0]), + .CEB(!sram0_wren[0]), + .OCE(VCC), + .RESETA(GND), + .RESETB(!rst_i) + ); + defparam ram_0.BIT_WIDTH_0=8; + defparam ram_0.BIT_WIDTH_1=8; + defparam ram_0.BLK_SEL_0=3'b001; + defparam ram_0.BLK_SEL_1=3'b001; + defparam ram_0.READ_MODE=1'b0; + defparam ram_0.RESET_MODE="SYNC"; + + SDPB ram_1 ( + .DO({dummy_sram0_rdata_1, sram0_rdata[15:8]}), + .DI({{24{GND}}, sram0_wdata[15:8]}), + .BLKSELA({GND, GND, sram0_cs}), + .BLKSELB({GND, GND, sram0_cs}), + .ADA({sram0_addr, GND,GND,GND}), + .ADB({sram0_addr, GND,GND,GND}), + .CLKA(clk), + .CLKB(clk), + .CEA(sram0_wren[1]), + .CEB(!sram0_wren[1]), + .OCE(VCC), + .RESETA(GND), + .RESETB(!rst_i) + ); + defparam ram_1.BIT_WIDTH_0=8; + defparam ram_1.BIT_WIDTH_1=8; + defparam ram_1.BLK_SEL_0=3'b001; + defparam ram_1.BLK_SEL_1=3'b001; + defparam ram_1.READ_MODE=1'b0; + defparam ram_1.RESET_MODE="SYNC"; + + SDPB ram_2 ( + .DO({dummy_sram0_rdata_2, sram0_rdata[23:16]}), + .DI({{24{GND}}, sram0_wdata[23:16]}), + .BLKSELA({GND, GND, sram0_cs}), + .BLKSELB({GND, GND, sram0_cs}), + .ADA({sram0_addr, GND,GND,GND}), + .ADB({sram0_addr, GND,GND,GND}), + .CLKA(clk), + .CLKB(clk), + .CEA(sram0_wren[2]), + .CEB(!sram0_wren[2]), + .OCE(VCC), + .RESETA(GND), + .RESETB(!rst_i) + ); + defparam ram_2.BIT_WIDTH_0=8; + defparam ram_2.BIT_WIDTH_1=8; + defparam ram_2.BLK_SEL_0=3'b001; + defparam ram_2.BLK_SEL_1=3'b001; + defparam ram_2.READ_MODE=1'b0; + defparam ram_2.RESET_MODE="SYNC"; + + SDPB ram_3 ( + .DO({dummy_sram0_rdata_3, sram0_rdata[31:24]}), + .DI({{24{GND}}, sram0_wdata[31:24]}), + .BLKSELA({GND, GND, sram0_cs}), + .BLKSELB({GND, GND, sram0_cs}), + .ADA({sram0_addr, GND,GND,GND}), + .ADB({sram0_addr, GND,GND,GND}), + .CLKA(clk), + .CLKB(clk), + .CEA(sram0_wren[3]), + .CEB(!sram0_wren[3]), + .OCE(VCC), + .RESETA(GND), + .RESETB(!rst_i) + ); + defparam ram_3.BIT_WIDTH_0=8; + defparam ram_3.BIT_WIDTH_1=8; + defparam ram_3.BLK_SEL_0=3'b001; + defparam ram_3.BLK_SEL_1=3'b001; + defparam ram_3.READ_MODE=1'b0; + defparam ram_3.RESET_MODE="SYNC"; + +endmodule diff --git a/examples/himbaechel/emcu-firmware/blinky-main.c-src b/examples/himbaechel/emcu-firmware/blinky-main.c-src new file mode 100755 index 00000000..e5321401 --- /dev/null +++ b/examples/himbaechel/emcu-firmware/blinky-main.c-src @@ -0,0 +1,79 @@ + /* Includes ------------------------------------------------------------------*/ + #include "gw1ns4c.h" + /*----------------------------------------------------------------------------*/ + + /* Declarations*/ + void initializeGPIO(); + void initializeTimer(); + void delayMillis(uint32_t ms); + + + int main(void) + { + SystemInit(); //Configures CPU for the defined system clock + initializeGPIO(); + initializeTimer(); + + /* Infinite loop */ + while(1) + { + GPIO_ResetBit(GPIO0, GPIO_Pin_0); + delayMillis(500); + GPIO_SetBit(GPIO0, GPIO_Pin_0); + delayMillis(500); + } + } + + + void initializeGPIO() { + GPIO_InitTypeDef gpioInitStruct; + + // --------- output + //Select pin0, you can OR pins together to initialize them at the same time + gpioInitStruct.GPIO_Pin = GPIO_Pin_0; + + //Set selected pins as output (see GPIOMode_TypeDef in gw1ns4c_gpio.h) + gpioInitStruct.GPIO_Mode = GPIO_Mode_OUT; + + //Disable interrupts on selected pins (see GPIOInt_TypeDef) + gpioInitStruct.GPIO_Int = GPIO_Int_Disable; + + //Initialize the GPIO using the configured init struct + GPIO_Init(GPIO0, &gpioInitStruct); + } + + void initializeTimer() { + TIMER_InitTypeDef timerInitStruct; + + timerInitStruct.Reload = 0; + + //Disable interrupt requests from timer for now + timerInitStruct.TIMER_Int = DISABLE; + + //Disable timer enabling/clocking from external pins (GPIO) + timerInitStruct.TIMER_Exti = TIMER_DISABLE; + + TIMER_Init(TIMER0, &timerInitStruct); + TIMER_StopTimer(TIMER0); + } + + #define CYCLES_PER_MILLISEC (SystemCoreClock / 1000) + void delayMillis(uint32_t ms) { + TIMER_StopTimer(TIMER0); + //Reset timer just in case it was modified elsewhere + TIMER_SetValue(TIMER0, 0); + TIMER_EnableIRQ(TIMER0); + + uint32_t reloadVal = CYCLES_PER_MILLISEC * ms; + //Timer interrupt will trigger when it reaches the reload value + TIMER_SetReload(TIMER0, reloadVal); + + TIMER_StartTimer(TIMER0); + //Block execution until timer wastes the calculated amount of cycles + while (TIMER_GetIRQStatus(TIMER0) != SET); + + TIMER_StopTimer(TIMER0); + TIMER_ClearIRQ(TIMER0); + TIMER_SetValue(TIMER0, 0); + } + diff --git a/examples/himbaechel/emcu-firmware/blinky.bin b/examples/himbaechel/emcu-firmware/blinky.bin new file mode 100755 index 0000000000000000000000000000000000000000..bf3689f377c5578e40d76b1b2e6f537ff0ed9e62 GIT binary patch literal 3232 zcmeHJUrbw782@hX1#W?if=cjGO-p0cHA_ae#m%Z=u(gba)Fu9f7;nc+P9-yJxJ0}U ztJ@NNm`i<|-HS2qiNt}f(S(t@Xrd-tLIV<4{DTj(jyZD|UA(1?`8)UA0W$E(n8k3K z-}jyKJHPYY?|xr7lzim7R8Dk`h%Nx*z(wFkVEMQN;+jL=fOktoF97!d3BV6*0Nw?n z6-3+M4+3uhe7p_+H29tHyMb=ZPr(lZqrlg|H^5K8RiFrzxrl0k`+$dmEx>l56L=m- zo}tr}9StYX_C@%7zOb@gs#%+hTK#8r$e>52cb3e0i_C{C$*;DP`AjkP$7~;&Td`KK ze!^LAw0P)+E0r0(MDF^@qS4Tq}>K{mE_+`dXWj$aYywOA_`_- zQ4UK%D<@XZI{U9I#61k9M`VllBHwuD9#8Vjn|2P{kh2jFu|^i+cA(TBV%-BH{RX2Z zP3N}Dwp!et+cs_6ylu5THgDUsZS%I(dTidd=^p+J&$Pi_Pq?lp50JmjYVwE`-C8B2 zO-9^E+zej1STZPBku#W<2qmW4v=+?bb<-t73YI&p*2Xy%oGVxcE)6B;((w_f>bUA< z!SMX@&YWk~)hqa}o|fqmoc<@R=4iE^_0Y<TulyA}RR^Fcb(&w$b8*s8&X?KcEebf+MUJrvwP5D*o z^e9WOy0cQ{M1JDk7c&rdygORiq3J6AF5Mk>>E-Y$yaHbVf9odW_Xhbsn>#5f@G4LZ zRPCznsE(f0<-S^BPWS7itJ-f2CX-EJvWvjw$18M*oA;0-djSVVhqkjHsU z5zygJ;eX_O;otqJ8S*P(GOH{l+Q2^Vm4{D6d|1DT+f7Ff8!nr%m`Uyjqeq6MR0FHQ zUZ?dybljr%@>YBN`0%UjrTf=S#7s%uv7`LTQRUF^ghkCGtyN>v-PQp>knmAbtfjemeX1V{)ZLd_wQe%LTBax literal 0 HcmV?d00001 diff --git a/examples/himbaechel/tangnano4k.cst b/examples/himbaechel/tangnano4k.cst index 35618673..7e10f37b 100644 --- a/examples/himbaechel/tangnano4k.cst +++ b/examples/himbaechel/tangnano4k.cst @@ -8,6 +8,9 @@ IO_LOC "led[5]" 32; IO_LOC "key_i" 15; IO_LOC "rst_i" 14; +IO_LOC "mode_led" 10; +IO_PORT "mode_led" PULL_MODE_NONE DRIVE=8; + IO_LOC "clk" 45; CLOCK_LOC "clk" BUFG; From d7276cd6bb86add2dc44bc4095c45cb90cbce126 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Sat, 14 Sep 2024 17:55:07 +1000 Subject: [PATCH 3/5] Add UART EMCU example Use first UART of the Cortex-M3 emcu for text adventure-like game. Signed-off-by: YRabbit --- examples/himbaechel/emcu-blinky.v | 4 + .../himbaechel/emcu-firmware/uart-game.c-src | 266 ++++++++++++++++++ .../himbaechel/emcu-firmware/uart-main.c-src | 96 +++++++ .../emcu-firmware/uart-retarget.c-src | 30 ++ examples/himbaechel/emcu-firmware/uart.bin | Bin 0 -> 31552 bytes 5 files changed, 396 insertions(+) create mode 100755 examples/himbaechel/emcu-firmware/uart-game.c-src create mode 100755 examples/himbaechel/emcu-firmware/uart-main.c-src create mode 100755 examples/himbaechel/emcu-firmware/uart-retarget.c-src create mode 100755 examples/himbaechel/emcu-firmware/uart.bin diff --git a/examples/himbaechel/emcu-blinky.v b/examples/himbaechel/emcu-blinky.v index fa8c2324..52558df4 100644 --- a/examples/himbaechel/emcu-blinky.v +++ b/examples/himbaechel/emcu-blinky.v @@ -4,6 +4,10 @@ * The LED on the board should blink. * Attention: flashing is performed with firmware as follows: * openFPGALoader -f -b tangnano4k --mcufw=emcu-firmware/blinky.bin emcu-blinky-tangnano4k.fs +* +* or +* openFPGALoader -f -b tangnano4k --mcufw=emcu-firmware/uart.bin emcu-blinky-tangnano4k.fs +* */ module top ( diff --git a/examples/himbaechel/emcu-firmware/uart-game.c-src b/examples/himbaechel/emcu-firmware/uart-game.c-src new file mode 100755 index 00000000..1ffa2425 --- /dev/null +++ b/examples/himbaechel/emcu-firmware/uart-game.c-src @@ -0,0 +1,266 @@ +/* +Copyright (c) 2018 Henri Landvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +*/ + +#include +#include +#include + +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_RESET "\x1b[0m" + +int readstr(char *ptr, int len); + + +const char *file_content[22] = { +"#", +"You wake up in a mysterious cave and don't remember why you are here. Your head is hurting and you feel tired. What to do you do? (Write a or b and press Enter)", +"a) Study the cave b) Start walking away from the cave", +"Spider webs are all around you and it is difficult for you to see but in distance you see light. It looks like this is the way out and you start walking towards the light.", +"You see in distance a light. This must be the way out from the cave and you start walking towards the light.", +"", +"#", +"There is a door with a lock. It is written that to open this door you must answer a question. What is 2*111? (Write the answer down and press Enter)", +"You opened the door and now you have escaped the cave.", +"", +"#", +"You find yourself in a forest where everything around you is very green and bright. It is a day and birds are singing.", +"In distance you see a lake and you start walking towards it. Write a and press Enter to continue.", +"", +"#", +"You are next to a lake. You see in the right a tree where is written a question. What goes up in the morning up and goes down in the evening? Write down the answer and press Enter.", +"You answered correctly and you see in distance a very high mountain. You plan to go there.", +"", +"#", +"You have arrived on top of a mountain. It is very windy here and you feel cold. There is a tower not so far. You start to go towards it.", +"To enter this tower you must answer this question. Why you are here?", +"a) I don't know b) I know c) What's the stupid question" +}; +int file_rows = 0; +int chapter_number = 1; +int count_chapters = 1; +int chapter_locations[5]; +int chapter_location_now = 0; +char answer[20] = ""; + + +/*********************************************************************************/ +/* READ THE FILE WHERE IS THE STORY AND SAVE IT TO A MULTIDIMENSIONAL CHAR ARRAY */ +/*********************************************************************************/ +int read_file(char *filename) +{ + file_rows = 22; + /* + FILE* file = fopen(filename, "r"); + if(!file) { + perror("File opening failed"); + return EXIT_FAILURE; + } + + while(fgets(file_content[file_rows], sizeof(file_content[file_rows]), file) != NULL) { + file_content[file_rows][strcspn(file_content[file_rows], "\n")] = 0; // Remove empty lines from char + file_rows++; + } + + if (ferror(file)) { puts("I/O error when reading"); } + else if (feof(file)) { /* Reading file was succesful */ //} + + /* + fclose(file); + */ + return 0; +} + +/*********************/ +/* CLEAR THE CONSOLE */ +/*********************/ +void clear_console() { + //puts("\x1B[2J"); +} + +/***********************************/ +/* PRINT MESSAGE TO CONSOLE SCREEN */ +/***********************************/ +void print_message_to_console(char *message) { + if(message == "error") { + printf(ANSI_COLOR_RED "Wrong answer. Please try again.\n" ANSI_COLOR_RESET); + } else { + puts(message); + } +} + +/*****************/ +/* TYPING READER */ +/*****************/ +void typing_reader() { + answer[0] = 0; + readstr(answer, 19); + printf("\n"); +} + +/***********************/ +/* PLAY A CHAPTER TEXT */ +/***********************/ +void play_chapter_text(char *chapter_text) { + printf("%s\n\n",chapter_text); +} + +/**************************/ +/* GO TO THE NEXT CHAPTER */ +/**************************/ +void go_to_next_chapter() { + chapter_number++; + chapter_location_now++; +} + +/*************************************************************************/ +/* FIND THE CHAPTER LOCATIONS FROM THE TEXT FILE AND SAVE IT TO AN ARRAY */ +/*************************************************************************/ +void find_chapter_locations() +{ + int j = 0; + for(int i = 0; i < file_rows; i++) + { + if(strcmp(file_content[i],"#") == 0) + { + chapter_locations[j] = i; + j++; + } + } +} + +/********************/ +/* CONTROL THE GAME */ +/********************/ +void controller() +{ + if(chapter_number == 1) + { + play_chapter_text(file_content[chapter_locations[chapter_location_now]+1]); + play_chapter_text(file_content[chapter_locations[chapter_location_now]+2]); + typing_reader(); + + if(strcmp(answer,"a") == 0) + { + clear_console(); + play_chapter_text(file_content[chapter_locations[chapter_location_now]+3]); + go_to_next_chapter(); + controller(); + } + else if(strcmp(answer,"b") == 0) + { + clear_console(); + play_chapter_text(file_content[chapter_locations[chapter_location_now]+4]); + go_to_next_chapter(); + controller(); + } + else { + clear_console(); + print_message_to_console("error"); + controller(); + } + } + else if(chapter_number == 2) + { + play_chapter_text(file_content[chapter_locations[chapter_location_now]+1]); + typing_reader(); + + if(strcmp(answer,"222") == 0) + { + clear_console(); + play_chapter_text(file_content[chapter_locations[chapter_location_now]+2]); + go_to_next_chapter(); + controller(); + } + else { + clear_console(); + print_message_to_console("error"); + controller(); + } + } + else if(chapter_number == 3) + { + play_chapter_text(file_content[chapter_locations[chapter_location_now]+1]); + play_chapter_text(file_content[chapter_locations[chapter_location_now]+2]); + typing_reader(); + + if(strcmp(answer,"a") == 0) + { + clear_console(); + go_to_next_chapter(); + controller(); + } + else { + clear_console(); + print_message_to_console("error"); + controller(); + } + } + else if(chapter_number == 4) + { + play_chapter_text(file_content[chapter_locations[chapter_location_now]+1]); + typing_reader(); + + if(strcmp(answer,"sun") == 0) + { + clear_console(); + play_chapter_text(file_content[chapter_locations[chapter_location_now]+2]); + go_to_next_chapter(); + controller(); + } + else { + clear_console(); + print_message_to_console("error"); + controller(); + } + } + else if(chapter_number == 5) + { + play_chapter_text(file_content[chapter_locations[chapter_location_now]+1]); + play_chapter_text(file_content[chapter_locations[chapter_location_now]+2]); + play_chapter_text(file_content[chapter_locations[chapter_location_now]+3]); + typing_reader(); + + if(strcmp(answer,"a") == 0 || strcmp(answer,"b") == 0 || strcmp(answer,"c") == 0) + { + clear_console(); + puts("---------------------------------------------------"); + puts("---------------------------------------------------"); + puts("YOU DID IT! YOU ENTERED THE TOWER AND WON THE GAME!"); + puts("---------------------------------------------------"); + puts("---------------------------------------------------"); + } + else { + clear_console(); + print_message_to_console("error"); + controller(); + } + } + else + { + puts("ERROR! NO CHAPTER FOUND!"); + } +} + +/*********************/ +/* START THE PROGRAM */ +/*********************/ +void go(void) +{ + read_file("story.txt"); + clear_console(); + find_chapter_locations(); + controller(); +} diff --git a/examples/himbaechel/emcu-firmware/uart-main.c-src b/examples/himbaechel/emcu-firmware/uart-main.c-src new file mode 100755 index 00000000..058b4fad --- /dev/null +++ b/examples/himbaechel/emcu-firmware/uart-main.c-src @@ -0,0 +1,96 @@ +/* Connect USB2COM to RXD and TXD pins */ +/* 9600 baud */ + + /* Includes ------------------------------------------------------------------*/ + #include "gw1ns4c.h" + #include + /*----------------------------------------------------------------------------*/ + + void go(void); + + /* Declarations*/ + void initializeTimer(); + void delayMillis(uint32_t ms); + void initializeUART(); + int readstr(char *ptr, int len); + + char buf[100]; + int main(void) + { + SystemInit(); //Configures CPU for the defined system clock + initializeTimer(); + initializeUART(); + + uint32_t counter = 0; + printf("************* Apicula on Tangnano4k with Cortex-M3 ************\n"); + delayMillis(1000); + go(); + while(1); + } + + int readstr(char *ptr, int len) { + int DataIdx; + + for (DataIdx = 0; DataIdx < len; DataIdx++) { + *ptr++ = UART_ReceiveChar(UART0); + if (*(ptr - 1) == '\r') { + --ptr; + --DataIdx; + break; + } + } + + *ptr = '\0'; + return DataIdx; + } + + //Initializes UART0 + void initializeUART() + { + UART_InitTypeDef uartInitStruct; + //Enable transmission + uartInitStruct.UART_Mode.UARTMode_Tx = ENABLE; + //Disable reception + uartInitStruct.UART_Mode.UARTMode_Rx = ENABLE; + //9600 baud rate typical of Arduinos + uartInitStruct.UART_BaudRate = 9600; + //Initialize UART0 using the struct configs + UART_Init(UART0, &uartInitStruct); + } + + void initializeTimer() { + TIMER_InitTypeDef timerInitStruct; + + timerInitStruct.Reload = 0; + + //Disable interrupt requests from timer for now + timerInitStruct.TIMER_Int = DISABLE; + + //Disable timer enabling/clocking from external pins (GPIO) + timerInitStruct.TIMER_Exti = TIMER_DISABLE; + + TIMER_Init(TIMER0, &timerInitStruct); + TIMER_StopTimer(TIMER0); + } + + #define CYCLES_PER_MILLISEC (SystemCoreClock / 1000) + void delayMillis(uint32_t ms) { + TIMER_StopTimer(TIMER0); + TIMER_SetValue(TIMER0, 0); //Reset timer just in case it was modified elsewhere + TIMER_EnableIRQ(TIMER0); + + uint32_t reloadVal = CYCLES_PER_MILLISEC * ms; + //Timer interrupt will trigger when it reaches the reload value + TIMER_SetReload(TIMER0, reloadVal); + + TIMER_StartTimer(TIMER0); + //Block execution until timer wastes the calculated amount of cycles + while (TIMER_GetIRQStatus(TIMER0) != SET); + + TIMER_StopTimer(TIMER0); + TIMER_ClearIRQ(TIMER0); + TIMER_SetValue(TIMER0, 0); + } + + + diff --git a/examples/himbaechel/emcu-firmware/uart-retarget.c-src b/examples/himbaechel/emcu-firmware/uart-retarget.c-src new file mode 100755 index 00000000..082e6108 --- /dev/null +++ b/examples/himbaechel/emcu-firmware/uart-retarget.c-src @@ -0,0 +1,30 @@ +/* + * ***************************************************************************************** + * + * Copyright (C) 2014-2021 Gowin Semiconductor Technology Co.,Ltd. + * + * @file retarget.c + * @author Embedded Development Team + * @version V1.x.x + * @date 2021-01-01 09:00:00 + * @brief UART printf and scanf retarget function. + ****************************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "gw1ns4c.h" +#include +#include + +__attribute__ ((used)) int _write (int fd, char *ptr, int len) +{ + size_t i; + + for (i=0; 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 BJr)1} literal 0 HcmV?d00001 From 172840b2da40b6318b871933071bd2f257634fd0 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Sun, 22 Sep 2024 19:04:34 +1000 Subject: [PATCH 4/5] EMCU. Add the APB example The processor built into the GW1NSR-4C can communicate with the outside world using another mechanism besides the Flash, memory and GPIO buses - this is the Advanced Peripheral Bus (APB). APB is part of the Advanced Microcontroller Bus Architecture hierarchy of buses and is optimized for minimal power consumption and reduced interface complexity. APB should be used to interface to any peripherals which are low-bandwidth and do not require the high performance of a piplined bus interface. Strictly speaking, according to the specification there must be a bridge between the high-speed AHB bus and the APB bus, among the functions of which are device selection (PSELx), generation of the PENABLE signal and holding of values on the address bus. And if PSELx signals have to be generated, there is no question, the EMCU primitive already has a PENABLE output. So I took the liberty and did not implement the latching of address lines, so the bridge turned out to be very small: ``` verilog wire psel1; assign psel1 = apbtargexp2_psel && (apbtargexp2_paddr[11:8] == 4'h4); // 0x40002 >4< 00 ``` Here I compare to the address of the first device - 0x40002400, there are 12 such devices with base addresses spaced 256 bytes apart (this does not cover the entire range of the 4 high bits of the APB address bus, so there are probably some unknown devices with fixed addresses). I don't use the [7:0] address bits in this example, but it's actually a very useful thing to implement the registers of a particular peripheral. The exchange is done in 32-bit words so 64 registers per device. Signed-off-by: YRabbit --- examples/himbaechel/Makefile.himbaechel | 2 +- .../himbaechel/emcu-firmware/apb_blinky.bin | Bin 0 -> 3244 bytes .../himbaechel/emcu-firmware/apb_blinky.c_src | 100 +++++ examples/himbaechel/emcu-with-apb-blinky.v | 402 ++++++++++++++++++ 4 files changed, 503 insertions(+), 1 deletion(-) create mode 100644 examples/himbaechel/emcu-firmware/apb_blinky.bin create mode 100644 examples/himbaechel/emcu-firmware/apb_blinky.c_src create mode 100644 examples/himbaechel/emcu-with-apb-blinky.v diff --git a/examples/himbaechel/Makefile.himbaechel b/examples/himbaechel/Makefile.himbaechel index 1d3c8a94..7083fa40 100644 --- a/examples/himbaechel/Makefile.himbaechel +++ b/examples/himbaechel/Makefile.himbaechel @@ -62,7 +62,7 @@ all: \ dsp-mult36x36-tangnano4k.fs dsp-padd9-tangnano4k.fs dsp-padd18-tangnano4k.fs \ dsp-mult9x9-tangnano4k.fs dsp-alu54d-tangnano4k.fs dsp-multalu18x18-tangnano4k.fs \ dsp-multalu36x18-tangnano4k.fs dsp-multaddalu18x18-tangnano4k.fs \ - dqce-tangnano4k.fs dcs-tangnano4k.fs emcu-blinky-tangnano4k.fs \ + dqce-tangnano4k.fs dcs-tangnano4k.fs emcu-blinky-tangnano4k.fs emcu-with-apb-blinky-tangnano4k.fs \ \ blinky-tangnano9k.fs shift-tangnano9k.fs blinky-tbuf-tangnano9k.fs blinky-oddr-tangnano9k.fs \ blinky-clkdiv-tangnano9k.fs dvi-example-tangnano9k.fs\ diff --git a/examples/himbaechel/emcu-firmware/apb_blinky.bin b/examples/himbaechel/emcu-firmware/apb_blinky.bin new file mode 100644 index 0000000000000000000000000000000000000000..98d70430edf949def890aaba5b9846889e483b26 GIT binary patch literal 3244 zcmeH}T}&KR6oAj{%);zXfr^r4p*pZNMmHoy+9+%^KQADTY!V>i)QGHNwyBDxzWQSb*JbS<{YRBE`(w5;dO%x*Ro-;8Mt zL%w_NIrrQ%XU_duKmzGZ0l>!qFpJC~-yuICe}8^K!&S?81EqrlcnY}#=|!rL8srpG zTnJE)au9g|Vb3cl%hA3M<)g@5*guVO3YkH^L@pvfBUg|#Vz&WoM|L3hB72Y~q#bz@ ziJgN9P-o=W`ACrUH&UCo`952HvsV9E9pW(I3{{W{a$yztrD^cn6NRl|tx*E)Vp>?X zTm5g+pvGoE#jPUk6ajW4F`Nt9avHP;DQMNS$nyOly)EP=r9+1?Vre9^Hk;|jXb;mu z!@5`F4C^PE@U>$R(C(+H6sRp2kHwC~MYd=^LJ9pg3 zpm0@vGi*N1ma}pG z0?W^|IhF&YbJ&)fEf}7lx>(%1)rIq$y3NqXbGl&YOF3OM^onCy z{}OY4PM6I2IlU2e_Exrz>-eQk-2eD~GOe%vfh*b-C7p!V+&uWX1o&W?^LgaktrfxJ zAZ7Q9OV%Txn%*3Gr;~4{d5P_byc$^hyB^Pjt~3yxl(xK{hF#_I5Xr19W^}^U<=er3 zIhoy|>{fP!oNZo3#53S%D^&_miYNt?g($PPk-3*Yx<1aa{M<+h;%arbxkKY#{s$rO z#S@7G`uEOOXB$YbHJ?|TsNh;piTh*0%v$OOXnQCCvCevn01|^Bz4$w~k@|Q4#5hz5 zGH5O;ggoRzA3t?6D53r|p3QE|q2`hn4r}1JCv<$08}*Q49BZd{hvq1}wMh4Oy*hQ2 z^xRoAAJ#arrKRBa5#jl%c?z{3HoFqsLw%L+UKNBtlOBxCPtN?Ng+bf({&S?7aDlVU zZgo)kl)@<7cPX(zU)nCN+pkxyaK#H$m=u$v!2!~-@2e!frS`q%Zxf%V7U;{h^E6gc zxxyFQlHAGB;FXjpj|NxpZfwN*uzVvyP#GI&qj8hRdb+x${+{jzDg4MbCqSMq%V=nd z^gc7#-zDumJaDvUsHVM6YC6y?9qjKt)HlrhJ-B|b6B^l?=40H(*a$pG{m49$wcTnG j{}nNwqPp3$yKj5;*ULZJ!F8)8xs}gW1^%ZMV0ZXmM-Fhp literal 0 HcmV?d00001 diff --git a/examples/himbaechel/emcu-firmware/apb_blinky.c_src b/examples/himbaechel/emcu-firmware/apb_blinky.c_src new file mode 100644 index 00000000..b13acf6a --- /dev/null +++ b/examples/himbaechel/emcu-firmware/apb_blinky.c_src @@ -0,0 +1,100 @@ +/* + ****************************************************************************************** + * @file main.c + * @author GowinSemiconductor + * @device Gowin_EMPU(GW1NS-4C) + * @brief Main program body. + ****************************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "gw1ns4c.h" +#include +#include + +// First APB master address +uint32_t const apb2_periph_base = 0x40002400; + +struct APB2_leds_peripheral { + uint32_t volatile led : 1; // not memory - read/write the bus ;) +}; + +struct APB2_leds_peripheral *leds = (struct APB2_leds_peripheral *)apb2_periph_base; + +void initialize_timer(); +void initialize_UART(); +void delay_millis(uint32_t ms); + +void print_led_state(void) { + if (leds->led) { + UART_SendString(UART0, "Read led: ON\r\n"); + } else { + UART_SendString(UART0, "Read led: OFF\r\n"); + } +} + +int main(void) { + SystemInit(); + initialize_timer(); + initialize_UART(); + + UART_SendString(UART0, "Apicula Cortex-M3 APB blinky\r\n"); + while (1) { + leds->led = 0; + print_led_state(); + delay_millis(100); + leds->led = 1; + print_led_state(); + delay_millis(1000); + } +} + +// Initializes UART0 +void initialize_UART() { + UART_InitTypeDef uartInitStruct; + // Enable transmission + uartInitStruct.UART_Mode.UARTMode_Tx = ENABLE; + // Disable reception + uartInitStruct.UART_Mode.UARTMode_Rx = DISABLE; + // 9600 baud rate typical of Arduinos + uartInitStruct.UART_BaudRate = 9600; + // Initialize UART0 using the struct configs + UART_Init(UART0, &uartInitStruct); +} + +void initialize_timer() { + TIMER_InitTypeDef timerInitStruct; + + timerInitStruct.Reload = 0; + + // Disable interrupt requests from timer for now + timerInitStruct.TIMER_Int = DISABLE; + + // Disable timer enabling/clocking from external pins (GPIO) + timerInitStruct.TIMER_Exti = TIMER_DISABLE; + + TIMER_Init(TIMER0, &timerInitStruct); + TIMER_StopTimer(TIMER0); +} + +#define CYCLES_PER_MILLISEC (SystemCoreClock / 1000) +void delay_millis(uint32_t ms) { + TIMER_StopTimer(TIMER0); + // Reset timer just in case it was modified elsewhere + TIMER_SetValue(TIMER0, 0); + TIMER_EnableIRQ(TIMER0); + + uint32_t reloadVal = CYCLES_PER_MILLISEC * ms; + // Timer interrupt will trigger when it reaches the reload value + TIMER_SetReload(TIMER0, reloadVal); + + TIMER_StartTimer(TIMER0); + // Block execution until timer wastes the calculated amount of cycles + while (TIMER_GetIRQStatus(TIMER0) != SET) + ; + + TIMER_StopTimer(TIMER0); + TIMER_ClearIRQ(TIMER0); + TIMER_SetValue(TIMER0, 0); +} + diff --git a/examples/himbaechel/emcu-with-apb-blinky.v b/examples/himbaechel/emcu-with-apb-blinky.v new file mode 100644 index 00000000..265df851 --- /dev/null +++ b/examples/himbaechel/emcu-with-apb-blinky.v @@ -0,0 +1,402 @@ +`default_nettype none + +/* +* The LED on the board should blink and its state should be reported through +* UART. +* Attention: flashing is performed with firmware as follows: +* openFPGALoader -f -b tangnano4k --mcufw=emcu-firmware/apb-blinky.bin emcu-apb-blinky-tangnano4k.fs +* +*/ + +module top ( + input wire clk, + output wire mode_led, + input wire RXD, + output wire TXD, + input wire rst_i); + + // dummy sinks + wire dummy_uart1_txd; + wire dummy_uart0_baudtick; + wire dummy_uart1_baudtick; + wire dummy_intmonitor; + wire dummy_targexp0_hsel; + wire [31:0] dummy_targexp0_haddr; + wire [1:0] dummy_targexp0_htrans; + wire dummy_targexp0_hwrite; + wire [2:0] dummy_targexp0_hsize; + wire [2:0] dummy_targexp0_hburst; + wire [3:0] dummy_targexp0_hprot; + wire [1:0] dummy_targexp0_memattr; + wire dummy_targexp0_exreq; + wire [3:0] dummy_targexp0_hmaster; + wire [31:0] dummy_targexp0_hwdata; + wire dummy_targexp0_hmastlock; + wire dummy_targexp0_hauser; + wire [3:0] dummy_targexp0_hwuser; + wire [31:0] dummy_initexp0_hrdata; + wire dummy_initexp0_hready; + wire dummy_initexp0_hresp; + wire dummy_initexp0_exresp; + wire [2:0] dummy_initexp0_hruser; + wire dummy_daptdo; + wire dummy_dapjtagnsw; + wire [3:0] dummy_tpiutracedata; + wire dummy_targexp0_hreadymux; + wire dummy_dapntdoen; + + // Periphery bus + wire apbtargexp2_psel; + wire [11:0] apbtargexp2_paddr; + wire apbtargexp2_pready; + wire apbtargexp2_penable; + wire apbtargexp2_pwrite; + wire [31:0] apbtargexp2_pwdata; + wire [31:0] apbtargexp2_prdata; + wire [3:0] apbtargexp2_pstrb; + wire [2:0] apbtargexp2_pprot; + + // ROM 32k + wire [12:0] rom_addr; + wire [15:0] dummy_rom_addr; // flash is addressed by 4 bytes each, and there are also unused high bits of the address + wire targflash0_hsel; + wire [1:0] targflash0_htrans; + wire [2:0] dummy_targflash0_hsize; + wire [2:0] dummy_targflash0_hburst; + wire dummy_targflash0_hreadymux; + wire [31:0] rom_out; + wire targflash0_readyout; + + // SRAM 8k + wire [10:0] sram0_addr; + wire [1:0] dummy_sram0_addr; // high address bits + wire sram0_cs; + wire [3:0] sram0_wren; // byte write mask + wire [31:0] sram0_wdata; + wire [31:0] sram0_rdata; // all 32bit + wire [23:0] dummy_sram0_rdata_0; // for unused bits + wire [23:0] dummy_sram0_rdata_1; + wire [23:0] dummy_sram0_rdata_2; + wire [23:0] dummy_sram0_rdata_3; + + wire mtx_hreset_n; + + // The processor reset inputs are not explicitly brought out - Global Set Reset is used. + GSR gsr ( + .GSRI(rst_i) + ); + + wire GND = 1'b0; + wire VCC = 1'b1; + + // dummy GPIO inout ports, unused + wire [15:0] gpio_out; + wire [15:0] gpio_oen; + wire [15:0] gpio_in; + + EMCU cpu ( + .FCLK(clk), + .PORESETN(GND), // doesn't matter + .SYSRESETN(GND), // doesn't matter + .RTCSRCCLK(GND), // this is normal port but we haven't RTC in this example + .MTXHRESETN(mtx_hreset_n), + + .IOEXPOUTPUTO(gpio_out), + .IOEXPOUTPUTENO(gpio_oen), + .IOEXPINPUTI(gpio_in), + + .UART0RXDI(RXD), + .UART1RXDI(GND), + .UART0TXDO(TXD), + .UART1TXDO(dummy_uart1_txd), + .UART0BAUDTICK(dummy_uart0_baudtick), + .UART1BAUDTICK(dummy_uart1_baudtick), + + .INTMONITOR(dummy_intmonitor), + + .SRAM0ADDR({dummy_sram0_addr, sram0_addr}), + .SRAM0CS(sram0_cs), + .SRAM0WREN(sram0_wren), + .SRAM0WDATA(sram0_wdata), + .SRAM0RDATA(sram0_rdata), + + .TARGFLASH0HSEL(targflash0_hsel), + .TARGFLASH0HADDR({dummy_rom_addr[15:2], rom_addr, dummy_rom_addr[1:0]}), + .TARGFLASH0HTRANS(targflash0_htrans), + .TARGFLASH0HSIZE(dummy_targflash0_hsize), + .TARGFLASH0HBURST(dummy_targflash0_hburst), + .TARGFLASH0HREADYMUX(dummy_targflash0_hreadymux), + .TARGFLASH0HRDATA(rom_out), + .TARGFLASH0HRUSER({GND,GND,GND}), + .TARGFLASH0HRESP(GND), + .TARGFLASH0EXRESP(GND), + .TARGFLASH0HREADYOUT(targflash0_readyout), + + .TARGEXP0HSEL(dummy_targexp0_hsel), + .TARGEXP0HADDR(dummy_targexp0_haddr), + .TARGEXP0HTRANS(dummy_targexp0_htrans), + .TARGEXP0HWRITE(dummy_targexp0_hwrite), + .TARGEXP0HSIZE(dummy_targexp0_hsize), + .TARGEXP0HBURST(dummy_targexp0_hburst[2:0]), + .TARGEXP0HPROT(dummy_targexp0_hprot[3:0]), + .TARGEXP0MEMATTR(dummy_targexp0_memattr), + .TARGEXP0EXREQ(dummy_targexp0_exreq), + .TARGEXP0HMASTER(dummy_targexp0_hmaster), + .TARGEXP0HWDATA(dummy_targexp0_hwdata), + .TARGEXP0HMASTLOCK(dummy_targexp0_hmastlock), + .TARGEXP0HREADYMUX(dummy_targexp0_hreadymux), + .TARGEXP0HAUSER(dummy_targexp0_hauser), + .TARGEXP0HWUSER(dummy_targexp0_hwuser), + .INITEXP0HRDATA(dummy_initexp0_hrdata), + .INITEXP0HREADY(dummy_initexp0_hready), + .INITEXP0HRESP(dummy_initexp0_hresp), + .INITEXP0EXRESP(dummy_initexp0_exresp), + .INITEXP0HRUSER(dummy_initexp0_hruser), + .DAPTDO(dummy_daptdo), + .DAPJTAGNSW(dummy_dapjtagnsw), + .DAPNTDOEN(dummy_dapntdoen), + .TPIUTRACEDATA(dummy_tpiutracedata), + .TARGEXP0HRDATA({32{GND}}), + .TARGEXP0HREADYOUT(GND), + .TARGEXP0HRESP(VCC), // XXX + .TARGEXP0EXRESP(GND), + .TARGEXP0HRUSER({GND,GND,GND}), + .INITEXP0HSEL(GND), + .INITEXP0HADDR({32{GND}}), + .INITEXP0HTRANS({GND,GND}), + .INITEXP0HWRITE(GND), + .INITEXP0HSIZE({GND,GND,GND}), + .INITEXP0HBURST({GND,GND,GND}), + .INITEXP0HPROT({GND,GND,GND,GND}), + .INITEXP0MEMATTR({GND,GND}), + .INITEXP0EXREQ(GND), + .INITEXP0HMASTER({GND,GND,GND,GND}), + .INITEXP0HWDATA({32{GND}}), + .INITEXP0HMASTLOCK(GND), + .INITEXP0HAUSER(GND), + .INITEXP0HWUSER({GND,GND,GND,GND}), + + .APBTARGEXP2PSEL(apbtargexp2_psel), + .APBTARGEXP2PADDR(apbtargexp2_paddr), + .APBTARGEXP2PSTRB(apbtargexp2_pstrb), + .APBTARGEXP2PPROT(apbtargexp2_pprot), + .APBTARGEXP2PENABLE(apbtargexp2_penable), + .APBTARGEXP2PWRITE(apbtargexp2_pwrite), + .APBTARGEXP2PWDATA(apbtargexp2_pwdata), + + .APBTARGEXP2PRDATA(apbtargexp2_prdata), + .APBTARGEXP2PREADY(apbtargexp2_pready), + .APBTARGEXP2PSLVERR(GND), + + .DAPSWDITMS(GND), + .FLASHERR(GND), + .FLASHINT(GND) + ); + + // ROM + // To understand what the entrances and outputs of this primitive, I followed the description of the AMBA protocol. + // https://developer.arm.com/documentation/ihi0011/a/ or search for IHI0011a.pdf + // It was from there and by the names of the ports of the primitive that it + // became clear that RAM is connected directly without tricks, but for Flash + // it would be necessary to implement a whole client of this AHB Bus. + localparam ROM_IDLE = 2'b00; + localparam ROM_READ = 2'b01; + localparam ROM_OKEY = 2'b10; + reg [1:0] rom_state; + reg rom_sel; + reg [12:0] flash_in_addr; + + // AHB slave + always @(posedge clk) begin + if (!(rst_i & mtx_hreset_n)) begin + rom_state <= ROM_IDLE; + rom_sel <= 1'b0; + end else begin + case (rom_state) + ROM_IDLE: begin + if (targflash0_hsel & targflash0_htrans[1]) begin // NONSEQ/SEQ transfer + rom_state <= ROM_READ; + flash_in_addr <= rom_addr; + rom_sel <= 1'b1; + end + end + ROM_READ: begin + if (targflash0_hsel & targflash0_htrans[1]) begin // NONSEQ/SEQ transfer + rom_state <= ROM_OKEY; + rom_sel <= 1'b0; + end else begin + rom_state <= ROM_IDLE; + rom_sel <= 1'b0; + end + end + ROM_OKEY: begin + if (targflash0_hsel & targflash0_htrans[1]) begin // NONSEQ/SEQ transfer + rom_state <= ROM_IDLE; + rom_sel <= 1'b0; + end + end + endcase + end + end + assign targflash0_readyout = rom_state == ROM_IDLE; + + // very simple APB bridge: decode only first APB address 0x4000240 + wire psel1; + assign psel1 = apbtargexp2_psel && (apbtargexp2_paddr[11:8] == 4'h4); // 0x40002 >4< 00 + + // APB slave device - led, writing to 0x40002400 changes state of the led, + // reading 0x40002400 returns led state in the bit 0 + // Honestly, reading/recording will work at any address from the range of + // the first APB Master:) + // One can use apbtargexp2_paddr[7:0] for master 1 registers. + reg led_reg; + reg [1:0] apb_slave_state; + + localparam APB_IDLE = 2'b00; + localparam APB_WRITE = 2'b01; + localparam APB_READ = 2'b10; + always @(negedge rst_i or posedge clk) begin + if (!rst_i) begin + apb_slave_state <= APB_IDLE; + apbtargexp2_pready <= 1'b0; + apbtargexp2_prdata <= {32{1'b0}}; + end else begin + case (apb_slave_state) + APB_IDLE: begin + apbtargexp2_pready <= 1'b0; + apbtargexp2_prdata <= {32{1'b0}}; + if (psel1) begin + if (apbtargexp2_pwrite) begin + apb_slave_state <= APB_WRITE; + end else begin + apb_slave_state <= APB_READ; + end + end + end + APB_WRITE: begin + if (psel1 && apbtargexp2_pwrite) begin // activate led + apbtargexp2_pready <= 1'b1; + led_reg <= apbtargexp2_pwdata[0]; + end + apb_slave_state <= APB_IDLE; + end + APB_READ: begin + if (psel1 && !apbtargexp2_pwrite) begin // return the led state + apbtargexp2_pready <= 1'b1; + apbtargexp2_prdata[0] <= led_reg; + end + apb_slave_state <= APB_IDLE; + end + default: begin + apb_slave_state <= APB_IDLE; + end + endcase + end + end + + assign mode_led = led_reg; + + FLASH256K rom( + .DOUT(rom_out[31:0]), + .XADR(flash_in_addr[12:6]), + .YADR(flash_in_addr[5:0]), + .XE(rst_i), + .YE(rst_i), + .SE(rom_sel), + .ERASE(GND), + .PROG(GND), + .NVSTR(GND), + .DIN({32{GND}}) + ); + + // RAM 4 block of 2K + // Inferring will probably also work, but with primitives it is somehow easier for me. + SDPB ram_0 ( + .DO({dummy_sram0_rdata_0, sram0_rdata[7:0]}), + .DI({{24{GND}}, sram0_wdata[7:0]}), + .BLKSELA({GND, GND, sram0_cs}), + .BLKSELB({GND, GND, sram0_cs}), + .ADA({sram0_addr, GND,GND,GND}), + .ADB({sram0_addr, GND,GND,GND}), + .CLKA(clk), + .CLKB(clk), + .CEA(sram0_wren[0]), + .CEB(!sram0_wren[0]), + .OCE(VCC), + .RESETA(GND), + .RESETB(!rst_i) + ); + defparam ram_0.BIT_WIDTH_0=8; + defparam ram_0.BIT_WIDTH_1=8; + defparam ram_0.BLK_SEL_0=3'b001; + defparam ram_0.BLK_SEL_1=3'b001; + defparam ram_0.READ_MODE=1'b0; + defparam ram_0.RESET_MODE="SYNC"; + + SDPB ram_1 ( + .DO({dummy_sram0_rdata_1, sram0_rdata[15:8]}), + .DI({{24{GND}}, sram0_wdata[15:8]}), + .BLKSELA({GND, GND, sram0_cs}), + .BLKSELB({GND, GND, sram0_cs}), + .ADA({sram0_addr, GND,GND,GND}), + .ADB({sram0_addr, GND,GND,GND}), + .CLKA(clk), + .CLKB(clk), + .CEA(sram0_wren[1]), + .CEB(!sram0_wren[1]), + .OCE(VCC), + .RESETA(GND), + .RESETB(!rst_i) + ); + defparam ram_1.BIT_WIDTH_0=8; + defparam ram_1.BIT_WIDTH_1=8; + defparam ram_1.BLK_SEL_0=3'b001; + defparam ram_1.BLK_SEL_1=3'b001; + defparam ram_1.READ_MODE=1'b0; + defparam ram_1.RESET_MODE="SYNC"; + + SDPB ram_2 ( + .DO({dummy_sram0_rdata_2, sram0_rdata[23:16]}), + .DI({{24{GND}}, sram0_wdata[23:16]}), + .BLKSELA({GND, GND, sram0_cs}), + .BLKSELB({GND, GND, sram0_cs}), + .ADA({sram0_addr, GND,GND,GND}), + .ADB({sram0_addr, GND,GND,GND}), + .CLKA(clk), + .CLKB(clk), + .CEA(sram0_wren[2]), + .CEB(!sram0_wren[2]), + .OCE(VCC), + .RESETA(GND), + .RESETB(!rst_i) + ); + defparam ram_2.BIT_WIDTH_0=8; + defparam ram_2.BIT_WIDTH_1=8; + defparam ram_2.BLK_SEL_0=3'b001; + defparam ram_2.BLK_SEL_1=3'b001; + defparam ram_2.READ_MODE=1'b0; + defparam ram_2.RESET_MODE="SYNC"; + + SDPB ram_3 ( + .DO({dummy_sram0_rdata_3, sram0_rdata[31:24]}), + .DI({{24{GND}}, sram0_wdata[31:24]}), + .BLKSELA({GND, GND, sram0_cs}), + .BLKSELB({GND, GND, sram0_cs}), + .ADA({sram0_addr, GND,GND,GND}), + .ADB({sram0_addr, GND,GND,GND}), + .CLKA(clk), + .CLKB(clk), + .CEA(sram0_wren[3]), + .CEB(!sram0_wren[3]), + .OCE(VCC), + .RESETA(GND), + .RESETB(!rst_i) + ); + defparam ram_3.BIT_WIDTH_0=8; + defparam ram_3.BIT_WIDTH_1=8; + defparam ram_3.BLK_SEL_0=3'b001; + defparam ram_3.BLK_SEL_1=3'b001; + defparam ram_3.READ_MODE=1'b0; + defparam ram_3.RESET_MODE="SYNC"; + +endmodule From bcafcfce4191ad4795102832bde04361677df554 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Thu, 10 Oct 2024 21:03:10 +1000 Subject: [PATCH 5/5] EMCU. Add a more complex APB device example. Here we demonstrate the implementation of a more advanced peripheral to the Tangnano4k embedded processor - the SPI controller as a device on the APB. It is very simple but nevertheless it is represented in the address space of the processor as status, control and data registers. The status register is used to indicate that the controller is busy, the control register allows the bit order to be changed during transmission. SPI is used to control the display, the picture is decompressed from ROM and sent byte by by byte to the controller. Signed-off-by: YRabbit --- apycula/gowin_pack.py | 2 +- examples/himbaechel/Makefile.himbaechel | 3 +- examples/himbaechel/emcu-firmware/apb_spi.bin | Bin 0 -> 15340 bytes .../himbaechel/emcu-firmware/apb_spi_.c-src | 327 ++++++++++++ .../emcu-firmware/apb_spi_image-apicula-h | 446 ++++++++++++++++ examples/himbaechel/emcu-with-apb-spi.v | 504 ++++++++++++++++++ examples/himbaechel/tangnano4k.cst | 14 +- 7 files changed, 1291 insertions(+), 5 deletions(-) create mode 100755 examples/himbaechel/emcu-firmware/apb_spi.bin create mode 100755 examples/himbaechel/emcu-firmware/apb_spi_.c-src create mode 100755 examples/himbaechel/emcu-firmware/apb_spi_image-apicula-h create mode 100644 examples/himbaechel/emcu-with-apb-spi.v diff --git a/apycula/gowin_pack.py b/apycula/gowin_pack.py index fbf9d5d0..d9a46ce1 100644 --- a/apycula/gowin_pack.py +++ b/apycula/gowin_pack.py @@ -267,7 +267,7 @@ def infovaluemap(infovalue, start=2): "GW1N-1": (400, 450, 3.125, 900, 400), "GW1NZ-1": (400, 400, 3.125, 800, 400), "GW1N-4": (400, 500, 3.125, 1000, 400), - "GW1NS-4": (400, 600, 4.6875, 1200, 600), + "GW1NS-4": (400, 600, 4.6875, 1200, 400), "GW1N-9": (400, 500, 3.125, 1000, 400), "GW1N-9C": (400, 600, 3.125, 1200, 400), "GW1NS-2": (400, 500, 3.125, 1200, 400), diff --git a/examples/himbaechel/Makefile.himbaechel b/examples/himbaechel/Makefile.himbaechel index 7083fa40..4a7599f1 100644 --- a/examples/himbaechel/Makefile.himbaechel +++ b/examples/himbaechel/Makefile.himbaechel @@ -63,6 +63,7 @@ all: \ dsp-mult9x9-tangnano4k.fs dsp-alu54d-tangnano4k.fs dsp-multalu18x18-tangnano4k.fs \ dsp-multalu36x18-tangnano4k.fs dsp-multaddalu18x18-tangnano4k.fs \ dqce-tangnano4k.fs dcs-tangnano4k.fs emcu-blinky-tangnano4k.fs emcu-with-apb-blinky-tangnano4k.fs \ + emcu-with-apb-spi-tangnano4k.fs \ \ blinky-tangnano9k.fs shift-tangnano9k.fs blinky-tbuf-tangnano9k.fs blinky-oddr-tangnano9k.fs \ blinky-clkdiv-tangnano9k.fs dvi-example-tangnano9k.fs\ @@ -303,7 +304,7 @@ bsram-%-tangnano1k-synth.json: pll/GW1NZ-1-dyn.vh %-image-rom.v %-video-ram.v %. # ============================================================ # Tangnano4k (GW1NS-4) %-tangnano4k.fs: %-tangnano4k.json - gowin_pack -d GW1NS-4 -o $@ $^ + gowin_pack -d GW1NS-4 --mspi_as_gpio -o $@ $^ %-tangnano4k.json: %-tangnano4k-synth.json tangnano4k.cst $(NEXTPNR) --json $< --write $@ --device GW1NSR-LV4CQN48PC7/I6 --vopt cst=tangnano4k.cst diff --git a/examples/himbaechel/emcu-firmware/apb_spi.bin b/examples/himbaechel/emcu-firmware/apb_spi.bin new file mode 100755 index 0000000000000000000000000000000000000000..0df56e11bcb12780d322b10114400bcd953d68e5 GIT binary patch literal 15340 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 ShJj3sj4u4)yC&L+ +#include +#include +#include + +#include "image-apicula.h" + +void initialize_GPIO(); +void delay_millis(uint32_t ms); + +// ============================ SPI ======================= + +// First APB master address +uint32_t const apb2_periph_base = 0x40002500; + +struct APB2_spi_peripheral_status { + volatile uint32_t status : 1; // not memory - read the bus ;) +}; +struct APB2_spi_peripheral_data { + volatile uint32_t data; // not memory - write the bus ;) +}; +struct APB2_spi_peripheral_control { + volatile uint32_t control : 1; // not memory - write the bus ;) +}; + +struct APB2_spi_peripheral_status *spi_status = (struct APB2_spi_peripheral_status *) apb2_periph_base; +struct APB2_spi_peripheral_data *spi_data = (struct APB2_spi_peripheral_data *) (apb2_periph_base + 4); +struct APB2_spi_peripheral_control *spi_control = (struct APB2_spi_peripheral_control *) apb2_periph_base; + +uint8_t spi_busy(void) { + return spi_status->status & 1; +} + +void initialize_spi(uint8_t msb) { + spi_control->control = msb; +} + +void spi_send_byte(uint8_t byte) { + while (spi_busy()); + spi_data->data = byte; +} + +void spi_send_array(uint8_t *buf, uint32_t len) { + while(len) { + spi_send_byte(*buf++); + --len; + } +} + +// =========================== Display ========================== +#define BLACK 0x0000 +#define WHITE 0xffff +#define RED 0xf800 +#define GREEN 0x07e0 +#define BLUE 0x001f +#define YELLOW 0xffe0 + +#define DSP_WIDTH 240 +#define DSP_HEIGHT 240 + +#define DSP_RST0 GPIO_ResetBit(GPIO0, GPIO_Pin_0) +#define DSP_RST1 GPIO_SetBit(GPIO0, GPIO_Pin_0) +#define DSP_DC0 GPIO_ResetBit(GPIO0, GPIO_Pin_1) +#define DSP_DC1 GPIO_SetBit(GPIO0, GPIO_Pin_1) +void initialize_dsp(void); +void dsp_send_cmd(uint8_t cmd); +void dsp_send_data(uint8_t data); +void dsp_send_array(uint8_t *buf, uint32_t len); +void dsp_fillcolor(uint16_t color); +void dsp_set_address_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); +void dsp_put_point(uint16_t color); + +void initialize_timer(); +void initialize_UART(); +void delay_millis(uint32_t ms); + +int main(void) { + SystemInit(); + initialize_timer(); + initialize_UART(); + initialize_GPIO(); + initialize_spi(1); + + UART_SendString(UART0, "Apicula Cortex-M3 APB SPI\r\n"); + + uint16_t *rowbuf = malloc(image_width * sizeof(uint16_t)); + + initialize_dsp(); + int phase = 0; + while(1) { + + int16_t cur_color; + int cur_image_idx = 0; + int16_t len = 0; + + dsp_set_address_window(0, 0, image_width - 1, image_height - 1); + for (int i = 0; i < image_height; ++i) { + memset(rowbuf, 0, sizeof(rowbuf)); + for (int j = 0; j < image_width; ++j) { + if (len == 0) { + len = image_data[cur_image_idx++]; + cur_color = image_colors[0x1ff & (len >> 7)]; // color 9 bit, count 7 bit + len = (len & 0x7f) + 1; + } + --len; + if (phase >= j) { + rowbuf[(phase - j) % image_width] = cur_color; + } + } + for (uint16_t k = 0; k < image_width; ++k) { + dsp_put_point(rowbuf[k]); + } + } + phase += 5; + //delay_millis(5); + } + free(rowbuf); +} + +// ============================ Display ======================= +void dsp_send_cmd(uint8_t cmd) { + DSP_DC0; + spi_send_byte(cmd); +} + +void dsp_send_data(uint8_t data) { + DSP_DC1; + spi_send_byte(data); +} + +void dsp_send_array(uint8_t *buf, uint32_t len) { + DSP_DC1; + spi_send_array(buf, len); +} + +#define DSP_ROTATION 3 +#define DSP_X_SHIFT 0 +#define DSP_Y_SHIFT 0 + +#define DSP_MADCTRL 0x36 +#define DSP_MAD_RGB 0x00 +#define DSP_MAD_BGR 0x08 + +#define DSP_SWRESET 0x01 +#define DSP_SLPIN 0x10 +#define DSP_SLPOUT 0x11 +#define DSP_NORON 0x13 +#define DSP_INVOFF 0x20 +#define DSP_INVON 0x21 +#define DSP_DISPOFF 0x28 +#define DSP_DISPON 0x29 +#define DSP_CASET 0x2a +#define DSP_RASET 0x2b +#define DSP_RAMWR 0x2c +#define DSP_COLMOD 0x3a +#define DSP_COLOR16BIT 0x55 +#define DSP_PORCTRL 0xb2 +#define DSP_GCTRL 0xb7 +#define DSP_VCOMS 0xbb +#define DSP_LCMCTRL 0xc0 +#define DSP_VDVVRHEN 0xc2 +#define DSP_VRHS 0xc3 +#define DSP_VDVS 0xc4 +#define DSP_FRCTRL2 0xc6 +#define DSP_PWRCTL1 0xd0 +#define DSP_PVGAMCTRL 0xe0 +#define DSP_NVGAMCTRL 0xe1 + +void dsp_set_address_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { + uint16_t x_start = x0 + DSP_X_SHIFT, x_end = x1 + DSP_X_SHIFT; + uint16_t y_start = y0 + DSP_Y_SHIFT, y_end = y1 + DSP_Y_SHIFT; + + dsp_send_cmd(DSP_CASET); + uint8_t buf[] = {x_start >> 8, x_start & 0xff, x_end >> 8, x_end & 0xff}; + dsp_send_array(buf, sizeof(buf)); + + dsp_send_cmd(DSP_RASET); + uint8_t buf1[] = {y_start >> 8, y_start & 0xff, y_end >> 8, y_end & 0xff}; + dsp_send_array(buf1, sizeof(buf1)); + + dsp_send_cmd(DSP_RAMWR); +} + +void dsp_put_point(uint16_t color) { + uint8_t buf[] = {color >> 8, color & 0xff}; + dsp_send_array(buf, sizeof(buf)); +} + +void dsp_fillcolor(uint16_t color) { + dsp_set_address_window(0, 0, DSP_WIDTH - 1, DSP_HEIGHT - 1); + for (uint16_t i = 0; i < DSP_WIDTH; ++i) { + for (uint16_t j = 0; j < DSP_HEIGHT; ++j) { + uint8_t buf[] = {color >> 8, color & 0xff}; + dsp_send_array(buf, sizeof(buf)); + } + } +} + +void initialize_dsp(void) { + DSP_RST0; + delay_millis(50); + DSP_RST1; + delay_millis(50); + dsp_send_cmd(DSP_SWRESET); + delay_millis(100); + dsp_send_cmd(DSP_MADCTRL); + dsp_send_data(DSP_MAD_BGR); + dsp_send_cmd(DSP_COLMOD); + dsp_send_data(DSP_COLOR16BIT); + delay_millis(10); + dsp_send_cmd(DSP_PORCTRL); + uint8_t buf[] = {0xb, 0xb, 0, 0x33, 0x33}; + dsp_send_array(buf, sizeof(buf)); + dsp_send_cmd(DSP_GCTRL); + dsp_send_data(0x35); + dsp_send_cmd(DSP_VCOMS); + dsp_send_data(0x20); + dsp_send_cmd(DSP_LCMCTRL); + dsp_send_data(0x2c); + dsp_send_cmd(DSP_VDVVRHEN); + dsp_send_data(0x01); + dsp_send_cmd(DSP_VRHS); + dsp_send_data(0x0b); + dsp_send_cmd(DSP_VDVS); + dsp_send_data(0x20); + dsp_send_cmd(DSP_FRCTRL2); + dsp_send_data(0x0f); + dsp_send_cmd(DSP_PWRCTL1); + dsp_send_data(0xa4); + dsp_send_data(0xa1); + dsp_send_cmd(DSP_PVGAMCTRL); + uint8_t buf1[] = {0xd0, 0x4, 0xd, 0x11, 0x13, 0x2b, 0x3f, 0x54, 0x4c, 0x18, 0xd, 0xb, 0x1f, 0x23}; + dsp_send_array(buf1, sizeof(buf1)); + dsp_send_cmd(DSP_NVGAMCTRL); + uint8_t buf2[] = {0xd0, 0x4, 0xc, 0x11, 0x13, 0x2c, 0x3f, 0x44, 0x51, 0x2f, 0x1f, 0x1f, 0x20, 0x23}; + dsp_send_array(buf2, sizeof(buf2)); + dsp_send_cmd(DSP_INVON); + dsp_send_cmd(DSP_SLPOUT); + dsp_send_cmd(DSP_NORON); + dsp_send_cmd(DSP_DISPON); + + delay_millis(50); + dsp_fillcolor(BLACK); +} + + + +// ============================= UART =========================== +// Initializes UART0 +void initialize_UART() { + UART_InitTypeDef uartInitStruct; + // Enable transmission + uartInitStruct.UART_Mode.UARTMode_Tx = ENABLE; + // Disable reception + uartInitStruct.UART_Mode.UARTMode_Rx = DISABLE; + // 9600 baud rate typical of Arduinos + uartInitStruct.UART_BaudRate = 9600; + // Initialize UART0 using the struct configs + UART_Init(UART0, &uartInitStruct); +} + +// ============================= GPIO =========================== +void initialize_GPIO() { + GPIO_InitTypeDef gpioInitStruct; + + // --------- output + //Select pin0, you can OR pins together to initialize them at the same time + gpioInitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; + + //Set selected pins as output (see GPIOMode_TypeDef in gw1ns4c_gpio.h) + gpioInitStruct.GPIO_Mode = GPIO_Mode_OUT; + + //Disable interrupts on selected pins (see GPIOInt_TypeDef) + gpioInitStruct.GPIO_Int = GPIO_Int_Disable; + + //Initialize the GPIO using the configured init struct + GPIO_Init(GPIO0, &gpioInitStruct); +} + + +void initialize_timer() { + TIMER_InitTypeDef timerInitStruct; + + timerInitStruct.Reload = 0; + + // Disable interrupt requests from timer for now + timerInitStruct.TIMER_Int = DISABLE; + + // Disable timer enabling/clocking from external pins (GPIO) + timerInitStruct.TIMER_Exti = TIMER_DISABLE; + + TIMER_Init(TIMER0, &timerInitStruct); + TIMER_StopTimer(TIMER0); +} + +#define CYCLES_PER_MILLISEC (SystemCoreClock / 1000) +void delay_millis(uint32_t ms) { + TIMER_StopTimer(TIMER0); + // Reset timer just in case it was modified elsewhere + TIMER_SetValue(TIMER0, 0); + TIMER_EnableIRQ(TIMER0); + + uint32_t reloadVal = CYCLES_PER_MILLISEC * ms; + // Timer interrupt will trigger when it reaches the reload value + TIMER_SetReload(TIMER0, reloadVal); + + TIMER_StartTimer(TIMER0); + // Block execution until timer wastes the calculated amount of cycles + while (TIMER_GetIRQStatus(TIMER0) != SET) + ; + + TIMER_StopTimer(TIMER0); + TIMER_ClearIRQ(TIMER0); + TIMER_SetValue(TIMER0, 0); +} + diff --git a/examples/himbaechel/emcu-firmware/apb_spi_image-apicula-h b/examples/himbaechel/emcu-firmware/apb_spi_image-apicula-h new file mode 100755 index 00000000..6dae02f3 --- /dev/null +++ b/examples/himbaechel/emcu-firmware/apb_spi_image-apicula-h @@ -0,0 +1,446 @@ +uint16_t const image_width = 240; +uint16_t const image_height = 240; +uint16_t const image_colors[297] = { + 0x0000, 0x0001, 0x0020, 0x0021, 0x0022, 0x0023, 0x0041, 0x0043, 0x0044, 0x0062, + 0x0064, 0x0065, 0x0066, 0x0082, 0x0083, 0x0086, 0x0087, 0x00a3, 0x00a7, 0x00a8, + 0x00a9, 0x00c4, 0x00c8, 0x00c9, 0x00ca, 0x00e5, 0x00e8, 0x00e9, 0x00ea, 0x0105, + 0x0109, 0x010a, 0x0126, 0x0129, 0x012a, 0x0147, 0x014a, 0x014b, 0x0167, 0x016b, + 0x0188, 0x018b, 0x018c, 0x01a8, 0x01a9, 0x01ac, 0x01ad, 0x01c9, 0x01cc, 0x01cd, + 0x01ed, 0x01ee, 0x020e, 0x022b, 0x022f, 0x024b, 0x024d, 0x024f, 0x0250, 0x026d, + 0x0270, 0x0271, 0x028d, 0x028e, 0x02ae, 0x02af, 0x02b1, 0x02b2, 0x02d2, 0x02ef, + 0x02f3, 0x030f, 0x0310, 0x0313, 0x0314, 0x0331, 0x0334, 0x0351, 0x0352, 0x0355, + 0x0371, 0x0373, 0x0375, 0x0392, 0x0393, 0x0395, 0x0396, 0x03b3, 0x03b4, 0x03b6, + 0x03d3, 0x03d4, 0x03d6, 0x03d7, 0x03f4, 0x03f5, 0x03f7, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0435, 0x0436, 0x0437, 0x0456, 0x0457, 0x0458, 0x0459, 0x0477, 0x0478, + 0x0479, 0x0498, 0x0499, 0x04b8, 0x04b9, 0x04ba, 0x04d9, 0x04da, 0x04fa, 0x04fb, + 0x051a, 0x051b, 0x051c, 0x053b, 0x053c, 0x055b, 0x055c, 0x055d, 0x057c, 0x057d, + 0x057e, 0x059d, 0x059e, 0x059f, 0x05bd, 0x05be, 0x05bf, 0x05de, 0x05df, 0x05ff, + 0x061f, 0x0841, 0x0842, 0x0861, 0x0862, 0x0863, 0x0883, 0x0884, 0x0885, 0x0886, + 0x08a6, 0x08a7, 0x08c5, 0x0906, 0x0926, 0x0927, 0x0947, 0x0948, 0x0967, 0x0968, + 0x0989, 0x09a9, 0x09aa, 0x09ca, 0x09ea, 0x09eb, 0x0a0b, 0x0a0c, 0x0a2c, 0x0a4c, + 0x0a6d, 0x0a6e, 0x0a8d, 0x0a8e, 0x0aae, 0x0acf, 0x0aef, 0x0af0, 0x0b11, 0x0b30, + 0x0b31, 0x0b32, 0x0b51, 0x0b52, 0x0b73, 0x0b93, 0x0bb3, 0x0bb4, 0x0bd4, 0x0bd5, + 0x0bf4, 0x0bf5, 0x0bf6, 0x0c15, 0x0c16, 0x0c36, 0x0c56, 0x0c57, 0x1000, 0x1021, + 0x1041, 0x1042, 0x1063, 0x1082, 0x1083, 0x1084, 0x10a2, 0x10a3, 0x10a4, 0x10c5, + 0x10e5, 0x10e6, 0x1106, 0x18a2, 0x18c3, 0x18c4, 0x18e3, 0x18e4, 0x18e5, 0x2104, + 0x2105, 0x2124, 0x2125, 0x2821, 0x2842, 0x2862, 0x28c3, 0x2945, 0x2946, 0x2965, + 0x2966, 0x3186, 0x3187, 0x31a6, 0x31a7, 0x39c7, 0x39c8, 0x39e7, 0x39e8, 0x4042, + 0x40c4, 0x40e4, 0x4208, 0x4228, 0x4229, 0x4a49, 0x4a69, 0x4a6a, 0x528a, 0x52aa, + 0x52ab, 0x58e4, 0x5acb, 0x5aeb, 0x5aec, 0x630c, 0x632c, 0x632d, 0x68a4, 0x68c4, + 0x68e5, 0x6b4d, 0x6b6d, 0x6b6e, 0x738e, 0x73ae, 0x73af, 0x7bcf, 0x7bef, 0x7bf0, + 0x80c5, 0x8106, 0x8410, 0x8430, 0x8431, 0x8c51, 0x8c71, 0x8c72, 0x9492, 0x94b2, + 0x94b3, 0x98c6, 0x98e6, 0x9906, 0x9cd3, 0x9cf3, 0x9cf4, 0xa514, 0xa534, 0xa535, + 0xad55, 0xad75, 0xb0e7, 0xb596, 0xbdf7, 0xc618, 0xce59}; +uint16_t const image_data[] = { + 0x922a, 0x6580, 0x8a00, 0x7980, 0x927f, 0x926c, 0x7e80, 0x9281, 0x8f80, 0x7c80, + 0x6a80, 0x927f, 0x9268, 0x7d80, 0x9000, 0x9283, 0x9100, 0x8000, 0x6b00, 0x927f, + 0x9266, 0x7e00, 0x9286, 0x9180, 0x8480, 0x6e80, 0x927f, 0x9264, 0x8f80, 0x9289, + 0x8800, 0x7380, 0x927f, 0x9261, 0x7c00, 0x928c, 0x8b00, 0x7900, 0x927f, 0x925f, + 0x7980, 0x8e80, 0x928d, 0x8e00, 0x7c00, 0x927f, 0x925f, 0x7a80, 0x8e00, 0x928d, + 0x9000, 0x7e80, 0x6700, 0x927f, 0x925e, 0x7980, 0x8e00, 0x928d, 0x9100, 0x8300, + 0x6d80, 0x927f, 0x925d, 0x7c00, 0x8880, 0x9000, 0x928d, 0x9180, 0x8b00, 0x7c80, + 0x7180, 0x4780, 0x927f, 0x9258, 0x4780, 0x7f81, 0x8000, 0x8800, 0x9000, 0x928e, + 0x8f80, 0x8800, 0x7e00, 0x7900, 0x7180, 0x6580, 0x921f, 0x0000, 0x0181, 0x4701, + 0x4804, 0x4702, 0x4680, 0x0181, 0x0000, 0x8700, 0x927f, 0x9222, 0x7180, 0x7f84, + 0x8800, 0x8f80, 0x928e, 0x9100, 0x8980, 0x8000, 0x7f80, 0x7e00, 0x7900, 0x7180, + 0x6580, 0x9217, 0x8c80, 0x0180, 0x4700, 0x4880, 0x6611, 0x4880, 0x4800, 0x4680, + 0x0180, 0x6300, 0x927f, 0x921e, 0x4680, 0x6e80, 0x7900, 0x7e00, 0x7f82, 0x8600, + 0x8f80, 0x928e, 0x9100, 0x8b00, 0x8280, 0x7f82, 0x7e00, 0x7900, 0x7180, 0x6580, + 0x9211, 0x0100, 0x4700, 0x661a, 0x4800, 0x4680, 0x0000, 0x927f, 0x921f, 0x6700, + 0x7380, 0x7b00, 0x7f81, 0x8580, 0x8f80, 0x928e, 0x9180, 0x8b80, 0x8400, 0x7f84, + 0x7e00, 0x7980, 0x7280, 0x6580, 0x920b, 0x0180, 0x4800, 0x661e, 0x6500, 0x3300, + 0x2280, 0x0880, 0x927f, 0x921f, 0x4680, 0x6d80, 0x7680, 0x7e00, 0x8580, 0x8e80, + 0x928f, 0x8e80, 0x8580, 0x7f86, 0x7e00, 0x7980, 0x7280, 0x6700, 0x9205, 0x0000, + 0x4800, 0x6620, 0x5400, 0x4580, 0x4600, 0x4480, 0x2d80, 0x0e80, 0x927f, 0x9221, + 0x6700, 0x7280, 0x7e80, 0x8e00, 0x928f, 0x8f80, 0x8600, 0x7f88, 0x7e80, 0x7980, + 0x7280, 0x6700, 0x9200, 0x4680, 0x6622, 0x3600, 0x4603, 0x4580, 0x2d00, 0x0880, + 0x927f, 0x9222, 0x8180, 0x7380, 0x8480, 0x9180, 0x928e, 0x9000, 0x8880, 0x8000, + 0x7f88, 0x7e80, 0x7300, 0x6622, 0x4e00, 0x4480, 0x4605, 0x4380, 0x2000, 0x927f, + 0x9224, 0x6b00, 0x8300, 0x9180, 0x928e, 0x9100, 0x8a00, 0x8280, 0x7f85, 0x7c80, + 0x6e00, 0x6623, 0x5e00, 0x4608, 0x3880, 0x0a80, 0x927f, 0x9224, 0x6b00, 0x8280, + 0x9100, 0x928e, 0x9180, 0x8a00, 0x8000, 0x7f82, 0x7c00, 0x6800, 0x6624, 0x3f00, + 0x4609, 0x4180, 0x1780, 0x927f, 0x9225, 0x6700, 0x8000, 0x9100, 0x928e, 0x9000, + 0x8600, 0x7f80, 0x7b00, 0x6625, 0x5780, 0x460b, 0x4580, 0x2000, 0x927f, 0x9226, + 0x6580, 0x7e80, 0x9000, 0x928e, 0x8e00, 0x7900, 0x6625, 0x3880, 0x460d, 0x2400, + 0x927f, 0x9227, 0x7880, 0x7e00, 0x9000, 0x928d, 0x9180, 0x8600, 0x6e00, 0x6622, + 0x4e00, 0x4480, 0x460e, 0x2380, 0x927f, 0x9228, 0x8780, 0x7c80, 0x8f80, 0x928d, + 0x8f80, 0x7f80, 0x6621, 0x5d80, 0x460f, 0x4580, 0x1d80, 0x927f, 0x922a, 0x7c00, + 0x8e80, 0x928d, 0x8b80, 0x7a00, 0x661e, 0x6500, 0x3d80, 0x4610, 0x4500, 0x1400, + 0x927f, 0x922b, 0x7a80, 0x8e00, 0x928c, 0x9180, 0x8680, 0x6f00, 0x661c, 0x5500, + 0x4580, 0x4611, 0x4000, 0x0700, 0x9270, 0x7a80, 0x923a, 0x8b80, 0x928d, 0x9000, + 0x8080, 0x6800, 0x661a, 0x6280, 0x4613, 0x3400, 0x926f, 0x7c00, 0x9280, 0x8b00, + 0x6c00, 0x9237, 0x7580, 0x9290, 0x8c00, 0x7a80, 0x6618, 0x6800, 0x4180, 0x4614, + 0x1b80, 0x926d, 0x6d80, 0x9100, 0x9281, 0x9100, 0x7a80, 0x9236, 0x8e00, 0x9291, + 0x9180, 0x8800, 0x7200, 0x6616, 0x5880, 0x4615, 0x4080, 0x0480, 0x926c, 0x8a00, + 0x9284, 0x8580, 0x7880, 0x9207, 0x7a80, 0x6e80, 0x9229, 0x7c80, 0x9294, 0x9000, + 0x8300, 0x6800, 0x6614, 0x3880, 0x4616, 0x2800, 0x926b, 0x7f80, 0x9286, 0x8e80, + 0x7280, 0x9205, 0x7280, 0x7f81, 0x7980, 0x4680, 0x9226, 0x6700, 0x9100, 0x9296, + 0x8e00, 0x7c00, 0x6612, 0x6900, 0x4380, 0x4616, 0x4480, 0x0a80, 0x9269, 0x7180, + 0x9180, 0x9287, 0x9180, 0x7e00, 0x9203, 0x4780, 0x7e80, 0x7f82, 0x7e00, 0x6d80, + 0x9225, 0x8400, 0x9298, 0x9180, 0x8980, 0x7400, 0x6610, 0x5b00, 0x4618, 0x2980, + 0x9269, 0x7100, 0x8600, 0x9289, 0x8980, 0x6700, 0x9201, 0x7980, 0x7f85, 0x7900, + 0x7080, 0x9222, 0x7180, 0x9180, 0x929a, 0x9100, 0x8400, 0x6b80, 0x660e, 0x3a00, + 0x4618, 0x4480, 0x0700, 0x926a, 0x7e00, 0x9180, 0x9288, 0x9000, 0x7680, 0x6d80, + 0x7f87, 0x7e00, 0x6c00, 0x9221, 0x8a00, 0x929d, 0x8e80, 0x7d00, 0x660c, 0x4c80, + 0x4480, 0x4619, 0x2280, 0x926b, 0x7380, 0x8f80, 0x9289, 0x8b80, 0x8000, 0x7f88, + 0x7580, 0x921f, 0x7980, 0x92a0, 0x8a00, 0x7580, 0x660a, 0x5b00, 0x461a, 0x3d80, + 0x926c, 0x6700, 0x8980, 0x9289, 0x9000, 0x8480, 0x7f88, 0x7c00, 0x6700, 0x921c, + 0x8780, 0x8f80, 0x92a1, 0x9100, 0x8500, 0x6c80, 0x6608, 0x3900, 0x461b, 0x1580, + 0x926d, 0x8280, 0x9289, 0x9180, 0x8a00, 0x7f89, 0x7380, 0x921c, 0x7c00, 0x9100, + 0x92a2, 0x8f80, 0x7f00, 0x6606, 0x6900, 0x4380, 0x461b, 0x2b80, 0x926e, 0x7900, + 0x9100, 0x9289, 0x8e80, 0x8300, 0x7f88, 0x7b00, 0x6580, 0x921b, 0x7500, 0x8e80, + 0x92a3, 0x8b00, 0x7900, 0x6604, 0x5800, 0x461c, 0x4180, 0x926f, 0x6c00, 0x8b80, + 0x9289, 0x9100, 0x8600, 0x7f88, 0x7e80, 0x7180, 0x9219, 0x6f80, 0x4880, 0x6c80, + 0x8600, 0x9180, 0x92a2, 0x9180, 0x8600, 0x6603, 0x6280, 0x461d, 0x1400, 0x926f, + 0x8d80, 0x8480, 0x928a, 0x8b80, 0x8000, 0x7f88, 0x7a80, 0x4680, 0x9217, 0x4700, + 0x6602, 0x7c00, 0x8f80, 0x92a2, 0x8680, 0x6602, 0x6500, 0x4000, 0x461d, 0x2680, + 0x9271, 0x7c00, 0x9180, 0x9289, 0x9000, 0x8400, 0x7f88, 0x7e80, 0x6d80, 0x9215, + 0x0000, 0x6604, 0x6e00, 0x8800, 0x9180, 0x929f, 0x8f80, 0x6e00, 0x6602, 0x5300, + 0x4580, 0x461d, 0x3b00, 0x9272, 0x7280, 0x8e80, 0x9289, 0x9180, 0x8880, 0x7f89, + 0x7900, 0x7080, 0x9213, 0x4800, 0x6606, 0x7d00, 0x8f80, 0x929e, 0x7e00, 0x6603, + 0x5d00, 0x461e, 0x4580, 0x0680, 0x9272, 0x6580, 0x8880, 0x928a, 0x8e00, 0x8280, + 0x7f88, 0x7e00, 0x6c00, 0x9211, 0x0180, 0x6608, 0x6f00, 0x8880, 0x929c, 0x8980, + 0x6604, 0x3a00, 0x461f, 0x1780, 0x9274, 0x7f80, 0x9180, 0x9289, 0x9100, 0x8580, + 0x7f89, 0x7580, 0x920f, 0x8100, 0x4880, 0x660a, 0x7e00, 0x9000, 0x9299, 0x9080, + 0x7380, 0x6603, 0x6800, 0x4300, 0x461f, 0x2400, 0x9275, 0x7580, 0x9000, 0x928a, + 0x8b00, 0x8000, 0x7f88, 0x7c00, 0x6700, 0x920d, 0x4700, 0x660c, 0x7200, 0x8980, + 0x9298, 0x8280, 0x6604, 0x5480, 0x4620, 0x3400, 0x9276, 0x6b00, 0x8b00, 0x928a, + 0x8f80, 0x8300, 0x7f89, 0x7380, 0x920b, 0x0000, 0x660f, 0x7f00, 0x9000, 0x9295, + 0x8b80, 0x6605, 0x5d00, 0x4620, 0x3f00, 0x9278, 0x8400, 0x928a, 0x9180, 0x8800, + 0x7f89, 0x7b00, 0x4780, 0x9209, 0x4700, 0x6610, 0x7300, 0x8a00, 0x9293, 0x9180, + 0x7900, 0x6605, 0x3880, 0x4620, 0x4580, 0x0480, 0x9278, 0x7a80, 0x9100, 0x928a, + 0x8b80, 0x8000, 0x7f88, 0x7e80, 0x7180, 0x9207, 0x0100, 0x6613, 0x8000, 0x9100, + 0x9291, 0x8580, 0x6606, 0x3f00, 0x4621, 0x1180, 0x9279, 0x6e80, 0x8e00, 0x928a, + 0x9000, 0x8480, 0x7f89, 0x7980, 0x4680, 0x9201, 0x6700, 0x9202, 0x4800, 0x6614, + 0x7500, 0x8b00, 0x928f, 0x8e80, 0x6c80, 0x6605, 0x4e00, 0x4500, 0x4621, 0x1a80, + 0x927a, 0x7100, 0x8600, 0x928a, 0x9180, 0x8980, 0x7f89, 0x7e00, 0x6d80, 0x9200, + 0x8a01, 0x6c00, 0x0180, 0x6617, 0x8280, 0x9100, 0x928c, 0x9180, 0x7d00, 0x6606, + 0x5600, 0x4622, 0x2400, 0x927c, 0x7e00, 0x9180, 0x928a, 0x8e80, 0x8300, 0x7f89, + 0x8600, 0x9281, 0x9100, 0x8380, 0x6800, 0x6617, 0x7600, 0x8b80, 0x928b, 0x8980, + 0x6607, 0x5c80, 0x4622, 0x2d80, 0x927d, 0x7480, 0x8f80, 0x928a, 0x9100, 0x8600, + 0x7f87, 0x8480, 0x9180, 0x9283, 0x8b80, 0x7580, 0x6618, 0x8380, 0x9100, 0x9288, + 0x9100, 0x7300, 0x6607, 0x6280, 0x4622, 0x3780, 0x927e, 0x6700, 0x8980, 0x928b, + 0x8b00, 0x8000, 0x7f84, 0x8000, 0x9000, 0x9285, 0x9100, 0x8000, 0x6618, 0x7900, + 0x8c00, 0x9287, 0x8300, 0x6608, 0x3a00, 0x4622, 0x3e80, 0x927f, 0x9200, 0x8280, + 0x928b, 0x9000, 0x8400, 0x7f83, 0x8b00, 0x9288, 0x8980, 0x7200, 0x6617, 0x6800, + 0x8480, 0x9180, 0x9284, 0x8e00, 0x6800, 0x6607, 0x6500, 0x3d80, 0x4622, 0x4480, + 0x927f, 0x9201, 0x7900, 0x9100, 0x928a, 0x9180, 0x8880, 0x7f81, 0x8480, 0x9180, + 0x9289, 0x8f80, 0x7c80, 0x6618, 0x7a00, 0x8e00, 0x9282, 0x9180, 0x7b80, 0x6608, + 0x6500, 0x4000, 0x4622, 0x4580, 0x0880, 0x927f, 0x9201, 0x6d80, 0x8b80, 0x928b, + 0x8e00, 0x8300, 0x9000, 0x928b, 0x9180, 0x8600, 0x6b80, 0x6617, 0x6b80, 0x8580, + 0x9180, 0x9280, 0x8980, 0x6609, 0x6480, 0x4180, 0x4623, 0x1000, 0x927f, 0x9202, + 0x8780, 0x8580, 0x928b, 0x9180, 0x928e, 0x8e00, 0x7a00, 0x6618, 0x7b80, 0x8e00, + 0x7500, 0x6609, 0x6480, 0x4380, 0x4623, 0x1780, 0x927f, 0x9204, 0x7c00, 0x9180, + 0x929a, 0x9180, 0x8380, 0x6618, 0x6800, 0x660a, 0x6480, 0x4180, 0x4623, 0x1a80, + 0x927f, 0x9205, 0x7280, 0x8e80, 0x929b, 0x8b00, 0x7400, 0x6622, 0x6500, 0x3f00, + 0x4623, 0x1f00, 0x927f, 0x9206, 0x6580, 0x8880, 0x929b, 0x9000, 0x7f00, 0x6622, + 0x3b00, 0x4623, 0x2400, 0x925c, 0x6e80, 0x8e00, 0x7c00, 0x9228, 0x7f80, 0x9180, + 0x929b, 0x8880, 0x6f00, 0x6620, 0x6080, 0x4623, 0x2680, 0x925b, 0x7980, 0x9100, + 0x9280, 0x9180, 0x7a80, 0x9228, 0x7580, 0x9000, 0x929b, 0x8f80, 0x7b80, 0x661f, + 0x5480, 0x4580, 0x4622, 0x2a00, 0x925a, 0x8300, 0x9283, 0x9180, 0x7680, 0x9228, + 0x6c00, 0x8b00, 0x929b, 0x9180, 0x8580, 0x6800, 0x661e, 0x3880, 0x4622, 0x2d00, + 0x9259, 0x7e80, 0x9285, 0x9180, 0x7480, 0x9228, 0x7f80, 0x929d, 0x8c00, 0x7700, + 0x661d, 0x4f00, 0x3f00, 0x4621, 0x2f80, 0x925a, 0x8980, 0x9285, 0x9100, 0x7280, + 0x9226, 0x6e80, 0x9180, 0x929e, 0x9100, 0x8280, 0x661d, 0x4f80, 0x3b00, 0x4620, + 0x3080, 0x925a, 0x6580, 0x8e00, 0x9285, 0x9000, 0x6e80, 0x9225, 0x8b00, 0x92a1, + 0x8a00, 0x7300, 0x661c, 0x6800, 0x5d00, 0x4380, 0x461e, 0x3300, 0x925b, 0x6c00, + 0x8f80, 0x9285, 0x8f80, 0x6c00, 0x9223, 0x7e80, 0x92a3, 0x9000, 0x7e00, 0x661d, + 0x4f80, 0x6180, 0x4380, 0x461c, 0x3280, 0x925c, 0x7180, 0x9100, 0x9285, 0x8e80, + 0x6b00, 0x9221, 0x6e80, 0x9180, 0x92a4, 0x9180, 0x8800, 0x6d00, 0x661d, 0x4c80, + 0x5d00, 0x3d80, 0x4580, 0x4619, 0x3080, 0x925d, 0x7580, 0x9180, 0x9285, 0x8e00, + 0x6580, 0x9220, 0x7680, 0x9100, 0x92a6, 0x8e80, 0x7a80, 0x661f, 0x5200, 0x5f80, + 0x3c80, 0x4480, 0x4616, 0x2f00, 0x925e, 0x7b00, 0x9286, 0x8b00, 0x6580, 0x9220, + 0x6d80, 0x8b80, 0x92a6, 0x9180, 0x7e00, 0x6620, 0x6500, 0x4f80, 0x5a00, 0x3600, + 0x3f00, 0x4500, 0x4612, 0x2d00, 0x925f, 0x7f80, 0x9286, 0x8e00, 0x7280, 0x9221, + 0x8400, 0x92a5, 0x8f80, 0x7180, 0x6624, 0x6500, 0x4e00, 0x5800, 0x5f80, 0x3a00, + 0x4000, 0x4580, 0x460d, 0x2980, 0x9260, 0x8480, 0x9286, 0x8f80, 0x7b00, 0x4780, + 0x9220, 0x7a80, 0x9180, 0x92a2, 0x9180, 0x7d00, 0x662b, 0x4c80, 0x5700, 0x5c80, + 0x6200, 0x3a00, 0x3f00, 0x4380, 0x4607, 0x2680, 0x9260, 0x7680, 0x8f80, 0x9286, + 0x8e80, 0x7f80, 0x7280, 0x921f, 0x4680, 0x7a80, 0x8f00, 0x92a1, 0x8800, 0x6632, + 0x6880, 0x4f80, 0x5700, 0x5b00, 0x5f80, 0x3600, 0x3b00, 0x3d80, 0x4180, 0x2000, + 0x925f, 0x8180, 0x7e00, 0x8280, 0x9000, 0x9286, 0x8e00, 0x8000, 0x7c00, 0x6700, + 0x921c, 0x6300, 0x4880, 0x6600, 0x6f00, 0x8980, 0x929f, 0x8e80, 0x6e00, 0x6639, + 0x6501, 0x0300, 0x9260, 0x4780, 0x7a80, 0x8400, 0x9100, 0x9286, 0x8b80, 0x7f81, + 0x7580, 0x8d00, 0x921a, 0x4700, 0x6603, 0x8080, 0x9100, 0x929c, 0x9180, 0x7b80, + 0x663c, 0x0180, 0x9262, 0x7180, 0x8400, 0x9180, 0x9286, 0x8b00, 0x7f81, 0x7c80, + 0x6d80, 0x9218, 0x0000, 0x6605, 0x7900, 0x8e80, 0x929b, 0x8580, 0x663d, 0x0000, + 0x9263, 0x4780, 0x8000, 0x9180, 0x9286, 0x8a00, 0x7f82, 0x7900, 0x4680, 0x9216, + 0x4700, 0x6606, 0x6d00, 0x8800, 0x9299, 0x8e00, 0x6800, 0x663d, 0x0000, 0x9265, + 0x7b00, 0x9180, 0x9286, 0x8980, 0x7f82, 0x7e80, 0x7180, 0x9214, 0x0000, 0x6609, + 0x7f80, 0x9100, 0x9296, 0x9180, 0x7900, 0x663e, 0x9267, 0x7e00, 0x9287, 0x8880, + 0x7f83, 0x7b00, 0x6580, 0x9212, 0x4700, 0x660a, 0x7600, 0x8e00, 0x9295, 0x8400, + 0x663e, 0x4880, 0x9268, 0x8300, 0x9287, 0x8800, 0x7f84, 0x7480, 0x9208, 0x8480, + 0x7580, 0x9205, 0x0000, 0x660c, 0x6b80, 0x8600, 0x9180, 0x9292, 0x8b80, 0x6800, + 0x663e, 0x4800, 0x9269, 0x8600, 0x9286, 0x9180, 0x8600, 0x7f84, 0x7c80, 0x6b00, + 0x9205, 0x7b00, 0x9281, 0x8300, 0x8780, 0x9203, 0x4700, 0x660e, 0x7e00, 0x9000, + 0x9290, 0x9100, 0x7580, 0x663f, 0x4700, 0x926a, 0x8a00, 0x9286, 0x9180, 0x8580, + 0x7f85, 0x7680, 0x6400, 0x9202, 0x6c00, 0x9100, 0x9282, 0x8e00, 0x7280, 0x9201, + 0x0000, 0x6610, 0x7500, 0x8b80, 0x928f, 0x8280, 0x6640, 0x0180, 0x926a, 0x6580, + 0x8e00, 0x9286, 0x9180, 0x8480, 0x7f85, 0x7e00, 0x6e80, 0x9201, 0x8a00, 0x9284, + 0x9180, 0x7f80, 0x9200, 0x4800, 0x6611, 0x6800, 0x8500, 0x9180, 0x928c, 0x8a00, + 0x6641, 0x0000, 0x926b, 0x6c00, 0x9000, 0x9286, 0x9100, 0x8400, 0x7f86, 0x7980, + 0x8000, 0x9287, 0x8b80, 0x7c00, 0x6613, 0x7c80, 0x9000, 0x928a, 0x9000, 0x7380, + 0x6641, 0x8c80, 0x926c, 0x7280, 0x9100, 0x9286, 0x9100, 0x8300, 0x7f85, 0x8580, + 0x9289, 0x9180, 0x8580, 0x6b80, 0x6612, 0x7300, 0x8b00, 0x9289, 0x7f00, 0x6641, + 0x4880, 0x926e, 0x7680, 0x9180, 0x9286, 0x9000, 0x8300, 0x7f83, 0x8000, 0x9000, + 0x928b, 0x8e00, 0x7a00, 0x6612, 0x6800, 0x8400, 0x9180, 0x9286, 0x8900, 0x6613, + 0x4d00, 0x5180, 0x5200, 0x5180, 0x4f80, 0x6880, 0x6500, 0x6627, 0x4700, 0x926f, + 0x7c00, 0x9287, 0x9000, 0x8280, 0x7f82, 0x8b80, 0x928d, 0x9180, 0x8400, 0x6613, + 0x7b80, 0x8f80, 0x9284, 0x8f80, 0x6f00, 0x660f, 0x6880, 0x5980, 0x3780, 0x4000, + 0x4480, 0x4602, 0x4580, 0x4380, 0x4000, 0x3b00, 0x3600, 0x5d00, 0x5700, 0x6a00, + 0x6622, 0x0180, 0x9270, 0x8000, 0x9287, 0x8f80, 0x8000, 0x7f80, 0x8600, 0x9290, + 0x8b80, 0x7580, 0x6612, 0x7180, 0x8980, 0x9282, 0x9180, 0x7d00, 0x660e, 0x6a00, + 0x5f80, 0x4180, 0x460d, 0x4580, 0x3f00, 0x3880, 0x5e00, 0x5500, 0x6800, 0x661d, + 0x0000, 0x9271, 0x8580, 0x9287, 0x8e80, 0x8300, 0x9100, 0x9291, 0x9100, 0x8080, + 0x6613, 0x8280, 0x9100, 0x9280, 0x8680, 0x660e, 0x5880, 0x4180, 0x4613, 0x4580, + 0x4380, 0x3c00, 0x6180, 0x5800, 0x4d80, 0x6500, 0x6617, 0x4880, 0x9273, 0x8980, + 0x9287, 0x9180, 0x9294, 0x8a00, 0x7300, 0x6612, 0x7a00, 0x8980, 0x6d00, 0x660c, + 0x6680, 0x6080, 0x4580, 0x4619, 0x4480, 0x3d80, 0x6180, 0x5800, 0x4d00, 0x6500, + 0x6613, 0x4700, 0x9273, 0x4780, 0x8b80, 0x929d, 0x9000, 0x7e80, 0x6621, 0x6280, + 0x461f, 0x4480, 0x3c00, 0x6080, 0x5680, 0x6800, 0x6610, 0x0180, 0x9274, 0x6b00, + 0x8f80, 0x929e, 0x8880, 0x6f00, 0x661e, 0x5f00, 0x4624, 0x4300, 0x3a00, 0x5d00, + 0x5180, 0x660d, 0x9276, 0x6e80, 0x9100, 0x929e, 0x8f80, 0x7c00, 0x661c, 0x5700, + 0x4580, 0x4627, 0x4580, 0x3f00, 0x6200, 0x5800, 0x6900, 0x6608, 0x4700, 0x9277, + 0x7480, 0x9180, 0x929e, 0x9180, 0x8600, 0x6c80, 0x6619, 0x6800, 0x3e80, 0x462c, + 0x4380, 0x3a00, 0x5c80, 0x5080, 0x6605, 0x0180, 0x9278, 0x7a80, 0x92a0, 0x8e80, + 0x7a00, 0x6618, 0x5a00, 0x4630, 0x4580, 0x3d80, 0x6180, 0x5500, 0x6800, 0x6601, + 0x927a, 0x7680, 0x9000, 0x929f, 0x9180, 0x8400, 0x6800, 0x6616, 0x3c00, 0x4634, + 0x4080, 0x3600, 0x5200, 0x927b, 0x6700, 0x8800, 0x92a0, 0x8b80, 0x7700, 0x6614, + 0x5000, 0x4580, 0x4636, 0x1600, 0x927d, 0x7b00, 0x9100, 0x929f, 0x9100, 0x8280, + 0x6613, 0x5b00, 0x4636, 0x3d80, 0x927f, 0x6c00, 0x8a00, 0x92a0, 0x8a80, 0x7380, + 0x6611, 0x6200, 0x4636, 0x2280, 0x927f, 0x9201, 0x7e80, 0x9180, 0x929f, 0x9000, + 0x7e00, 0x6610, 0x3a00, 0x4635, 0x4480, 0x0700, 0x927f, 0x9202, 0x7280, 0x8f80, + 0x929f, 0x7f00, 0x6610, 0x3c00, 0x4635, 0x2b80, 0x927f, 0x9203, 0x0180, 0x7300, + 0x8a00, 0x929d, 0x8980, 0x6611, 0x3d80, 0x4634, 0x4580, 0x0e80, 0x927f, 0x9202, + 0x0000, 0x6602, 0x8080, 0x9100, 0x929a, 0x9000, 0x7300, 0x6611, 0x3c00, 0x4634, + 0x3080, 0x927f, 0x9203, 0x4800, 0x6603, 0x7600, 0x8b80, 0x9299, 0x7f80, 0x6612, + 0x3a00, 0x4633, 0x4580, 0x1000, 0x927f, 0x9202, 0x0180, 0x6605, 0x6800, 0x8480, + 0x9180, 0x9296, 0x8980, 0x6613, 0x3600, 0x4580, 0x4632, 0x3080, 0x927f, 0x9202, + 0x0000, 0x6608, 0x7a80, 0x8e80, 0x9294, 0x9000, 0x7300, 0x6610, 0x4980, 0x4b80, + 0x0980, 0x1b00, 0x2a80, 0x2b00, 0x2c80, 0x2e00, 0x2e80, 0x3000, 0x3200, 0x3500, + 0x3580, 0x3700, 0x3800, 0x3980, 0x3a80, 0x3b81, 0x3c80, 0x3e00, 0x3f00, 0x4080, + 0x4180, 0x4380, 0x4480, 0x4583, 0x4618, 0x4580, 0x0e80, 0x927f, 0x9202, 0x4800, + 0x6609, 0x6d00, 0x8800, 0x9180, 0x9292, 0x7f80, 0x6611, 0x4b80, 0x0981, 0x1380, + 0x2617, 0x2900, 0x2b00, 0x2e00, 0x3000, 0x3180, 0x3500, 0x3700, 0x3980, 0x3a80, + 0x3b80, 0x3e00, 0x3f00, 0x4080, 0x4200, 0x4380, 0x4581, 0x4609, 0x2b80, 0x927f, + 0x9202, 0x4680, 0x660c, 0x7e00, 0x9000, 0x9290, 0x8a00, 0x6611, 0x4a00, 0x0983, + 0x2200, 0x2626, 0x2780, 0x2a80, 0x2e80, 0x3180, 0x3500, 0x3800, 0x3a80, 0x3b80, + 0x3e00, 0x3f80, 0x4000, 0x0a80, 0x927f, 0x9201, 0x0000, 0x660e, 0x7200, 0x8a00, + 0x928e, 0x9000, 0x7380, 0x6610, 0x4980, 0x0984, 0x1900, 0x2630, 0x1900, 0x0781, + 0x0600, 0x0581, 0x0400, 0x0380, 0x0280, 0x0200, 0x0180, 0x7000, 0x9277, 0x4880, + 0x6610, 0x8080, 0x9100, 0x928c, 0x7f80, 0x6611, 0x4b80, 0x0984, 0x0b00, 0x2180, + 0x262e, 0x2200, 0x0900, 0x078b, 0x0600, 0x0580, 0x0500, 0x0400, 0x0380, 0x0200, + 0x0080, 0x8c80, 0x926d, 0x4700, 0x6612, 0x7580, 0x8b80, 0x928a, 0x8a00, 0x6611, + 0x4b00, 0x0986, 0x1280, 0x2500, 0x262d, 0x1480, 0x0795, 0x0580, 0x0500, 0x0380, + 0x0280, 0x0200, 0x0080, 0x9265, 0x0100, 0x6614, 0x6800, 0x8400, 0x9180, 0x9287, + 0x9080, 0x7400, 0x6610, 0x4a00, 0x0988, 0x1880, 0x2500, 0x262b, 0x1e00, 0x079d, + 0x0580, 0x0400, 0x0380, 0x0200, 0x0080, 0x925f, 0x4880, 0x6616, 0x7a80, 0x8e80, + 0x9286, 0x8000, 0x6610, 0x4980, 0x0900, 0x0989, 0x1b00, 0x262a, 0x2300, 0x0d00, + 0x07a3, 0x0580, 0x0400, 0x0380, 0x0180, 0x9259, 0x4700, 0x6618, 0x6c80, 0x8680, + 0x9180, 0x9283, 0x8a00, 0x6611, 0x4b80, 0x098b, 0x1c80, 0x2629, 0x1680, 0x07a9, + 0x0580, 0x0400, 0x0280, 0x0080, 0x9253, 0x0180, 0x661b, 0x7d00, 0x8f80, 0x9281, + 0x9100, 0x7400, 0x6610, 0x4a80, 0x098d, 0x1b00, 0x2627, 0x1e00, 0x07ae, 0x0600, + 0x0500, 0x0380, 0x0080, 0x924e, 0x8100, 0x4880, 0x661c, 0x7200, 0x8980, 0x9280, + 0x8080, 0x6610, 0x4980, 0x098f, 0x1a00, 0x2500, 0x2624, 0x2300, 0x0d00, 0x07b2, + 0x0600, 0x0400, 0x0200, 0x924b, 0x4700, 0x661f, 0x7c00, 0x6611, 0x4b80, 0x0990, + 0x1680, 0x2480, 0x2623, 0x1480, 0x07b7, 0x0400, 0x0200, 0x9247, 0x0180, 0x6632, + 0x4b00, 0x0992, 0x1200, 0x2200, 0x2621, 0x1c80, 0x07ba, 0x0600, 0x0380, 0x9244, + 0x0000, 0x4880, 0x6631, 0x4a00, 0x0994, 0x0d80, 0x1e00, 0x261f, 0x2200, 0x0900, + 0x07bd, 0x0380, 0x9242, 0x4700, 0x6631, 0x4980, 0x0900, 0x0996, 0x1900, 0x2480, + 0x261c, 0x2500, 0x1080, 0x07bf, 0x0600, 0x0280, 0x923f, 0x0180, 0x6632, 0x4b80, + 0x0998, 0x1200, 0x2180, 0x261b, 0x1800, 0x07c2, 0x0580, 0x0200, 0x923c, 0x0000, + 0x4880, 0x6631, 0x4b00, 0x099a, 0x0b00, 0x1a00, 0x2500, 0x2618, 0x1d00, 0x0800, + 0x07c4, 0x0580, 0x0080, 0x923a, 0x4800, 0x6631, 0x4980, 0x099d, 0x1200, 0x2100, + 0x2616, 0x2200, 0x0e00, 0x0b80, 0x0a00, 0x0980, 0x0801, 0x07c2, 0x0380, 0x9238, + 0x0180, 0x6631, 0x6680, 0x4b80, 0x099e, 0x0b00, 0x1900, 0x2300, 0x2613, 0x2300, + 0x1280, 0x0b85, 0x0a00, 0x0980, 0x0801, 0x07bf, 0x0580, 0x0180, 0x9235, 0x0000, + 0x6632, 0x4b00, 0x09a1, 0x0f00, 0x1e00, 0x2500, 0x2610, 0x2500, 0x1700, 0x0b8a, + 0x0a00, 0x0980, 0x0801, 0x07bd, 0x0400, 0x9234, 0x4800, 0x6631, 0x4a00, 0x09a4, + 0x1380, 0x2180, 0x260f, 0x1a00, 0x0b8f, 0x0a00, 0x0980, 0x0800, 0x07bb, 0x0580, + 0x0180, 0x9231, 0x4680, 0x6631, 0x4980, 0x09a6, 0x0b00, 0x1880, 0x2300, 0x260c, + 0x1e00, 0x0b94, 0x0a00, 0x0980, 0x0800, 0x07b9, 0x0380, 0x922f, 0x0000, 0x6626, + 0x6501, 0x6609, 0x4b80, 0x09a8, 0x0b00, 0x1a00, 0x2300, 0x2609, 0x2180, 0x0c00, + 0x0b97, 0x0a00, 0x0980, 0x0801, 0x07b6, 0x0580, 0x922e, 0x4800, 0x6623, 0x5580, + 0x6100, 0x3a80, 0x3d00, 0x3c80, 0x3980, 0x5e80, 0x5280, 0x6500, 0x6604, 0x4b00, + 0x09ab, 0x0f00, 0x1d00, 0x2500, 0x2606, 0x2300, 0x0f80, 0x0b9c, 0x0a00, 0x0980, + 0x0800, 0x07b4, 0x0600, 0x0080, 0x9220, 0x0000, 0x0180, 0x4680, 0x4700, 0x4803, + 0x4701, 0x0180, 0x4680, 0x6622, 0x5580, 0x3b80, 0x4400, 0x4505, 0x4400, 0x3800, + 0x5380, 0x6602, 0x4a00, 0x09ae, 0x1100, 0x1e00, 0x2500, 0x2603, 0x2480, 0x1280, + 0x0ba0, 0x0a00, 0x0980, 0x0800, 0x07b3, 0x0200, 0x921c, 0x0000, 0x4680, 0x4880, + 0x662d, 0x5d80, 0x4400, 0x4509, 0x4280, 0x6000, 0x6900, 0x4980, 0x0900, 0x09b0, + 0x1200, 0x1e80, 0x2500, 0x2600, 0x2500, 0x1500, 0x0ba5, 0x0981, 0x0800, 0x07b0, + 0x0380, 0x9219, 0x0000, 0x4700, 0x662f, 0x6100, 0x450d, 0x3e00, 0x5580, 0x4b80, + 0x09b2, 0x1200, 0x1e80, 0x1980, 0x0ba9, 0x0a00, 0x0980, 0x0800, 0x07ae, 0x0400, + 0x9217, 0x0180, 0x4880, 0x662f, 0x5d80, 0x4400, 0x450e, 0x4400, 0x5e80, 0x4c00, + 0x4b00, 0x4b80, 0x09b0, 0x0bae, 0x0a00, 0x0980, 0x0800, 0x07ac, 0x0580, 0x9215, + 0x4680, 0x6630, 0x5680, 0x4400, 0x4511, 0x3b80, 0x5200, 0x6600, 0x4a00, 0x4b00, + 0x0900, 0x09ac, 0x0b00, 0x0bb1, 0x0a00, 0x0980, 0x0800, 0x07aa, 0x0580, 0x9213, + 0x0180, 0x6630, 0x6800, 0x3c80, 0x4513, 0x4100, 0x5a00, 0x6602, 0x4a00, 0x4b00, + 0x09aa, 0x0bb5, 0x0980, 0x0800, 0x07a9, 0x0580, 0x8c80, 0x9210, 0x0180, 0x6631, + 0x5b80, 0x4515, 0x4400, 0x3380, 0x6900, 0x6603, 0x4a00, 0x4b80, 0x09a5, 0x0b00, + 0x0a00, 0x0bb7, 0x0a00, 0x0980, 0x0800, 0x07a7, 0x0580, 0x9210, 0x4880, 0x6631, + 0x3b80, 0x4517, 0x3c80, 0x5280, 0x6604, 0x4980, 0x4a80, 0x4b80, 0x09a2, 0x0bbc, + 0x0a00, 0x0800, 0x07a6, 0x0580, 0x920e, 0x0180, 0x6631, 0x5300, 0x4400, 0x4518, + 0x4100, 0x5900, 0x6606, 0x4980, 0x4b00, 0x4b80, 0x099e, 0x0bbf, 0x0a00, 0x0980, + 0x0800, 0x07a4, 0x0580, 0x920d, 0x4880, 0x6631, 0x5a80, 0x451a, 0x4400, 0x6100, + 0x6800, 0x6607, 0x4980, 0x4b00, 0x4b80, 0x099a, 0x0bc3, 0x0980, 0x0800, 0x07a3, + 0x0400, 0x920b, 0x0100, 0x6632, 0x5880, 0x451c, 0x3a80, 0x5000, 0x6609, 0x4a00, + 0x4b00, 0x0900, 0x0996, 0x0a00, 0x0bc5, 0x0980, 0x0800, 0x07a2, 0x0380, 0x920a, + 0x4680, 0x6632, 0x5180, 0x4400, 0x451c, 0x3f80, 0x5680, 0x660b, 0x4a00, 0x4b00, + 0x0993, 0x0a00, 0x0bc8, 0x0980, 0x0800, 0x07a1, 0x0200, 0x9209, 0x4800, 0x6632, + 0x6800, 0x3f80, 0x451d, 0x4200, 0x5c00, 0x660d, 0x4a00, 0x4b80, 0x098f, 0x0b00, + 0x0bcb, 0x0980, 0x07a1, 0x0080, 0x9208, 0x4880, 0x6633, 0x3800, 0x451e, 0x4400, + 0x3480, 0x6900, 0x660d, 0x6680, 0x4a00, 0x4b80, 0x098c, 0x0bcd, 0x0a00, 0x0800, + 0x079f, 0x0580, 0x9208, 0x6634, 0x5c00, 0x4520, 0x3b80, 0x5100, 0x660f, 0x4980, + 0x4a00, 0x4b80, 0x0987, 0x0b00, 0x0a00, 0x0bcf, 0x0980, 0x079f, 0x0400, 0x9207, + 0x6634, 0x4e80, 0x4280, 0x4520, 0x3f80, 0x5680, 0x6611, 0x4980, 0x4a00, 0x4b80, + 0x0984, 0x0bd2, 0x0a00, 0x0800, 0x079e, 0x0200, 0x9206, 0x6635, 0x3a80, 0x4521, + 0x4200, 0x5c00, 0x6613, 0x4980, 0x4a80, 0x4b80, 0x0980, 0x0bd4, 0x0a00, 0x0800, + 0x079d, 0x0600, 0x9206, 0x4880, 0x661a, 0x6c80, 0x6f00, 0x7300, 0x7381, 0x7300, + 0x7180, 0x6d80, 0x6611, 0x5b80, 0x4522, 0x4400, 0x3380, 0x6880, 0x6614, 0x0780, + 0x0980, 0x0a00, 0x0bd4, 0x0980, 0x079d, 0x0400, 0x9205, 0x4880, 0x6617, 0x6800, + 0x7380, 0x7680, 0x7580, 0x7380, 0x7180, 0x6e81, 0x7180, 0x7280, 0x7480, 0x7680, + 0x7580, 0x7300, 0x6b80, 0x660d, 0x4c80, 0x4100, 0x4523, 0x3a80, 0x4f80, 0x6612, + 0x4a00, 0x0782, 0x0800, 0x0980, 0x0a00, 0x0bd2, 0x0980, 0x079d, 0x0180, 0x9204, + 0x4700, 0x6616, 0x7180, 0x7680, 0x7280, 0x4780, 0x0008, 0x6700, 0x7280, 0x7680, + 0x7580, 0x6f00, 0x660c, 0x3480, 0x4524, 0x3f80, 0x5480, 0x6610, 0x4a00, 0x0786, + 0x0800, 0x0980, 0x0a00, 0x0bd0, 0x0980, 0x079c, 0x0580, 0x9204, 0x0180, 0x6615, + 0x7380, 0x7580, 0x6580, 0x000d, 0x6c00, 0x7581, 0x6e00, 0x660a, 0x5500, 0x4400, + 0x4524, 0x4200, 0x5900, 0x660e, 0x4980, 0x078a, 0x0800, 0x0980, 0x0a00, 0x0bce, + 0x0a00, 0x0800, 0x079b, 0x0200, 0x9203, 0x0000, 0x6614, 0x7180, 0x7680, 0x4680, + 0x0010, 0x6c00, 0x7680, 0x7500, 0x6800, 0x6608, 0x6500, 0x3c80, 0x4525, 0x4400, + 0x5e80, 0x660c, 0x4980, 0x078e, 0x0800, 0x0980, 0x0a00, 0x0bcc, 0x0a00, 0x0800, + 0x079a, 0x0580, 0x9204, 0x4880, 0x6612, 0x6780, 0x7900, 0x6b00, 0x0013, 0x7280, + 0x7680, 0x6e00, 0x6608, 0x5c00, 0x4527, 0x3800, 0x6a00, 0x6609, 0x4980, 0x0792, + 0x0800, 0x0981, 0x0bca, 0x0a00, 0x0800, 0x079a, 0x0200, 0x9203, 0x4700, 0x6612, + 0x7180, 0x7580, 0x0015, 0x6c00, 0x7680, 0x7180, 0x6607, 0x6a00, 0x4080, 0x4527, + 0x3c80, 0x5100, 0x6607, 0x4980, 0x0796, 0x0801, 0x0980, 0x0bc8, 0x0a00, 0x0800, + 0x0799, 0x0580, 0x9203, 0x0180, 0x6612, 0x7500, 0x7280, 0x0016, 0x6700, 0x7680, + 0x7200, 0x6607, 0x6180, 0x4528, 0x3f80, 0x5580, 0x6605, 0x4980, 0x079b, 0x0800, + 0x0980, 0x0a00, 0x0bc5, 0x0a00, 0x0800, 0x0799, 0x0080, 0x9203, 0x4880, 0x6611, + 0x7580, 0x6e80, 0x0017, 0x6580, 0x7680, 0x7180, 0x6606, 0x5200, 0x4400, 0x4528, + 0x4200, 0x5a80, 0x6603, 0x4980, 0x079f, 0x0800, 0x0980, 0x0a00, 0x0bc3, 0x0a00, + 0x0800, 0x0798, 0x0400, 0x9203, 0x4680, 0x6611, 0x7580, 0x6e80, 0x0018, 0x6b00, + 0x7900, 0x6c80, 0x6606, 0x3800, 0x4529, 0x4400, 0x5f80, 0x6800, 0x6600, 0x4800, + 0x0500, 0x07a2, 0x0800, 0x0980, 0x0a00, 0x0bc1, 0x0a00, 0x0800, 0x0797, 0x0600, + 0x9203, 0x0000, 0x6611, 0x7480, 0x7280, 0x0014, 0x7380, 0x7e00, 0x0100, 0x0001, + 0x6e80, 0x7680, 0x6606, 0x5680, 0x4400, 0x452a, 0x3800, 0x4900, 0x9201, 0x0180, + 0x0580, 0x07a3, 0x0800, 0x0980, 0x0a00, 0x0bbf, 0x0a00, 0x0798, 0x0200, 0x9203, + 0x4700, 0x6610, 0x7180, 0x7580, 0x0013, 0x7580, 0x9300, 0x9400, 0x8980, 0x0002, + 0x7580, 0x7300, 0x6605, 0x6500, 0x3b80, 0x4529, 0x4400, 0x1f80, 0x9204, 0x0200, + 0x0580, 0x07a4, 0x0800, 0x0980, 0x0a00, 0x0bbd, 0x0a00, 0x0797, 0x0400, 0x9203, + 0x0000, 0x6610, 0x6800, 0x7900, 0x4780, 0x0012, 0x8600, 0x9401, 0x9300, 0x4680, + 0x0001, 0x6c00, 0x7700, 0x6606, 0x5900, 0x4528, 0x3c80, 0x1180, 0x9207, 0x0200, + 0x0600, 0x07a5, 0x0801, 0x0980, 0x0bbb, 0x0980, 0x0796, 0x0580, 0x9204, 0x4680, + 0x6610, 0x7500, 0x7280, 0x0012, 0x8800, 0x9401, 0x9300, 0x4780, 0x0002, 0x7580, + 0x6f00, 0x6605, 0x6800, 0x3e00, 0x4525, 0x4400, 0x2c00, 0x7800, 0x920a, 0x0280, + 0x0600, 0x07a7, 0x0800, 0x0980, 0x0a00, 0x0bb8, 0x0980, 0x0796, 0x8100, 0x9204, + 0x4880, 0x660f, 0x6c80, 0x7900, 0x6580, 0x0011, 0x7900, 0x9380, 0x9400, 0x8b00, + 0x0003, 0x7180, 0x7500, 0x6606, 0x5c80, 0x4524, 0x3d00, 0x1780, 0x920e, 0x0380, + 0x0600, 0x07a8, 0x0800, 0x0980, 0x0a00, 0x0bb6, 0x0800, 0x0795, 0x0200, 0x9204, + 0x0100, 0x6610, 0x7380, 0x7580, 0x0012, 0x7980, 0x8280, 0x4780, 0x0003, 0x6c00, + 0x7680, 0x6606, 0x6980, 0x3f80, 0x4521, 0x4280, 0x2580, 0x8200, 0x9211, 0x0380, + 0x07aa, 0x0800, 0x0981, 0x0bb3, 0x0a00, 0x0800, 0x0794, 0x0380, 0x9205, 0x4700, + 0x6610, 0x7580, 0x7280, 0x0018, 0x6700, 0x7900, 0x6607, 0x5e80, 0x451f, 0x4400, + 0x3100, 0x0c80, 0x9214, 0x8100, 0x0400, 0x07ac, 0x0800, 0x0980, 0x0a00, 0x0bb0, + 0x0a00, 0x0794, 0x0400, 0x9206, 0x4880, 0x660f, 0x6b80, 0x7680, 0x6e80, 0x0017, + 0x6700, 0x7900, 0x6607, 0x4e00, 0x4100, 0x451d, 0x3680, 0x1300, 0x9218, 0x0080, + 0x0400, 0x07ad, 0x0800, 0x0980, 0x0a00, 0x0bae, 0x0980, 0x0793, 0x0580, 0x9206, + 0x0000, 0x6610, 0x6b80, 0x7680, 0x7180, 0x0016, 0x6d80, 0x7680, 0x6608, 0x6100, + 0x451a, 0x4400, 0x3480, 0x1400, 0x921c, 0x0080, 0x0400, 0x07af, 0x0800, 0x0980, + 0x0a00, 0x0bab, 0x0800, 0x0792, 0x0600, 0x9207, 0x0180, 0x6610, 0x6b80, 0x7680, + 0x7380, 0x0015, 0x7381, 0x6608, 0x5000, 0x4200, 0x4517, 0x4200, 0x2c00, 0x1000, + 0x9220, 0x0080, 0x0500, 0x07b0, 0x0800, 0x0981, 0x0a00, 0x0ba7, 0x0a00, 0x0793, + 0x9208, 0x4680, 0x6610, 0x6780, 0x7480, 0x7580, 0x6700, 0x0012, 0x6580, 0x7900, + 0x6b80, 0x6609, 0x3480, 0x4515, 0x3b80, 0x2080, 0x0700, 0x9224, 0x0180, 0x0580, + 0x07b2, 0x0800, 0x0980, 0x0a00, 0x0ba5, 0x0980, 0x0792, 0x9209, 0x4700, 0x6611, + 0x6f00, 0x7680, 0x7380, 0x4680, 0x000f, 0x0100, 0x7580, 0x7300, 0x660a, 0x5280, + 0x4400, 0x4511, 0x3e00, 0x2880, 0x1180, 0x9229, 0x0180, 0x0580, 0x07b3, 0x0801, + 0x0980, 0x0a00, 0x0ba2, 0x0800, 0x0791, 0x920a, 0x4800, 0x6611, 0x6800, 0x7380, + 0x7680, 0x7280, 0x4780, 0x000c, 0x6580, 0x7580, 0x7380, 0x660c, 0x3680, 0x450d, + 0x4400, 0x3c80, 0x2700, 0x1400, 0x922e, 0x0180, 0x0580, 0x07b5, 0x0801, 0x0980, + 0x0a00, 0x0b9e, 0x0a00, 0x0791, 0x920b, 0x4800, 0x6612, 0x6800, 0x7300, 0x7680, + 0x7580, 0x6e80, 0x6580, 0x0007, 0x6700, 0x7380, 0x7680, 0x7180, 0x660d, 0x5400, + 0x4400, 0x4509, 0x3f80, 0x3100, 0x1f00, 0x0c80, 0x9233, 0x0200, 0x0580, 0x07b7, + 0x0801, 0x0980, 0x0a00, 0x0b9b, 0x0800, 0x078f, 0x0600, 0x920c, 0x4800, 0x6614, + 0x6e00, 0x7380, 0x7580, 0x7680, 0x7580, 0x7380, 0x7281, 0x7380, 0x7480, 0x7680, + 0x7580, 0x7300, 0x6800, 0x660f, 0x3900, 0x4504, 0x4200, 0x3a80, 0x2c00, 0x1c00, + 0x0e80, 0x9239, 0x0200, 0x0580, 0x07b9, 0x0801, 0x0980, 0x0a00, 0x0b97, 0x0a00, + 0x078f, 0x0580, 0x920d, 0x4700, 0x6617, 0x6b80, 0x6f00, 0x7181, 0x6f00, 0x6c80, + 0x6800, 0x6612, 0x5500, 0x3a80, 0x2f80, 0x2580, 0x1a80, 0x1000, 0x8d00, 0x923f, + 0x0200, 0x0580, 0x07bc, 0x0800, 0x0981, 0x0a00, 0x0b93, 0x0980, 0x078e, 0x0400, + 0x920e, 0x4700, 0x662c, 0x4680, 0x0180, 0x0001, 0x9248, 0x0200, 0x0580, 0x07be, + 0x0801, 0x0980, 0x0a00, 0x0b8f, 0x0a00, 0x078e, 0x0380, 0x920f, 0x0180, 0x662b, + 0x8c80, 0x924d, 0x0200, 0x0580, 0x07c1, 0x0801, 0x0981, 0x0a00, 0x0b8a, 0x0980, + 0x078d, 0x0180, 0x9210, 0x0100, 0x4880, 0x6628, 0x4800, 0x9250, 0x0200, 0x0580, + 0x07c4, 0x0801, 0x0982, 0x0a01, 0x0b83, 0x0a00, 0x078a, 0x0600, 0x0400, 0x0080, + 0x9212, 0x0000, 0x4800, 0x6627, 0x0180, 0x9252, 0x0200, 0x0580, 0x07c9, 0x0802, + 0x0981, 0x0600, 0x0401, 0x0500, 0x0580, 0x0500, 0x0401, 0x0380, 0x0200, 0x0080, + 0x9217, 0x0180, 0x6625, 0x4880, 0x8100, 0x9254, 0x0200, 0x0580, 0x07cc, 0x0580, + 0x9222, 0x0000, 0x4800, 0x6623, 0x4680, 0x9257, 0x0200, 0x0580, 0x07cb, 0x0080, + 0x9223, 0x0180, 0x4880, 0x6620, 0x4880, 0x925a, 0x0180, 0x0580, 0x07c9, 0x0380, + 0x9224, 0x7780, 0x4700, 0x661e, 0x4880, 0x0000, 0x925c, 0x0180, 0x0580, 0x07c7, + 0x0600, 0x9226, 0x0000, 0x4700, 0x661b, 0x4880, 0x0000, 0x925f, 0x0180, 0x0400, + 0x07c6, 0x0180, 0x9227, 0x0000, 0x4680, 0x4880, 0x6617, 0x4880, 0x0000, 0x9262, + 0x0080, 0x0400, 0x07c4, 0x0380, 0x922a, 0x0180, 0x4800, 0x6614, 0x4680, 0x9266, + 0x6380, 0x0400, 0x07c2, 0x0580, 0x922c, 0x6f80, 0x0180, 0x4700, 0x4880, 0x660d, + 0x4880, 0x4680, 0x0000, 0x9269, 0x8700, 0x0380, 0x07c1, 0x9230, 0x0000, 0x0180, + 0x4701, 0x4881, 0x6602, 0x4880, 0x4800, 0x4700, 0x0180, 0x0000, 0x926f, 0x0380, + 0x0600, 0x07be, 0x0180, 0x927f, 0x922f, 0x0200, 0x0580, 0x07bc, 0x0380, 0x927f, + 0x9231, 0x0200, 0x0580, 0x07ba, 0x0400, 0x927f, 0x9233, 0x0180, 0x0500, 0x07b8, + 0x0580, 0x927f, 0x9235, 0x0080, 0x0400, 0x07b6, 0x0600, 0x927f, 0x9238, 0x0380, + 0x0600, 0x07b4, 0x927f, 0x923a, 0x0200, 0x0580, 0x07b2, 0x927f, 0x923c, 0x0180, + 0x0400, 0x07b0, 0x8700, 0x927f, 0x923d, 0x7000, 0x0380, 0x0600, 0x07ad, 0x8100, + 0x927f, 0x9240, 0x0200, 0x0580, 0x07ab, 0x927f, 0x9243, 0x0080, 0x0400, 0x07a9, + 0x927f, 0x9246, 0x0280, 0x0580, 0x07a6, 0x927f, 0x922b, 0x4505, 0x9216, 0x0180, + 0x0400, 0x07a3, 0x0580, 0x927f, 0x922b, 0x4505, 0x9219, 0x0200, 0x0580, 0x07a0, + 0x0500, 0x927f, 0x922b, 0x4505, 0x921b, 0x0080, 0x0380, 0x0600, 0x079d, 0x0380, + 0x927f, 0x922b, 0x4505, 0x921e, 0x0180, 0x0400, 0x079b, 0x0200, 0x927f, 0x922b, + 0x4505, 0x9221, 0x0200, 0x0400, 0x0798, 0x8c80, 0x927f, 0x922b, 0x4505, 0x9224, + 0x0200, 0x0400, 0x0600, 0x0793, 0x0580, 0x927f, 0x922c, 0x4505, 0x9227, 0x0180, + 0x0380, 0x0580, 0x0790, 0x0380, 0x924b, 0x4505, 0x9202, 0x4505, 0x9205, 0x4505, + 0x9204, 0x4505, 0x9202, 0x4505, 0x9209, 0x4507, 0x9208, 0x4505, 0x9208, 0x4504, + 0x9202, 0x4505, 0x9203, 0x4506, 0x9209, 0x4506, 0x920e, 0x8100, 0x0200, 0x0400, + 0x0580, 0x078c, 0x0080, 0x924b, 0x4505, 0x9200, 0x4508, 0x9204, 0x4505, 0x9204, + 0x4505, 0x9200, 0x4508, 0x9207, 0x450a, 0x9206, 0x4505, 0x9206, 0x4508, 0x9200, + 0x4505, 0x9204, 0x4505, 0x9209, 0x4505, 0x9214, 0x0180, 0x0280, 0x0400, 0x0581, + 0x0600, 0x0781, 0x0600, 0x0580, 0x0380, 0x0080, 0x924c, 0x4510, 0x9203, 0x4505, + 0x9204, 0x4510, 0x9206, 0x450c, 0x9204, 0x4505, 0x9205, 0x4510, 0x9204, 0x4505, + 0x9209, 0x4505, 0x926d, 0x4511, 0x9202, 0x4505, 0x9204, 0x4510, 0x9206, 0x450c, + 0x9204, 0x4505, 0x9204, 0x4511, 0x9204, 0x4506, 0x9207, 0x4506, 0x926d, 0x4507, + 0x9202, 0x4506, 0x9202, 0x4505, 0x9204, 0x4507, 0x9202, 0x4506, 0x9205, 0x4501, + 0x9204, 0x4506, 0x9203, 0x4505, 0x9204, 0x4506, 0x9202, 0x4507, 0x9205, 0x4505, + 0x9207, 0x4505, 0x926e, 0x4506, 0x9204, 0x4505, 0x9202, 0x4505, 0x9204, 0x4506, + 0x9204, 0x4505, 0x9205, 0x4500, 0x9206, 0x4505, 0x9203, 0x4505, 0x9203, 0x4506, + 0x9204, 0x4506, 0x9205, 0x4513, 0x926e, 0x4505, 0x9205, 0x4505, 0x9202, 0x4505, + 0x9204, 0x4505, 0x9205, 0x4505, 0x920e, 0x4505, 0x9202, 0x4505, 0x9203, 0x4505, + 0x9206, 0x4505, 0x9205, 0x4513, 0x926e, 0x4505, 0x9204, 0x4506, 0x9202, 0x4505, + 0x9204, 0x4505, 0x9205, 0x4505, 0x920e, 0x4505, 0x9202, 0x4505, 0x9203, 0x4505, + 0x9206, 0x4505, 0x9206, 0x4511, 0x926f, 0x4510, 0x9203, 0x4505, 0x9204, 0x4505, + 0x9205, 0x4505, 0x920e, 0x4505, 0x9202, 0x4505, 0x9203, 0x4505, 0x9206, 0x4505, + 0x9206, 0x4511, 0x926f, 0x450f, 0x9204, 0x4505, 0x9204, 0x4505, 0x9205, 0x4505, + 0x920e, 0x4505, 0x9202, 0x4505, 0x9203, 0x4505, 0x9206, 0x4505, 0x9206, 0x4506, + 0x9203, 0x4506, 0x926f, 0x450d, 0x9206, 0x4505, 0x9204, 0x4505, 0x9205, 0x4505, + 0x920e, 0x4505, 0x9202, 0x4505, 0x9203, 0x4505, 0x9206, 0x4505, 0x9207, 0x4505, + 0x9203, 0x4505, 0x9270, 0x4505, 0x920e, 0x4505, 0x9204, 0x4505, 0x9205, 0x4505, + 0x920e, 0x4505, 0x9202, 0x4505, 0x9203, 0x4505, 0x9206, 0x4505, 0x9207, 0x4506, + 0x9201, 0x4506, 0x9270, 0x4505, 0x920e, 0x4505, 0x9204, 0x4505, 0x9205, 0x4505, + 0x9205, 0x4500, 0x9206, 0x4505, 0x9203, 0x4505, 0x9203, 0x4506, 0x9204, 0x4506, + 0x9208, 0x4505, 0x9201, 0x4505, 0x9272, 0x4505, 0x9206, 0x4501, 0x9204, 0x4505, + 0x9204, 0x4505, 0x9205, 0x4505, 0x9205, 0x4501, 0x9204, 0x4506, 0x9203, 0x4505, + 0x9204, 0x4506, 0x9202, 0x4507, 0x9208, 0x4505, 0x9201, 0x4505, 0x9272, 0x450e, + 0x9204, 0x4505, 0x9204, 0x4505, 0x9205, 0x4505, 0x9205, 0x450c, 0x9204, 0x4505, + 0x9204, 0x4511, 0x9208, 0x450d, 0x9273, 0x450d, 0x9204, 0x4505, 0x9204, 0x4505, + 0x9205, 0x4505, 0x9205, 0x450c, 0x9204, 0x4505, 0x9205, 0x4510, 0x9209, 0x450b, + 0x9275, 0x450c, 0x9204, 0x4505, 0x9204, 0x4505, 0x9205, 0x4505, 0x9205, 0x450a, + 0x9206, 0x4505, 0x9206, 0x4508, 0x9200, 0x4505, 0x9209, 0x450b, 0x9277, 0x4508, + 0x9206, 0x4505, 0x9204, 0x4505, 0x9205, 0x4505, 0x9206, 0x4507, 0x9208, 0x4505, + 0x9208, 0x4504, 0x9202, 0x4505, 0x9209, 0x450b, 0x927f, 0x9207, 0x4505, 0x9256, + 0x4509, 0x927f, 0x9208, 0x4505, 0x9256, 0x4509, 0x927f, 0x9208, 0x4505, 0x922e, + 0x4505, 0x9222, 0x4507, 0x927f, 0x9209, 0x4505, 0x922e, 0x4505, 0x9222, 0x4507, + 0x927f, 0x9209, 0x4505, 0x922e, 0x4505, 0x9222, 0x4507, 0x927f, 0x9209, 0x4505, + 0x922e, 0x4505, 0x927f, 0x927f, 0x927f, 0x927f, 0x927f, 0x927f, 0x927f, 0x927f, + 0x927f, 0x927f, 0x927f, 0x927f, 0x927f, 0x927f, 0x927f, 0x927f, 0x927f, 0x927f, + 0x927f, 0x927f, 0x927f, 0x927f, 0x927f, 0x927f, 0x927f, 0x927f, 0x927e}; +int const image_colors_cnt = 297; +int const image_data_cnt = sizeof(image_data)/sizeof(uint16_t); diff --git a/examples/himbaechel/emcu-with-apb-spi.v b/examples/himbaechel/emcu-with-apb-spi.v new file mode 100644 index 00000000..3ed37fb3 --- /dev/null +++ b/examples/himbaechel/emcu-with-apb-spi.v @@ -0,0 +1,504 @@ +`default_nettype none + +/* +* The apprate SPI is implemented with the following limitations: +* - master only, +* - SPI3 mode, +* - write only, +* - LSB/MSB format switching is performed by a bit in the control/status register, +* - the status register contains one bit - BUSY. +* - speed is fixed = 0.5 clk (~13MHz) +* +* Attention: flashing is performed with firmware as follows: +* openFPGALoader -f -b tangnano4k --mcufw=emcu-firmware/apb-spi.bin emcu-apb-spi-tangnano4k.fs +* +*/ + +module top ( + input wire clk_i, + output wire mode_led, + input wire RXD, + output wire TXD, + input wire rst_i, + // gpio + inout wire [1:0] gpio, + // SPI + output wire spi_OUT, + output reg spi_SCL, + output [5:0] led + ); + + // dummy sinks + wire dummy_uart1_txd; + wire dummy_uart0_baudtick; + wire dummy_uart1_baudtick; + wire dummy_intmonitor; + wire dummy_targexp0_hsel; + wire [31:0] dummy_targexp0_haddr; + wire [1:0] dummy_targexp0_htrans; + wire dummy_targexp0_hwrite; + wire [2:0] dummy_targexp0_hsize; + wire [2:0] dummy_targexp0_hburst; + wire [3:0] dummy_targexp0_hprot; + wire [1:0] dummy_targexp0_memattr; + wire dummy_targexp0_exreq; + wire [3:0] dummy_targexp0_hmaster; + wire [31:0] dummy_targexp0_hwdata; + wire dummy_targexp0_hmastlock; + wire dummy_targexp0_hauser; + wire [3:0] dummy_targexp0_hwuser; + wire [31:0] dummy_initexp0_hrdata; + wire dummy_initexp0_hready; + wire dummy_initexp0_hresp; + wire dummy_initexp0_exresp; + wire [2:0] dummy_initexp0_hruser; + wire dummy_daptdo; + wire dummy_dapjtagnsw; + wire [3:0] dummy_tpiutracedata; + wire dummy_targexp0_hreadymux; + wire dummy_dapntdoen; + + // Periphery bus + wire apbtargexp2_psel; + wire [11:0] apbtargexp2_paddr; + wire apbtargexp2_pready; + wire apbtargexp2_penable; + wire apbtargexp2_pwrite; + wire [31:0] apbtargexp2_pwdata; + wire [31:0] apbtargexp2_prdata; + wire [3:0] apbtargexp2_pstrb; + wire [2:0] apbtargexp2_pprot; + + // ROM 32k + wire [12:0] rom_addr; + wire [15:0] dummy_rom_addr; // flash is addressed by 4 bytes each, and there are also unused high bits of the address + wire targflash0_hsel; + wire [1:0] targflash0_htrans; + wire [2:0] dummy_targflash0_hsize; + wire [2:0] dummy_targflash0_hburst; + wire dummy_targflash0_hreadymux; + wire [31:0] rom_out; + wire targflash0_readyout; + + // SRAM 8k + wire [10:0] sram0_addr; + wire [1:0] dummy_sram0_addr; // high address bits + wire sram0_cs; + wire [3:0] sram0_wren; // byte write mask + wire [31:0] sram0_wdata; + wire [31:0] sram0_rdata; // all 32bit + wire [23:0] dummy_sram0_rdata_0; // for unused bits + wire [23:0] dummy_sram0_rdata_1; + wire [23:0] dummy_sram0_rdata_2; + wire [23:0] dummy_sram0_rdata_3; + + wire mtx_hreset_n; + + // The processor reset inputs are not explicitly brought out - Global Set Reset is used. + GSR gsr ( + .GSRI(rst_i) + ); + + wire GND = 1'b0; + wire VCC = 1'b1; + + wire dummy_lock; + wire clk; + PLLVR #( + .FCLKIN("27.0"), + .IDIV_SEL(4), // -> PFD = 5.4 MHz (range: 3-400 MHz) + .FBDIV_SEL(12), // -> CLKOUT = 70.2 MHz (range: 400-600 MHz) + .ODIV_SEL(8) // -> VCO = 561.6 MHz (range: 600-1200 MHz) +) + pll (.CLKOUTP(), .CLKOUTD(), .CLKOUTD3(), .RESET(1'b0), .RESET_P(1'b0), .CLKFB(1'b0), .FBDSEL(6'b0), .IDSEL(6'b0), .ODSEL(6'b0), .PSDA(4'b0), .DUTYDA(4'b0), .FDLY(4'b0), .VREN(1'b1), + .CLKIN(clk_i), // 27.0 MHz + .CLKOUT(clk), // 70.2 MHz + .LOCK(dummy_lock) + ); + + // dummy GPIO inout ports, unused + wire [15:0] gpio_out; + wire [15:0] gpio_oen; + wire [15:0] gpio_in; + + // GPIO inout ports, 16 total but we need only two + wire [15:0] gpio_out; + wire [15:0] gpio_oen; // active low + wire [15:0] gpio_in; + + IOBUF gpio0( + .O(gpio_in[0]), + .IO(gpio[0]), + .I(gpio_out[0]), + .OEN(~gpio_oen[0]) + ); + + IOBUF gpio1( + .O(gpio_in[1]), + .IO(gpio[1]), + .I(gpio_out[1]), + .OEN(~gpio_oen[1]) + ); + + + EMCU cpu ( + .FCLK(clk), + .PORESETN(GND), // doesn't matter + .SYSRESETN(GND), // doesn't matter + .RTCSRCCLK(GND), // this is normal port but we haven't RTC in this example + .MTXHRESETN(mtx_hreset_n), + + .IOEXPOUTPUTO(gpio_out), + .IOEXPOUTPUTENO(gpio_oen), + .IOEXPINPUTI(gpio_in), + + .UART0RXDI(RXD), + .UART1RXDI(GND), + .UART0TXDO(TXD), + .UART1TXDO(dummy_uart1_txd), + .UART0BAUDTICK(dummy_uart0_baudtick), + .UART1BAUDTICK(dummy_uart1_baudtick), + + .INTMONITOR(dummy_intmonitor), + + .SRAM0ADDR({dummy_sram0_addr, sram0_addr}), + .SRAM0CS(sram0_cs), + .SRAM0WREN(sram0_wren), + .SRAM0WDATA(sram0_wdata), + .SRAM0RDATA(sram0_rdata), + + .TARGFLASH0HSEL(targflash0_hsel), + .TARGFLASH0HADDR({dummy_rom_addr[15:2], rom_addr, dummy_rom_addr[1:0]}), + .TARGFLASH0HTRANS(targflash0_htrans), + .TARGFLASH0HSIZE(dummy_targflash0_hsize), + .TARGFLASH0HBURST(dummy_targflash0_hburst), + .TARGFLASH0HREADYMUX(dummy_targflash0_hreadymux), + .TARGFLASH0HRDATA(rom_out), + .TARGFLASH0HRUSER({GND,GND,GND}), + .TARGFLASH0HRESP(GND), + .TARGFLASH0EXRESP(GND), + .TARGFLASH0HREADYOUT(targflash0_readyout), + + .TARGEXP0HSEL(dummy_targexp0_hsel), + .TARGEXP0HADDR(dummy_targexp0_haddr), + .TARGEXP0HTRANS(dummy_targexp0_htrans), + .TARGEXP0HWRITE(dummy_targexp0_hwrite), + .TARGEXP0HSIZE(dummy_targexp0_hsize), + .TARGEXP0HBURST(dummy_targexp0_hburst[2:0]), + .TARGEXP0HPROT(dummy_targexp0_hprot[3:0]), + .TARGEXP0MEMATTR(dummy_targexp0_memattr), + .TARGEXP0EXREQ(dummy_targexp0_exreq), + .TARGEXP0HMASTER(dummy_targexp0_hmaster), + .TARGEXP0HWDATA(dummy_targexp0_hwdata), + .TARGEXP0HMASTLOCK(dummy_targexp0_hmastlock), + .TARGEXP0HREADYMUX(dummy_targexp0_hreadymux), + .TARGEXP0HAUSER(dummy_targexp0_hauser), + .TARGEXP0HWUSER(dummy_targexp0_hwuser), + .INITEXP0HRDATA(dummy_initexp0_hrdata), + .INITEXP0HREADY(dummy_initexp0_hready), + .INITEXP0HRESP(dummy_initexp0_hresp), + .INITEXP0EXRESP(dummy_initexp0_exresp), + .INITEXP0HRUSER(dummy_initexp0_hruser), + .DAPTDO(dummy_daptdo), + .DAPJTAGNSW(dummy_dapjtagnsw), + .DAPNTDOEN(dummy_dapntdoen), + .TPIUTRACEDATA(dummy_tpiutracedata), + .TARGEXP0HRDATA({32{GND}}), + .TARGEXP0HREADYOUT(GND), + .TARGEXP0HRESP(VCC), // XXX + .TARGEXP0EXRESP(GND), + .TARGEXP0HRUSER({GND,GND,GND}), + .INITEXP0HSEL(GND), + .INITEXP0HADDR({32{GND}}), + .INITEXP0HTRANS({GND,GND}), + .INITEXP0HWRITE(GND), + .INITEXP0HSIZE({GND,GND,GND}), + .INITEXP0HBURST({GND,GND,GND}), + .INITEXP0HPROT({GND,GND,GND,GND}), + .INITEXP0MEMATTR({GND,GND}), + .INITEXP0EXREQ(GND), + .INITEXP0HMASTER({GND,GND,GND,GND}), + .INITEXP0HWDATA({32{GND}}), + .INITEXP0HMASTLOCK(GND), + .INITEXP0HAUSER(GND), + .INITEXP0HWUSER({GND,GND,GND,GND}), + + .APBTARGEXP2PSEL(apbtargexp2_psel), + .APBTARGEXP2PADDR(apbtargexp2_paddr), + .APBTARGEXP2PSTRB(apbtargexp2_pstrb), + .APBTARGEXP2PPROT(apbtargexp2_pprot), + .APBTARGEXP2PENABLE(apbtargexp2_penable), + .APBTARGEXP2PWRITE(apbtargexp2_pwrite), + .APBTARGEXP2PWDATA(apbtargexp2_pwdata), + + .APBTARGEXP2PRDATA(apbtargexp2_prdata), + .APBTARGEXP2PREADY(apbtargexp2_pready), + .APBTARGEXP2PSLVERR(GND), + + .DAPSWDITMS(GND), + .FLASHERR(GND), + .FLASHINT(GND) + ); + + // ROM + // To understand what the entrances and outputs of this primitive, I followed the description of the AMBA protocol. + // https://developer.arm.com/documentation/ihi0011/a/ or search for IHI0011a.pdf + // It was from there and by the names of the ports of the primitive that it + // became clear that RAM is connected directly without tricks, but for Flash + // it would be necessary to implement a whole client of this AHB Bus. + localparam ROM_IDLE = 2'b00; + localparam ROM_READ = 2'b01; + localparam ROM_OKEY = 2'b10; + reg [1:0] rom_state; + reg rom_sel; + reg [12:0] flash_in_addr; + + // AHB slave + always @(posedge clk) begin + if (!(rst_i & mtx_hreset_n)) begin + rom_state <= ROM_IDLE; + rom_sel <= 1'b0; + end else begin + case (rom_state) + ROM_IDLE: begin + if (targflash0_hsel & targflash0_htrans[1]) begin // NONSEQ/SEQ transfer + rom_state <= ROM_READ; + flash_in_addr <= rom_addr; + rom_sel <= 1'b1; + end + end + ROM_READ: begin + if (targflash0_hsel & targflash0_htrans[1]) begin // NONSEQ/SEQ transfer + rom_state <= ROM_OKEY; + rom_sel <= 1'b0; + end else begin + rom_state <= ROM_IDLE; + rom_sel <= 1'b0; + end + end + ROM_OKEY: begin + if (targflash0_hsel & targflash0_htrans[1]) begin // NONSEQ/SEQ transfer + rom_state <= ROM_IDLE; + rom_sel <= 1'b0; + end + end + endcase + end + end + assign targflash0_readyout = rom_state == ROM_IDLE; + + // very simple APB bridge: decode only second APB address 0x4000250 + wire psel2; + assign psel2 = apbtargexp2_psel && (apbtargexp2_paddr[11:8] == 4'h5); // 0x40002 >5< 00 + + + // SPI device + wire spi_status; + reg spi_msb; + reg spi_start; + reg [7:0] spi_WDATA; + reg [9:0] spi_tmp_wdata; + assign spi_OUT = spi_msb ? spi_tmp_wdata[9] : spi_tmp_wdata[0]; + reg spi_clk; + assign spi_SCL = spi_clk; + + assign led[0] = spi_start; + assign led[1] = spi_status; + assign led[2] = psel2; + + // spi clock + reg [4:0] spi_clk_cnt; + always @(posedge clk or negedge rst_i) begin + spi_clk <= 1'b1; + spi_status <= 1'b0; + if (!rst_i) begin + spi_clk <= 1'b1; + spi_clk_cnt <= 5'd0; + end else begin + if (spi_start) begin + spi_clk_cnt <= 5'd16; + spi_status <= 1'b1; + end else begin + if (spi_clk_cnt != 5'd0) begin + spi_status <= 1'b1; + spi_clk_cnt <= spi_clk_cnt - 1'b1; + spi_clk <= ~spi_clk; + end + end + end + end + + // spi data + always @(posedge clk or negedge rst_i) begin + if (!rst_i) begin + spi_tmp_wdata <= 8'b0; + end else begin + if (spi_start) begin + spi_tmp_wdata[8:1] <= spi_WDATA; + end else begin + if (spi_status && (spi_clk)) begin + spi_tmp_wdata <= spi_msb ? {spi_tmp_wdata[8:0], 1'b0} : {1'b0, spi_tmp_wdata[9:1]}; + end + end + end + end + + // APB slave device + // One can use apbtargexp2_paddr[7:0] for master 1 registers. + localparam APB_IDLE = 2'b00; + localparam APB_WRITE = 2'b01; + localparam APB_READ = 2'b10; + reg [1:0] apb_slave_state; + always @(posedge clk or negedge rst_i) begin + spi_start <= 1'b0; + if (!rst_i) begin + apb_slave_state <= APB_IDLE; + apbtargexp2_pready <= 1'b0; + apbtargexp2_prdata <= {32{1'b0}}; + end else begin + case (apb_slave_state) + APB_IDLE: begin + apbtargexp2_pready <= 1'b0; + apbtargexp2_prdata <= {32{1'b0}}; + if (psel2) begin + if (apbtargexp2_pwrite) begin + apb_slave_state <= APB_WRITE; + end else begin + apb_slave_state <= APB_READ; + end + end + end + APB_WRITE: begin + if (psel2 && apbtargexp2_pwrite) begin + apbtargexp2_pready <= 1'b1; + if (|apbtargexp2_paddr[7:0]) begin // any addr != 0 + spi_WDATA <= apbtargexp2_pwdata[7:0]; + spi_start <= 1'b1; + end else begin + spi_msb <= apbtargexp2_pwdata[0]; + end + end + apb_slave_state <= APB_IDLE; + end + APB_READ: begin + if (psel2 && !apbtargexp2_pwrite) begin // return the spi status + apbtargexp2_pready <= 1'b1; + if (!(|apbtargexp2_paddr[7:0])) begin + apbtargexp2_prdata[0] <= spi_status; + end + end + apb_slave_state <= APB_IDLE; + end + default: begin + apb_slave_state <= APB_IDLE; + end + endcase + end + end + + assign mode_led = spi_status; + + FLASH256K rom( + .DOUT(rom_out[31:0]), + .XADR(flash_in_addr[12:6]), + .YADR(flash_in_addr[5:0]), + .XE(rst_i), + .YE(rst_i), + .SE(rom_sel), + .ERASE(GND), + .PROG(GND), + .NVSTR(GND), + .DIN({32{GND}}) + ); + + // RAM 4 block of 2K + // Inferring will probably also work, but with primitives it is somehow easier for me. + SDPB ram_0 ( + .DO({dummy_sram0_rdata_0, sram0_rdata[7:0]}), + .DI({{24{GND}}, sram0_wdata[7:0]}), + .BLKSELA({GND, GND, sram0_cs}), + .BLKSELB({GND, GND, sram0_cs}), + .ADA({sram0_addr, GND,GND,GND}), + .ADB({sram0_addr, GND,GND,GND}), + .CLKA(clk), + .CLKB(clk), + .CEA(sram0_wren[0]), + .CEB(!sram0_wren[0]), + .OCE(VCC), + .RESETA(GND), + .RESETB(!rst_i) + ); + defparam ram_0.BIT_WIDTH_0=8; + defparam ram_0.BIT_WIDTH_1=8; + defparam ram_0.BLK_SEL_0=3'b001; + defparam ram_0.BLK_SEL_1=3'b001; + defparam ram_0.READ_MODE=1'b0; + defparam ram_0.RESET_MODE="SYNC"; + + SDPB ram_1 ( + .DO({dummy_sram0_rdata_1, sram0_rdata[15:8]}), + .DI({{24{GND}}, sram0_wdata[15:8]}), + .BLKSELA({GND, GND, sram0_cs}), + .BLKSELB({GND, GND, sram0_cs}), + .ADA({sram0_addr, GND,GND,GND}), + .ADB({sram0_addr, GND,GND,GND}), + .CLKA(clk), + .CLKB(clk), + .CEA(sram0_wren[1]), + .CEB(!sram0_wren[1]), + .OCE(VCC), + .RESETA(GND), + .RESETB(!rst_i) + ); + defparam ram_1.BIT_WIDTH_0=8; + defparam ram_1.BIT_WIDTH_1=8; + defparam ram_1.BLK_SEL_0=3'b001; + defparam ram_1.BLK_SEL_1=3'b001; + defparam ram_1.READ_MODE=1'b0; + defparam ram_1.RESET_MODE="SYNC"; + + SDPB ram_2 ( + .DO({dummy_sram0_rdata_2, sram0_rdata[23:16]}), + .DI({{24{GND}}, sram0_wdata[23:16]}), + .BLKSELA({GND, GND, sram0_cs}), + .BLKSELB({GND, GND, sram0_cs}), + .ADA({sram0_addr, GND,GND,GND}), + .ADB({sram0_addr, GND,GND,GND}), + .CLKA(clk), + .CLKB(clk), + .CEA(sram0_wren[2]), + .CEB(!sram0_wren[2]), + .OCE(VCC), + .RESETA(GND), + .RESETB(!rst_i) + ); + defparam ram_2.BIT_WIDTH_0=8; + defparam ram_2.BIT_WIDTH_1=8; + defparam ram_2.BLK_SEL_0=3'b001; + defparam ram_2.BLK_SEL_1=3'b001; + defparam ram_2.READ_MODE=1'b0; + defparam ram_2.RESET_MODE="SYNC"; + + SDPB ram_3 ( + .DO({dummy_sram0_rdata_3, sram0_rdata[31:24]}), + .DI({{24{GND}}, sram0_wdata[31:24]}), + .BLKSELA({GND, GND, sram0_cs}), + .BLKSELB({GND, GND, sram0_cs}), + .ADA({sram0_addr, GND,GND,GND}), + .ADB({sram0_addr, GND,GND,GND}), + .CLKA(clk), + .CLKB(clk), + .CEA(sram0_wren[3]), + .CEB(!sram0_wren[3]), + .OCE(VCC), + .RESETA(GND), + .RESETB(!rst_i) + ); + defparam ram_3.BIT_WIDTH_0=8; + defparam ram_3.BIT_WIDTH_1=8; + defparam ram_3.BLK_SEL_0=3'b001; + defparam ram_3.BLK_SEL_1=3'b001; + defparam ram_3.READ_MODE=1'b0; + defparam ram_3.RESET_MODE="SYNC"; + +endmodule diff --git a/examples/himbaechel/tangnano4k.cst b/examples/himbaechel/tangnano4k.cst index 7e10f37b..30f2e0a4 100644 --- a/examples/himbaechel/tangnano4k.cst +++ b/examples/himbaechel/tangnano4k.cst @@ -1,7 +1,7 @@ // these are the HDMI pins! -IO_LOC "led[0]" 34; -IO_LOC "led[1]" 35; -IO_LOC "led[2]" 29; +IO_LOC "led[0]" 39; +IO_LOC "led[1]" 40; +IO_LOC "led[2]" 41; IO_LOC "led[3]" 30; IO_LOC "led[4]" 31; IO_LOC "led[5]" 32; @@ -26,6 +26,14 @@ IO_PORT "TXD" PULL_MODE=UP; IO_LOC "RXD" 46; IO_PORT "RXD" PULL_MODE=UP; +// gpio +IO_LOC "gpio[0]" 47; +IO_LOC "gpio[1]" 48; + +// SPI +IO_LOC "spi_OUT" 42; +IO_LOC "spi_SCL" 43; + // oser IO_LOC "oser_out" 35; IO_LOC "io16" 35;