hdl.mem: implement memories.
This commit is contained in:
		
							parent
							
								
									6672ab2e3f
								
							
						
					
					
						commit
						6d9a6b5d84
					
				|  | @ -54,9 +54,14 @@ Compatibility summary | |||
|       - (−) `Tristate` ? | ||||
|       - (+) `TSTriple` → `.lib.io.TSTriple`, `bits_sign=`→`shape=` | ||||
|       - (−) `Instance` ? | ||||
|       - (−) `READ_FIRST`/`WRITE_FIRST`/`NO_CHANGE` ? | ||||
|       - (−) `_MemoryPort` ? | ||||
|       - (−) `Memory` ? | ||||
|       - (−) `Memory` id | ||||
|         - (−) `.get_port` **obs** → `.read_port()` + `.write_port()` | ||||
|       - (−) `_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` | ||||
|       - (+) `DUID` id | ||||
|       - (+) `_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.cd import ClockDomain | ||||
| from .hdl.ir import Fragment, Instance | ||||
| from .hdl.mem import Memory | ||||
| from .hdl.xfrm import ResetInserter, CEInserter | ||||
| 
 | ||||
| from .lib.cdc import MultiReg | ||||
|  |  | |||
|  | @ -236,7 +236,7 @@ class Const(Value): | |||
|             shape = shape, self.value < 0 | ||||
|         self.nbits, self.signed = shape | ||||
|         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) | ||||
| 
 | ||||
|     def shape(self): | ||||
|  | @ -1067,7 +1067,7 @@ class ValueSet(_MappedKeySet): | |||
| class SignalKey: | ||||
|     def __init__(self, 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 | ||||
| 
 | ||||
|     def __hash__(self): | ||||
|  | @ -1080,7 +1080,7 @@ class SignalKey: | |||
| 
 | ||||
|     def __lt__(self, other): | ||||
|         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 | ||||
| 
 | ||||
|     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