Skip to content

Commit 1279ed5

Browse files
committed
more vlog
1 parent 13074a9 commit 1279ed5

2 files changed

Lines changed: 128 additions & 11 deletions

File tree

src/emit/tk_vlog.c

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,99 @@ em_vlog(const rt_mod_t *M, const lb_lib_t *lib,
390390
}
391391
fprintf(fp, "\n");
392392

393+
/* ---- Inferred memories ---- */
394+
for (i = 0; i < M->n_mem; i++) {
395+
const char *mnam = M->strs + M->mems[i].name_off;
396+
uint32_t dw = M->mems[i].data_w;
397+
uint32_t dp = M->mems[i].depth;
398+
399+
fprintf(fp, "// Memory: %.*s (%ux%u)\n",
400+
(int)M->mems[i].name_len, mnam, dp, dw);
401+
fprintf(fp, "reg [%u:0] %.*s [0:%u];\n",
402+
dw - 1, (int)M->mems[i].name_len, mnam, dp - 1);
403+
404+
/* Memory writes are synchronous, so we need a clock.
405+
* Borrow it from the first DFF we find — they all
406+
* share the same clock in a single-clock design. */
407+
{
408+
uint32_t clk_net = 0;
409+
uint32_t ci;
410+
for (ci = 1; ci < M->n_cell; ci++) {
411+
if ((M->cells[ci].type == RT_DFF ||
412+
M->cells[ci].type == RT_DFFR) &&
413+
M->cells[ci].n_in >= 2) {
414+
clk_net = M->cells[ci].ins[1];
415+
break;
416+
}
417+
}
418+
419+
/* Reconstruct the always block from MEMWR cells.
420+
* The third input, if present, is the write-enable. */
421+
{
422+
uint32_t waddr = 0, wdata = 0, we_net = 0;
423+
uint32_t ci2;
424+
for (ci2 = 1; ci2 < M->n_cell; ci2++) {
425+
if (M->cells[ci2].type == RT_MEMWR &&
426+
M->cells[ci2].param == (int64_t)i) {
427+
waddr = M->cells[ci2].ins[0];
428+
wdata = M->cells[ci2].ins[1];
429+
if (M->cells[ci2].n_in >= 3)
430+
we_net = M->cells[ci2].ins[2];
431+
break;
432+
}
433+
}
434+
435+
if (waddr > 0 && wdata > 0) {
436+
char ab[64], db[64], cb[64];
437+
438+
if (clk_net > 0)
439+
fprintf(fp, "always @(posedge %s) begin\n",
440+
em_cin(M, clk_net, cb, 64));
441+
else
442+
fprintf(fp, "always @(*) begin\n");
443+
444+
if (we_net > 0) {
445+
char wb[64];
446+
fprintf(fp, " if (%s)\n ",
447+
em_cin(M, we_net, wb, 64));
448+
}
449+
450+
fprintf(fp, " %.*s[%s] <= %s;\n",
451+
(int)M->mems[i].name_len, mnam,
452+
em_cin(M, waddr, ab, 64),
453+
em_cin(M, wdata, db, 64));
454+
455+
fprintf(fp, "end\n");
456+
}
457+
}
458+
459+
/* Read port is combinational — assign, not always.
460+
* The DFF on the output handles the registration. */
461+
{
462+
uint32_t raddr = 0, rout = 0;
463+
uint32_t ci3;
464+
for (ci3 = 1; ci3 < M->n_cell; ci3++) {
465+
if (M->cells[ci3].type == RT_MEMRD &&
466+
M->cells[ci3].param == (int64_t)i) {
467+
raddr = M->cells[ci3].ins[0];
468+
rout = M->cells[ci3].out;
469+
break;
470+
}
471+
}
472+
473+
if (raddr > 0 && rout > 0) {
474+
char ab2[64], ob[64];
475+
fprintf(fp, "assign %s = %.*s[%s];\n",
476+
em_cnet(M, rout, ob, 64),
477+
(int)M->mems[i].name_len, mnam,
478+
em_cin(M, raddr, ab2, 64));
479+
}
480+
}
481+
}
482+
483+
fprintf(fp, "\n");
484+
}
485+
393486
/* ---- Cell instances ---- */
394487
for (i = 1; i < M->n_cell; i++) {
395488
const rt_cell_t *c = &M->cells[i];
@@ -403,6 +496,9 @@ em_vlog(const rt_mod_t *M, const lb_lib_t *lib,
403496
/* Skip CONST cells — inlined at consumers */
404497
if (ct == RT_CONST) continue;
405498

499+
/* Already handled above as reg arrays + always blocks */
500+
if (ct == RT_MEMRD || ct == RT_MEMWR) continue;
501+
406502
/* Look up mapped cell */
407503
if (!tbl[ct].valid) {
408504
fprintf(fp, "// UNMAPPED: %s w=%u\n",

src/rtl/tk_lower.c

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ typedef struct {
4848
#define LW_RDIR_MAX 512
4949
struct { uint32_t net, cur, cell; } rdir[LW_RDIR_MAX];
5050
uint32_t n_rdir;
51+
52+
/* Current write-enable condition for memory writes.
53+
* Set by lw_ifmux when descending into an if body,
54+
* cleared when leaving. 0 = unconditional. */
55+
uint32_t mem_we;
5156
} lw_ctx_t;
5257

5358
/* ---- Sequential redirect helpers ---- */
@@ -598,15 +603,27 @@ lw_asgn(lw_ctx_t *C, uint32_t nidx, int is_reg)
598603
uint32_t mw = C->M->mems[mi].data_w;
599604
uint32_t ci2;
600605

601-
/* Lower address and data */
606+
/* Both sides of mem[addr] <= data need evaluating
607+
* before we can build the write cell */
602608
anet = idx_n ? lw_expr(C, idx_n) : 0;
603609
dnet = lw_expr(C, rhs_n);
604610
if (anet == 0 || dnet == 0) return;
605611

606-
/* MEMWR: side-effecting, output is a dummy net */
612+
/* If we're inside an if(we) block, the condition
613+
* net rides along as a third input so the emitter
614+
* can reconstruct the conditional write */
607615
onet = rt_anet(C->M, "mwr", 3, mw, 0, C->radix);
608-
ins[0] = anet; ins[1] = dnet;
609-
ci2 = rt_acell(C->M, RT_MEMWR, onet, ins, 2, mw);
616+
{
617+
uint32_t mins[3];
618+
uint8_t mn = 2;
619+
mins[0] = anet;
620+
mins[1] = dnet;
621+
if (C->mem_we > 0) {
622+
mins[2] = C->mem_we;
623+
mn = 3;
624+
}
625+
ci2 = rt_acell(C->M, RT_MEMWR, onet, mins, mn, mw);
626+
}
610627
if (ci2 > 0 && ci2 < C->M->n_cell)
611628
C->M->cells[ci2].param = (int64_t)mi;
612629
return;
@@ -925,14 +942,18 @@ lw_ifmux(lw_ctx_t *C, uint32_t nidx, int is_reg)
925942
}
926943

927944
flat:
928-
/* Pattern didn't match: lower all children flat */
945+
/* Pattern didn't match: lower all children flat.
946+
* Set mem_we so memory writes inside the if body
947+
* pick up the condition as their write-enable. */
929948
{
930-
uint32_t c = C->P->nodes[nidx].first_child;
931-
KA_GUARD(g, 100);
932-
while (c && g--) {
933-
lw_stms(C, c, is_reg);
934-
c = C->P->nodes[c].next_sib;
935-
}
949+
uint32_t saved_we = C->mem_we;
950+
uint32_t cnet = cond_n ? lw_expr(C, cond_n) : 0;
951+
if (cnet > 0)
952+
C->mem_we = cnet;
953+
954+
if (then_n) lw_stms(C, then_n, is_reg);
955+
C->mem_we = saved_we;
956+
if (else_n) lw_stms(C, else_n, is_reg);
936957
}
937958
}
938959

0 commit comments

Comments
 (0)