Fixed rval3 register for multicycle_merged

import ClientServer::*;
import Connectable::*;
import DefaultValue::*;
import FIFO::*;
import GetPut::*;
import Vector::*;

import Abstraction::*;
import RVRFile::*;
import RVCsrFile::*;
import RVExec::*;
import RVFpu::*;
import RVMulDiv::*;
import RVTypes::*;
import VerificationPacket::*;

import RVAlu::*;
import RVControl::*;
import RVDecode::*;
import RVMemory::*;

// This interface is the combination of FrontEnd and BackEnd
interface Core;
    method Action start(Addr startPc);
    method Action stop;

    method Action configure(Data miobase);
    method ActionValue#(VerificationPacket) getVerificationPacket;
    method ActionValue#(VMInfo) updateVMInfoI;
    method ActionValue#(VMInfo) updateVMInfoD;

    interface Client#(RVIMMUReq, RVIMMUResp) ivat;
    interface Client#(RVIMemReq, RVIMemResp) ifetch;
    interface Client#(RVDMMUReq, RVDMMUResp) dvat;
    interface Client#(RVDMemReq, RVDMemResp) dmem;
    interface Client#(FenceReq, FenceResp) fence;
    interface Client#(Data, Data) htif;
endinterface

instance Connectable#(Core, MemorySystem);
    module mkConnection#(Core core, MemorySystem mem)(Empty);
        mkConnection(core.ivat, mem.ivat);
        mkConnection(core.ifetch, mem.ifetch);
        mkConnection(core.dvat, mem.dvat);
        mkConnection(core.dmem, mem.dmem);
        mkConnection(core.fence, mem.fence);
        mkConnection(toGet(core.updateVMInfoI), toPut(mem.updateVMInfoI));
        mkConnection(toGet(core.updateVMInfoD), toPut(mem.updateVMInfoD));
    endmodule
endinstance

typedef enum {
    Wait,
    IMMU,
    IF,
    Dec,
    RegRead,
    Execute,
    Mem,
    WB,
    Trap,
    Trap2
} ProcState deriving (Bits, Eq, FShow);

(* synthesize *)
module mkMulticycleCore(Core);
    let verbose = False;
    File fout = stdout;

    ArchRFile rf <- mkArchRFile;
    RVCsrFile csrf <- mkRVCsrFile;
    MulDivExec mulDiv <- mkBoothRoughMulDivExec;
    FpuExec fpu <- mkFpuExecPipeline;

    Reg#(Bool) htifStall <- mkReg(False);
    Reg#(Bool) running <- mkReg(False);
    Reg#(ProcState) state <- mkReg(Wait);

    Reg#(Addr) pc <- mkReg(0);
    Reg#(Maybe#(ExceptionCause)) exception <- mkReg(tagged Invalid);
    Reg#(Instruction) inst <- mkReg(0);
    Reg#(RVDecodedInst) dInst <- mkReg(unpack(0));
    Reg#(FrontEndCsrs) csrState <- mkReadOnlyReg( FrontEndCsrs { vmI: csrf.vmI, state: csrf.csrState } );

    FIFO#(RVIMMUReq)    immuReq <- mkFIFO1;
    FIFO#(RVIMMUResp)   immuResp <- mkFIFO1;

    FIFO#(RVIMemReq)    imemReq <- mkFIFO1;
    FIFO#(RVIMemResp)   imemResp <- mkFIFO1;

    Reg#(Data) rVal1 <- mkReg(0);
    Reg#(Data) rVal2 <- mkReg(0);
    Reg#(Data) rVal3 <- mkReg(0);
    Reg#(Data) data <- mkReg(0);
    Reg#(Data) addr <- mkReg(0);
    Reg#(Data) nextPc <- mkReg(0);

    FIFO#(RVDMMUReq)    dmmuReq <- mkFIFO1;
    FIFO#(RVDMMUResp)   dmmuResp <- mkFIFO1;

    FIFO#(RVDMemReq)    dmemReq <- mkFIFO1;
    FIFO#(RVDMemResp)   dmemResp <- mkFIFO1;

    FIFO#(Data)         toHost <- mkFIFO1;
    FIFO#(Data)         fromHost <- mkFIFO1;

    FIFO#(VerificationPacket) verificationPackets <- mkFIFO1;

    rule doInstMMU(running && state == IMMU);
        // request address translation from MMU
        immuReq.enq(pc);
        // reset states
        inst <= unpack(0);
        dInst <= unpack(0);
        exception <= tagged Invalid;
        // go to InstFetch stage
        state <= IF;
    endrule

    rule doInstFetch(state == IF);
        // I wanted notation like this:
        // let {addr: .phyPc, exception: .exMMU} = mmuResp.first;

        let phyPc = immuResp.first.addr;
        let exMMU = immuResp.first.exception;
        immuResp.deq;

        if (!isValid(exMMU)) begin
            // no translation exception
            imemReq.enq(phyPc);
            // go to decode stage
            state <= Dec;
        end else begin
            // translation exception (instruction access fault)
            exception <= exMMU;
            // send instruction to backend
            state <= Trap;
        end
    endrule

    rule doDecode(state == Dec);
        let fInst = imemResp.first;
        imemResp.deq;

        let decInst = decodeInst(fInst);

        if (decInst matches tagged Valid .validDInst) begin
            // Legal instruction
            dInst <= validDInst;
        end else begin
            // Illegal instruction
            exception <= tagged Valid IllegalInst;
        end

        inst <= fInst;
        state <= isValid(decInst) ? RegRead : Trap;
    endrule

    rule doRegRead(!htifStall && state == RegRead);
        rVal1 <= rf.rd1(fromMaybe(Gpr, dInst.rs1), getInstFields(inst).rs1);
        rVal2 <= rf.rd2(fromMaybe(Gpr, dInst.rs2), getInstFields(inst).rs2);
        rVal3 <= rf.rd3(fromMaybe(Gpr, dInst.rs3), getInstFields(inst).rs3);
        state <= Execute;
    endrule

    rule doExecute(state == Execute);
        let dataEx = 0;
        let addrEx = 0;
        let nextPcEx = pc + 4;

        Maybe#(Data) imm = getImmediate(dInst.imm, dInst.inst);
        case (dInst.execFunc) matches
            tagged Alu    .aluInst:
                begin
                    dataEx = execAluInst(aluInst, rVal1, rVal2, imm, pc);
                end
            tagged Br     .brFunc:
                begin
                    // data for jal
                    dataEx = pc + 4;
                    nextPcEx = execControl(brFunc, rVal1, rVal2, imm, pc);
                end
            tagged Mem    .memInst:
                begin
                    // data for store and AMO
                    dataEx = rVal2;
                    addrEx = addrCalc(rVal1, imm);
                    dmmuReq.enq(RVDMMUReq {addr: addrEx, size: memInst.size, op: (memInst.op matches tagged Mem .memOp ? memOp : St)});
                end
            tagged MulDiv .mulDivInst: mulDiv.exec(mulDivInst, rVal1, rVal2);
            tagged Fence  .fenceInst:  noAction;
            // TODO: Handle dynamic rounding mode
            tagged Fpu    .fpuInst:    fpu.exec(fpuInst, getInstFields(inst).rm, rVal1, rVal2, rVal3);
            tagged System .systemInst:
                begin
                    // data for CSR instructions
                    dataEx = fromMaybe(rVal1, imm);
                end
        endcase

        data <= dataEx;
        addr <= addrEx;
        nextPc <= nextPcEx;

        state <= dInst.execFunc matches tagged Mem .* ? Mem : WB;
    endrule

    rule doMem(state == Mem);
        let pAddr = dmmuResp.first.addr;
        let exMMU = dmmuResp.first.exception;
        dmmuResp.deq;

        // TODO: make this type safe! get rid of .Mem accesses to tagged union
        if (!isValid(exMMU)) begin
            dmemReq.enq( RVDMemReq {
                    op: dInst.execFunc.Mem.op,
                    byteEn: toByteEn(dInst.execFunc.Mem.size),
                    addr: pAddr,
                    data: data,
                    unsignedLd: isUnsigned(dInst.execFunc.Mem.size) } );
            state <= WB;
        end else begin
            exception <= exMMU;
            state <= Trap;
        end
    endrule

    rule doWB(state == WB);
        let dataWb = data;
        let addrWb = addr;
        let nextPcWb = nextPc;
        let fflagsWb = 0;
        let exceptionWB = exception;

        case(dInst.execFunc) matches
            tagged MulDiv .*: begin
                    dataWb = mulDiv.result_data();
                    mulDiv.result_deq;
                end
            tagged Fpu .*: begin
                    let fpuResult = toFullResult(fpu.result_data);
                    dataWb = fpuResult.data;
                    fflagsWb = fpuResult.fflags;
                    fpu.result_deq;
                end
            tagged Mem .memInst:
                begin
                    if (getsResponse(memInst.op)) begin
                        dataWb = dmemResp.first;
                        dmemResp.deq;
                    end
                end
        endcase

        // TODO: add comment
        Bool extensionDirty = False;
        Bool fpuDirty = (dInst.dst == tagged Valid Fpu);
        let {maybeTrap, maybeData, maybeNextPc} <- csrf.wr(
                // performing system instructions
                dInst.execFunc matches tagged System .sysInst ? tagged Valid sysInst : tagged Invalid,
                getInstFields(inst).csr,
                dataWb,  // either rf[rs1] or zimm, computed in basicExec
                // handling exceptions
                exceptionWB,    // exception cause
                pc,             // for writing to mepc/sepc
                dInst.execFunc matches tagged Br .* ? True : False, // check inst allignment if Br Func
                dInst.execFunc matches tagged Br .* ? nextPcWb : addrWb, // either data address or next PC, used to detect misaligned instruction addresses
                // indirect writes
                fflagsWb,
                fpuDirty,
                extensionDirty);

        // send verification packet
        verificationPackets.enq( VerificationPacket {
                skippedPackets: 0,
                pc: pc,
                nextPc: fromMaybe(nextPcWb, maybeNextPc),
                data: fromMaybe(dataWb, maybeData),
                instruction: inst,
                dst: {pack(dInst.dst), getInstFields(inst).rd},
                trap: isValid(maybeTrap),
                trapType: (case (fromMaybe(unpack(0), maybeTrap)) matches
                        tagged Exception .x: (zeroExtend(pack(x)));
                        tagged Interrupt .x: (zeroExtend(pack(x)) | 8'h80);
                    endcase) });

        if (maybeNextPc matches tagged Valid .replayPc) begin
            // This instruction didn't retire

            // redirect happens in Trap2
            nextPc <= replayPc;
            state <= Trap2;
        end else begin
            // This instruction retired
            if (dInst.dst matches tagged Valid .dstRegType) begin
                // Use data from CSR if available
                rf.wr(dstRegType, getInstFields(inst).rd, fromMaybe(dataWb, maybeData));
            end
            // always redirect
            pc <= nextPc;
            state <= IMMU;
        end
    endrule

    rule doTrap(state == Trap);
        // TODO: move this to WB
        let {maybeTrap, maybeData, maybeNextPc} <- csrf.wr(
                tagged Invalid,
                getInstFields(inst).csr,
                0, // data
                exception, // exception cause
                pc, // pc
                False,
                addr, // vaddr
                0,
                False,
                False);

        // send verification packet
        verificationPackets.enq( VerificationPacket {
                skippedPackets: 0,
                pc: pc,
                nextPc: fromMaybe(?, maybeNextPc),
                data: fromMaybe(data, maybeData),
                instruction: inst,
                dst: {pack(dInst.dst), getInstFields(inst).rd},
                trap: isValid(maybeTrap),
                trapType: (case (fromMaybe(unpack(0), maybeTrap)) matches
                        tagged Exception .x: (zeroExtend(pack(x)));
                        tagged Interrupt .x: (zeroExtend(pack(x)) | 8'h80);
                    endcase) });

        // redirection will happpen in trap2
        // by construction maybeNextPc is always valid
        nextPc <= fromMaybe(nextPc, maybeNextPc);
        state <= Trap2;
    endrule

    // There is a second trap state to ensure that the frontEndCsrs reflect the updated state of the processor
    rule doTrap2(state == Trap2);
        pc <= nextPc;
        state <= IMMU;
    endrule

    rule htifToHost;
        let msg <- csrf.csrfToHost;
        if (truncateLSB(msg) != 16'h0100) begin
            htifStall <= True;
        end
        toHost.enq(msg);
    endrule

    rule htifFromHost;
        htifStall <= False;
        let msg = fromHost.first;
        fromHost.deq;
        csrf.hostToCsrf(msg);
    endrule

    interface Client ivat = toGPClient(immuReq, immuResp);
    interface Client ifetch = toGPClient(imemReq, imemResp);

    method Action start(Addr startPc);
        running <= True;
        pc <= startPc;
        state <= IMMU;
        csrState <= defaultValue;
        if (verbose) $fdisplay(fout, "[frontend] starting from pc = 0x%08x", startPc);
    endmethod
    method Action stop;
        running <= False;
        state <= Wait;
    endmethod

    interface Client dvat = toGPClient(dmmuReq, dmmuResp);
    interface Client dmem = toGPClient(dmemReq, dmemResp);
    interface Client htif = toGPClient(toHost, fromHost);

    method Action configure(Data miobase);
        csrf.configure(miobase);
    endmethod
    method ActionValue#(VerificationPacket) getVerificationPacket;
        let verificationPacket = verificationPackets.first;
        verificationPackets.deq;
        return verificationPacket;
    endmethod

    method ActionValue#(VMInfo) updateVMInfoI;
        return csrf.vmI;
    endmethod
    method ActionValue#(VMInfo) updateVMInfoD;
        return csrf.vmD;
    endmethod
endmodule

import ClientServer::*;
import Connectable::*;
import DefaultValue::*;
import FIFO::*;
import GetPut::*;
import Vector::*;

import Abstraction::*;
import RVRFile::*;
import RVCsrFile::*;
import RVExec::*;
import RVFpu::*;
import RVMulDiv::*;
import RVTypes::*;
import VerificationPacket::*;

import RVAlu::*;
import RVControl::*;
import RVDecode::*;
import RVMemory::*;

// This interface is the combination of FrontEnd and BackEnd
interface Core;
    method Action start(Addr startPc);
    method Action stop;

    method Action configure(Data miobase);
    method ActionValue#(VerificationPacket) getVerificationPacket;
    method ActionValue#(VMInfo) updateVMInfoI;
    method ActionValue#(VMInfo) updateVMInfoD;

    interface Client#(RVIMMUReq, RVIMMUResp) ivat;
    interface Client#(RVIMemReq, RVIMemResp) ifetch;
    interface Client#(RVDMMUReq, RVDMMUResp) dvat;
    interface Client#(RVDMemReq, RVDMemResp) dmem;
    interface Client#(FenceReq, FenceResp) fence;
    interface Client#(Data, Data) htif;
endinterface

instance Connectable#(Core, MemorySystem);
    module mkConnection#(Core core, MemorySystem mem)(Empty);
        mkConnection(core.ivat, mem.ivat);
        mkConnection(core.ifetch, mem.ifetch);
        mkConnection(core.dvat, mem.dvat);
        mkConnection(core.dmem, mem.dmem);
        mkConnection(core.fence, mem.fence);
        mkConnection(toGet(core.updateVMInfoI), toPut(mem.updateVMInfoI));
        mkConnection(toGet(core.updateVMInfoD), toPut(mem.updateVMInfoD));
    endmodule
endinstance

typedef enum {
    Wait,
    IMMU,
    IF,
    Dec,
    RegRead,
    Execute,
    Mem,
    WB,
    Trap,
    Trap2
} ProcState deriving (Bits, Eq, FShow);

(* synthesize *)
module mkMulticycleCore(Core);
    let verbose = False;
    File fout = stdout;

    ArchRFile rf <- mkArchRFile;
    RVCsrFile csrf <- mkRVCsrFile;
    MulDivExec mulDiv <- mkBoothRoughMulDivExec;
    FpuExec fpu <- mkFpuExecPipeline;

    Reg#(Bool) htifStall <- mkReg(False);
    Reg#(Bool) running <- mkReg(False);
    Reg#(ProcState) state <- mkReg(Wait);

    Reg#(Addr) pc <- mkReg(0);
    Reg#(Maybe#(ExceptionCause)) exception <- mkReg(tagged Invalid);
    Reg#(Instruction) inst <- mkReg(0);
    Reg#(RVDecodedInst) dInst <- mkReg(unpack(0));
    Reg#(FrontEndCsrs) csrState <- mkReadOnlyReg( FrontEndCsrs { vmI: csrf.vmI, state: csrf.csrState } );

    FIFO#(RVIMMUReq)    immuReq <- mkFIFO1;
    FIFO#(RVIMMUResp)   immuResp <- mkFIFO1;

    FIFO#(RVIMemReq)    imemReq <- mkFIFO1;
    FIFO#(RVIMemResp)   imemResp <- mkFIFO1;

    Reg#(Data) rVal1 <- mkReg(0);
    Reg#(Data) rVal2 <- mkReg(0);
    Reg#(Data) rVal3 <- mkReadOnlyReg(0);
    Reg#(Data) data <- mkReg(0);
    Reg#(Data) addr <- mkReg(0);
    Reg#(Data) nextPc <- mkReg(0);

    FIFO#(RVDMMUReq)    dmmuReq <- mkFIFO1;
    FIFO#(RVDMMUResp)   dmmuResp <- mkFIFO1;

    FIFO#(RVDMemReq)    dmemReq <- mkFIFO1;
    FIFO#(RVDMemResp)   dmemResp <- mkFIFO1;

    FIFO#(Data)         toHost <- mkFIFO1;
    FIFO#(Data)         fromHost <- mkFIFO1;

    FIFO#(VerificationPacket) verificationPackets <- mkFIFO1;

    rule doInstMMU(running && state == IMMU);
        // request address translation from MMU
        immuReq.enq(pc);
        // reset states
        inst <= unpack(0);
        dInst <= unpack(0);
        exception <= tagged Invalid;
        // go to InstFetch stage
        state <= IF;
    endrule

    rule doInstFetch(state == IF);
        // I wanted notation like this:
        // let {addr: .phyPc, exception: .exMMU} = mmuResp.first;

        let phyPc = immuResp.first.addr;
        let exMMU = immuResp.first.exception;
        immuResp.deq;

        if (!isValid(exMMU)) begin
            // no translation exception
            imemReq.enq(phyPc);
            // go to decode stage
            state <= Dec;
        end else begin
            // translation exception (instruction access fault)
            exception <= exMMU;
            // send instruction to backend
            state <= Trap;
        end
    endrule

    rule doDecode(state == Dec);
        let fInst = imemResp.first;
        imemResp.deq;

        let decInst = decodeInst(fInst);

        if (decInst matches tagged Valid .validDInst) begin
            // Legal instruction
            dInst <= validDInst;
        end else begin
            // Illegal instruction
            exception <= tagged Valid IllegalInst;
        end

        inst <= fInst;
        state <= isValid(decInst) ? RegRead : Trap;
    endrule

    rule doRegRead(!htifStall && state == RegRead);
        rVal1 <= rf.rd1(fromMaybe(Gpr, dInst.rs1), getInstFields(inst).rs1);
        rVal2 <= rf.rd2(fromMaybe(Gpr, dInst.rs2), getInstFields(inst).rs2);
        rVal3 <= rf.rd3(fromMaybe(Gpr, dInst.rs3), getInstFields(inst).rs3);
        state <= Execute;
    endrule

    rule doExecute(state == Execute);
        let dataEx = 0;
        let addrEx = 0;
        let nextPcEx = pc + 4;

        Maybe#(Data) imm = getImmediate(dInst.imm, dInst.inst);
        case (dInst.execFunc) matches
            tagged Alu    .aluInst:
                begin
                    dataEx = execAluInst(aluInst, rVal1, rVal2, imm, pc);
                end
            tagged Br     .brFunc:
                begin
                    // data for jal
                    dataEx = pc + 4;
                    nextPcEx = execControl(brFunc, rVal1, rVal2, imm, pc);
                end
            tagged Mem    .memInst:
                begin
                    // data for store and AMO
                    dataEx = rVal2;
                    addrEx = addrCalc(rVal1, imm);
                    dmmuReq.enq(RVDMMUReq {addr: addrEx, size: memInst.size, op: (memInst.op matches tagged Mem .memOp ? memOp : St)});
                end
            tagged MulDiv .mulDivInst: mulDiv.exec(mulDivInst, rVal1, rVal2);
            tagged Fence  .fenceInst:  noAction;
            // TODO: Handle dynamic rounding mode
            tagged Fpu    .fpuInst:    fpu.exec(fpuInst, getInstFields(inst).rm, rVal1, rVal2, rVal3);
            tagged System .systemInst:
                begin
                    // data for CSR instructions
                    dataEx = fromMaybe(rVal1, imm);
                end
        endcase

        data <= dataEx;
        addr <= addrEx;
        nextPc <= nextPcEx;

        state <= dInst.execFunc matches tagged Mem .* ? Mem : WB;
    endrule

    rule doMem(state == Mem);
        let pAddr = dmmuResp.first.addr;
        let exMMU = dmmuResp.first.exception;
        dmmuResp.deq;

        // TODO: make this type safe! get rid of .Mem accesses to tagged union
        if (!isValid(exMMU)) begin
            dmemReq.enq( RVDMemReq {
                    op: dInst.execFunc.Mem.op,
                    byteEn: toByteEn(dInst.execFunc.Mem.size),
                    addr: pAddr,
                    data: data,
                    unsignedLd: isUnsigned(dInst.execFunc.Mem.size) } );
            state <= WB;
        end else begin
            exception <= exMMU;
            state <= Trap;
        end
    endrule

    rule doWB(state == WB);
        let dataWb = data;
        let addrWb = addr;
        let nextPcWb = nextPc;
        let fflagsWb = 0;
        let exceptionWB = exception;

        case(dInst.execFunc) matches
            tagged MulDiv .*: begin
                    dataWb = mulDiv.result_data();
                    mulDiv.result_deq;
                end
            tagged Fpu .*: begin
                    let fpuResult = toFullResult(fpu.result_data);
                    dataWb = fpuResult.data;
                    fflagsWb = fpuResult.fflags;
                    fpu.result_deq;
                end
            tagged Mem .memInst:
                begin
                    if (getsResponse(memInst.op)) begin
                        dataWb = dmemResp.first;
                        dmemResp.deq;
                    end
                end
        endcase

        // TODO: add comment
        Bool extensionDirty = False;
        Bool fpuDirty = (dInst.dst == tagged Valid Fpu);
        let {maybeTrap, maybeData, maybeNextPc} <- csrf.wr(
                // performing system instructions
                dInst.execFunc matches tagged System .sysInst ? tagged Valid sysInst : tagged Invalid,
                getInstFields(inst).csr,
                dataWb,  // either rf[rs1] or zimm, computed in basicExec
                // handling exceptions
                exceptionWB,    // exception cause
                pc,             // for writing to mepc/sepc
                dInst.execFunc matches tagged Br .* ? True : False, // check inst allignment if Br Func
                dInst.execFunc matches tagged Br .* ? nextPcWb : addrWb, // either data address or next PC, used to detect misaligned instruction addresses
                // indirect writes
                fflagsWb,
                fpuDirty,
                extensionDirty);

        // send verification packet
        verificationPackets.enq( VerificationPacket {
                skippedPackets: 0,
                pc: pc,
                nextPc: fromMaybe(nextPcWb, maybeNextPc),
                data: fromMaybe(dataWb, maybeData),
                instruction: inst,
                dst: {pack(dInst.dst), getInstFields(inst).rd},
                trap: isValid(maybeTrap),
                trapType: (case (fromMaybe(unpack(0), maybeTrap)) matches
                        tagged Exception .x: (zeroExtend(pack(x)));
                        tagged Interrupt .x: (zeroExtend(pack(x)) | 8'h80);
                    endcase) });

        if (maybeNextPc matches tagged Valid .replayPc) begin
            // This instruction didn't retire

            // redirect happens in Trap2
            nextPc <= replayPc;
            state <= Trap2;
        end else begin
            // This instruction retired
            if (dInst.dst matches tagged Valid .dstRegType) begin
                // Use data from CSR if available
                rf.wr(dstRegType, getInstFields(inst).rd, fromMaybe(dataWb, maybeData));
            end
            // always redirect
            pc <= nextPc;
            state <= IMMU;
        end
    endrule

    rule doTrap(state == Trap);
        // TODO: move this to WB
        let {maybeTrap, maybeData, maybeNextPc} <- csrf.wr(
                tagged Invalid,
                getInstFields(inst).csr,
                0, // data
                exception, // exception cause
                pc, // pc
                False,
                addr, // vaddr
                0,
                False,
                False);

        // send verification packet
        verificationPackets.enq( VerificationPacket {
                skippedPackets: 0,
                pc: pc,
                nextPc: fromMaybe(?, maybeNextPc),
                data: fromMaybe(data, maybeData),
                instruction: inst,
                dst: {pack(dInst.dst), getInstFields(inst).rd},
                trap: isValid(maybeTrap),
                trapType: (case (fromMaybe(unpack(0), maybeTrap)) matches
                        tagged Exception .x: (zeroExtend(pack(x)));
                        tagged Interrupt .x: (zeroExtend(pack(x)) | 8'h80);
                    endcase) });

        // redirection will happpen in trap2
        // by construction maybeNextPc is always valid
        nextPc <= fromMaybe(nextPc, maybeNextPc);
        state <= Trap2;
    endrule

    // There is a second trap state to ensure that the frontEndCsrs reflect the updated state of the processor
    rule doTrap2(state == Trap2);
        pc <= nextPc;
        state <= IMMU;
    endrule

    rule htifToHost;
        let msg <- csrf.csrfToHost;
        if (truncateLSB(msg) != 16'h0100) begin
            htifStall <= True;
        end
        toHost.enq(msg);
    endrule

    rule htifFromHost;
        htifStall <= False;
        let msg = fromHost.first;
        fromHost.deq;
        csrf.hostToCsrf(msg);
    endrule

    interface Client ivat = toGPClient(immuReq, immuResp);
    interface Client ifetch = toGPClient(imemReq, imemResp);

    method Action start(Addr startPc);
        running <= True;
        pc <= startPc;
        state <= IMMU;
        csrState <= defaultValue;
        if (verbose) $fdisplay(fout, "[frontend] starting from pc = 0x%08x", startPc);
    endmethod
    method Action stop;
        running <= False;
        state <= Wait;
    endmethod

    interface Client dvat = toGPClient(dmmuReq, dmmuResp);
    interface Client dmem = toGPClient(dmemReq, dmemResp);
    interface Client htif = toGPClient(toHost, fromHost);

    method Action configure(Data miobase);
        csrf.configure(miobase);
    endmethod
    method ActionValue#(VerificationPacket) getVerificationPacket;
        let verificationPacket = verificationPackets.first;
        verificationPackets.deq;
        return verificationPacket;
    endmethod

    method ActionValue#(VMInfo) updateVMInfoI;
        return csrf.vmI;
    endmethod
    method ActionValue#(VMInfo) updateVMInfoD;
        return csrf.vmD;
    endmethod
endmodule


Added KC705 specific definitions for JtagTap

package JtagTap;

import BUtils ::*;
import Clocks ::*;
import DefaultValue ::*;
import FIFOF ::*;
import FIFOLevel ::*;
import Reserved ::*;

import Giraffe_IFC ::*;

typedef 6 ABITS;
`ifdef XILINX_BSCAN
`ifdef XILINX_XCVU095
typedef 6 IR_LENGTH;
`elsif XILINX_XCVU9P
typedef 18 IR_LENGTH;
`elsif XILINX_XC7K325T
typedef 6 IR_LENGTH;
`endif
`else
typedef 5 IR_LENGTH;
`endif
typedef TAdd#(ABITS,34) DR_LENGTH;
Bit#(IR_LENGTH) irmask = zExtendLSB(1'b1);
Bit#(IR_LENGTH) ir_bypass0 = 0;
Bit#(IR_LENGTH) ir_idcode = 1;
`ifdef XILINX_BSCAN
`ifdef XILINX_XCVU095
Bit#(IR_LENGTH) ir_dtmcs = 'h02;
Bit#(IR_LENGTH) ir_dmi = 'h03;
`elsif XILINX_XCVU9P

Bit#(IR_LENGTH) ir_dtmcs = 'b100010100100100100;    // USER3
                        // 'b000010100100100100;    USER1

Bit#(IR_LENGTH) ir_dmi = 'b000011100100100100;
`elsif XILINX_XC7K325T
Bit#(IR_LENGTH) ir_dtmcs = 'h22;
Bit#(IR_LENGTH) ir_dmi = 'h03;
`endif
`else
Bit#(IR_LENGTH) ir_dtmcs = 'h10;
Bit#(IR_LENGTH) ir_dmi = 'h11;
`endif
Bit#(IR_LENGTH) ir_reserved12 = 'h12;
Bit#(IR_LENGTH) ir_reserved13 = 'h13;
Bit#(IR_LENGTH) ir_reserved14 = 'h14;
Bit#(IR_LENGTH) ir_reserved15 = 'h15;
Bit#(IR_LENGTH) ir_reserved16 = 'h16;
Bit#(IR_LENGTH) ir_reserved17 = 'h17;
Bit#(IR_LENGTH) ir_bypass1f = '1;
Bit#(32) idcode = 'h00000ffd;
Bit#(DR_LENGTH) drmask_bypass = 1;
Bit#(DR_LENGTH) drmask_idcode = 1<<31;
Bit#(DR_LENGTH) drmask_dtmcs = 1<<31;
Bit#(DR_LENGTH) drmask_dmi = zExtendLSB(1'b1);

typedef enum {
   TEST_LOGIC_RESET,
   RUN_TEST_IDLE,
   SELECT_DR_SCAN,
   CAPTURE_DR,
   SHIFT_DR,
   EXIT1_DR,
   PAUSE_DR,
   EXIT2_DR,
   UPDATE_DR,
   SELECT_IR_SCAN,
   CAPTURE_IR,
   SHIFT_IR,
   EXIT1_IR,
   PAUSE_IR,
   EXIT2_IR,
   UPDATE_IR
   } JtagState deriving (Bits, Eq, FShow);

typedef struct {
   ReservedZero#(14) reserved;
   Bit#(1) dmihardreset;
   Bit#(1) dmireset;
   ReservedZero#(1) reserved2;
   Bit#(3) idle;
   Bit#(2) dmistat;
   Bit#(6) abits;
   Bit#(4) version;
   } DTMCS deriving (Bits, Eq, FShow);

instance DefaultValue#(DTMCS);
   defaultValue = DTMCS {
      reserved: ?,
      dmihardreset: 0,
      dmireset: 0,
      reserved2: ?,
      idle: 0,
      dmistat: 0,
      abits: fromInteger(valueOf(ABITS)),
      version: 1
      };
endinstance

// This would be an enum, but bsv doens't allow more than one tag for
// a particular value.
typedef Bit#(2) DMI_OP;
DMI_OP opNOP = 0;
DMI_OP opREAD = 1;
DMI_OP opWRITE = 2;
DMI_OP opRESERVED = 3;
DMI_OP opSUCCESS = 0;
DMI_OP opFAILED = 2;
DMI_OP opBUSY = 3;

typedef struct {
   Bit#(6) address;
   Bit#(32) data;
   DMI_OP op;
   } DMI deriving (Bits, Eq, FShow);

instance DefaultValue#(DMI);
   defaultValue = unpack(0);
endinstance

function Bool f_dmi_stuck(DMI dmi);
   case (dmi.op)
      opFAILED, opBUSY: return True;
      default: return False;
   endcase
endfunction

function JtagState f_next_state(JtagState state, Bit#(1) tms);
   if (tms == 0)
      case (state)
	 TEST_LOGIC_RESET: return RUN_TEST_IDLE;
	 RUN_TEST_IDLE: return RUN_TEST_IDLE;
	 SELECT_DR_SCAN: return CAPTURE_DR;
	 CAPTURE_DR: return SHIFT_DR;
	 SHIFT_DR: return SHIFT_DR;
	 EXIT1_DR: return PAUSE_DR;
	 PAUSE_DR: return PAUSE_DR;
	 EXIT2_DR: return SHIFT_DR;
	 UPDATE_DR: return RUN_TEST_IDLE;
	 SELECT_IR_SCAN: return CAPTURE_IR;
	 CAPTURE_IR: return SHIFT_IR;
	 SHIFT_IR: return SHIFT_IR;
	 EXIT1_IR: return PAUSE_IR;
	 PAUSE_IR: return PAUSE_IR;
	 EXIT2_IR: return SHIFT_IR;
	 UPDATE_IR: return RUN_TEST_IDLE;
      endcase
   else
      case (state)
	 TEST_LOGIC_RESET: return TEST_LOGIC_RESET;
	 RUN_TEST_IDLE: return SELECT_DR_SCAN;
	 SELECT_DR_SCAN: return SELECT_IR_SCAN;
	 CAPTURE_DR: return EXIT1_DR;
	 SHIFT_DR: return EXIT1_DR;
	 EXIT1_DR: return UPDATE_DR;
	 PAUSE_DR: return EXIT2_DR;
	 EXIT2_DR: return UPDATE_DR;
	 UPDATE_DR: return SELECT_DR_SCAN;
	 SELECT_IR_SCAN: return TEST_LOGIC_RESET;
	 CAPTURE_IR: return EXIT1_IR;
	 SHIFT_IR: return EXIT1_IR;
	 EXIT1_IR: return UPDATE_IR;
	 PAUSE_IR: return EXIT2_IR;
	 EXIT2_IR: return UPDATE_IR;
	 UPDATE_IR: return SELECT_DR_SCAN;
      endcase
endfunction

interface JtagTap_IFC;
   interface JTAG_IFC jtag;
   interface DMI_Master_IFC dmi;
endinterface

(* synthesize *)
module mkJtagTap(JtagTap_IFC);
   let clk <- exposeCurrentClock;
   let rst <- exposeCurrentReset;

   Wire#(Bit#(1)) w_tck <- mkDWire(?);

   let tck_clock <- mkUngatedClock(?);
   let tck = tck_clock.new_clk;

   (* no_implicit_conditions, fire_when_enabled *)
   rule rl_tck;
      tck_clock.setClockValue(w_tck);
   endrule

   let rst_tck <- mkAsyncResetFromCR(4, tck);

   Wire#(Bit#(1)) w_tms <- mkDWire(?, clocked_by tck, reset_by rst_tck);
   Wire#(Bit#(1)) w_tdi <- mkDWire(?, clocked_by tck, reset_by rst_tck);

   Wire#(Bit#(1)) w_req_ready <- mkWire;
   Wire#(Bit#(1)) w_req_valid <- mkDWire(0);
   Wire#(Bit#(7)) w_req_addr <- mkDWire(?);
   Wire#(Bit#(32)) w_req_data <- mkDWire(?);
   Wire#(Bit#(2)) w_req_op <- mkDWire(?);
   Wire#(Bit#(1)) w_rsp_ready <- mkDWire(0);
   Wire#(Bit#(1)) w_rsp_valid <- mkWire;
   Wire#(Bit#(32)) w_rsp_data <- mkDWire(?);
   Wire#(Bit#(2)) w_rsp_response <- mkDWire(?);

   Array#(Reg#(Bit#(1))) r_tdo <- mkCRegU(2, clocked_by tck, reset_by rst_tck);

   Reg#(JtagState) r_state <- mkReg(TEST_LOGIC_RESET, clocked_by tck, reset_by rst_tck);

   Reg#(Bit#(IR_LENGTH)) r_ir <- mkRegU(clocked_by tck, reset_by rst_tck);
   Reg#(Bit#(DR_LENGTH)) r_dr <- mkRegU(clocked_by tck, reset_by rst_tck);
   Reg#(Bit#(DR_LENGTH)) r_drmask <- mkRegU(clocked_by tck, reset_by rst_tck);

   Reg#(DMI) r_dmi <- mkReg(defaultValue, clocked_by tck, reset_by rst_tck);

   Wire#(Tuple3#(Bit#(7),Bit#(32),Bit#(2))) w_dmi_req <- mkWire(clocked_by tck, reset_by rst_tck);
   SyncFIFOLevelIfc#(Tuple3#(Bit#(7),Bit#(32),Bit#(2)), 2) f_dmi_req <- mkSyncFIFOLevel(tck, rst_tck, clk);
   FIFOF#(void) f_dmi_busy <- mkFIFOF(clocked_by tck, reset_by rst_tck);
   Wire#(Bool) w_dmi_reset <- mkWire(clocked_by tck, reset_by rst_tck);
   Array#(Reg#(Bool)) r_dmistat_busy <- mkCReg(2, False, clocked_by tck, reset_by rst_tck);
   SyncFIFOLevelIfc#(DMI, 2) f_dmi_rsp <- mkSyncFIFOLevel(clk, rst, tck);

   (* no_implicit_conditions, fire_when_enabled *)
   rule tick;
      let newir = r_ir;
      let newdr = r_dr;
      let newdrmask = r_drmask;

      if (r_state == TEST_LOGIC_RESET) begin
	 newir = ir_idcode;
      end
      else if (r_state == CAPTURE_DR) begin
	 if (newir == ir_bypass0 ||
	     newir == ir_reserved12 ||
	     newir == ir_reserved13 ||
	     newir == ir_reserved14 ||
	     newir == ir_reserved15 ||
	     newir == ir_reserved16 ||
	     newir == ir_reserved17 ||
	     newir == ir_bypass1f) begin
            newdr = 0;
	 end
	 else if (newir == ir_idcode) begin
	    newdr = cExtend(idcode);
	    //newdrmask = drmask_idcode;
	 end
	 else if (newir == ir_dtmcs) begin
	    DTMCS dtmcs = defaultValue;
	    dtmcs.dmistat = cExtend(r_dmi.op);
	    newdr = cExtend(dtmcs);
	    //newdrmask = drmask_dtmcs;
	 end
	 else if (newir == ir_dmi) begin
	    if (r_dmistat_busy[0] || (!f_dmi_stuck(r_dmi) && f_dmi_busy.notEmpty))
	       newdr = cExtend(DMI { address: ?, data: ?, op: opBUSY });
	    else
	       newdr = cExtend(r_dmi);

	    //newdrmask = drmask_dmi;
	 end
	 else begin
	    $display("WARNING: unsupported IR: 'h%x\n", newir);
	    newdr = cExtend(newir) | 'hf << 24;
	 end
      end
      else if (r_state == SHIFT_DR) begin
	 r_tdo[0] <= truncate(newdr);
	 newdr = (newdr >> 1) | (w_tdi == 1 ? r_drmask : 0);
      end
      else if (r_state == UPDATE_DR) begin
	 if (newir == ir_dtmcs) begin
	    /// \todo is this what the debug spec means by "write dtmcs"?
	    DTMCS dtmcs = cExtend(newdr);
	    if (dtmcs.dmihardreset == 1)
	       w_dmi_reset <= True;
	    else if (dtmcs.dmireset == 1)
	       w_dmi_reset <= False;
	 end
	 else if (newir == ir_dmi) begin
	    if (f_dmi_stuck(r_dmi)) begin
	       // drop request
	       noAction;
	    end
	    else if (f_dmi_busy.notEmpty) begin
	       // busy
	       r_dmistat_busy[0] <= True;
	    end
	    else begin
	       // issue request
	       w_dmi_req <= cExtend(newdr);
	    end
	 end
      end
      else if (r_state == SHIFT_IR) begin
	 r_tdo[0] <= truncate(newir);
	 newir = (newir >> 1) | (w_tdi == 1 ? irmask : 0);
      end

      // bsc complains if this is written above in the more logical way
      if (r_state == CAPTURE_DR) begin
	 if (newir == ir_bypass0 ||
	     newir == ir_reserved12 ||
	     newir == ir_reserved13 ||
	     newir == ir_reserved14 ||
	     newir == ir_reserved15 ||
	     newir == ir_reserved16 ||
	     newir == ir_reserved17 ||
	     newir == ir_bypass1f)
	    newdrmask = drmask_bypass;
	 else if (newir == ir_idcode)
	    newdrmask = drmask_idcode;
	 else if (newir == ir_dtmcs)
	    newdrmask = drmask_dtmcs;
	 else if (newir == ir_dmi)
	    newdrmask = drmask_dmi;
	 else
	    newdrmask = 1<<32;
      end

      r_state <= f_next_state(r_state, w_tms);
      r_ir <= newir;
      r_dr <= newdr;
      r_drmask <= newdrmask;
   endrule

   (* fire_when_enabled *)
   rule dmi_reset;
      let tmp = w_dmi_reset;
      if (tmp) begin
	 f_dmi_req.sClear;
	 f_dmi_rsp.dClear;
	 f_dmi_busy.clear;
      end
      r_dmistat_busy[1] <= False;
   endrule

   (* fire_when_enabled *)
   rule dmi_start(tpl_3(w_dmi_req) != opNOP);
      f_dmi_req.enq(w_dmi_req);
      f_dmi_busy.enq(?);
   endrule

   rule dmi_request;
      match {.addr, .data, .op} = f_dmi_req.first;
      w_req_addr <= addr;
      w_req_data <= data;
      w_req_op <= op;
   endrule

   rule dmi_request_valid;
      w_req_valid <= f_dmi_req.dNotEmpty ? 1 : 0;
   endrule

   rule dmi_request_deq(w_req_ready == 1 && w_req_valid == 1);
      f_dmi_req.deq;
   endrule

   rule dmi_response(w_rsp_valid == 1 && w_rsp_ready == 1);
      let newdmi = DMI {
	 address: ?,
	 data: w_rsp_data,
	 op: w_rsp_response
	 };

      f_dmi_rsp.enq(newdmi);
   endrule

   rule dmi_response_tck;
      let newdmi = f_dmi_rsp.first;
      f_dmi_rsp.deq;

      if (!f_dmi_stuck(r_dmi))
	 r_dmi <= newdmi;

      f_dmi_busy.deq;
   endrule

   rule dmi_response_ready;
      w_rsp_ready <= f_dmi_rsp.sNotFull ? 1 : 0;
   endrule

   interface JTAG_IFC jtag;
      method tclk = w_tck._write;
      method tms = w_tms._write;
      method tdi = w_tdi._write;
      method tdo = r_tdo[1];
      interface tclk_out = tck;
   endinterface

   interface DMI_Master_IFC dmi;
      method req_ready = w_req_ready._write;
      method req_valid = w_req_valid;
      method req_addr = w_req_addr;
      method req_data = w_req_data;
      method req_op = w_req_op;
      method rsp_ready = w_rsp_ready;
      method rsp_valid = w_rsp_valid._write;
      method rsp_data = w_rsp_data._write;
      method rsp_response = w_rsp_response._write;
   endinterface

endmodule

endpackage

package JtagTap;

import BUtils ::*;
import Clocks ::*;
import DefaultValue ::*;
import FIFOF ::*;
import FIFOLevel ::*;
import Reserved ::*;

import Giraffe_IFC ::*;

typedef 6 ABITS;
`ifdef XILINX_BSCAN
`ifdef XILINX_XCVU095
typedef 6 IR_LENGTH;
`elsif XILINX_XCVU9P
typedef 18 IR_LENGTH;
`endif
`else
typedef 5 IR_LENGTH;
`endif
typedef TAdd#(ABITS,34) DR_LENGTH;
Bit#(IR_LENGTH) irmask = zExtendLSB(1'b1);
Bit#(IR_LENGTH) ir_bypass0 = 0;
Bit#(IR_LENGTH) ir_idcode = 1;
`ifdef XILINX_BSCAN
`ifdef XILINX_XCVU095
Bit#(IR_LENGTH) ir_dtmcs = 'h02;
Bit#(IR_LENGTH) ir_dmi = 'h03;
`elsif XILINX_XCVU9P

Bit#(IR_LENGTH) ir_dtmcs = 'b100010100100100100;    // USER3
                        // 'b000010100100100100;    USER1

Bit#(IR_LENGTH) ir_dmi = 'b000011100100100100;
`endif
`else
Bit#(IR_LENGTH) ir_dtmcs = 'h10;
Bit#(IR_LENGTH) ir_dmi = 'h11;
`endif
Bit#(IR_LENGTH) ir_reserved12 = 'h12;
Bit#(IR_LENGTH) ir_reserved13 = 'h13;
Bit#(IR_LENGTH) ir_reserved14 = 'h14;
Bit#(IR_LENGTH) ir_reserved15 = 'h15;
Bit#(IR_LENGTH) ir_reserved16 = 'h16;
Bit#(IR_LENGTH) ir_reserved17 = 'h17;
Bit#(IR_LENGTH) ir_bypass1f = '1;
Bit#(32) idcode = 'h00000ffd;
Bit#(DR_LENGTH) drmask_bypass = 1;
Bit#(DR_LENGTH) drmask_idcode = 1<<31;
Bit#(DR_LENGTH) drmask_dtmcs = 1<<31;
Bit#(DR_LENGTH) drmask_dmi = zExtendLSB(1'b1);

typedef enum {
   TEST_LOGIC_RESET,
   RUN_TEST_IDLE,
   SELECT_DR_SCAN,
   CAPTURE_DR,
   SHIFT_DR,
   EXIT1_DR,
   PAUSE_DR,
   EXIT2_DR,
   UPDATE_DR,
   SELECT_IR_SCAN,
   CAPTURE_IR,
   SHIFT_IR,
   EXIT1_IR,
   PAUSE_IR,
   EXIT2_IR,
   UPDATE_IR
   } JtagState deriving (Bits, Eq, FShow);

typedef struct {
   ReservedZero#(14) reserved;
   Bit#(1) dmihardreset;
   Bit#(1) dmireset;
   ReservedZero#(1) reserved2;
   Bit#(3) idle;
   Bit#(2) dmistat;
   Bit#(6) abits;
   Bit#(4) version;
   } DTMCS deriving (Bits, Eq, FShow);

instance DefaultValue#(DTMCS);
   defaultValue = DTMCS {
      reserved: ?,
      dmihardreset: 0,
      dmireset: 0,
      reserved2: ?,
      idle: 0,
      dmistat: 0,
      abits: fromInteger(valueOf(ABITS)),
      version: 1
      };
endinstance

// This would be an enum, but bsv doens't allow more than one tag for
// a particular value.
typedef Bit#(2) DMI_OP;
DMI_OP opNOP = 0;
DMI_OP opREAD = 1;
DMI_OP opWRITE = 2;
DMI_OP opRESERVED = 3;
DMI_OP opSUCCESS = 0;
DMI_OP opFAILED = 2;
DMI_OP opBUSY = 3;

typedef struct {
   Bit#(6) address;
   Bit#(32) data;
   DMI_OP op;
   } DMI deriving (Bits, Eq, FShow);

instance DefaultValue#(DMI);
   defaultValue = unpack(0);
endinstance

function Bool f_dmi_stuck(DMI dmi);
   case (dmi.op)
      opFAILED, opBUSY: return True;
      default: return False;
   endcase
endfunction

function JtagState f_next_state(JtagState state, Bit#(1) tms);
   if (tms == 0)
      case (state)
	 TEST_LOGIC_RESET: return RUN_TEST_IDLE;
	 RUN_TEST_IDLE: return RUN_TEST_IDLE;
	 SELECT_DR_SCAN: return CAPTURE_DR;
	 CAPTURE_DR: return SHIFT_DR;
	 SHIFT_DR: return SHIFT_DR;
	 EXIT1_DR: return PAUSE_DR;
	 PAUSE_DR: return PAUSE_DR;
	 EXIT2_DR: return SHIFT_DR;
	 UPDATE_DR: return RUN_TEST_IDLE;
	 SELECT_IR_SCAN: return CAPTURE_IR;
	 CAPTURE_IR: return SHIFT_IR;
	 SHIFT_IR: return SHIFT_IR;
	 EXIT1_IR: return PAUSE_IR;
	 PAUSE_IR: return PAUSE_IR;
	 EXIT2_IR: return SHIFT_IR;
	 UPDATE_IR: return RUN_TEST_IDLE;
      endcase
   else
      case (state)
	 TEST_LOGIC_RESET: return TEST_LOGIC_RESET;
	 RUN_TEST_IDLE: return SELECT_DR_SCAN;
	 SELECT_DR_SCAN: return SELECT_IR_SCAN;
	 CAPTURE_DR: return EXIT1_DR;
	 SHIFT_DR: return EXIT1_DR;
	 EXIT1_DR: return UPDATE_DR;
	 PAUSE_DR: return EXIT2_DR;
	 EXIT2_DR: return UPDATE_DR;
	 UPDATE_DR: return SELECT_DR_SCAN;
	 SELECT_IR_SCAN: return TEST_LOGIC_RESET;
	 CAPTURE_IR: return EXIT1_IR;
	 SHIFT_IR: return EXIT1_IR;
	 EXIT1_IR: return UPDATE_IR;
	 PAUSE_IR: return EXIT2_IR;
	 EXIT2_IR: return UPDATE_IR;
	 UPDATE_IR: return SELECT_DR_SCAN;
      endcase
endfunction

interface JtagTap_IFC;
   interface JTAG_IFC jtag;
   interface DMI_Master_IFC dmi;
endinterface

(* synthesize *)
module mkJtagTap(JtagTap_IFC);
   let clk <- exposeCurrentClock;
   let rst <- exposeCurrentReset;

   Wire#(Bit#(1)) w_tck <- mkDWire(?);

   let tck_clock <- mkUngatedClock(?);
   let tck = tck_clock.new_clk;

   (* no_implicit_conditions, fire_when_enabled *)
   rule rl_tck;
      tck_clock.setClockValue(w_tck);
   endrule

   let rst_tck <- mkAsyncResetFromCR(4, tck);

   Wire#(Bit#(1)) w_tms <- mkDWire(?, clocked_by tck, reset_by rst_tck);
   Wire#(Bit#(1)) w_tdi <- mkDWire(?, clocked_by tck, reset_by rst_tck);

   Wire#(Bit#(1)) w_req_ready <- mkWire;
   Wire#(Bit#(1)) w_req_valid <- mkDWire(0);
   Wire#(Bit#(7)) w_req_addr <- mkDWire(?);
   Wire#(Bit#(32)) w_req_data <- mkDWire(?);
   Wire#(Bit#(2)) w_req_op <- mkDWire(?);
   Wire#(Bit#(1)) w_rsp_ready <- mkDWire(0);
   Wire#(Bit#(1)) w_rsp_valid <- mkWire;
   Wire#(Bit#(32)) w_rsp_data <- mkDWire(?);
   Wire#(Bit#(2)) w_rsp_response <- mkDWire(?);

   Array#(Reg#(Bit#(1))) r_tdo <- mkCRegU(2, clocked_by tck, reset_by rst_tck);

   Reg#(JtagState) r_state <- mkReg(TEST_LOGIC_RESET, clocked_by tck, reset_by rst_tck);

   Reg#(Bit#(IR_LENGTH)) r_ir <- mkRegU(clocked_by tck, reset_by rst_tck);
   Reg#(Bit#(DR_LENGTH)) r_dr <- mkRegU(clocked_by tck, reset_by rst_tck);
   Reg#(Bit#(DR_LENGTH)) r_drmask <- mkRegU(clocked_by tck, reset_by rst_tck);

   Reg#(DMI) r_dmi <- mkReg(defaultValue, clocked_by tck, reset_by rst_tck);

   Wire#(Tuple3#(Bit#(7),Bit#(32),Bit#(2))) w_dmi_req <- mkWire(clocked_by tck, reset_by rst_tck);
   SyncFIFOLevelIfc#(Tuple3#(Bit#(7),Bit#(32),Bit#(2)), 2) f_dmi_req <- mkSyncFIFOLevel(tck, rst_tck, clk);
   FIFOF#(void) f_dmi_busy <- mkFIFOF(clocked_by tck, reset_by rst_tck);
   Wire#(Bool) w_dmi_reset <- mkWire(clocked_by tck, reset_by rst_tck);
   Array#(Reg#(Bool)) r_dmistat_busy <- mkCReg(2, False, clocked_by tck, reset_by rst_tck);
   SyncFIFOLevelIfc#(DMI, 2) f_dmi_rsp <- mkSyncFIFOLevel(clk, rst, tck);

   (* no_implicit_conditions, fire_when_enabled *)
   rule tick;
      let newir = r_ir;
      let newdr = r_dr;
      let newdrmask = r_drmask;

      if (r_state == TEST_LOGIC_RESET) begin
	 newir = ir_idcode;
      end
      else if (r_state == CAPTURE_DR) begin
	 if (newir == ir_bypass0 ||
	     newir == ir_reserved12 ||
	     newir == ir_reserved13 ||
	     newir == ir_reserved14 ||
	     newir == ir_reserved15 ||
	     newir == ir_reserved16 ||
	     newir == ir_reserved17 ||
	     newir == ir_bypass1f) begin
            newdr = 0;
	 end
	 else if (newir == ir_idcode) begin
	    newdr = cExtend(idcode);
	    //newdrmask = drmask_idcode;
	 end
	 else if (newir == ir_dtmcs) begin
	    DTMCS dtmcs = defaultValue;
	    dtmcs.dmistat = cExtend(r_dmi.op);
	    newdr = cExtend(dtmcs);
	    //newdrmask = drmask_dtmcs;
	 end
	 else if (newir == ir_dmi) begin
	    if (r_dmistat_busy[0] || (!f_dmi_stuck(r_dmi) && f_dmi_busy.notEmpty))
	       newdr = cExtend(DMI { address: ?, data: ?, op: opBUSY });
	    else
	       newdr = cExtend(r_dmi);

	    //newdrmask = drmask_dmi;
	 end
	 else begin
	    $display("WARNING: unsupported IR: 'h%x\n", newir);
	    newdr = cExtend(newir) | 'hf << 24;
	 end
      end
      else if (r_state == SHIFT_DR) begin
	 r_tdo[0] <= truncate(newdr);
	 newdr = (newdr >> 1) | (w_tdi == 1 ? r_drmask : 0);
      end
      else if (r_state == UPDATE_DR) begin
	 if (newir == ir_dtmcs) begin
	    /// \todo is this what the debug spec means by "write dtmcs"?
	    DTMCS dtmcs = cExtend(newdr);
	    if (dtmcs.dmihardreset == 1)
	       w_dmi_reset <= True;
	    else if (dtmcs.dmireset == 1)
	       w_dmi_reset <= False;
	 end
	 else if (newir == ir_dmi) begin
	    if (f_dmi_stuck(r_dmi)) begin
	       // drop request
	       noAction;
	    end
	    else if (f_dmi_busy.notEmpty) begin
	       // busy
	       r_dmistat_busy[0] <= True;
	    end
	    else begin
	       // issue request
	       w_dmi_req <= cExtend(newdr);
	    end
	 end
      end
      else if (r_state == SHIFT_IR) begin
	 r_tdo[0] <= truncate(newir);
	 newir = (newir >> 1) | (w_tdi == 1 ? irmask : 0);
      end

      // bsc complains if this is written above in the more logical way
      if (r_state == CAPTURE_DR) begin
	 if (newir == ir_bypass0 ||
	     newir == ir_reserved12 ||
	     newir == ir_reserved13 ||
	     newir == ir_reserved14 ||
	     newir == ir_reserved15 ||
	     newir == ir_reserved16 ||
	     newir == ir_reserved17 ||
	     newir == ir_bypass1f)
	    newdrmask = drmask_bypass;
	 else if (newir == ir_idcode)
	    newdrmask = drmask_idcode;
	 else if (newir == ir_dtmcs)
	    newdrmask = drmask_dtmcs;
	 else if (newir == ir_dmi)
	    newdrmask = drmask_dmi;
	 else
	    newdrmask = 1<<32;
      end

      r_state <= f_next_state(r_state, w_tms);
      r_ir <= newir;
      r_dr <= newdr;
      r_drmask <= newdrmask;
   endrule

   (* fire_when_enabled *)
   rule dmi_reset;
      let tmp = w_dmi_reset;
      if (tmp) begin
	 f_dmi_req.sClear;
	 f_dmi_rsp.dClear;
	 f_dmi_busy.clear;
      end
      r_dmistat_busy[1] <= False;
   endrule

   (* fire_when_enabled *)
   rule dmi_start(tpl_3(w_dmi_req) != opNOP);
      f_dmi_req.enq(w_dmi_req);
      f_dmi_busy.enq(?);
   endrule

   rule dmi_request;
      match {.addr, .data, .op} = f_dmi_req.first;
      w_req_addr <= addr;
      w_req_data <= data;
      w_req_op <= op;
   endrule

   rule dmi_request_valid;
      w_req_valid <= f_dmi_req.dNotEmpty ? 1 : 0;
   endrule

   rule dmi_request_deq(w_req_ready == 1 && w_req_valid == 1);
      f_dmi_req.deq;
   endrule

   rule dmi_response(w_rsp_valid == 1 && w_rsp_ready == 1);
      let newdmi = DMI {
	 address: ?,
	 data: w_rsp_data,
	 op: w_rsp_response
	 };

      f_dmi_rsp.enq(newdmi);
   endrule

   rule dmi_response_tck;
      let newdmi = f_dmi_rsp.first;
      f_dmi_rsp.deq;

      if (!f_dmi_stuck(r_dmi))
	 r_dmi <= newdmi;

      f_dmi_busy.deq;
   endrule

   rule dmi_response_ready;
      w_rsp_ready <= f_dmi_rsp.sNotFull ? 1 : 0;
   endrule

   interface JTAG_IFC jtag;
      method tclk = w_tck._write;
      method tms = w_tms._write;
      method tdi = w_tdi._write;
      method tdo = r_tdo[1];
      interface tclk_out = tck;
   endinterface

   interface DMI_Master_IFC dmi;
      method req_ready = w_req_ready._write;
      method req_valid = w_req_valid;
      method req_addr = w_req_addr;
      method req_data = w_req_data;
      method req_op = w_req_op;
      method rsp_ready = w_rsp_ready;
      method rsp_valid = w_rsp_valid._write;
      method rsp_data = w_rsp_data._write;
      method rsp_response = w_rsp_response._write;
   endinterface

endmodule

endpackage


remove dtp global wrapper

remove dtp global wrapper

/*
   /home/hwang/dev/sonic-lite/scripts/../../connectal//generated/scripts/importbvi.py
   -o
   DTP_GLOBAL_TIMESTAMP_WRAPPER.bsv
   -I
   DtpGlobalWrap
   -P
   DtpGlobalWrap
   -c
   clock
   -r
   reset
   -f
   timestamp
   ../verilog/timestamp/global_timestamp.sv
*/

import Clocks::*;
import DefaultValue::*;
import XilinxCells::*;
import GetPut::*;

(* always_ready, always_enabled *)
interface DtpglobalwrapTimestamp;
    method Bit#(53)     maximum();
    method Action      p0(Bit#(53) v);
    method Action      p1(Bit#(53) v);
    method Action      p2(Bit#(53) v);
    method Action      p3(Bit#(53) v);
endinterface
(* always_ready, always_enabled *)
interface DtpGlobalWrap;
    interface DtpglobalwrapTimestamp     timestamp;
endinterface
import "BVI" global_timestamp =
module mkDtpGlobalWrap#(Clock clock, Reset clock_reset, Reset reset)(DtpGlobalWrap);
    default_clock clk();
    default_reset rst();
    input_clock clock(clock) = clock;
    input_reset clock_reset() = clock_reset; /* from clock*/
    input_reset reset(reset) = reset;
    interface DtpglobalwrapTimestamp     timestamp;
        method timestamp_maximum maximum();
        method p0(timestamp_p0) enable((*inhigh*) EN_timestamp_p0);
        method p1(timestamp_p1) enable((*inhigh*) EN_timestamp_p1);
        method p2(timestamp_p2) enable((*inhigh*) EN_timestamp_p2);
        method p3(timestamp_p3) enable((*inhigh*) EN_timestamp_p3);
    endinterface
    schedule (timestamp.maximum, timestamp.p0, timestamp.p1, timestamp.p2, timestamp.p3) CF (timestamp.maximum, timestamp.p0, timestamp.p1, timestamp.p2, timestamp.p3);
endmodule


put type parameters of AxiSlaveBits all on one line for readability

// Copyright (c) 2015 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import Vector::*;

interface AxiMasterBits#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth, type extraType);
    method Bit#(addrWidth)     araddr();
    method Bit#(2)     arburst();
    method Bit#(4)     arcache();
    method Bit#(1)     aresetn();
    method Bit#(tagWidth)     arid();
    method Bit#(4)     arlen();
    method Bit#(2)     arlock();
    method Bit#(3)     arprot();
    method Bit#(4)     arqos();
    method Action      arready(Bit#(1) v);
    method Bit#(2)     arsize();
    method Bit#(1)     arvalid();
    method Bit#(addrWidth)     awaddr();
    method Bit#(2)     awburst();
    method Bit#(4)     awcache();
    method Bit#(tagWidth)     awid();
    method Bit#(4)     awlen();
    method Bit#(2)     awlock();
    method Bit#(3)     awprot();
    method Bit#(4)     awqos();
    method Action      awready(Bit#(1) v);
    method Bit#(2)     awsize();
    method Bit#(1)     awvalid();
    method Action      bid(Bit#(tagWidth) v);
    method Bit#(1)     bready();
    method Action      bresp(Bit#(2) v);
    method Action      bvalid(Bit#(1) v);
    method Action      rdata(Bit#(dataWidth) v);
    method Action      rid(Bit#(tagWidth) v);
    method Action      rlast(Bit#(1) v);
    method Bit#(1)     rready();
    method Action      rresp(Bit#(2) v);
    method Action      rvalid(Bit#(1) v);
    method Bit#(dataWidth)     wdata();
    method Bit#(tagWidth)     wid();
    method Bit#(1)     wlast();
    method Action      wready(Bit#(1) v);
    method Bit#(TDiv#(dataWidth,8))     wstrb();
    method Bit#(1)     wvalid();
    interface extraType   extra;
endinterface

interface HPType;
    method Bit#(3)     racount();
    method Bit#(8)     rcount();
    method Action      rdissuecap1en(Bit#(1) v);
    method Bit#(6)     wacount();
    method Bit#(8)     wcount();
    method Action      wrissuecap1en(Bit#(1) v);
endinterface

interface ACPType;
    method Action      aruser(Bit#(5) v);
    method Action      awuser(Bit#(5) v);
endinterface

interface AxiSlaveBits#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth, type extraType);
    method Action      araddr(Bit#(addrWidth) v);
    method Action      arburst(Bit#(2) v);
    method Action      arcache(Bit#(4) v);
    method Bit#(1)     aresetn();
    method Action      arid(Bit#(tagWidth) v);
    method Action      arlen(Bit#(4) v);
    method Action      arlock(Bit#(2) v);
    method Action      arprot(Bit#(3) v);
    method Action      arqos(Bit#(4) v);
    method Bit#(1)     arready();
    method Action      arsize(Bit#(2) v);
    method Action      arvalid(Bit#(1) v);
    method Action      awaddr(Bit#(addrWidth) v);
    method Action      awburst(Bit#(2) v);
    method Action      awcache(Bit#(4) v);
    method Action      awid(Bit#(tagWidth) v);
    method Action      awlen(Bit#(4) v);
    method Action      awlock(Bit#(2) v);
    method Action      awprot(Bit#(3) v);
    method Action      awqos(Bit#(4) v);
    method Bit#(1)     awready();
    method Action      awsize(Bit#(2) v);
    method Action      awvalid(Bit#(1) v);
    method Bit#(tagWidth)     bid();
    method Action      bready(Bit#(1) v);
    method Bit#(2)     bresp();
    method Bit#(1)     bvalid();
    method Bit#(dataWidth)     rdata();
    method Bit#(1)     rlast();
    method Action      rready(Bit#(1) v);
    method Bit#(2)     rresp();
    method Bit#(1)     rvalid();
    method Action      wdata(Bit#(dataWidth) v);
    method Action      wid(Bit#(tagWidth) v);
    method Action      wlast(Bit#(1) v);
    method Bit#(1)     wready();
    method Action      wstrb(Bit#(TDiv#(dataWidth,8)) v);
    method Action      wvalid(Bit#(1) v);
    method Bit#(tagWidth)     rid();
    interface extraType   extra;
endinterface

typedef AxiMasterBits#(32,32,12,Empty) Pps7Maxigp;
typedef AxiSlaveBits#(32,32,6,Empty) Pps7Saxigp;
typedef AxiSlaveBits#(32,64,6,HPType) Pps7Saxihp;
typedef AxiSlaveBits#(32,64,3,ACPType) Pps7Saxiacp;


compiles

compiles

// Copyright (c) 2014 Quanta Research Cambridge, Inc.
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import FIFOF::*;

/* This is a serial to parallel converter for messages of type a
 * The data register is assumed to always be available, so an arriving
 * message must be removed ASAP or be overwritten
 */
interface SerialLinkOut;
   method bit frame();
   method bit data();
endinterface

interface LinkOut#(type a);
   interface SerialLinkOut link;
   interface FIFOF#(a) data;
endinterface

module mkLinkOut(LinkOut#(a))
       provisos(Bits#(a,asize),
	        Log#(asize, k),
	        PrimSelectable#(a, Bit#(1)),
	        Bitwise#(a),
	        Literal#(a));

   // registers for sending data messages
   Reg#(bit) framebit <- mkReg(0);
   Reg#(bit) databit <- mkReg(0);

   Reg#(Bit#(k)) count <- mkReg(0);
   Reg#(a) shifter <- mkReg(0);
   FIFOF#(a) datafifo <- mkSizedFIFOF(1);

   rule startshift;
      if (count == 0)
	 begin
            shifter <= datafifo.first >> 1;
	    datafifo.deq();
	    framebit <= 1;
	    databit <= datafifo.first[0];
	    count <= count + 1;
	 end
   endrule

   rule continueshift;
      if (count != 0)
	 begin
	    if (count == fromInteger(valueof(asize) - 1))
	       begin
		  count <= 0;
		  framebit <= 0;
	       end
	    else
	       begin
		  count <= count + 1;
		  framebit <= 1;
		  databit <= shifter[0];
		  shifter <= shifter >> 1;
	       end
	 end
   endrule

   interface SerialLinkOut link;

      method bit frame();
         return framebit;
      endmethod

      method bit data();
         return databit;
      endmethod

   endinterface

   interface FIFOF data = datafifo;

endmodule

// Copyright (c) 2014 Quanta Research Cambridge, Inc.
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import FIFOF::*;

/* This is a serial to parallel converter for messages of type a
 * The data register is assumed to always be available, so an arriving
 * message must be removed ASAP or be overwritten
 */
interface SerialLinkOut;
   method bit frame(bit f);
   method bit data(bit d);
endinterface

interface LinkOut#(type a);
   interface SerialLinkOut link;
   interface FIFOF#(a) data;
endinterface

module mkLinkOut(LinkOut#(a))
       provisos(Bits#(a,asize)),
	        Log#(asize, k);

   // registers for sending data messages
   Reg#(bit) framebit <- mkReg(0);
   Reg#(bit) databit <- mkReg(0);

   Reg#(Bit#(k)) count <= mkReg(0);
   Reg#(a) shifter <- mkReg(0);
   FIFO#(a) datafifo <- mkSizedFIFOF(1);

   rule startshift;
      if (count == 0)
	 begin
            shifter <= datafifo.first >> 1;
	    datafifo.deq();
	    framebit <= 1;
	    databit <= datafifo.first[0];
	    count <= count + 1;
	 end
   endrule

   rule continueshift;
      if (count != 0)
	 begin
	    if (count == asize - 1)
	       begin
		  count <= 0;
		  framebit <= 0;
	       end
	    else
	       begin
		  count <= count + 1;
		  framebit <= 1;
		  databit <= shifter[0];
		  shifter <= shifter >> 1;
	       end
	 end
   endrule

   interface LinkOut;

      method bit frame();
         return framebit;
      endmethod

      method bit data();
         return databit;
      endmethod

      interface FIFO#(a) data = datafifo;

   endinterface

endmodule


fixed callback in sumOfErrorSquaredDebugRule

Change-Id: Ie4d668119254f888d45597f3bc249eb23cb58760

// Copyright (c) 2014 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import Vector::*;
import FIFO::*;
import FIFOF::*;
import DefaultValue::*;
import GetPut::*;
import ClientServer::*;
import Connectable::*;
import FloatingPoint::*;
import BRAM::*;

import PortalMemory::*;
import MemTypes::*;
import DmaVector::*;
import AxiMasterSlave::*;
import HostInterface::*;
import MemreadEngine::*;
import MemwriteEngine::*;
import MatrixTN::*;
import Timer::*;

import Sigmoid::*;
import FloatOps::*;
import Pipe::*;
import RbmTypes::*;
import DotProdServer::*;

function Float tokenValue(MmToken v) = v.v;

interface StatesPipe#(numeric type n, numeric type dmasz);
   method Action start(Bit#(32) readPointer, Bit#(32) readOffset,
		       Bit#(32) readPointer2, Bit#(32) readOffset2,
		       Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
   method ActionValue#(Bool) finish();
endinterface

module  mkComputeStatesPipe#(PipeOut#(Vector#(n, Float)) pipe_in,
			     PipeOut#(Vector#(n, Float)) randomPipe,
			     PipeIn#(Vector#(n,Float))   writePipe)(PipeOut#(Vector#(n, Float)))
   provisos(Add#(a__, 1, n));
   function Float greater(Float a, Float b);
      if (compareFP(a, b) == GT)
	 return 1.0;
      else
	 return 0.0;
   endfunction
   function Vector#(n, Float) vgreater(Vector#(n, Float) x, Vector#(n, Float) y);
      return map(uncurry(greater), zip(x, y));
   endfunction
   rule foo;
      let vs <- toGet(pipe_in).get;
      let rs <- toGet(randomPipe).get;
      let gs = vgreater(vs, rs);
      //$display($format(fshow("vs=")+fshow(pack(vs)) + fshow(" rs=") + fshow(pack(rs)) + fshow(" states=") + fshow(gs)));
      writePipe.enq(gs);
   endrule
endmodule

module  mkStatesPipe#(Vector#(2,Server#(MemengineCmd,Bool)) readServers,
		      Vector#(2, PipeOut#(Bit#(TMul#(N,32)))) readPipes,
		      Vector#(1,Server#(MemengineCmd,Bool)) writeServers,
		      Vector#(1, PipeIn#(Bit#(TMul#(N,32))))  writePipes)(StatesPipe#(N, DmaSz))
   provisos ( Bits#(Vector#(N, Float), DmaSz)
	     ,Log#(N,nshift));

   let verbose = True;
   let nshift = valueOf(nshift);

   Vector#(2, VectorSource#(DmaSz, Vector#(N,Float))) statesources <- mapM(uncurry(mkMemreadVectorSource), zip(readServers, readPipes));
   VectorSink#(DmaSz, Vector#(N, Float)) dmaStatesSink <- mkMemwriteVectorSink(writeServers[0], writePipes[0]);
   PipeOut#(Vector#(N, Float)) dmaStatesPipe <- mkComputeStatesPipe(statesources[0].pipe, statesources[1].pipe, dmaStatesSink.pipe);

   method Action start(Bit#(32) readPointer, Bit#(32) readOffset,
		       Bit#(32) readPointer2, Bit#(32) readOffset2,
		       Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
      statesources[0].start(readPointer, extend(readOffset), extend(unpack(numElts)>>nshift));
      statesources[1].start(readPointer2, extend(readOffset2), extend(unpack(numElts)>>nshift));
      dmaStatesSink.start(writePointer, extend(writeOffset), extend(unpack(numElts)>>nshift));
      if (verbose) $display("mkStatesPipe::start(%d %d %d %d %d %d)", readPointer, readOffset, readPointer2, readOffset2, writePointer, writeOffset, numElts);
   endmethod
   method ActionValue#(Bool) finish();
      let x0 <- statesources[0].finish;
      let x1 <- statesources[1].finish;
      let b <- dmaStatesSink.finish;
      return b;
   endmethod
endmodule

interface UpdateWeights#(numeric type n, numeric type dmasz);
   method Action start(Bit#(32) posAssociationsPointer, Bit#(32) negAssociationsPointer,
		       Bit#(32) weightsPointer, Bit#(32) numElts, Float learningRateOverNumExamples);
   method ActionValue#(Bool) finish();
endinterface

module  mkUpdateWeights#(Vector#(3,Server#(MemengineCmd,Bool)) readServers,
			    Vector#(3, PipeOut#(Bit#(TMul#(N,32)))) readPipes,
			    Vector#(1,Server#(MemengineCmd,Bool)) writeServers,
			    Vector#(1, PipeIn#(Bit#(TMul#(N,32))))  writePipes)(UpdateWeights#(N, DmaSz))
   provisos ( Bits#(Vector#(N, Float), DmaSz)
	     ,Log#(N,nshift));

   Vector#(3, VectorSource#(DmaSz, Vector#(N,Float))) sources <- mapM(uncurry(mkMemreadVectorSource), zip(readServers, readPipes));

   let n = valueOf(N);
   let nshift = valueOf(nshift);

   Reg#(Float) learningRateOverNumExamples <- mkReg(defaultValue);

   Vector#(N, FloatAlu) adders <- replicateM(mkFloatAdder(defaultValue));
   Vector#(N, FloatAlu) adders2 <- replicateM(mkFloatAdder(defaultValue));
   Vector#(N, FloatAlu) multipliers <- replicateM(mkFloatMultiplier(defaultValue));
   VectorSink#(DmaSz, Vector#(N, Float)) sink <- mkMemwriteVectorSink(writeServers[0], writePipes[0]);

// weights += learningRate * (pos_associations - neg_associations) / num_examples;
   rule sub;
      let pa = sources[0].pipe.first();
      sources[0].pipe.deq();
      let na = sources[1].pipe.first();
      sources[1].pipe.deq();
      for (Integer i = 0; i < n; i = i+1) begin
	 adders[i].request.put(tuple2(pa[i], -na[i]));
      end
   endrule
   rule mul;
      for (Integer i = 0; i < n; i = i+1) begin
	 let sumexc <- adders[i].response.get();
	 multipliers[i].request.put(tuple2(learningRateOverNumExamples, tpl_1(sumexc)));
      end
   endrule
   rule add;
      let weights = sources[2].pipe.first();
      sources[2].pipe.deq();
      for (Integer i = 0; i < n; i = i+1) begin
	 let resultexc <- multipliers[i].response.get();
	 adders2[i].request.put(tuple2(weights[i], tpl_1(resultexc)));
      end
   endrule
   rule result;
      Vector#(N, Float) r;
      for (Integer i = 0; i < n; i = i+1) begin
	 let resultexc <- adders2[i].response.get();
	 r[i] = tpl_1(resultexc);
      end
      sink.pipe.enq(r);
   endrule

   for (Integer i = 0; i < 3; i = i + 1)
      rule finishSources;
	 let b <- sources[i].finish();
      endrule

   method Action start(Bit#(32) posAssociationsPointer, Bit#(32) negAssociationsPointer, Bit#(32) weightsPointer, Bit#(32) numElts, Float lrone);
      learningRateOverNumExamples <= lrone;
      sources[0].start(posAssociationsPointer, 0, extend(numElts)>>nshift);
      sources[1].start(negAssociationsPointer, 0, extend(numElts)>>nshift);
      sources[2].start(weightsPointer, 0, extend(numElts)>>nshift);
      sink.start(weightsPointer, 0, extend(numElts)>>nshift);
   endmethod
   method ActionValue#(Bool) finish();
      let b <- sink.finish();
      return b;
   endmethod
endmodule

interface SumOfErrorSquaredDebug;
   interface PipeOut#(Bit#(32)) macCount;
endinterface

interface SumOfErrorSquared#(numeric type n, numeric type dmasz);
   interface PipeOut#(Float) pipe;
   method Action start(Bit#(32) dataPointer, Bit#(32) predPointer, Bit#(32) numElts);
   interface SumOfErrorSquaredDebug debug;
endinterface

module  mkSumOfErrorSquared#(Vector#(2,Server#(MemengineCmd,Bool)) readServers,
			     Vector#(2, PipeOut#(Bit#(TMul#(N,32)))) readPipes)(SumOfErrorSquared#(N, DmaSz))
   provisos ( Bits#(Vector#(N, Float), DmaSz)
	     ,Log#(N,nshift));

   Vector#(2, VectorSource#(DmaSz, Vector#(N,Float))) sources <- mapM(uncurry(mkMemreadVectorSource), zip(readServers, readPipes));
   let n = valueOf(N);
   let nshift = valueOf(nshift);
   SharedDotProdServer#(1) dotprod <- mkSharedInterleavedDotProdServerConfig(0);

   FirstLastPipe#(Bit#(ObjectOffsetSize)) firstlastPipe <- mkFirstLastPipe();
   PipeOut#(Float) aPipe <- mkFunnel1(sources[0].pipe);
   PipeOut#(Float) bPipe <- mkFunnel1(sources[1].pipe);
   let joinPipe <- mkJoin(tuple2, aPipe, bPipe);
   let subPipe <- mkFloatSubPipe(joinPipe);
   rule fromsub;
      match {.first, .last} <- toGet(firstlastPipe.pipe).get();
      let diff <- toGet(subPipe).get();
      MmToken t = MmToken { v: diff, first: first, last: last };
      dotprod.aInput.put(t);
      dotprod.bInput.put(t);
      //$display("%d %d", first, last);
   endrule

   for (Integer i = 0; i < 2; i = i + 1)
      rule finishSources;
	 let b <- sources[i].finish();
      endrule

   interface PipeOut pipe = mapPipe(tokenValue, dotprod.pipes[0]);
   method Action start(Bit#(32) dataPointer, Bit#(32) predPointer, Bit#(32) numElts);
      sources[0].start(dataPointer, 0, extend(numElts)>>nshift);
      sources[1].start(predPointer, 0, extend(numElts)>>nshift);
      firstlastPipe.start(extend(numElts));
   endmethod
   interface SumOfErrorSquaredDebug debug;
      interface PipeOut macCount = dotprod.debug.macCount;
   endinterface
endmodule: mkSumOfErrorSquared

interface Rbm#(numeric type n);
   interface RbmRequest rbmRequest;
   interface SigmoidRequest sigmoidRequest;
   interface MmRequestTN mmRequest;
   interface TimerRequest timerRequest;
   interface Vector#(3,ObjectReadClient#(TMul#(32,n))) readClients;
   interface Vector#(3,ObjectWriteClient#(TMul#(32,n))) writeClients;
endinterface

module  mkRbm#(HostType host, RbmIndication rbmInd, SigmoidIndication sigmoidInd, MmIndication mmInd, TimerIndication timerInd)(Rbm#(N))
   provisos (Add#(1,a__,N),
	     Add#(N,0,n),
	     Mul#(N,32,DmaSz));

   let n = valueOf(n);

   // TODO: figure out the correct amount of buffering required
   MemreadEngineV#(TMul#(n,32), 2, 9) readEngine  <- mkMemreadEngine;
   MemwriteEngineV#(TMul#(n,32),2, 3) writeEngine <- mkMemwriteEngine;

   let res = readEngine.readServers;
   let rep = readEngine.dataPipes;
   let wes = writeEngine.writeServers;
   let wep = writeEngine.dataPipes;

   SigmoidIfc#(TMul#(32,n)) sigmoid <- mkSigmoid(takeAt(0,res), takeAt(0,rep), takeAt(0,wes), takeAt(0,wep)); // 2 read, 1 write
   StatesPipe#(N, DmaSz) states <- mkStatesPipe(takeAt(2,res), takeAt(2,rep), takeAt(1,wes), takeAt(1,wep));              // 2 read, 1 write
   UpdateWeights#(N, DmaSz) updateWeights <- mkUpdateWeights(takeAt(4,res), takeAt(4,rep), takeAt(2,wes), takeAt(2,wep)); // 3 read, 1 write
   SumOfErrorSquared#(N, DmaSz) sumOfErrorSquared <- mkSumOfErrorSquared(takeAt(7,res), takeAt(7,rep));                   // 2 read, 0 write
   MmTNInternal#(N) mm <- mkMmTNInternal(host);

   ///////////////////////////////////////////////
   // timing cruft

   FIFOF#(Bool) busyFifo <- mkFIFOF();
   FIFOF#(Bool) timerRunning <- mkFIFOF();
   Reg#(Bit#(64)) cycleCount <- mkReg(0);
   Reg#(Bit#(64)) idleCount <- mkReg(0);
   rule countCycles if (timerRunning.notEmpty());
      cycleCount <= cycleCount + 1;
      if (!busyFifo.notEmpty())
	 idleCount <= idleCount + 1;
   endrule

   ///////////////////////////////////////////////

   ///////////////////////////////////////////////
   // sigmoid indication

   rule sigmoidDone;
      sigmoid.sigmoidDone();
      sigmoidInd.sigmoidDone();
      busyFifo.deq;
   endrule

   rule sigmoidTableUpdateDone;
      let b <- sigmoid.updateDone();
      sigmoidInd.tableUpdated(0);
      busyFifo.deq;
   endrule

   ///////////////////////////////////////////////

   ///////////////////////////////////////////////
   // mm indication

   rule mmfDone;
      let d <- mm.mmfDone;
      busyFifo.deq();
      mmInd.mmfDone(d);
   endrule

   rule mmDebugDone;
      let d <- mm.debugDone;
      mmInd.debug(d);
   endrule

   FIFO#(Bit#(32)) sumOfErrorSquaredDebugFifo <- mkFIFO();
   rule sumOfErrorSquaredDebugRule;
      let unused <- toGet(sumOfErrorSquaredDebugFifo).get();
      let macCount <- toGet(sumOfErrorSquared.debug.macCount).get();
      rbmInd.sumOfErrorSquaredDebug(macCount);
   endrule

   ///////////////////////////////////////////////

   ///////////////////////////////////////////////
   // rbm indication

   rule statesDone;
      $display("statesDone");
      let b <- states.finish();
      rbmInd.statesDone();
      busyFifo.deq;
   endrule

   rule updateWeightsDone;
      $display("updateWeightsDone");
      let b <- updateWeights.finish();
      rbmInd.updateWeightsDone();
      busyFifo.deq;
   endrule

   rule sumOfErrorSquaredDone;
      $display("sumOfErrorSquaredDone");
      sumOfErrorSquared.pipe.deq();
      rbmInd.sumOfErrorSquared(pack(sumOfErrorSquared.pipe.first()));
      busyFifo.deq;
   endrule

   ///////////////////////////////////////////////

   interface TimerRequest timerRequest;
      method Action startTimer() if (!timerRunning.notEmpty());
	 cycleCount <= 0;
	 idleCount <= 0;
	 timerRunning.enq(True);
      endmethod
      method Action stopTimer();
	 timerRunning.deq();
	 timerInd.elapsedCycles(cycleCount, idleCount);
      endmethod
   endinterface
   interface MmRequestTN mmRequest;
      method Action mmf(Bit#(32) h1, Bit#(32) r1, Bit#(32) c1,
			Bit#(32) h2, Bit#(32) r2, Bit#(32) c2,
			Bit#(32) h3,
			Bit#(32) r1_x_c1, Bit#(32) c1_x_j,
			Bit#(32) r1_x_c2, Bit#(32) c2_x_j,
			Bit#(32) c1_x_c2, Bit#(32) r2_x_c2);
	 mm.mmRequest.mmf(h1,r1,c1,
			  h2,r2,c2,
			  h3,
			  r1_x_c1, c1_x_j,
			  r1_x_c2, c2_x_j,
			  c1_x_c2, r2_x_c2);
	 busyFifo.enq(True);
      endmethod
      method Action debug = mm.mmRequest.debug;
   endinterface
   interface RbmRequest rbmRequest;
      method Action finish();
	 $finish(0);
      endmethod
      method Action computeStates(Bit#(32) readPointer, Bit#(32) readOffset,
				  Bit#(32) readPointer2, Bit#(32) readOffset2,
				  Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
	 states.start(readPointer, readOffset,
		      readPointer2, readOffset2,
		      writePointer,writeOffset, numElts);
	 busyFifo.enq(True);
      endmethod
      method Action updateWeights(Bit#(32) posAssociationsPointer,
	 Bit#(32) negAssociationsPointer,
				  Bit#(32) weightsPointer,
				  Bit#(32) numElts,
				  Bit#(32) learningRateOverNumExamples);
	 updateWeights.start(posAssociationsPointer, negAssociationsPointer,
			     weightsPointer, numElts,
			     unpack(learningRateOverNumExamples));
	 busyFifo.enq(True);
      endmethod
      method Action sumOfErrorSquared(Bit#(32) dataPointer, Bit#(32) predPointer, Bit#(32) numElts);
	 sumOfErrorSquared.start(dataPointer, predPointer, numElts);
	 busyFifo.enq(True);
      endmethod
      method Action sumOfErrorSquaredDebug();
	 sumOfErrorSquaredDebugFifo.enq(0);
      endmethod
   endinterface
   interface SigmoidRequest sigmoidRequest;
      method Action sigmoid(Bit#(32) readPointer, Bit#(32) readOffset,
   			    Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numvalues);
	 sigmoid.sigmoidRequest.sigmoid(readPointer, readOffset, writePointer, writeOffset, numvalues);
	 busyFifo.enq(True);
      endmethod
      method Action setLimits(Bit#(32) rscale, Bit#(32) llimit, Bit#(32) ulimit);
	 sigmoid.sigmoidRequest.setLimits(rscale, llimit, ulimit);
      endmethod
      method Action updateTable(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) numvalues);
	 sigmoid.sigmoidRequest.updateTable(readPointer, readOffset, numvalues);
	 busyFifo.enq(True);
      endmethod
      method Action tableSize();
	 sigmoidInd.tableSize(sigmoid.tableSize);
      endmethod
   endinterface
   interface Vector readClients = cons(readEngine.dmaClient,mm.readClients);
   interface Vector writeClients = cons(writeEngine.dmaClient,mm.writeClients);

endmodule

// Copyright (c) 2014 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import Vector::*;
import FIFO::*;
import FIFOF::*;
import DefaultValue::*;
import GetPut::*;
import ClientServer::*;
import Connectable::*;
import FloatingPoint::*;
import BRAM::*;

import PortalMemory::*;
import MemTypes::*;
import DmaVector::*;
import AxiMasterSlave::*;
import HostInterface::*;
import MemreadEngine::*;
import MemwriteEngine::*;
import MatrixTN::*;
import Timer::*;

import Sigmoid::*;
import FloatOps::*;
import Pipe::*;
import RbmTypes::*;
import DotProdServer::*;

function Float tokenValue(MmToken v) = v.v;

interface StatesPipe#(numeric type n, numeric type dmasz);
   method Action start(Bit#(32) readPointer, Bit#(32) readOffset,
		       Bit#(32) readPointer2, Bit#(32) readOffset2,
		       Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
   method ActionValue#(Bool) finish();
endinterface

module  mkComputeStatesPipe#(PipeOut#(Vector#(n, Float)) pipe_in,
			     PipeOut#(Vector#(n, Float)) randomPipe,
			     PipeIn#(Vector#(n,Float))   writePipe)(PipeOut#(Vector#(n, Float)))
   provisos(Add#(a__, 1, n));
   function Float greater(Float a, Float b);
      if (compareFP(a, b) == GT)
	 return 1.0;
      else
	 return 0.0;
   endfunction
   function Vector#(n, Float) vgreater(Vector#(n, Float) x, Vector#(n, Float) y);
      return map(uncurry(greater), zip(x, y));
   endfunction
   rule foo;
      let vs <- toGet(pipe_in).get;
      let rs <- toGet(randomPipe).get;
      let gs = vgreater(vs, rs);
      //$display($format(fshow("vs=")+fshow(pack(vs)) + fshow(" rs=") + fshow(pack(rs)) + fshow(" states=") + fshow(gs)));
      writePipe.enq(gs);
   endrule
endmodule

module  mkStatesPipe#(Vector#(2,Server#(MemengineCmd,Bool)) readServers,
		      Vector#(2, PipeOut#(Bit#(TMul#(N,32)))) readPipes,
		      Vector#(1,Server#(MemengineCmd,Bool)) writeServers,
		      Vector#(1, PipeIn#(Bit#(TMul#(N,32))))  writePipes)(StatesPipe#(N, DmaSz))
   provisos ( Bits#(Vector#(N, Float), DmaSz)
	     ,Log#(N,nshift));

   let verbose = True;
   let nshift = valueOf(nshift);

   Vector#(2, VectorSource#(DmaSz, Vector#(N,Float))) statesources <- mapM(uncurry(mkMemreadVectorSource), zip(readServers, readPipes));
   VectorSink#(DmaSz, Vector#(N, Float)) dmaStatesSink <- mkMemwriteVectorSink(writeServers[0], writePipes[0]);
   PipeOut#(Vector#(N, Float)) dmaStatesPipe <- mkComputeStatesPipe(statesources[0].pipe, statesources[1].pipe, dmaStatesSink.pipe);

   method Action start(Bit#(32) readPointer, Bit#(32) readOffset,
		       Bit#(32) readPointer2, Bit#(32) readOffset2,
		       Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
      statesources[0].start(readPointer, extend(readOffset), extend(unpack(numElts)>>nshift));
      statesources[1].start(readPointer2, extend(readOffset2), extend(unpack(numElts)>>nshift));
      dmaStatesSink.start(writePointer, extend(writeOffset), extend(unpack(numElts)>>nshift));
      if (verbose) $display("mkStatesPipe::start(%d %d %d %d %d %d)", readPointer, readOffset, readPointer2, readOffset2, writePointer, writeOffset, numElts);
   endmethod
   method ActionValue#(Bool) finish();
      let x0 <- statesources[0].finish;
      let x1 <- statesources[1].finish;
      let b <- dmaStatesSink.finish;
      return b;
   endmethod
endmodule

interface UpdateWeights#(numeric type n, numeric type dmasz);
   method Action start(Bit#(32) posAssociationsPointer, Bit#(32) negAssociationsPointer,
		       Bit#(32) weightsPointer, Bit#(32) numElts, Float learningRateOverNumExamples);
   method ActionValue#(Bool) finish();
endinterface

module  mkUpdateWeights#(Vector#(3,Server#(MemengineCmd,Bool)) readServers,
			    Vector#(3, PipeOut#(Bit#(TMul#(N,32)))) readPipes,
			    Vector#(1,Server#(MemengineCmd,Bool)) writeServers,
			    Vector#(1, PipeIn#(Bit#(TMul#(N,32))))  writePipes)(UpdateWeights#(N, DmaSz))
   provisos ( Bits#(Vector#(N, Float), DmaSz)
	     ,Log#(N,nshift));

   Vector#(3, VectorSource#(DmaSz, Vector#(N,Float))) sources <- mapM(uncurry(mkMemreadVectorSource), zip(readServers, readPipes));

   let n = valueOf(N);
   let nshift = valueOf(nshift);

   Reg#(Float) learningRateOverNumExamples <- mkReg(defaultValue);

   Vector#(N, FloatAlu) adders <- replicateM(mkFloatAdder(defaultValue));
   Vector#(N, FloatAlu) adders2 <- replicateM(mkFloatAdder(defaultValue));
   Vector#(N, FloatAlu) multipliers <- replicateM(mkFloatMultiplier(defaultValue));
   VectorSink#(DmaSz, Vector#(N, Float)) sink <- mkMemwriteVectorSink(writeServers[0], writePipes[0]);

// weights += learningRate * (pos_associations - neg_associations) / num_examples;
   rule sub;
      let pa = sources[0].pipe.first();
      sources[0].pipe.deq();
      let na = sources[1].pipe.first();
      sources[1].pipe.deq();
      for (Integer i = 0; i < n; i = i+1) begin
	 adders[i].request.put(tuple2(pa[i], -na[i]));
      end
   endrule
   rule mul;
      for (Integer i = 0; i < n; i = i+1) begin
	 let sumexc <- adders[i].response.get();
	 multipliers[i].request.put(tuple2(learningRateOverNumExamples, tpl_1(sumexc)));
      end
   endrule
   rule add;
      let weights = sources[2].pipe.first();
      sources[2].pipe.deq();
      for (Integer i = 0; i < n; i = i+1) begin
	 let resultexc <- multipliers[i].response.get();
	 adders2[i].request.put(tuple2(weights[i], tpl_1(resultexc)));
      end
   endrule
   rule result;
      Vector#(N, Float) r;
      for (Integer i = 0; i < n; i = i+1) begin
	 let resultexc <- adders2[i].response.get();
	 r[i] = tpl_1(resultexc);
      end
      sink.pipe.enq(r);
   endrule

   for (Integer i = 0; i < 3; i = i + 1)
      rule finishSources;
	 let b <- sources[i].finish();
      endrule

   method Action start(Bit#(32) posAssociationsPointer, Bit#(32) negAssociationsPointer, Bit#(32) weightsPointer, Bit#(32) numElts, Float lrone);
      learningRateOverNumExamples <= lrone;
      sources[0].start(posAssociationsPointer, 0, extend(numElts)>>nshift);
      sources[1].start(negAssociationsPointer, 0, extend(numElts)>>nshift);
      sources[2].start(weightsPointer, 0, extend(numElts)>>nshift);
      sink.start(weightsPointer, 0, extend(numElts)>>nshift);
   endmethod
   method ActionValue#(Bool) finish();
      let b <- sink.finish();
      return b;
   endmethod
endmodule

interface SumOfErrorSquaredDebug;
   interface PipeOut#(Bit#(32)) macCount;
endinterface

interface SumOfErrorSquared#(numeric type n, numeric type dmasz);
   interface PipeOut#(Float) pipe;
   method Action start(Bit#(32) dataPointer, Bit#(32) predPointer, Bit#(32) numElts);
   interface SumOfErrorSquaredDebug debug;
endinterface

module  mkSumOfErrorSquared#(Vector#(2,Server#(MemengineCmd,Bool)) readServers,
			     Vector#(2, PipeOut#(Bit#(TMul#(N,32)))) readPipes)(SumOfErrorSquared#(N, DmaSz))
   provisos ( Bits#(Vector#(N, Float), DmaSz)
	     ,Log#(N,nshift));

   Vector#(2, VectorSource#(DmaSz, Vector#(N,Float))) sources <- mapM(uncurry(mkMemreadVectorSource), zip(readServers, readPipes));
   let n = valueOf(N);
   let nshift = valueOf(nshift);
   SharedDotProdServer#(1) dotprod <- mkSharedInterleavedDotProdServerConfig(0);

   FirstLastPipe#(Bit#(ObjectOffsetSize)) firstlastPipe <- mkFirstLastPipe();
   PipeOut#(Float) aPipe <- mkFunnel1(sources[0].pipe);
   PipeOut#(Float) bPipe <- mkFunnel1(sources[1].pipe);
   let joinPipe <- mkJoin(tuple2, aPipe, bPipe);
   let subPipe <- mkFloatSubPipe(joinPipe);
   rule fromsub;
      match {.first, .last} <- toGet(firstlastPipe.pipe).get();
      let diff <- toGet(subPipe).get();
      MmToken t = MmToken { v: diff, first: first, last: last };
      dotprod.aInput.put(t);
      dotprod.bInput.put(t);
      //$display("%d %d", first, last);
   endrule

   for (Integer i = 0; i < 2; i = i + 1)
      rule finishSources;
	 let b <- sources[i].finish();
      endrule

   interface PipeOut pipe = mapPipe(tokenValue, dotprod.pipes[0]);
   method Action start(Bit#(32) dataPointer, Bit#(32) predPointer, Bit#(32) numElts);
      sources[0].start(dataPointer, 0, extend(numElts)>>nshift);
      sources[1].start(predPointer, 0, extend(numElts)>>nshift);
      firstlastPipe.start(extend(numElts));
   endmethod
   interface SumOfErrorSquaredDebug debug;
      interface PipeOut macCount = dotprod.debug.macCount;
   endinterface
endmodule: mkSumOfErrorSquared

interface Rbm#(numeric type n);
   interface RbmRequest rbmRequest;
   interface SigmoidRequest sigmoidRequest;
   interface MmRequestTN mmRequest;
   interface TimerRequest timerRequest;
   interface Vector#(3,ObjectReadClient#(TMul#(32,n))) readClients;
   interface Vector#(3,ObjectWriteClient#(TMul#(32,n))) writeClients;
endinterface

module  mkRbm#(HostType host, RbmIndication rbmInd, SigmoidIndication sigmoidInd, MmIndication mmInd, TimerIndication timerInd)(Rbm#(N))
   provisos (Add#(1,a__,N),
	     Add#(N,0,n),
	     Mul#(N,32,DmaSz));

   let n = valueOf(n);

   // TODO: figure out the correct amount of buffering required
   MemreadEngineV#(TMul#(n,32), 2, 9) readEngine  <- mkMemreadEngine;
   MemwriteEngineV#(TMul#(n,32),2, 3) writeEngine <- mkMemwriteEngine;

   let res = readEngine.readServers;
   let rep = readEngine.dataPipes;
   let wes = writeEngine.writeServers;
   let wep = writeEngine.dataPipes;

   SigmoidIfc#(TMul#(32,n)) sigmoid <- mkSigmoid(takeAt(0,res), takeAt(0,rep), takeAt(0,wes), takeAt(0,wep)); // 2 read, 1 write
   StatesPipe#(N, DmaSz) states <- mkStatesPipe(takeAt(2,res), takeAt(2,rep), takeAt(1,wes), takeAt(1,wep));              // 2 read, 1 write
   UpdateWeights#(N, DmaSz) updateWeights <- mkUpdateWeights(takeAt(4,res), takeAt(4,rep), takeAt(2,wes), takeAt(2,wep)); // 3 read, 1 write
   SumOfErrorSquared#(N, DmaSz) sumOfErrorSquared <- mkSumOfErrorSquared(takeAt(7,res), takeAt(7,rep));                   // 2 read, 0 write
   MmTNInternal#(N) mm <- mkMmTNInternal(host);

   ///////////////////////////////////////////////
   // timing cruft

   FIFOF#(Bool) busyFifo <- mkFIFOF();
   FIFOF#(Bool) timerRunning <- mkFIFOF();
   Reg#(Bit#(64)) cycleCount <- mkReg(0);
   Reg#(Bit#(64)) idleCount <- mkReg(0);
   rule countCycles if (timerRunning.notEmpty());
      cycleCount <= cycleCount + 1;
      if (!busyFifo.notEmpty())
	 idleCount <= idleCount + 1;
   endrule

   ///////////////////////////////////////////////

   ///////////////////////////////////////////////
   // sigmoid indication

   rule sigmoidDone;
      sigmoid.sigmoidDone();
      sigmoidInd.sigmoidDone();
      busyFifo.deq;
   endrule

   rule sigmoidTableUpdateDone;
      let b <- sigmoid.updateDone();
      sigmoidInd.tableUpdated(0);
      busyFifo.deq;
   endrule

   ///////////////////////////////////////////////

   ///////////////////////////////////////////////
   // mm indication

   rule mmfDone;
      let d <- mm.mmfDone;
      busyFifo.deq();
      mmInd.mmfDone(d);
   endrule

   rule mmDebugDone;
      let d <- mm.debugDone;
      mmInd.debug(d);
   endrule

   FIFO#(Bit#(32)) sumOfErrorSquaredDebugFifo <- mkFIFO();
   rule sumOfErrorSquaredDebugRule;
      let unused <- toGet(sumOfErrorSquaredDebugFifo).get();
      let macCount <- toGet(sumOfErrorSquared.debug.macCount).get();
      rbmInd.sumOfErrorSquared(macCount);
   endrule

   ///////////////////////////////////////////////

   ///////////////////////////////////////////////
   // rbm indication

   rule statesDone;
      $display("statesDone");
      let b <- states.finish();
      rbmInd.statesDone();
      busyFifo.deq;
   endrule

   rule updateWeightsDone;
      $display("updateWeightsDone");
      let b <- updateWeights.finish();
      rbmInd.updateWeightsDone();
      busyFifo.deq;
   endrule

   rule sumOfErrorSquaredDone;
      $display("sumOfErrorSquaredDone");
      sumOfErrorSquared.pipe.deq();
      rbmInd.sumOfErrorSquared(pack(sumOfErrorSquared.pipe.first()));
      busyFifo.deq;
   endrule

   ///////////////////////////////////////////////

   interface TimerRequest timerRequest;
      method Action startTimer() if (!timerRunning.notEmpty());
	 cycleCount <= 0;
	 idleCount <= 0;
	 timerRunning.enq(True);
      endmethod
      method Action stopTimer();
	 timerRunning.deq();
	 timerInd.elapsedCycles(cycleCount, idleCount);
      endmethod
   endinterface
   interface MmRequestTN mmRequest;
      method Action mmf(Bit#(32) h1, Bit#(32) r1, Bit#(32) c1,
			Bit#(32) h2, Bit#(32) r2, Bit#(32) c2,
			Bit#(32) h3,
			Bit#(32) r1_x_c1, Bit#(32) c1_x_j,
			Bit#(32) r1_x_c2, Bit#(32) c2_x_j,
			Bit#(32) c1_x_c2, Bit#(32) r2_x_c2);
	 mm.mmRequest.mmf(h1,r1,c1,
			  h2,r2,c2,
			  h3,
			  r1_x_c1, c1_x_j,
			  r1_x_c2, c2_x_j,
			  c1_x_c2, r2_x_c2);
	 busyFifo.enq(True);
      endmethod
      method Action debug = mm.mmRequest.debug;
   endinterface
   interface RbmRequest rbmRequest;
      method Action finish();
	 $finish(0);
      endmethod
      method Action computeStates(Bit#(32) readPointer, Bit#(32) readOffset,
				  Bit#(32) readPointer2, Bit#(32) readOffset2,
				  Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
	 states.start(readPointer, readOffset,
		      readPointer2, readOffset2,
		      writePointer,writeOffset, numElts);
	 busyFifo.enq(True);
      endmethod
      method Action updateWeights(Bit#(32) posAssociationsPointer,
	 Bit#(32) negAssociationsPointer,
				  Bit#(32) weightsPointer,
				  Bit#(32) numElts,
				  Bit#(32) learningRateOverNumExamples);
	 updateWeights.start(posAssociationsPointer, negAssociationsPointer,
			     weightsPointer, numElts,
			     unpack(learningRateOverNumExamples));
	 busyFifo.enq(True);
      endmethod
      method Action sumOfErrorSquared(Bit#(32) dataPointer, Bit#(32) predPointer, Bit#(32) numElts);
	 sumOfErrorSquared.start(dataPointer, predPointer, numElts);
	 busyFifo.enq(True);
      endmethod
      method Action sumOfErrorSquaredDebug();
	 sumOfErrorSquaredDebugFifo.enq(0);
      endmethod
   endinterface
   interface SigmoidRequest sigmoidRequest;
      method Action sigmoid(Bit#(32) readPointer, Bit#(32) readOffset,
   			    Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numvalues);
	 sigmoid.sigmoidRequest.sigmoid(readPointer, readOffset, writePointer, writeOffset, numvalues);
	 busyFifo.enq(True);
      endmethod
      method Action setLimits(Bit#(32) rscale, Bit#(32) llimit, Bit#(32) ulimit);
	 sigmoid.sigmoidRequest.setLimits(rscale, llimit, ulimit);
      endmethod
      method Action updateTable(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) numvalues);
	 sigmoid.sigmoidRequest.updateTable(readPointer, readOffset, numvalues);
	 busyFifo.enq(True);
      endmethod
      method Action tableSize();
	 sigmoidInd.tableSize(sigmoid.tableSize);
      endmethod
   endinterface
   interface Vector readClients = cons(readEngine.dmaClient,mm.readClients);
   interface Vector writeClients = cons(writeEngine.dmaClient,mm.writeClients);

endmodule