Skip to content

Commit

Permalink
Merge branch 'draft' of github.com:sylefeb/Silice into draft
Browse files Browse the repository at this point in the history
  • Loading branch information
sylefeb committed Dec 5, 2023
2 parents e5bc129 + 31c2cf8 commit 89568d2
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 87 deletions.
22 changes: 22 additions & 0 deletions frameworks/templates/simple_dualport_bram_generic_rw.v.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SL 2019, MIT license
module %MODULE%(
input [%ADDR0_WIDTH%-1:0] in_addr0,
output reg %DATA_TYPE% [%DATA_WIDTH%-1:0] out_rdata0,
output reg %DATA_TYPE% [%DATA_WIDTH%-1:0] out_rdata1,
input [%WENABLE1_WIDTH%-1:0] in_wenable1,
input [%DATA_WIDTH%-1:0] in_wdata1,
input [%ADDR1_WIDTH%-1:0] in_addr1,
input clock0,
input clock1
);
reg %DATA_TYPE% [%DATA_WIDTH%-1:0] buffer[%DATA_SIZE%-1:0];
always @(posedge clock0) begin
out_rdata0 <= buffer[in_addr0];
end
always @(posedge clock1) begin
if (in_wenable1) begin
buffer[in_addr1] <= in_wdata1;
end
end
%INITIAL%
endmodule
4 changes: 3 additions & 1 deletion get_started_mingw64.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ pacman -S --noconfirm --needed ${MINGW_PACKAGE_PREFIX}-glfw

# -------------- retrieve oss-cad-suite package --------------
OSS_CAD_MONTH=11
OSS_CAD_DAY=15
OSS_CAD_DAY=29
OSS_CAD_YEAR=2023

rm -rf tools/fpga-binutils/
rm -rf tools/oss-cad-suite/
wget -c https://github.com/YosysHQ/oss-cad-suite-build/releases/download/$OSS_CAD_YEAR-$OSS_CAD_MONTH-$OSS_CAD_DAY/oss-cad-suite-windows-x64-$OSS_CAD_YEAR$OSS_CAD_MONTH$OSS_CAD_DAY.exe
cd tools ; ../oss-cad-suite-windows-x64-$OSS_CAD_YEAR$OSS_CAD_MONTH$OSS_CAD_DAY.exe ; cd -

Expand Down
59 changes: 32 additions & 27 deletions projects/ice-v/CPUs/ice-v-ram.si
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ $$ cycleW = 32

$$if ICEV_MULDIV then
$$ print("Ice-V-ram configured with mul and div (*not* full RV32IM)")
$$div_width = 32
$$div_signed = 1
$$div_width = 32
$$div_unsigned = 1
$$div_remainder = 1
$include('../../common/divint_std.si')
$$end

Expand Down Expand Up @@ -415,32 +416,36 @@ $$end

$$if ICEV_MULDIV then
// mul div
uint1 mulh = op[0,2] == 2b01;
uint1 mulhsu = op[0,2] == 2b10;
uint1 signa = xa[31,1];
uint1 signb = xb[31,1]; // vvvvvvvvvv keep the sign?
int33 ma = {signa & (mulh | mulhsu), xa};
int33 mb = {signb & mulh, xb};
int64 mul = ma * mb; // multiply
uint1 signdiv = ~ op[0,1];
uint1 divdone = isdone(div) & ~prev_divdone; // pulses on div done
uint1 prev_divdone = isdone(div);
//if (muldiv & working & divdone) {
// __display("DIVISION %d / %d = %d (%d)\n",div.inum,div.iden,div.ret,div.rem);
//}
working = (working | (trigger & op[2,1]))
& muldiv
& ~(working & divdone);
if (trigger) { // div restarts each trigger
div.inum = (signdiv&signa) ? -xa : xa;
div.iden = (signdiv&signb) ? -xb : xb;
div <- ();
}
uint1 div_negate = signdiv & (signa ^ signb);
uint1 ret_h = |op[0,2];
if (muldiv) {
// __display("[cycle %d] dividing:%b working:%b isdone(div):%b",cycle,dividing,working,isdone(div));
switch ({op}) {
case 3b000: { // MUL
// __display("MULTIPLICATION %d * %d",xa,xb);
r = xa * xb;
}
case 3b100: { // DIV
if (trigger) {
// __display("[cycle %d] DIVISION trigger",cycle);
working = 1;
dividing = 1;
div <- (xa,xb);
} else {
if (isdone(div) & dividing) {
// __display("[cycle %d] DIVISION %d / %d = %d",cycle,div.inum,div.iden,div.ret);
dividing = 0;
working = 0;
}
}
r = div.ret;
}
default: { r = {32{1bx}}; }
}
} else {
dividing = 0;
r = ((~op[2,1] & ret_h) ? mul[32,32] : 32b0) // MULH, MULHSU, MULHU
| ((~op[2,1] & ~ret_h) ? mul[ 0,32] : 32b0) // MUL
| (( op[2,1] & div_negate & op[1,1] ) ? -div.rem : 32b0) // REM
| (( op[2,1] & ~div_negate & op[1,1] ) ? div.rem : 32b0) // REMU
| (( op[2,1] & div_negate & ~op[1,1] ) ? -div.ret : 32b0) // DIV
| (( op[2,1] & ~div_negate & ~op[1,1] ) ? div.ret : 32b0);// DIVU
}
$$end

Expand Down
49 changes: 35 additions & 14 deletions projects/ice-v/CPUs/ice-v-swirl.si
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ $$end
// Risc-V RV32I pipelined CPU
$$print("====== ice-v swirl (pipeline, data bypass, rdcycle) ======")
//
// Four stages pipeline
// Five stages pipeline
// --------------------
// Stage 1, in: instruction, setup: reg read A,B, next fetch
// => [registers read] =>
Expand Down Expand Up @@ -67,9 +67,7 @@ $$print("====== ice-v swirl (pipeline, data bypass, rdcycle) ======")
// Overview
// --------
//
// The CPU has four stages, which deviates a bit from the typical five stages
// design. I have no specific reason for this apart from this being the most
// natural evolution of prior IceV version.
// The CPU has five stages (see above).
//
// The pipeline implements bypasses on data hazards, such that it does not have
// to insert bubbles ('do nothing') in case of potential trouble (see also the
Expand Down Expand Up @@ -119,11 +117,13 @@ $$if ICEV_STALL then
input uint1 stall_cpu,
$$end
$$if TRACE_swirl then
// input uint1 trace_on,
input uint1 trace_on,
$$end
) {

// register file, uses two BRAMs to fetch two registers at once
//simple_dualport_bram int32 xregsA<"simple_dualport_bram_generic_rw">[32] = {pad(0)};
//simple_dualport_bram int32 xregsB<"simple_dualport_bram_generic_rw">[32] = {pad(0)};
simple_dualport_bram int32 xregsA[32] = {pad(0)};
simple_dualport_bram int32 xregsB[32] = {pad(0)};
// ^^^^^^^^^^^^^ dualport so that we can read/write simultaneously
Expand Down Expand Up @@ -159,11 +159,10 @@ $$end
decode_and_ALU_swirl exec<reginputs>;

$$if SIMULATION then
uint32 cycle(0); uint32 nretired(0);
uint32 cycle(0); uint32 nretired(0); uint1 has_rs2(0); uint1 stage2_bubble(0);
$$end
$$if TRACE_swirl then
uint32 last_cycle(0);
uint1 trace_on <:: nretired > 3145018;
$$end
$$if not ICEV_STALL then
uint1 stall_cpu(0); // stall disabled, never used
Expand All @@ -173,11 +172,15 @@ $$end
always {

$$if DEBUG_swirl then
uint1 debug_on = 1; // cycle > 95753466; // nretired > 3145018;
uint1 debug_on = 1
$$end

// tracks whether a register was written cycle before
uint1 reg_was_written = xregsA.wenable1;
$$if SIMULATION then
uint5 xregsA_conflict_possible = xregsA.wenable1 && xregsA.addr1 == xregsA.addr0;
uint5 xregsB_conflict_possible = xregsB.wenable1 && xregsB.addr1 == xregsB.addr0;
$$end
// maintain register wenable low (pulsed when necessary)
xregsA.wenable1 = 0;
// maintain memory write low, or to its previous state if stalled
Expand Down Expand Up @@ -237,7 +240,10 @@ $$end
// maintain bpred on bubbles
uint1 prev_bpred(0);
// for data hazard detection
uint1 has_rs2(0); uint1 store(0);
$$if not SIMULATION then
uint1 has_rs2(0);
$$end
uint1 store(0);
// give instruction, pc and registers to decoder+ALU
instr = (hold | exec.working) ? exec.instr : instr;
pc = (hold | exec.working) ? exec.pc : pc;
Expand All @@ -254,9 +260,10 @@ $$end
| (Rtype(instr).opcode[2,5] == 5b11000) // branch
| store;
// by default we select the register value read after stage 1
// (assuming no data haward)
xa_regR = ~hold; xa_regW = 0; xa_regW_prev = 0; xa_keep = hold;
xb_regR = ~hold; xb_regW = 0; xb_regW_prev = 0; xb_keep = hold;
// or keep the values as is on a hold or alu is working
uint1 keep = hold | exec.working;
xa_regR = ~keep; xa_regW = 0; xa_regW_prev = 0; xa_keep = keep;
xb_regR = ~keep; xb_regW = 0; xb_regW_prev = 0; xb_keep = keep;
// [data hazards] case (c) detection
// instruction in stage 3 will (cycle+2) write on a register needed now
// instruction in stage 4 will (cycle+1) write on a register needed now
Expand Down Expand Up @@ -295,10 +302,13 @@ if (debug_on) {
$$end
// update bubble
bubble = bubble | refetch | hold;
$$if SIMULATION then
stage2_bubble = bubble;
$$end
$$if DEBUG_swirl then
if (debug_on) {
if (~stall_cpu | on_stall) {
__display("[2] instr: %x @%x (bubble:%b bpred:%b) rA:%x rB:%x",instr,pc<<2,bubble,bpred,xregsA.rdata0,xregsB.rdata0);
__display("[2] instr: %x @%x (bubble:%b bpred:%b) rA(%d):%x rB(%d):%x",instr,pc<<2,bubble,bpred,Rtype(instr).rs1,xregsA.rdata0,Rtype(instr).rs2,xregsB.rdata0);
}
}
$$end
Expand All @@ -317,7 +327,7 @@ $$end
xa_regR = 0; xa_regW = 0; xa_regW_prev = 1; xa_keep = 0;
// ^^^^^^^^^^^^^ selects value previously written
}
if (Rtype(instr).rs2 == xregsA.addr1 & reg_was_written & has_rs2) {
if (Rtype(instr).rs2 == xregsB.addr1 & reg_was_written & has_rs2) {
$$if DEBUG_swirl then
if (debug_on) {
if (~stall_cpu | on_stall) {
Expand Down Expand Up @@ -566,10 +576,21 @@ $$if TRACE_swirl then
}
}
$$end

// register bank B follows A writes
xregsB.wenable1 = xregsA.wenable1;
xregsB.wdata1 = xregsA.wdata1;
xregsB.addr1 = xregsA.addr1;
$$if SIMULATION then
if (xregsA_conflict_possible & xa_regR & ~stage2_bubble) {
__display("[cycle %d] ERROR reading from a written register (A) @%h",cycle,pc<<2);
__finish();
}
if (xregsB_conflict_possible & xb_regR & ~stage2_bubble & has_rs2) {
__display("[cycle %d] ERROR reading from a written register (B) @%h",cycle,pc<<2);
__finish();
}
$$end
$$if DEBUG_swirl then
if (debug_on) {
if (~stall_cpu) {
Expand Down
54 changes: 10 additions & 44 deletions src/Algorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1952,12 +1952,6 @@ Algorithm::t_combinational_block *Algorithm::gatherBreakLoop(siliceParser::Break

Algorithm::t_combinational_block *Algorithm::gatherWhile(siliceParser::WhileLoopContext* loop, t_combinational_block *_current, t_gather_context *_context)
{
// pipeline nesting check
if (_current->context.pipeline_stage != nullptr) {
if (hasPipeline(loop->while_block)) {
reportError(sourceloc(loop->while_block),"while loop contains another pipeline: pipelines cannot be nested.");
}
}
// while header block
t_combinational_block *while_header = addBlock("__while" + generateBlockName(), _current, nullptr, sourceloc(loop));
_current->next(while_header);
Expand Down Expand Up @@ -2407,7 +2401,7 @@ Algorithm::t_combinational_block *Algorithm::concatenatePipeline(siliceParser::P
// go through the pipeline
// -> for each stage block
t_combinational_block *prev = _current;
bool resume = (_current->context.pipeline_stage != nullptr); // if in an existing pipeline, start by adding to the last stage
bool resume = (_current->context.pipeline_stage != nullptr) && !isSpawningNewPipeline(pip); // if in an existing pipeline, start by adding to the last stage
for (auto b : pip->instructionList()) {
t_fsm_nfo* fsm = nullptr;
t_pipeline_stage_nfo* snfo = nullptr;
Expand Down Expand Up @@ -2500,10 +2494,10 @@ Algorithm::t_combinational_block *Algorithm::gatherPipeline(siliceParser::Pipeli
sl_assert(pip->instructionList().size() > 1); // otherwise not a pipeline
// inform change log
CHANGELOG.addPointOfInterest("CL0003", sourceloc(pip));
// are we already within a parent pipeline?
if (_current->context.pipeline_stage == nullptr) {
// are we already within a parent pipeline or spawning a new onesss?
if (_current->context.pipeline_stage == nullptr || isSpawningNewPipeline(pip)) {

/// no: create a new pipeline
/// create a new pipeline
auto nfo = new t_pipeline_nfo();
m_Pipelines.push_back(nfo);
// name of the pipeline
Expand Down Expand Up @@ -2659,12 +2653,7 @@ Algorithm::t_combinational_block *Algorithm::gatherPipeline(siliceParser::Pipeli

} else {

/// yes: expand the parent pipeline
// check for nesting (forbidden)
if (isSpawningNewPipeline(pip)) {
reportError(sourceloc(pip), "cannot start a new pipeline from within anonhter pipeline.");
}
// concatenate pipeline
/// concatenate to the parent pipeline
auto nfo = _current->context.pipeline_stage->pipeline;
return concatenatePipeline(pip, _current, _context, nfo);

Expand Down Expand Up @@ -3025,15 +3014,6 @@ Algorithm::t_combinational_block* Algorithm::gatherCircuitryInst(

Algorithm::t_combinational_block *Algorithm::gatherIfElse(siliceParser::IfThenElseContext* ifelse, t_combinational_block *_current, t_gather_context *_context)
{
// pipeline nesting check
if (_current->context.pipeline_stage != nullptr) {
if (hasPipeline(ifelse->if_block)) {
reportError(sourceloc(ifelse->if_block), "conditonal statement (if side) contains another pipeline: pipelines cannot be nested.");
}
if (hasPipeline(ifelse->else_block)) {
reportError(sourceloc(ifelse->else_block), "conditonal statement (else side) contains another pipeline: pipelines cannot be nested.");
}
}
// blocks for both sides
t_combinational_block *if_block = addBlock(generateBlockName(), _current, nullptr, sourceloc(ifelse->if_block));
t_combinational_block *else_block = addBlock(generateBlockName(), _current, nullptr, sourceloc(ifelse->else_block));
Expand Down Expand Up @@ -3067,12 +3047,6 @@ Algorithm::t_combinational_block *Algorithm::gatherIfElse(siliceParser::IfThenEl

Algorithm::t_combinational_block *Algorithm::gatherIfThen(siliceParser::IfThenContext* ifthen, t_combinational_block *_current, t_gather_context *_context)
{
// pipeline nesting check
if (_current->context.pipeline_stage != nullptr) {
if (hasPipeline(ifthen->if_block)) {
reportError(sourceloc(ifthen->if_block), "conditonal statement contains another pipeline: pipelines cannot be nested.");
}
}
// blocks for both sides
t_combinational_block *if_block = addBlock(generateBlockName(), _current, nullptr, sourceloc(ifthen->if_block));
t_combinational_block *else_block = addBlock(generateBlockName(), _current);
Expand Down Expand Up @@ -3100,14 +3074,6 @@ Algorithm::t_combinational_block *Algorithm::gatherIfThen(siliceParser::IfThenCo

Algorithm::t_combinational_block* Algorithm::gatherSwitchCase(siliceParser::SwitchCaseContext* switchCase, t_combinational_block* _current, t_gather_context* _context)
{
// pipeline nesting check
if (_current->context.pipeline_stage != nullptr) {
for (auto cb : switchCase->caseBlock()) {
if (hasPipeline(cb)) {
reportError(sourceloc(cb), "switch case contains another pipeline: pipelines cannot be nested.");
}
}
}
// create a block for after the switch-case
t_combinational_block* after = addBlock(generateBlockName(), _current, nullptr, sourceloc(switchCase));
// create a block per case statement
Expand Down Expand Up @@ -8720,10 +8686,11 @@ void Algorithm::writeStatelessBlockGraph(
auto prev = current;
if (current->context.fsm != nullptr) {
// if in an algorithm, pipelines are written later
std::ostringstream _;
t_writer_context wpip(w.pipes,_,w.wires);
sl_assert(_.str().empty());
std::ostringstream subpip; // child pipelines are written here
t_writer_context wpip(w.pipes,subpip,w.wires);
current = writeStatelessPipeline(prefix, wpip, ictx, current, _q, _dependencies, _ff_usage, _post_dependencies, _lines);
// combine any child pipeline with parents
w.pipes << subpip.str();
// also check that blocks between here and next states are empty
if (!emptyUntilNextStates(current)) {
reportError(prev->srcloc, "in an algorithm, a pipeline has to be followed by a new cycle.\n"
Expand Down Expand Up @@ -9935,9 +9902,8 @@ void Algorithm::writeAsModule(std::ostream& out, const t_instantiation_context&
if (stage_id == 0) {
// parent state active?
if (fsm->parentBlock->context.fsm != nullptr) {
sl_assert(fsm->parentBlock->context.fsm == &m_RootFSM); // no nested pipelines
out << " && ((";
out << fsmNextState("_", &m_RootFSM);
out << fsmNextState("_", fsm->parentBlock->context.fsm);
out << ')';
out << " == " << toFSMState(fsm->parentBlock->context.fsm, fsmParentTriggerState(fsm));
out << ")" << nxl;
Expand Down
26 changes: 26 additions & 0 deletions tests/pipeline29.si
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

// nested pipelines test

algorithm main(output uint8 leds)
{

uint5 i = 0;
while (i<4) {

// stage 0
i = i + 1;

->

// stage 1
uint5 j = 0;
while (j<4) {
// nested pipeline
__display("[0] %d,%d",i,j);
->
__display("[1] %d,%d",i,j);
}

}

}

0 comments on commit 89568d2

Please sign in to comment.