Skip to content

Commit

Permalink
Himbaechel. Add BSRAM for all chips.
Browse files Browse the repository at this point in the history
The following primitives are implemented for the GW1N-1, GW2A-18,
GW2AR-18C, GW1NSR-4C, GW1NR-9C, GW1NR-9 and GW1N-4 chips:

    * pROM     - read only memory - (bitwidth: 1, 2, 4, 8, 16, 32).
    * pROMX9   - read only memory - (bitwidth: 9, 18, 36).
    * SDPB     - semidual port    - (bitwidth: 1, 2, 4, 8, 16, 32).
    * SDPX9B   - semidual port    - (bitwidth: 9, 18, 36).
    * DPB      - dual port        - (bitwidth: 16).
    * DPX9B    - dual port        - (bitwidth: 18).
    * SP       - single port      - (bitwidth: 1, 2, 4, 8, 16, 32).
    * SPX9     - single port      - (bitwidth: 9, 18, 36).

For GW1NSR-4C and GW1NR-9 chips, SP/SPX9 primitives with data widths of
32/36 bits are implemented using a pair of 16-bit wide primitives.

Added examples for all boards except those based on GW1NSR-4C, GW1NR-9
and GW1N-4 chips for memory primitives with a width of 8 bits (as well
as 16 bits where 8 is not supported).

And these very examples are the weakest point - I tried to make the
primitives themselves work and the result of compiling the examples was
similar between the vendor IDE and Apicula, but the examples themselves
were poorly written. This is due to my lack of experience working with
BSRAM.  In general, they need to be rewritten.

Signed-off-by: YRabbit <[email protected]>
  • Loading branch information
yrabbit committed Nov 27, 2023
1 parent 93e5c54 commit 6a2469a
Show file tree
Hide file tree
Showing 41 changed files with 2,826 additions and 35 deletions.
9 changes: 5 additions & 4 deletions apycula/chipdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -1196,7 +1196,7 @@ def fse_iologic(device, fse, ttyp):
# the column indicated there is the last column of the left quadrant.

# It is enough to empirically determine the correspondence of clocks and
# speakers in the new quadrant (even three clocks is enough, since the fourth
# columns in the new quadrant (even three clocks is enough, since the fourth
# becomes obvious).
# [3, 2, 1, 0] turned out to be the unwritten standard for all the chips studied.

Expand Down Expand Up @@ -1233,9 +1233,9 @@ def fse_iologic(device, fse, ttyp):
# wires of the same name involved in some kind of switching anywhere in the
# chip are combined into one Himbaechel node. Further, when routing, there is
# already a choice of which pip to use and which cell.
# It also follows that for the Himbaechel watch wires should not be mixed
# It also follows that for the Himbaechel clock wires should not be mixed
# together with any other wires. At least I came to this conclusion and that
# is why the HCLK wires, which have the same numbers as the watch spines, are
# is why the HCLK wires, which have the same numbers as the clock spines, are
# stored separately.

# dat['CmuxIns'] and 80 - here, the places of entry points into the clock
Expand Down Expand Up @@ -1562,6 +1562,7 @@ def fse_bram(fse, aux = False):
bels[name] = Bel()
return bels


def disable_plls(dev, device):
if device in {'GW2A-18C'}:
# (9, 0) and (9, 55) are the coordinates of cells when trying to place
Expand Down Expand Up @@ -1920,7 +1921,7 @@ def dat_portmap(dat, dev, device):
elif i in range(132, 135):
nam = f'BLKSELA{i - 132}'
wire_idx = dat['BsramIn'][i - 132 + 15]
off = 0
off = [0, 0, 2][i - 132]
else:
nam = f'BLKSELB{i - 135}'
wire_idx = wirenumbers[['CE2', 'LSR2', 'CE1'][i - 135]]
Expand Down
96 changes: 74 additions & 22 deletions apycula/gowin_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,9 @@ def extra_bsram_bels(cell, row, col, num, cellname):
def store_bsram_init_val(db, row, col, typ, parms, attrs):
global bsram_init_map
global has_bsram_init
if typ == 'BSRAM_AUX':
if typ == 'BSRAM_AUX' or 'INIT_RAM_00' not in parms:
return

subtype = attrs['BSRAM_SUBTYPE']
if not has_bsram_init:
has_bsram_init = True
Expand All @@ -113,7 +114,7 @@ def store_bsram_init_val(db, row, col, typ, parms, attrs):
# 3 BSRAM cells have width 3 * 60
loc_map = np.zeros((256, 3 * 60), dtype = np.int8)
#print("mapping")
if subtype in {''}:
if not subtype.strip():
width = 256
elif subtype in {'X9'}:
width = 288
Expand Down Expand Up @@ -484,56 +485,104 @@ def set_pll_attrs(db, typ, idx, attrs):
add_attr_val(db, 'PLL', fin_attrs, attrids.pll_attrids[attr], val)
return fin_attrs

_bsram_defaults = {
'READ_MODE': "0", 'WRITE_MODE': "00", 'RESET_MODE': "SYNC", 'BLK_SEL': "000",
'BIT_WIDTH': "00000000000000000000000000100000"}
def bsram_add_defaults(params):
ret_params = _bsram_defaults.copy()
for parm, val in params.items():
if parm in ret_params:
ret_params[parm] = val
return ret_params

_bsram_bit_widths = { 1: '1', 2: '2', 4: '4', 8: '9', 9: '9', 16: '16', 18: '16'}
_bsram_bit_widths = { 1: '1', 2: '2', 4: '4', 8: '9', 9: '9', 16: '16', 18: '16', 32: 'X36', 36: 'X36'}
def set_bsram_attrs(db, typ, params):
bsram_attrs = {}
bsram_attrs['MODE'] = 'ENABLE'
bsram_attrs['GSR'] = 'DISABLE'

for parm, val in bsram_add_defaults(params).items():
for parm, val in params.items():
if parm == 'BIT_WIDTH':
val = int(val, 2)
if val in _bsram_bit_widths:
bsram_attrs[f'{typ}A_DATA_WIDTH'] = _bsram_bit_widths[val]
if typ not in {'ROM'}:
if val in {16, 18}: # XXX no dynamic byte enable
bsram_attrs[f'{typ}A_BEHB'] = 'DISABLE'
bsram_attrs[f'{typ}A_BELB'] = 'DISABLE'
elif val in {32, 36}: # XXX no dynamic byte enable
bsram_attrs[f'{typ}A_BEHB'] = 'DISABLE'
bsram_attrs[f'{typ}A_BELB'] = 'DISABLE'
bsram_attrs[f'{typ}A_BEHB'] = 'DISABLE'
bsram_attrs[f'{typ}A_BELB'] = 'DISABLE'
bsram_attrs[f'{typ}B_DATA_WIDTH'] = _bsram_bit_widths[val]
bsram_attrs[f'{typ}B_BEHB'] = 'DISABLE'
bsram_attrs[f'{typ}B_BELB'] = 'DISABLE'
if val not in {32, 36}:
bsram_attrs[f'{typ}A_DATA_WIDTH'] = _bsram_bit_widths[val]
bsram_attrs[f'{typ}B_DATA_WIDTH'] = _bsram_bit_widths[val]
elif typ != 'SP':
bsram_attrs['DBLWA'] = _bsram_bit_widths[val]
bsram_attrs['DBLWB'] = _bsram_bit_widths[val]
else:
raise Exception(f"BSRAM width of {val} isn't supported for now")
elif parm == 'BIT_WIDTH_0':
val = int(val, 2)
if val in _bsram_bit_widths:
if val not in {32, 36}:
bsram_attrs[f'{typ}A_DATA_WIDTH'] = _bsram_bit_widths[val]
else:
bsram_attrs['DBLWA'] = _bsram_bit_widths[val]
if val in {16, 18, 32, 36}: # XXX no dynamic byte enable
bsram_attrs[f'{typ}A_BEHB'] = 'DISABLE'
bsram_attrs[f'{typ}A_BELB'] = 'DISABLE'
else:
raise Exception(f"BSRAM width of {val} isn't supported for now")
elif parm == 'BIT_WIDTH_1':
val = int(val, 2)
if val in _bsram_bit_widths:
if val not in {32, 36}:
bsram_attrs[f'{typ}B_DATA_WIDTH'] = _bsram_bit_widths[val]
else:
bsram_attrs['DBLWB'] = _bsram_bit_widths[val]
if val in {16, 18, 32, 36}: # XXX no dynamic byte enable
bsram_attrs[f'{typ}B_BEHB'] = 'DISABLE'
bsram_attrs[f'{typ}B_BELB'] = 'DISABLE'
else:
raise Exception(f"BSRAM width of {val} isn't supported for now")
elif parm == 'BLK_SEL':
for i in range(3):
if val[-1 - i] == '0':
bsram_attrs[f'CSA_{i}'] = 'SET'
bsram_attrs[f'CSB_{i}'] = 'SET'
elif parm == 'BLK_SEL_0':
for i in range(3):
if val[-1 - i] == '0':
bsram_attrs[f'CSA_{i}'] = 'SET'
elif parm == 'BLK_SEL_1':
for i in range(3):
if val[-1 - i] == '0':
bsram_attrs[f'CSB_{i}'] = 'SET'
elif parm == 'READ_MODE0':
val = int(val, 2)
if val == 1:
bsram_attrs[f'{typ}A_REGMODE'] = 'OUTREG'
elif parm == 'READ_MODE1':
val = int(val, 2)
if val == 1:
bsram_attrs[f'{typ}B_REGMODE'] = 'OUTREG'
elif parm == 'READ_MODE':
if val == '1':
val = int(val, 2)
if val == 1:
bsram_attrs[f'{typ}A_REGMODE'] = 'OUTREG'
bsram_attrs[f'{typ}B_REGMODE'] = 'OUTREG'
elif parm == 'RESET_MODE':
if val == 'ASYNC':
bsram_attrs[f'OUTREG_ASYNC'] = 'RESET'
elif parm == 'WRITE_MODE0':
val = int(val, 2)
if val == 1:
bsram_attrs[f'{typ}A_MODE'] = 'WT'
elif val == 2:
bsram_attrs[f'{typ}A_MODE'] = 'RBW'
elif parm == 'WRITE_MODE1':
val = int(val, 2)
if val == 1:
bsram_attrs[f'{typ}B_MODE'] = 'WT'
elif val == 2:
bsram_attrs[f'{typ}B_MODE'] = 'RBW'
elif parm == 'WRITE_MODE':
if val == '01':
val = int(val, 2)
if val == 1:
bsram_attrs[f'{typ}A_MODE'] = 'WT'
bsram_attrs[f'{typ}B_MODE'] = 'WT'
elif val == '10':
elif val == 2:
bsram_attrs[f'{typ}A_MODE'] = 'RBW'
bsram_attrs[f'{typ}B_MODE'] = 'RBW'
fin_attrs = set()
Expand Down Expand Up @@ -732,7 +781,10 @@ def refine_io_attrs(attr):
def place_lut(db, tiledata, tile, parms, num):
lutmap = tiledata.bels[f'LUT{num}'].flags
init = str(parms['INIT'])
init = init*(16//len(init))
if len(init) > 16:
init = init[-16:]
else:
init = init*(16//len(init))
for bitnum, lutbit in enumerate(init[::-1]):
if lutbit == '0':
fuses = lutmap[bitnum]
Expand Down
17 changes: 14 additions & 3 deletions apycula/gowin_unpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,11 +355,12 @@ def parse_tile_(db, row, col, tile, default=True, noalias=False, noiostd = True)
if 'BSRAM_SP' not in db.shortval[tiledata.ttyp]:
continue
idx = _bsram_cells.setdefault(get_bsram_main_cell(db, row, col, name), len(_bsram_cells))
print(row, col, name, tiledata.ttyp)
#print(row, col, name, idx, tiledata.ttyp)
attrvals = parse_attrvals(tile, db.logicinfo['BSRAM'], db.shortval[tiledata.ttyp]['BSRAM_SP'], attrids.bsram_attrids)
if not attrvals:
continue
print(row, col, idx, attrvals)
#print(row, col, name, idx, tiledata.ttyp, attrvals)
bels[f'{name}'] = {}
continue
if name.startswith("IOLOGIC"):
idx = name[-1]
Expand Down Expand Up @@ -802,7 +803,7 @@ def tile2verilog(dbrow, dbcol, bels, pips, clock_pips, mod, cst, db):
mod.wires.update({srcg, destg})
mod.assigns.append((destg, srcg))

belre = re.compile(r"(IOB|LUT|DFF|BANK|CFG|ALU|RAM16|ODDR|OSC[ZFHWO]?|BUFS|RPLL[AB]|PLLVR|IOLOGIC)(\w*)")
belre = re.compile(r"(IOB|LUT|DFF|BANK|CFG|ALU|RAM16|ODDR|OSC[ZFHWO]?|BUFS|RPLL[AB]|PLLVR|IOLOGIC|BSRAM)(\w*)")
bels_items = move_iologic(bels)

iologic_detected = set()
Expand Down Expand Up @@ -911,6 +912,15 @@ def tile2verilog(dbrow, dbcol, bels, pips, clock_pips, mod, cst, db):
portmap = db.grid[dbrow][dbcol].bels[bel[:-1]].portmap
for port, wname in portmap.items():
pll.portmap[port] = f"R{row}C{col}_{wname}"
elif typ.startswith("BSRAM"):
name = f"BSRAM_{idx}"
pll = mod.primitives.setdefault(name, codegen.Primitive("BSRAM", name))
for paramval in flags:
param, _, val = paramval.partition('=')
pll.params[param] = val
portmap = db.grid[dbrow][dbcol].bels[bel].portmap
for port, wname in portmap.items():
pll.portmap[port] = f"R{row}C{col}_{wname}"
elif typ == "ALU":
#print(flags)
kind, = flags # ALU only have one flag
Expand All @@ -937,6 +947,7 @@ def tile2verilog(dbrow, dbcol, bels, pips, clock_pips, mod, cst, db):
elif kind == "0":
alu.portmap['I0'] = f"R{row}C{col}_B{idx}"
alu.portmap['I1'] = f"R{row}C{col}_D{idx}"
alu.portmap['I3'] = f"R{row}C{col}_A{idx}"
elif kind == "C2L":
alu.portmap['I0'] = f"R{row}C{col}_B{idx}"
alu.portmap['I1'] = f"R{row}C{col}_D{idx}"
Expand Down
1 change: 1 addition & 0 deletions examples/himbaechel/DPB-image-rom.v
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pROM-image-rom.v
51 changes: 51 additions & 0 deletions examples/himbaechel/DPB-video-ram.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
`default_nettype none
module video_ram(
input wire clk,
input wire reset,
input wire write_clk,
input wire write_reset,
input wire write_ce,
input wire read_wre,
input wire [10:0] write_ad,
input wire [7:0] write_data,
input wire [10:0] read_ad,
output wire [7:0] read_data
);

wire gnd, vcc;
assign gnd = 1'b0;
assign vcc = 1'b1;

wire [7:0] dummy;

DPB mem(
.DOB({dummy, read_data}),
.DIA({{8{gnd}}, write_data}),
.DIB({16{gnd}}),
.ADA({write_ad, gnd, gnd, gnd}),
.ADB({ read_ad, gnd, gnd, gnd}),
.CLKA(write_clk),
.CLKB(clk),
.OCEA(vcc),
.OCEB(vcc),
.CEA(write_ce),
.CEB(vcc),
.WREA(vcc),
.WREB(read_wre),
.BLKSELA(3'b000),
.BLKSELB(3'b000),
.RESETA(write_reset),
.RESETB(reset)
);
defparam mem.READ_MODE0 = 1'b1;
defparam mem.READ_MODE1 = 1'b1;
defparam mem.WRITE_MODE0 = 2'b01;
defparam mem.WRITE_MODE1 = 2'b01;
defparam mem.BIT_WIDTH_0 = 8;
defparam mem.BIT_WIDTH_1 = 8;
defparam mem.BLK_SEL_0 = 3'b000;
defparam mem.BLK_SEL_1 = 3'b000;
defparam mem.RESET_MODE = "SYNC";
`include "img-video-ram.vh"
endmodule

Loading

0 comments on commit 6a2469a

Please sign in to comment.