aboutsummaryrefslogtreecommitdiffstats
path: root/techlibs/common/cmp2lut.v
blob: c753bd2f1b7b0b2e1860386130c8996b8ed7de0f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Certain arithmetic operations between a signal of width n and a constant can be directly mapped
// to a single k-LUT (where n <= k). This is preferable to normal alumacc techmapping process
// because for many targets, arithmetic techmapping creates hard logic (such as carry cells) which often
// cannot be optimized further.
//
// TODO: Currently, only comparisons with 1-bit output are mapped. Potentially, all arithmetic cells
// with n <= k inputs should be techmapped in this way, because this shortens the critical path
// from n to 1 by avoiding carry chains.

(* techmap_celltype = "$lt $le $gt $ge" *)
module _90_lut_cmp_ (A, B, Y);

parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 0;
parameter B_WIDTH = 0;
parameter Y_WIDTH = 0;

(* force_downto *)
input [A_WIDTH-1:0] A;
(* force_downto *)
input [B_WIDTH-1:0] B;
(* force_downto *)
output [Y_WIDTH-1:0] Y;

parameter _TECHMAP_CELLTYPE_ = "";

parameter _TECHMAP_CONSTMSK_A_ = 0;
parameter _TECHMAP_CONSTVAL_A_ = 0;
parameter _TECHMAP_CONSTMSK_B_ = 0;
parameter _TECHMAP_CONSTVAL_B_ = 0;

function automatic [(1 << `LUT_WIDTH)-1:0] gen_lut;
	input integer width;
	input integer operation;
	input integer swap;
	input integer sign;
	input integer operand;
	integer n, i_var, i_cst, lhs, rhs, o_bit;
	begin
		gen_lut = width'b0;
		for (n = 0; n < (1 << width); n++) begin
			if (sign)
				i_var = n[width-1:0];
			else
				i_var = n;
			i_cst = operand;
			if (swap) begin
				lhs = i_cst;
				rhs = i_var;
			end else begin
				lhs = i_var;
				rhs = i_cst;
			end
			if (operation == 0)
				o_bit = (lhs <  rhs);
			if (operation == 1)
				o_bit = (lhs <= rhs);
			if (operation == 2)
				o_bit = (lhs >  rhs);
			if (operation == 3)
				o_bit = (lhs >= rhs);
			gen_lut = gen_lut | (o_bit << n);
		end
	end
endfunction

generate
	localparam operation =
		_TECHMAP_CELLTYPE_ == "$lt" ? 0 :
		_TECHMAP_CELLTYPE_ == "$le" ? 1 :
		_TECHMAP_CELLTYPE_ == "$gt" ? 2 :
		_TECHMAP_CELLTYPE_ == "$ge" ? 3 :
		-1;

	if (A_WIDTH > `LUT_WIDTH || B_WIDTH > `LUT_WIDTH || Y_WIDTH != 1)
		wire _TECHMAP_FAIL_ = 1;
	else if (&_TECHMAP_CONSTMSK_B_)
		\$lut #(
			.WIDTH(A_WIDTH),
			.LUT({ gen_lut(A_WIDTH, operation, 0, A_SIGNED && B_SIGNED, _TECHMAP_CONSTVAL_B_) })
		) _TECHMAP_REPLACE_ (
			.A(A),
			.Y(Y)
		);
	else if (&_TECHMAP_CONSTMSK_A_)
		\$lut #(
			.WIDTH(B_WIDTH),
			.LUT({ gen_lut(B_WIDTH, operation, 1, A_SIGNED && B_SIGNED, _TECHMAP_CONSTVAL_A_) })
		) _TECHMAP_REPLACE_ (
			.A(B),
			.Y(Y)
		);
	else
		wire _TECHMAP_FAIL_ = 1;
endgenerate

endmodule
="p">, 0x009E, /* 10baseT */ 0x0004, 0x009E, /* 10baseT-FD */ 0x0903, 0x006D, /* 100baseTx */ 0x0905, 0x006D, /* 100baseTx-FD */ }}, {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f, 0x0107, 0x8021, /* 100baseFx */ 0x0108, 0x8021, /* 100baseFx-FD */ 0x0100, 0x009E, /* 10baseT */ 0x0104, 0x009E, /* 10baseT-FD */ 0x0103, 0x006D, /* 100baseTx */ 0x0105, 0x006D, /* 100baseTx-FD */ }}, {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513, 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ 0x0000, 0x009E, /* 10baseT */ 0x0004, 0x009E, /* 10baseT-FD */ 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}}, {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F, 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */ 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */ }}, {"NetWinder", 0x00, 0x10, 0x57, /* Default media = MII * MII block, reset sequence (3) = 0x0821 0x0000 0x0001, capabilities 0x01e1 */ { 0x1e00, 0x0000, 0x000b, 0x8f01, 0x0103, 0x0300, 0x0821, 0x000, 0x0001, 0x0000, 0x01e1 } }, {0, 0, 0, 0, {}}}; static const char *block_name[] __devinitdata = { "21140 non-MII", "21140 MII PHY", "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method" }; /** * tulip_build_fake_mediatable - Build a fake mediatable entry. * @tp: Ptr to the tulip private data. * * Some cards like the 3x5 HSC cards (J3514A) do not have a standard * srom and can not be handled under the fixup routine. These cards * still need a valid mediatable entry for correct csr12 setup and * mii handling. * * Since this is currently a parisc-linux specific function, the * #ifdef __hppa__ should completely optimize this function away for * non-parisc hardware. */ static void __devinit tulip_build_fake_mediatable(struct tulip_private *tp) { #ifdef __hppa__ unsigned char *ee_data = tp->eeprom; if (ee_data[0] == 0x3c && ee_data[1] == 0x10 && (ee_data[2] == 0x63 || ee_data[2] == 0x61) && ee_data[3] == 0x10) { static unsigned char leafdata[] = { 0x01, /* phy number */ 0x02, /* gpr setup sequence length */ 0x02, 0x00, /* gpr setup sequence */ 0x02, /* phy reset sequence length */ 0x01, 0x00, /* phy reset sequence */ 0x00, 0x78, /* media capabilities */ 0x00, 0xe0, /* nway advertisment */ 0x00, 0x05, /* fdx bit map */ 0x00, 0x06 /* ttm bit map */ }; tp->mtable = (struct mediatable *) kmalloc(sizeof(struct mediatable) + sizeof(struct medialeaf), GFP_KERNEL); if (tp->mtable == NULL) return; /* Horrible, impossible failure. */ tp->mtable->defaultmedia = 0x800; tp->mtable->leafcount = 1; tp->mtable->csr12dir = 0x3f; /* inputs on bit7 for hsc-pci, bit6 for pci-fx */ tp->mtable->has_nonmii = 0; tp->mtable->has_reset = 0; tp->mtable->has_mii = 1; tp->mtable->csr15dir = tp->mtable->csr15val = 0; tp->mtable->mleaf[0].type = 1; tp->mtable->mleaf[0].media = 11; tp->mtable->mleaf[0].leafdata = &leafdata[0]; tp->flags |= HAS_PHY_IRQ; tp->csr12_shadow = -1; } #endif } void __devinit tulip_parse_eeprom(struct net_device *dev) { /* The last media info list parsed, for multiport boards. */ static struct mediatable *last_mediatable; static unsigned char *last_ee_data; static int controller_index; struct tulip_private *tp = (struct tulip_private *)dev->priv; unsigned char *ee_data = tp->eeprom; int i; tp->mtable = 0; /* Detect an old-style (SA only) EEPROM layout: memcmp(eedata, eedata+16, 8). */ for (i = 0; i < 8; i ++) if (ee_data[i] != ee_data[16+i]) break; if (i >= 8) { if (ee_data[0] == 0xff) { if (last_mediatable) { controller_index++; printk(KERN_INFO "%s: Controller %d of multiport board.\n", dev->name, controller_index); tp->mtable = last_mediatable; ee_data = last_ee_data; goto subsequent_board; } else printk(KERN_INFO "%s: Missing EEPROM, this interface may " "not work correctly!\n", dev->name); return; } /* Do a fix-up based on the vendor half of the station address prefix. */ for (i = 0; eeprom_fixups[i].name; i++) { if (dev->dev_addr[0] == eeprom_fixups[i].addr0 && dev->dev_addr[1] == eeprom_fixups[i].addr1 && dev->dev_addr[2] == eeprom_fixups[i].addr2) { if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) i++; /* An Accton EN1207, not an outlaw Maxtech. */ memcpy(ee_data + 26, eeprom_fixups[i].newtable, sizeof(eeprom_fixups[i].newtable)); printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using" " substitute media control info.\n", dev->name, eeprom_fixups[i].name); break; } } if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ printk(KERN_INFO "%s: Old style EEPROM with no media selection " "information.\n", dev->name); return; } } controller_index = 0; if (ee_data[19] > 1) { /* Multiport board. */ last_ee_data = ee_data; } subsequent_board: if (ee_data[27] == 0) { /* No valid media table. */ tulip_build_fake_mediatable(tp); } else if (tp->chip_id == DC21041) { unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3]; int media = get_u16(p); int count = p[2]; p += 3; printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n", dev->name, media, media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]); for (i = 0; i < count; i++) { unsigned char media_block = *p++; int media_code = media_block & MEDIA_MASK; if (media_block & 0x40) p += 6; printk(KERN_INFO "%s: 21041 media #%d, %s.\n", dev->name, media_code, medianame[media_code]); } } else { unsigned char *p = (void *)ee_data + ee_data[27]; unsigned char csr12dir = 0; int count, new_advertise = 0; struct mediatable *mtable; u16 media = get_u16(p); p += 2; if (tp->flags & CSR12_IN_SROM) csr12dir = *p++; count = *p++; /* there is no phy information, don't even try to build mtable */ if (count == 0) { if (tulip_debug > 0) printk(KERN_WARNING "%s: no phy info, aborting mtable build\n", dev->name); return; } mtable = (struct mediatable *) kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf), GFP_KERNEL); if (mtable == NULL) return; /* Horrible, impossible failure. */ last_mediatable = tp->mtable = mtable; mtable->defaultmedia = media; mtable->leafcount = count; mtable->csr12dir = csr12dir; mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0; mtable->csr15dir = mtable->csr15val = 0; printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]); for (i = 0; i < count; i++) { struct medialeaf *leaf = &mtable->mleaf[i]; if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */ leaf->type = 0; leaf->media = p[0] & 0x3f; leaf->leafdata = p; if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */ mtable->has_mii = 1; p += 4; } else { leaf->type = p[1]; if (p[1] == 0x05) { mtable->has_reset = i; leaf->media = p[2] & 0x0f; } else if (tp->chip_id == DM910X && p[1] == 0x80) { /* Hack to ignore Davicom delay period block */ mtable->leafcount--; count--; i--; leaf->leafdata = p + 2; p += (p[0] & 0x3f) + 1; continue; } else if (p[1] & 1) { int gpr_len, reset_len; mtable->has_mii = 1; leaf->media = 11; gpr_len=p[3]*2; reset_len=p[4+gpr_len]*2; new_advertise |= get_u16(&p[7+gpr_len+reset_len]); } else { mtable->has_nonmii = 1; leaf->media = p[2] & MEDIA_MASK; /* Davicom's media number for 100BaseTX is strange */ if (tp->chip_id == DM910X && leaf->media == 1) leaf->media = 3; switch (leaf->media) { case 0: new_advertise |= 0x0020; break; case 4: new_advertise |= 0x0040; break; case 3: new_advertise |= 0x0080; break; case 5: new_advertise |= 0x0100; break; case 6: new_advertise |= 0x0200; break; } if (p[1] == 2 && leaf->media == 0) { if (p[2] & 0x40) { u32 base15 = get_unaligned((u16*)&p[7]); mtable->csr15dir = (get_unaligned((u16*)&p[9])<<16) + base15; mtable->csr15val = (get_unaligned((u16*)&p[11])<<16) + base15; } else { mtable->csr15dir = get_unaligned((u16*)&p[3])<<16; mtable->csr15val = get_unaligned((u16*)&p[5])<<16; } } } leaf->leafdata = p + 2; p += (p[0] & 0x3f) + 1; } if (tulip_debug > 1 && leaf->media == 11) { unsigned char *bp = leaf->leafdata; printk(KERN_INFO "%s: MII interface PHY %d, setup/reset " "sequences %d/%d long, capabilities %2.2x %2.2x.\n", dev->name, bp[0], bp[1], bp[2 + bp[1]*2], bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); } printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " "by a %s (%d) block.\n", dev->name, i, medianame[leaf->media & 15], leaf->media, leaf->type < ARRAY_SIZE(block_name) ? block_name[leaf->type] : "<unknown>", leaf->type); } if (new_advertise) tp->sym_advertise = new_advertise; } } /* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ /* EEPROM_Ctrl bits. */ #define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ #define EE_CS 0x01 /* EEPROM chip select. */ #define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */ #define EE_WRITE_0 0x01 #define EE_WRITE_1 0x05 #define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */ #define EE_ENB (0x4800 | EE_CS) /* Delay between EEPROM clock transitions. Even at 33Mhz current PCI implementations don't overrun the EEPROM clock. We add a bus turn-around to insure that this remains true. */ #define eeprom_delay() inl(ee_addr) /* The EEPROM commands include the alway-set leading bit. */ #define EE_READ_CMD (6) /* Note: this routine returns extra data bits for size detection. */ int __devinit tulip_read_eeprom(long ioaddr, int location, int addr_len) { int i; unsigned retval = 0; long ee_addr = ioaddr + CSR9; int read_cmd = location | (EE_READ_CMD << addr_len); outl(EE_ENB & ~EE_CS, ee_addr); outl(EE_ENB, ee_addr); /* Shift the read command bits out. */ for (i = 4 + addr_len; i >= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; outl(EE_ENB | dataval, ee_addr); eeprom_delay(); outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay(); retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); } outl(EE_ENB, ee_addr); eeprom_delay(); for (i = 16; i > 0; i--) { outl(EE_ENB | EE_SHIFT_CLK, ee_addr); eeprom_delay(); retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); outl(EE_ENB, ee_addr); eeprom_delay(); } /* Terminate the EEPROM access. */ outl(EE_ENB & ~EE_CS, ee_addr); return retval; }