mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
sim: memory access
This commit is contained in:
parent
db8f8bf2e3
commit
8160ced2e9
8 changed files with 98 additions and 32 deletions
|
@ -7,12 +7,12 @@ class Counter:
|
|||
self.ce = Signal()
|
||||
self.count = Signal(BV(37, True), reset=-5)
|
||||
|
||||
def do_simulation(self, s, cycle):
|
||||
if cycle % 2:
|
||||
def do_simulation(self, s):
|
||||
if s.cycle_counter % 2:
|
||||
s.wr(self.ce, 0)
|
||||
else:
|
||||
s.wr(self.ce, 1)
|
||||
print("Cycle: " + str(cycle) + " Count: " + str(s.rd(self.count)))
|
||||
print("Cycle: " + str(s.cycle_counter) + " Count: " + str(s.rd(self.count)))
|
||||
|
||||
def get_fragment(self):
|
||||
sync = [If(self.ce, self.count.eq(self.count + 1))]
|
||||
|
|
27
examples/memory_sim.py
Normal file
27
examples/memory_sim.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
from migen.fhdl.structure import *
|
||||
from migen.sim.generic import Simulator, TopLevel
|
||||
from migen.sim.icarus import Runner
|
||||
|
||||
class Mem:
|
||||
def __init__(self):
|
||||
self.a = Signal(BV(12))
|
||||
self.d = Signal(BV(16))
|
||||
p = MemoryPort(self.a, self.d)
|
||||
self.mem = Memory(16, 2**12, p, init=list(range(20)))
|
||||
|
||||
def do_simulation(self, s):
|
||||
if s.cycle_counter >= 0:
|
||||
value = s.rd(self.mem, s.cycle_counter)
|
||||
print(value)
|
||||
if value == 10:
|
||||
s.interrupt = True
|
||||
|
||||
def get_fragment(self):
|
||||
return Fragment(memories=[self.mem], sim=[self.do_simulation])
|
||||
|
||||
def main():
|
||||
dut = Mem()
|
||||
sim = Simulator(dut.get_fragment(), Runner())
|
||||
sim.run()
|
||||
|
||||
main()
|
|
@ -276,6 +276,6 @@ class Fragment:
|
|||
self.pads | other.pads,
|
||||
self.sim + other.sim)
|
||||
|
||||
def call_sim(self, simulator, cycle):
|
||||
def call_sim(self, simulator):
|
||||
for s in self.sim:
|
||||
s(simulator, cycle)
|
||||
s(simulator)
|
||||
|
|
|
@ -84,7 +84,7 @@ class Simulator:
|
|||
rst_signal=rst_signal,
|
||||
return_ns=True)
|
||||
|
||||
self.cycle_counter = 0
|
||||
self.cycle_counter = -1
|
||||
self.interrupt = False
|
||||
|
||||
self.sim_runner = sim_runner
|
||||
|
@ -92,36 +92,46 @@ class Simulator:
|
|||
self.ipc.accept()
|
||||
reply = self.ipc.recv()
|
||||
assert(isinstance(reply, MessageTick))
|
||||
self.fragment.call_sim(self, -1)
|
||||
self.fragment.call_sim(self)
|
||||
|
||||
def run(self, ncycles=-1):
|
||||
self.interrupt = False
|
||||
counter = 0
|
||||
while not self.interrupt and (ncycles < 0 or counter < ncycles):
|
||||
self.cycle_counter += 1
|
||||
counter += 1
|
||||
self.ipc.send(MessageGo())
|
||||
reply = self.ipc.recv()
|
||||
assert(isinstance(reply, MessageTick))
|
||||
self.fragment.call_sim(self, self.cycle_counter)
|
||||
self.cycle_counter += 1
|
||||
counter += 1
|
||||
self.fragment.call_sim(self)
|
||||
|
||||
def rd(self, signal):
|
||||
def rd(self, item, index=0):
|
||||
name = self.top_level.top_name + "." \
|
||||
+ self.top_level.dut_name + "." \
|
||||
+ self.namespace.get_name(signal)
|
||||
self.ipc.send(MessageRead(name))
|
||||
+ self.namespace.get_name(item)
|
||||
self.ipc.send(MessageRead(name, Int32(index)))
|
||||
reply = self.ipc.recv()
|
||||
assert(isinstance(reply, MessageReadReply))
|
||||
nbits = signal.bv.width
|
||||
if isinstance(item, Memory):
|
||||
signed = False
|
||||
nbits = item.width
|
||||
else:
|
||||
signed = item.bv.signed
|
||||
nbits = item.bv.width
|
||||
value = reply.value & (2**nbits - 1)
|
||||
if signal.bv.signed and (value & 2**(nbits - 1)):
|
||||
if signed and (value & 2**(nbits - 1)):
|
||||
value -= 2**nbits
|
||||
return value
|
||||
|
||||
def wr(self, signal, value):
|
||||
def wr(self, item, value, index=0):
|
||||
name = self.top_level.top_name + "." \
|
||||
+ self.top_level.dut_name + "." \
|
||||
+ self.namespace.get_name(signal)
|
||||
+ self.namespace.get_name(item)
|
||||
if isinstance(item, Memory):
|
||||
nbits = item.width
|
||||
else:
|
||||
nbits = item.bv.width
|
||||
if value < 0:
|
||||
value += 2**signal.bv.width
|
||||
assert(value >= 0 and value < 2**signal.bv.width)
|
||||
self.ipc.send(MessageWrite(name, value))
|
||||
value += 2**nbits
|
||||
assert(value >= 0 and value < 2**nbits)
|
||||
self.ipc.send(MessageWrite(name, Int32(index), value))
|
||||
|
|
|
@ -5,6 +5,9 @@ import os
|
|||
# Message classes
|
||||
#
|
||||
|
||||
class Int32(int):
|
||||
pass
|
||||
|
||||
class Message:
|
||||
def __init__(self, *pvalues):
|
||||
for parameter, value in zip(self.parameters, pvalues):
|
||||
|
@ -29,11 +32,11 @@ class MessageGo(Message):
|
|||
|
||||
class MessageWrite(Message):
|
||||
code = 2
|
||||
parameters = [(str, "name"), (int, "value")]
|
||||
parameters = [(str, "name"), (Int32, "index"), (int, "value")]
|
||||
|
||||
class MessageRead(Message):
|
||||
code = 3
|
||||
parameters = [(str, "name")]
|
||||
parameters = [(str, "name"), (Int32, "index")]
|
||||
|
||||
class MessageReadReply(Message):
|
||||
code = 4
|
||||
|
@ -58,6 +61,14 @@ def _pack_str(v):
|
|||
p.append(0)
|
||||
return p
|
||||
|
||||
def _pack_int32(v):
|
||||
return [
|
||||
v & 0xff,
|
||||
(v & 0xff00) >> 8,
|
||||
(v & 0xff0000) >> 16,
|
||||
(v & 0xff000000) >> 24
|
||||
]
|
||||
|
||||
def _pack(message):
|
||||
r = [message.code]
|
||||
for t, p in message.parameters:
|
||||
|
@ -67,6 +78,8 @@ def _pack(message):
|
|||
r += _pack_int(value)
|
||||
elif t == str:
|
||||
r += _pack_str(value)
|
||||
elif t == Int32:
|
||||
r += _pack_int32(value)
|
||||
else:
|
||||
raise TypeError
|
||||
return bytes(r)
|
||||
|
@ -75,10 +88,11 @@ def _pack(message):
|
|||
# Unpacking
|
||||
#
|
||||
|
||||
def _unpack_int(i):
|
||||
def _unpack_int(i, nchunks=None):
|
||||
v = 0
|
||||
power = 1
|
||||
nchunks = next(i)
|
||||
if nchunks is None:
|
||||
nchunks = next(i)
|
||||
for j in range(nchunks):
|
||||
v += power*next(i)
|
||||
power *= 256
|
||||
|
@ -102,6 +116,8 @@ def _unpack(message):
|
|||
v = _unpack_int(i)
|
||||
elif t == str:
|
||||
v = _unpack_str(i)
|
||||
elif t == Int32:
|
||||
v = _unpack_int(i, 4)
|
||||
else:
|
||||
raise TypeError
|
||||
pvalues.append(v)
|
||||
|
|
13
vpi/ipc.c
13
vpi/ipc.c
|
@ -90,24 +90,29 @@ int ipc_receive(struct ipc_softc *sc)
|
|||
char *name;
|
||||
int nchunks;
|
||||
unsigned char *chunks;
|
||||
unsigned int index;
|
||||
|
||||
name = &buffer[i];
|
||||
i += strlen(name) + 1;
|
||||
assert(i < l);
|
||||
assert((i+4) < l);
|
||||
index = buffer[i] | buffer[i+1] << 8 | buffer[i+2] << 16 | buffer[i+3] << 24;
|
||||
i += 4;
|
||||
nchunks = buffer[i++];
|
||||
assert(i + nchunks == l);
|
||||
chunks = (unsigned char *)&buffer[i];
|
||||
|
||||
return sc->h_write(name, nchunks, chunks, sc->user);
|
||||
return sc->h_write(name, index, nchunks, chunks, sc->user);
|
||||
}
|
||||
case MESSAGE_READ: {
|
||||
char *name;
|
||||
unsigned int index;
|
||||
|
||||
name = &buffer[i];
|
||||
i += strlen(name) + 1;
|
||||
assert(i == l);
|
||||
assert((i+4) == l);
|
||||
index = buffer[i] | buffer[i+1] << 8 | buffer[i+2] << 16 | buffer[i+3] << 24;
|
||||
|
||||
return sc->h_read(name, sc->user);
|
||||
return sc->h_read(name, index, sc->user);
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
struct ipc_softc;
|
||||
|
||||
typedef int(*go_handler)(void *);
|
||||
typedef int(*write_handler)(char *, int, const unsigned char *, void *);
|
||||
typedef int(*read_handler)(char *, void *);
|
||||
typedef int(*write_handler)(char *, int, int, const unsigned char *, void *);
|
||||
typedef int(*read_handler)(char *, int, void *);
|
||||
|
||||
struct ipc_softc *ipc_connect(const char *sockaddr,
|
||||
go_handler h_go, write_handler h_write, read_handler h_read, void *user);
|
||||
|
|
12
vpi/main.c
12
vpi/main.c
|
@ -23,7 +23,7 @@ static s_vpi_time zero_delay = {
|
|||
.low = 0
|
||||
};
|
||||
|
||||
static int h_write(char *name, int nchunks, const unsigned char *chunks, void *user)
|
||||
static int h_write(char *name, int index, int nchunks, const unsigned char *chunks, void *user)
|
||||
{
|
||||
vpiHandle item;
|
||||
s_vpi_vecval vector[64];
|
||||
|
@ -35,6 +35,10 @@ static int h_write(char *name, int nchunks, const unsigned char *chunks, void *u
|
|||
fprintf(stderr, "Attempted to write non-existing signal %s\n", name);
|
||||
return 0;
|
||||
}
|
||||
if(vpi_get(vpiType, item) == vpiMemory)
|
||||
item = vpi_handle_by_index(item, index);
|
||||
else
|
||||
assert(index == 0);
|
||||
|
||||
assert(nchunks <= 255);
|
||||
for(i=0;i<64;i++) {
|
||||
|
@ -51,7 +55,7 @@ static int h_write(char *name, int nchunks, const unsigned char *chunks, void *u
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int h_read(char *name, void *user)
|
||||
static int h_read(char *name, int index, void *user)
|
||||
{
|
||||
struct migensim_softc *sc = (struct migensim_softc *)user;
|
||||
vpiHandle item;
|
||||
|
@ -68,6 +72,10 @@ static int h_read(char *name, void *user)
|
|||
fprintf(stderr, "Attempted to read non-existing signal %s\n", name);
|
||||
return 0;
|
||||
}
|
||||
if(vpi_get(vpiType, item) == vpiMemory)
|
||||
item = vpi_handle_by_index(item, index);
|
||||
else
|
||||
assert(index == 0);
|
||||
|
||||
value.format = vpiVectorVal;
|
||||
vpi_get_value(item, &value);
|
||||
|
|
Loading…
Reference in a new issue