hdl.mem: implement memories.
This commit is contained in:
		
							parent
							
								
									6672ab2e3f
								
							
						
					
					
						commit
						6d9a6b5d84
					
				|  | @ -54,9 +54,14 @@ Compatibility summary | ||||||
|       - (−) `Tristate` ? |       - (−) `Tristate` ? | ||||||
|       - (+) `TSTriple` → `.lib.io.TSTriple`, `bits_sign=`→`shape=` |       - (+) `TSTriple` → `.lib.io.TSTriple`, `bits_sign=`→`shape=` | ||||||
|       - (−) `Instance` ? |       - (−) `Instance` ? | ||||||
|       - (−) `READ_FIRST`/`WRITE_FIRST`/`NO_CHANGE` ? |       - (−) `Memory` id | ||||||
|       - (−) `_MemoryPort` ? |         - (−) `.get_port` **obs** → `.read_port()` + `.write_port()` | ||||||
|       - (−) `Memory` ? |       - (−) `_MemoryPort` **obs** | ||||||
|  |         <br>Note: nMigen separates read and write ports. | ||||||
|  |       - (−) `READ_FIRST`/`WRITE_FIRST` **obs** | ||||||
|  |         <br>Note: `READ_FIRST` corresponds to `mem.read_port(transparent=False)`, and `WRITE_FIRST` to `mem.read_port(transparent=True)`. | ||||||
|  |       - (-) `NO_CHANGE` **brk** | ||||||
|  |         <br>Note: in designs using `NO_CHANGE`, repalce it with an asynchronous read port and logic implementing required semantics explicitly. | ||||||
|     - (−) `structure` → `.hdl.ast` |     - (−) `structure` → `.hdl.ast` | ||||||
|       - (+) `DUID` id |       - (+) `DUID` id | ||||||
|       - (+) `_Value` → `Value` |       - (+) `_Value` → `Value` | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ from .hdl.ast import Value, Const, C, Mux, Cat, Repl, Array, Signal, ClockSignal | ||||||
| from .hdl.dsl import Module | from .hdl.dsl import Module | ||||||
| from .hdl.cd import ClockDomain | from .hdl.cd import ClockDomain | ||||||
| from .hdl.ir import Fragment, Instance | from .hdl.ir import Fragment, Instance | ||||||
|  | from .hdl.mem import Memory | ||||||
| from .hdl.xfrm import ResetInserter, CEInserter | from .hdl.xfrm import ResetInserter, CEInserter | ||||||
| 
 | 
 | ||||||
| from .lib.cdc import MultiReg | from .lib.cdc import MultiReg | ||||||
|  |  | ||||||
|  | @ -236,7 +236,7 @@ class Const(Value): | ||||||
|             shape = shape, self.value < 0 |             shape = shape, self.value < 0 | ||||||
|         self.nbits, self.signed = shape |         self.nbits, self.signed = shape | ||||||
|         if not isinstance(self.nbits, int) or self.nbits < 0: |         if not isinstance(self.nbits, int) or self.nbits < 0: | ||||||
|             raise TypeError("Width must be a non-negative integer") |             raise TypeError("Width must be a non-negative integer, not '{!r}'", self.nbits) | ||||||
|         self.value = self.normalize(self.value, shape) |         self.value = self.normalize(self.value, shape) | ||||||
| 
 | 
 | ||||||
|     def shape(self): |     def shape(self): | ||||||
|  | @ -1067,7 +1067,7 @@ class ValueSet(_MappedKeySet): | ||||||
| class SignalKey: | class SignalKey: | ||||||
|     def __init__(self, signal): |     def __init__(self, signal): | ||||||
|         if type(signal) is not Signal: |         if type(signal) is not Signal: | ||||||
|             raise TypeError("Object '{!r}' is not an nMigen signal") |             raise TypeError("Object '{!r}' is not an nMigen signal".format(signal)) | ||||||
|         self.signal = signal |         self.signal = signal | ||||||
| 
 | 
 | ||||||
|     def __hash__(self): |     def __hash__(self): | ||||||
|  | @ -1080,7 +1080,7 @@ class SignalKey: | ||||||
| 
 | 
 | ||||||
|     def __lt__(self, other): |     def __lt__(self, other): | ||||||
|         if type(other) is not SignalKey: |         if type(other) is not SignalKey: | ||||||
|             raise TypeError("Object '{!r}' cannot be compared to a SignalKey") |             raise TypeError("Object '{!r}' cannot be compared to a SignalKey".format(signal)) | ||||||
|         return self.signal.duid < other.signal.duid |         return self.signal.duid < other.signal.duid | ||||||
| 
 | 
 | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|  |  | ||||||
							
								
								
									
										92
									
								
								nmigen/hdl/mem.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								nmigen/hdl/mem.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,92 @@ | ||||||
|  | import traceback | ||||||
|  | 
 | ||||||
|  | from .. import tracer | ||||||
|  | from .ast import * | ||||||
|  | from .ir import Instance | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Memory: | ||||||
|  |     def __init__(self, width, depth, init=None, name=None): | ||||||
|  |         if not isinstance(width, int) or width < 0: | ||||||
|  |             raise TypeError("Memory width must be a non-negative integer, not '{!r}'" | ||||||
|  |                             .format(width)) | ||||||
|  |         if not isinstance(depth, int) or depth < 0: | ||||||
|  |             raise TypeError("Memory depth must be a non-negative integer, not '{!r}'" | ||||||
|  |                             .format(depth)) | ||||||
|  | 
 | ||||||
|  |         tb = traceback.extract_stack(limit=2) | ||||||
|  |         self.src_loc = (tb[0].filename, tb[0].lineno) | ||||||
|  | 
 | ||||||
|  |         if name is None: | ||||||
|  |             try: | ||||||
|  |                 name = tracer.get_var_name(depth=2) | ||||||
|  |             except tracer.NameNotFound: | ||||||
|  |                 name = "$memory" | ||||||
|  |         self.name  = name | ||||||
|  | 
 | ||||||
|  |         self.width = width | ||||||
|  |         self.depth = depth | ||||||
|  |         self.init  = None if init is None else list(init) | ||||||
|  | 
 | ||||||
|  |     def read_port(self, domain="sync", asynchronous=False, transparent=True): | ||||||
|  |         return ReadPort(self, domain, asynchronous, transparent) | ||||||
|  | 
 | ||||||
|  |     def write_port(self, domain="sync", priority=0, granularity=None): | ||||||
|  |         if granularity is None: | ||||||
|  |             granularity = self.width | ||||||
|  |         if not isinstance(granularity, int) or granularity < 0 or granularity > self.width: | ||||||
|  |             raise TypeError("Write port granularity must be a non-negative integer not greater " | ||||||
|  |                             "than memory width, not '{!r}'" | ||||||
|  |                             .format(granularity)) | ||||||
|  |         return WritePort(self, domain, priority, granularity) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class ReadPort: | ||||||
|  |     def __init__(self, memory, domain, asynchronous, transparent): | ||||||
|  |         self.memory       = memory | ||||||
|  |         self.domain       = domain | ||||||
|  |         self.asynchronous = asynchronous | ||||||
|  |         self.transparent  = transparent | ||||||
|  | 
 | ||||||
|  |         self.addr = Signal(max=memory.depth) | ||||||
|  |         self.data = Signal(memory.width) | ||||||
|  |         self.en   = Signal() | ||||||
|  | 
 | ||||||
|  |     def get_fragment(self, platform): | ||||||
|  |         return Instance("$memrd", | ||||||
|  |             p_MEMID=self.memory, | ||||||
|  |             p_ABITS=self.addr.nbits, | ||||||
|  |             p_WIDTH=self.data.nbits, | ||||||
|  |             p_CLK_ENABLE=not self.asynchronous, | ||||||
|  |             p_CLK_POLARITY=1, | ||||||
|  |             p_TRANSPARENT=self.transparent, | ||||||
|  |             i_CLK=ClockSignal(self.domain), | ||||||
|  |             i_EN=self.en, | ||||||
|  |             i_ADDR=self.addr, | ||||||
|  |             o_DATA=self.data, | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  | class WritePort: | ||||||
|  |     def __init__(self, memory, domain, priority, granularity): | ||||||
|  |         self.memory       = memory | ||||||
|  |         self.domain       = domain | ||||||
|  |         self.priority     = priority | ||||||
|  |         self.granularity  = granularity | ||||||
|  | 
 | ||||||
|  |         self.addr = Signal(max=memory.depth) | ||||||
|  |         self.data = Signal(memory.width) | ||||||
|  |         self.en   = Signal(memory.width // granularity) | ||||||
|  | 
 | ||||||
|  |     def get_fragment(self, platform): | ||||||
|  |         return Instance("$memwr", | ||||||
|  |             p_MEMID=self.memory, | ||||||
|  |             p_ABITS=self.addr.nbits, | ||||||
|  |             p_WIDTH=self.data.nbits, | ||||||
|  |             p_CLK_ENABLE=1, | ||||||
|  |             p_CLK_POLARITY=1, | ||||||
|  |             p_PRIORITY=self.priority, | ||||||
|  |             i_CLK=ClockSignal(self.domain), | ||||||
|  |             i_EN=Cat(Repl(en_bit, self.granularity) for en_bit in self.en), | ||||||
|  |             i_ADDR=self.addr, | ||||||
|  |             i_DATA=self.data, | ||||||
|  |         ) | ||||||
		Loading…
	
		Reference in a new issue
	
	 whitequark
						whitequark