diff --git a/api/scaffold/__init__.py b/api/scaffold/__init__.py index b90f88e..9df200d 100644 --- a/api/scaffold/__init__.py +++ b/api/scaffold/__init__.py @@ -1117,11 +1117,11 @@ def raw_transaction(self, data, read_size, trigger=None): # Verify trigger parameter before doing anything t_start = False t_end = False - if isinstance(type(trigger), int): + if isinstance(trigger, int): if trigger not in range(2): raise ValueError("Invalid trigger parameter") t_start = trigger == 1 - elif isinstance(type(trigger), str): + elif isinstance(trigger, str): t_start = "a" in trigger t_end = "b" in trigger else: @@ -1605,6 +1605,106 @@ def glitch_count(self, value): self.reg_count.set(value) +class SWDStatus(Enum): + OK = 0 + WAIT = 1 + FAULT = 2 + ERROR = 3 + + +class SWD(Module): + """ + SWD peripheral of Scaffold. + """ + + __REG_STATUS_BIT_READY = 0 + + def __init__(self, parent): + """ + :param parent: The Scaffold instance owning the SWD module. + """ + super().__init__(parent, "/swd") + # Declare the signals + self.add_signals("swclk", "swd_in", "swd_out", "trigger") + # Declare the registers + self.__addr_base = base = 0x0b00 + self.add_register("rdata", "rv", base) + self.add_register("wdata", "w", base + 4, reset=0x00) + self.add_register("status", "rv", base + 0x10) + self.add_register("cmd", "w", base + 0x20) + + def reset(self, trigger=False): + """ + Reset the debug interface. This emits a reset sequence, followed by + the JTAG-to-SWD select sequence and a second reset sequence. The deviceid + register is then read. + """ + val = 0x80 + if trigger: + val = val | (1 << 6) + self.reg_cmd.write(val) + self.read(0, 0) + return self.status() + + def read(self, apndp, addr): + """ + Emits a read command to a given debug register. + + :param apndp: Address space of the register (0 for DP, 1 for AP). + :param addr: Address of the register. + """ + val = 0b0000_0100 | ((apndp & 0b1) << 3) | (((addr >> 2) & 1) << 1) \ + | ((addr >> 3) & 1) + self.reg_cmd.write(val) + return (self.status(), self.rdata()) + + def write(self, apndp, addr, wdata: int): + """ + Emits a write command to a given debug register. + + :param apndp: Address space of the register (0 for DP, 1 for AP). + :param addr: Address of the register. + :param wdata: 32-bit integer to write into the register. + """ + val = 0b0000_0000 | ((apndp & 0b1) << 3) | (((addr >> 2) & 1) << 1) \ + | ((addr >> 3) & 1) + wdata_bytes = wdata.to_bytes(4, "little") + self.reg_wdata.write(wdata_bytes) + self.reg_cmd.write(val) + return self.status() + + def clear_errors(self): + """ + Clear any previous errors. + """ + self.write(0, 0, 0b11110) + + def debug_power_up(self, retry=10): + """ + Fully powers up the debug interface by writing to the CRTL/STAT register. + """ + self.write(0, 0x4, (1 << 28) | (1 << 30)) + self.clear_errors() + self.read(0, 0) + for _ in range(retry): + (status, ctrl_stat) = self.read(0, 0x4) + if ((ctrl_stat >> 29) & 0x1) == 1 and ((ctrl_stat >> 31) & 0x1) == 1: + return True + return False + + def status(self): + """ + Retrieve the status of the last emitted SWD transaction. + """ + return SWDStatus(self.reg_status.read()[0] & 0b11) + + def rdata(self): + """ + Retrieve the data read by the last emitted Read transaction. + """ + return int.from_bytes(self.reg_rdata.read(4), 'little') + + class IOMode(Enum): AUTO = 0 OPEN_DRAIN = 1 @@ -2098,6 +2198,7 @@ def __init__( "0.7.2", "0.8", "0.9", + "0.10", ) ], ) @@ -2202,6 +2303,10 @@ def connect( self.clocks.append(clock) self.__setattr__(f"clock{i}", clock) + # Declare the swd module + if self.version >= parse_version("0.10"): + self.swd = SWD(self) + # Create the ISO7816 module self.iso7816 = ISO7816(self) @@ -2238,6 +2343,8 @@ def connect( self.add_mtxl_in(f"/pgen{i}/out") for i in range(len(self.chains)): self.add_mtxl_in(f"/chain{i}/trigger") + if self.version >= parse_version("0.10"): + self.add_mtxl_in("/swd/trigger") # FPGA left matrix output signals # Update this section when adding new modules with inputs @@ -2259,6 +2366,8 @@ def connect( self.add_mtxl_out(f"/chain{i}/event{j}") for i in range(len(self.clocks)): self.add_mtxl_out(f"/clock{i}/glitch") + if self.version >= parse_version("0.10"): + self.add_mtxl_out("/swd/swd_in") # FPGA right matrix input signals # Update this section when adding new modules with outpus @@ -2290,6 +2399,10 @@ def connect( self.add_mtxr_in(f"/chain{i}/trigger") for i in range(len(self.clocks)): self.add_mtxr_in(f"/clock{i}/out") + if self.version >= parse_version("0.10"): + self.add_mtxr_in("/swd/swclk") + self.add_mtxr_in("/swd/swd_out") + self.add_mtxr_in("/swd/trigger") # FPGA right matrix output signals self.add_mtxr_out("/io/a0") @@ -2355,3 +2468,5 @@ def reset_config(self, init_ios=False): i2c.reset_config() for spi in self.spis: spi.reset_registers() + if self.version >= parse_version("0.10"): + self.swd.reset_registers() diff --git a/api/setup.py b/api/setup.py index 291ed18..d77f770 100755 --- a/api/setup.py +++ b/api/setup.py @@ -26,13 +26,13 @@ setup( name="donjon-scaffold", - version="0.9.0", + version="0.10.0", author="Olivier Heriveaux", description="Python3 API for the Scaffold board", long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/Ledger-Donjon/scaffold", - install_requires=["pyserial", "crcmod", "requests"], + install_requires=["pyserial", "crcmod", "requests", "packaging"], packages=find_packages(), python_requires=">=3.6", ) diff --git a/api/tests/__init__.py b/api/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/docs/requirements.txt b/docs/requirements.txt index 22117ad..af3c4fe 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,5 +2,6 @@ sphinxcontrib-wavedrom sphinxcontrib-spelling matplotlib pyserial +packaging crcmod sphinx-rtd-theme>=1.3.0rc1 diff --git a/fpga-arch/bsv/Counter.v b/fpga-arch/bsv/Counter.v new file mode 100644 index 0000000..0259385 --- /dev/null +++ b/fpga-arch/bsv/Counter.v @@ -0,0 +1,109 @@ +// +// Copied without modifications from: +// https://github.com/B-Lang-org/bsc/blob/9a97f9d037c462e42441b6af8d0000314302214f/src/Verilog/Counter.v +// +// Copyright (c) 2020 Bluespec, Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the +// distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +`ifdef BSV_ASSIGNMENT_DELAY +`else + `define BSV_ASSIGNMENT_DELAY +`endif + +`ifdef BSV_POSITIVE_RESET + `define BSV_RESET_VALUE 1'b1 + `define BSV_RESET_EDGE posedge +`else + `define BSV_RESET_VALUE 1'b0 + `define BSV_RESET_EDGE negedge +`endif + + +`ifdef BSV_ASYNC_RESET + `define BSV_ARESET_EDGE_META or `BSV_RESET_EDGE RST +`else + `define BSV_ARESET_EDGE_META +`endif + + +// N -bit counter with load, set and 2 increment +module Counter(CLK, + RST, + Q_OUT, + DATA_A, ADDA, + DATA_B, ADDB, + DATA_C, SETC, + DATA_F, SETF); + + parameter width = 1; + parameter init = 0; + + input CLK; + input RST; + input [width - 1 : 0] DATA_A; + input ADDA; + input [width - 1 : 0] DATA_B; + input ADDB; + input [width - 1 : 0] DATA_C; + input SETC; + input [width - 1 : 0] DATA_F; + input SETF; + + output [width - 1 : 0] Q_OUT; + + + + reg [width - 1 : 0] q_state ; + + assign Q_OUT = q_state ; + + always@(posedge CLK `BSV_ARESET_EDGE_META) begin + if (RST == `BSV_RESET_VALUE) + q_state <= `BSV_ASSIGNMENT_DELAY init; + else + begin + if ( SETF ) + q_state <= `BSV_ASSIGNMENT_DELAY DATA_F ; + else + q_state <= `BSV_ASSIGNMENT_DELAY (SETC ? DATA_C : q_state ) + (ADDA ? DATA_A : {width {1'b0}}) + (ADDB ? DATA_B : {width {1'b0}} ) ; + end // else: !if(RST == `BSV_RESET_VALUE) + end // always@ (posedge CLK) + +`ifdef BSV_NO_INITIAL_BLOCKS +`else // not BSV_NO_INITIAL_BLOCKS + // synopsys translate_off + initial begin + q_state = {((width + 1)/2){2'b10}} ; + end + // synopsys translate_on +`endif // BSV_NO_INITIAL_BLOCKS + +endmodule diff --git a/fpga-arch/bsv/Prescaler.bsv b/fpga-arch/bsv/Prescaler.bsv new file mode 100644 index 0000000..3471970 --- /dev/null +++ b/fpga-arch/bsv/Prescaler.bsv @@ -0,0 +1,56 @@ +// This file is part of Scaffold +// +// Scaffold is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// +// Copyright 2024 Ledger SAS, written by Charles Christen + +package Prescaler; + +import Counter::*; + +(* always_enabled *) +interface Prescaler#(numeric type n); + method Action reset; + method Bool rising; + method Bool falling; + method Bool pre_rising; +endinterface + +module mkPrescaler (Prescaler#(prescale)) + provisos ( + Mul#(__a, 2, prescale), + Add#(ctr_max, 1, prescale), + Log#(ctr_max, __b), + Add#(__b, 1, ctr_sz) + ); + + Counter#(ctr_sz) ctr <- mkCounter(fromInteger(valueof(ctr_max))); + + rule count_dow (ctr.value > 0); + ctr.down(); + endrule + + rule reset_count (ctr.value == 0); + ctr.setF(fromInteger(valueof(ctr_max))); + endrule + + method reset = ctr.setF(fromInteger(valueof(ctr_max))); + method rising = (ctr.value == 0); + method pre_rising = (ctr.value == 1); + method falling = (ctr.value == fromInteger(valueof(__a))); + +endmodule + +endpackage diff --git a/fpga-arch/bsv/SWD.bsv b/fpga-arch/bsv/SWD.bsv new file mode 100644 index 0000000..bdcb5c8 --- /dev/null +++ b/fpga-arch/bsv/SWD.bsv @@ -0,0 +1,197 @@ +// This file is part of Scaffold +// +// Scaffold is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// +// Copyright 2024 Ledger SAS, written by Charles Christen + +import SWDInner::*; + +import GetPut::*; +import Vector::*; +import ClientServer::*; + +(* always_enabled *) +interface ScaffoldBus; + // bus_in_t + (* prefix="" *) method Action address((* port="address" *) Bit#(16) a); + (* prefix="" *) method Action write_data((* port="write_data" *) Bit#(8) w); + (* prefix="" *) method Action write((* port="write" *) Bit#(1) b); + (* prefix="" *) method Action read((* port="read" *) Bit#(1) b); + + // register selection + (* prefix="" *) method Action en_rdata((* port="en_rdata" *) Bit#(1) en); + (* prefix="" *) method Action en_wdata((* port="en_wdata" *) Bit#(1) en); + (* prefix="" *) method Action en_cmd((* port="en_cmd" *) Bit#(1) en); + (* prefix="" *) method Action en_status((* port="en_status" *) Bit#(1) en); + + // readable register out + (* prefix="" *) method Bit#(8) reg_rdata; + (* prefix="" *) method Bit#(8) reg_status; +endinterface + +interface ScaffoldSWDModule; + (* prefix="" *) interface ScaffoldBus bus; + (* prefix="" *) interface SWDControllerPins pins; + (* always_ready, prefix="" *) method Bit#(1) trigger; +endinterface + +typedef struct { + Bit#(1) reset; + Bit#(1) trigger; + Bit#(2) reserved; + Bit#(1) apndp; + Bit#(1) rnw; + Bit#(2) addr; +} Cmd deriving (Eq, Bits); + +typedef enum { + IDLE, + CMD_IN, + RESET, + RW +} State deriving (Eq, Bits); + +(* synthesize *) +module swd_module (ScaffoldSWDModule); + SWDController#(100) swd_controller <- mkSWDController(); + + Wire#(Bit#(16)) bus_address <- mkDWire(0); + Wire#(Bit#(8)) bus_write_data <- mkDWire(0); + Wire#(Bit#(1)) bus_write <- mkDWire(0); + Wire#(Bit#(1)) bus_read <- mkDWire(0); + Wire#(Bit#(1)) bus_en_rdata <- mkDWire(0); + Wire#(Bit#(1)) bus_en_wdata <- mkDWire(0); + Wire#(Bit#(1)) bus_en_cmd <- mkDWire(0); + Wire#(Bit#(1)) bus_en_status <- mkDWire(0); + + Reg#(Bit#(8)) bus_reg_rdata <- mkRegA(0); + Reg#(Bit#(8)) bus_reg_status <- mkRegA(0); + + PulseWire trig <- mkPulseWire(); + + Reg#(Vector#(4, Bit#(8))) rdata <- mkRegA(unpack(0)); + Reg#(Status) status <- mkRegA(unpack(0)); + Reg#(Vector#(4, Bit#(8))) wdata <- mkRegA(unpack(0)); + Reg#(Maybe#(Cmd)) cmd <- mkRegA(tagged Invalid); + + Reg#(Bool) ready <- mkRegA(False); + Reg#(State) state <- mkRegA(IDLE); + + rule do_bus_read_rdata ((bus_read == 1) && (bus_en_rdata == 1) && (state != RW)); + bus_reg_rdata <= rdata[0]; + rdata <= shiftInAtN(rdata, 0); + endrule + + rule do_bus_read_status ((bus_read == 1) && (bus_en_status == 1)); + bus_reg_status <= {pack(state == IDLE), 5'b0, pack(status)}; + endrule + + // Only register writes if we are currently idling + rule do_bus_write ((bus_write == 1) && (state == IDLE)); + if (bus_en_wdata == 1) begin + wdata <= shiftInAt0(wdata, bus_write_data); + end + + if (bus_en_cmd == 1) begin + cmd <= tagged Valid(unpack(bus_write_data)); + state <= CMD_IN; + end + endrule + + rule do_ready; + ready <= swd_controller.ready; + endrule + + rule do_cmd ((state == CMD_IN) && isValid(cmd)); + let new_cmd = fromMaybe(?, cmd); + + if (new_cmd.reset == 1) begin + swd_controller.reset(); + state <= RESET; + end + + else if (new_cmd.rnw == 1) begin + swd_controller.rw.request.put( + tagged Read { register: Register { apndp: new_cmd.apndp, addr: new_cmd.addr } } + ); + state <= RW; + end + + else begin + swd_controller.rw.request.put( + tagged Write { register: Register { apndp: new_cmd.apndp, addr: new_cmd.addr }, wdata: pack(reverse(wdata)) } + ); + state <= RW; + end + + if (new_cmd.trigger == 1) begin + trig.send(); + end + endrule + + rule do_reset (state == RESET); + if (ready) begin + swd_controller.rw.request.put( + tagged Read { register: Register { apndp: 0, addr: 0 } } + ); + state <= RW; + end + endrule + + rule do_rw (state == RW); + let response <- swd_controller.rw.response.get(); + case (response) matches + tagged Write .w_resp: begin + status <= w_resp.status; + rdata <= unpack(0); + end + tagged Read .r_resp: begin + Vector#(32, Bit#(1)) resp_rdata; + resp_rdata = take(unpack(r_resp.rdata)); + + if (parity(r_resp.rdata) != 0) begin + status <= ERROR; + rdata <= unpack(0); + end + else begin + status <= r_resp.status; + rdata <= unpack(pack(resp_rdata)); + end + end + endcase + + cmd <= tagged Invalid; + state <= IDLE; + endrule + + interface ScaffoldBus bus; + method Action address(a) = bus_address._write(a); + method Action write_data(w) = bus_write_data._write(w); + method Action write(b) = bus_write._write(b); + method Action read(b) = bus_read._write(b); + + method Action en_rdata(en) = bus_en_rdata._write(en); + method Action en_wdata(en) = bus_en_wdata._write(en); + method Action en_cmd(en) = bus_en_cmd._write(en); + method Action en_status(en) = bus_en_status._write(en); + + method Bit#(8) reg_rdata = bus_reg_rdata; + method Bit#(8) reg_status = bus_reg_status; + endinterface + + interface SWDControllerPins pins = swd_controller.pins; + + method Bit#(1) trigger = pack(trig); +endmodule \ No newline at end of file diff --git a/fpga-arch/bsv/SWDInner.bsv b/fpga-arch/bsv/SWDInner.bsv new file mode 100644 index 0000000..650c701 --- /dev/null +++ b/fpga-arch/bsv/SWDInner.bsv @@ -0,0 +1,453 @@ +// This file is part of Scaffold +// +// Scaffold is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// +// +// Copyright 2024 Ledger SAS, written by Charles Christen + +package SWDInner; + +import Prescaler::*; + +import GetPut::*; +import Vector::*; +import ClientServer::*; + +/// An AP or DP register. +typedef struct { + Bit#(1) apndp; + Bit#(2) addr; +} Register deriving (Eq, Bits); + +/// A full 8-bits request packet. +typedef struct { + Bit#(1) start; + Bit#(1) apndp; + Bit#(1) rnw; + Bit#(2) addr; + Bit#(1) parity; + Bit#(1) stop; + Bit#(1) park; +} RequestPacket deriving (Eq, Bits); + +/// A transaction status. +typedef enum { + OK, + WAIT, + FAULT, + ERROR +} Status deriving (Eq, Bits, FShow); + +/// The internal state of the SWD controller. +typedef enum { + IDLE, + PACKET, + P_TRN, + ACK, + A_TRN, + RDATA, + WDATA, + DONE, + RESET +} State deriving (Eq, Bits, FShow); + +/// A request, for either a Read or a Write +/// transaction. +typedef union tagged { + struct { + Register register; + Bit#(32) wdata; + } Write; + + struct { + Register register; + } Read; +} Request deriving (Eq, Bits); + +/// A response, to either a Read or a Write +/// transaction. +typedef union tagged { + struct { + Status status; + } Write; + + struct { + Status status; + Bit#(33) rdata; + } Read; +} Response deriving (Eq, Bits); + +/// The peripheral-facing pins of the SWD controller, +/// with swdio split into swd_in and swd_out. +(* always_enabled *) +interface SWDControllerPins; + (* prefix="" *) method Bit#(1) swclk; + (* prefix="" *) method Action swd_in((* port="swd_in" *) Bit#(1) b); + (* prefix="" *) method Bit#(1) swd_out; + (* prefix="" *) method Bool out_en; +endinterface + +/// The full SWD controller interface, with endpoints for +/// issuing Read and Write requests, and peripheral-facing +/// pins. +interface SWDController#(numeric type clk_divider); + method Action reset; + interface Server#(Request, Response) rw; + (* always_enabled *) method Bool ready; + (* always_enabled *) interface SWDControllerPins pins; +endinterface + +module mkSWDController (SWDController#(clk_divider)) + provisos ( + Mul#(__a, 2, clk_divider), + Add#(__b, 1, clk_divider) + ); + + // When a request comes in, the packet (and data, in case of a write request) + // are registered, and swclk is kicked-off. + // We then move sequencially through the steps of the transaction, shifting out + // or in bits at a time, synchronously with the generated swclk falling/rising edges. + // When the transaction is done, the transaction status is updated and marked + // as Valid, triggering the release of the Get interface of the R/W server. + // + // The tricky thing, however, is to coordinate the state changes with the rising + // and falling edges of the SWD clock. + // Indeed we want to say that on the rising edge of the prescaler, meaning when it is zero + // but will be one in the next cycle, we want to do a certain operation, that depends + // on which step of the transaction we are in, i.e. which state. + // Thus the state must have been updated *before*, on the cycle immediately preceding + // the cycle itself preceding swclk == 0. + // This is what [prescaler.pre_rising] is for. + + Prescaler#(clk_divider) prescaler <- mkPrescaler(); + + // Status and ACK of the current transaction. + Reg#(Maybe#(Status)) status <- mkRegA(tagged Invalid); + Reg#(Vector#(3, Bit#(1))) ack <- mkRegA(unpack(0)); + + // Controller pins. + Reg#(Bit#(1)) swd_out <- mkRegA(0); + Wire#(Bit#(1)) swd_in <- mkDWire(0); + Reg#(Bool) out_en <- mkRegA(True); + Reg#(Bit#(1)) swclk <- mkRegA(0); + + // Inner state. + Reg#(State) state <- mkRegA(IDLE); + Reg#(Bool) rnw <- mkRegU; + Reg#(Vector#(8, Bit#(1))) packet <- mkRegU; + Reg#(Vector#(33, Bit#(1))) data <- mkRegU; + + // Counter for tracking bits in the transfered packet/data. + Reg#(Bit#(7)) cnt <- mkRegU; + + // Same-cycle signals + PulseWire request_in <- mkPulseWire(); + PulseWire reset_in <- mkPulseWire(); + + rule do_prescaler; + if (request_in || reset_in) begin + prescaler.reset(); + end + endrule + + // Generate the SWD clock, whenever there is an + // ongoing transaction. + // Note that the polarity is inverted (the peripheral samples the IO line on rising edges of swclk) + rule do_swclk (state != IDLE); + if (prescaler.rising) begin + swclk <= 0; + end + else if (prescaler.falling) begin + swclk <= 1; + end + endrule + + // SWDIO is treated as an input only when in + // the ACK or RDATA phase. + rule do_out_en; + out_en <= ((state == RESET) || (state == PACKET) || (state == WDATA)); + endrule + + // Stop idling when a request has been received. + rule do_idle (state == IDLE); + if (request_in) begin + state <= PACKET; + cnt <= 10; + end + else if (reset_in) begin + state <= RESET; + cnt <= 126; + end + else begin + swclk <= 1; + swd_out <= 1; + end + endrule + + // Shift out the reset and switch sequence + rule do_reset (state == RESET); + if (prescaler.rising) begin + // > 50 cycles with swdio high (the specification says + // "more than 50", we err on the side on caution and + // take it to mean strictly more) + if (cnt > 71) begin + swd_out <= 1; + cnt <= cnt - 1; + end + // followed by the 16 bits of the JTAG-to-SWD switching + // sequence + else if (cnt > 55) begin + let switch_sequence = 16'hE79E; + swd_out <= switch_sequence[71 - cnt]; + cnt <= cnt - 1; + end + // and finally > 50 more cycles high + // (bits xx to 1, because the case cnt == 0 is preempted + // by the pre_rising condition below) + else begin + swd_out <= 1; + cnt <= cnt - 1; + end + end + + if (prescaler.pre_rising && (cnt == 0)) begin + state <= IDLE; + end + endrule + + // Shift out the command packet. + rule do_packet (state == PACKET); + if (prescaler.rising) begin + if (cnt > 8) begin + swd_out <= 0; + cnt <= cnt - 1; + end + + else begin + // On every falling edge of the generated swclk, we need to shift out a + // new bit of the packet + swd_out <= last(packet); + packet <= shiftInAt0(packet, 0); + cnt <= cnt - 1; + end + end + + // If we have shifted out the last bit of the packet, + // and the next swclk falling edge is upcoming shortly, + // we need to pre-emptively transition to the next state (the TRN period) + // so that the corresponding rule is enabled when prescaler.rising becomes true, + // so that it can actually do something useful on the very same cycle + // where swclk is going to be low. + else if (prescaler.pre_rising && (cnt == 0)) begin + state <= P_TRN; + end + + endrule + + // Shift out a TRN bit immediately following the packet. + rule do_p_trn (state == P_TRN); + if (prescaler.rising) begin + swd_out <= 0; + end + + else if (prescaler.pre_rising) begin + cnt <= 3; + state <= ACK; + end + endrule + + // Shift in the received ACK, by sampling the swd_in line in the + // middle of the swclk cycles. + rule do_ack (state == ACK); + if (prescaler.rising) begin + cnt <= cnt - 1; + ack <= shiftInAt0(ack, swd_in); + end + + else begin + // if (prescaler.falling) begin + // ack <= shiftInAt0(ack, swd_in); + // end + + if (prescaler.pre_rising && (cnt == 0)) begin + // If we're shifting in the last ACK bit, next up will either + // be a TRN period or the RDATA, depending on wether the current + // request is a Read or a Write. + if (rnw) begin + cnt <= 33; + state <= RDATA; + end + else begin + state <= A_TRN; + end + end + end + endrule + + // Shift out a TRN bit immediately following the ACK. + // If the ACK is OK, go through with the DATA phase, + // otherwise abort. + rule do_a_trn (state == A_TRN); + if (prescaler.rising) begin + swd_out <= 0; + end + + else if (prescaler.pre_rising) begin + case (pack(ack)) matches + 3'b100: + begin + cnt <= 33; + state <= WDATA; + end + default: + begin + cnt <= 1; + state <= DONE; + end + endcase + end + endrule + + // Shift in the 32-bits read data, plus parity bit. + rule do_rdata (state == RDATA); + if (prescaler.rising) begin + cnt <= cnt - 1; + data <= shiftInAtN(data, swd_in); + end + + else begin + // if (prescaler.falling) begin + // data <= shiftInAtN(data, swd_in); + // end + + if (prescaler.pre_rising && (cnt == 0)) begin + cnt <= 1; + state <= DONE; + end + end + endrule + + // Shift out the 32-bits write data, and parity bit. + rule do_wdata (state == WDATA); + if (prescaler.rising) begin + swd_out <= data[0]; + data <= shiftInAtN(data, 0); + cnt <= cnt - 1; + end + + else if (prescaler.pre_rising && (cnt == 0)) begin + cnt <= 1; + state <= DONE; + end + endrule + + // We're done. Update the status but keep swclk going for + // a full period, and then go back to IDLE. + rule do_done (state == DONE); + if (prescaler.rising) begin + cnt <= cnt - 1; + + case (pack(ack)) matches + 3'b100: status <= Valid(OK); + 3'b010: status <= Valid(WAIT); + 3'b001: status <= Valid(FAULT); + default: status <= Valid(ERROR); + endcase + end + + else if (prescaler.pre_rising && (cnt == 0)) begin + state <= IDLE; + end + endrule + + // For debug purposes. + rule log; + $display($format("state: ") + fshow(state), ", swclk: %b, swd_out: %b, swd_in: %b, out_en: %b", + swclk, swd_out, swd_in, out_en); + endrule + + // Interface methods and subinterfaces + // + method Bool ready = (state == IDLE); + method Action reset if (state == IDLE); + reset_in.send(); + endmethod + + interface Server rw; + interface Put request; + method Action put(req) if ((state == IDLE) && !isValid(status)); + case (req) matches + tagged Write .w_in : begin + let apndp = w_in.register.apndp; + let addr = w_in.register.addr; + let p = apndp ^ 0 ^ addr[0] ^ addr[1]; + packet <= unpack(pack(RequestPacket { + start: 1, + apndp: apndp, + rnw: 0, + addr: addr, + parity: p, + stop: 0, + park: 1 })); + data <= append(unpack(w_in.wdata), replicate(parity(w_in.wdata))); + rnw <= False; + request_in.send(); + end + tagged Read .r_in : begin + let apndp = r_in.register.apndp; + let addr = r_in.register.addr; + let p = apndp ^ 1 ^ addr[0] ^ addr[1]; + packet <= unpack(pack(RequestPacket { + start: 1, + apndp: apndp, + rnw: 1, + addr: addr, + parity: p, + stop: 0, + park: 1 })); + rnw <= True; + request_in.send(); + end + endcase + endmethod + endinterface + + interface Get response; + method ActionValue#(Response) get() if ((state == IDLE) && isValid(status)); + let transaction_status = fromMaybe(?, status); + Response ret; + ret = rnw ? tagged Read { status: transaction_status, rdata: pack(data) } : + tagged Write { status: transaction_status }; + + // reset state + status <= tagged Invalid; + data <= unpack(0); + packet <= unpack(0); + + return ret; + endmethod + endinterface + endinterface + + interface SWDControllerPins pins; + method swclk = swclk; + method swd_out = swd_out; + method Action swd_in(b); + swd_in <= b; + endmethod + method out_en = out_en; + endinterface +endmodule + +endpackage \ No newline at end of file diff --git a/fpga-arch/swd_module.v b/fpga-arch/swd_module.v new file mode 100644 index 0000000..f6512cb --- /dev/null +++ b/fpga-arch/swd_module.v @@ -0,0 +1,1062 @@ +// +// Generated by Bluespec Compiler, version 2024.01-9-gc481d7f5 (build c481d7f5) +// +// On Mon Sep 9 13:18:32 CEST 2024 +// +// +// Ports: +// Name I/O size props +// reg_rdata O 8 reg +// reg_status O 8 reg +// swclk O 1 reg +// swd_out O 1 reg +// out_en O 1 reg +// trigger O 1 +// CLK I 1 clock +// RST_N I 1 reset +// address I 16 unused +// write_data I 8 +// write I 1 +// read I 1 +// en_rdata I 1 +// en_wdata I 1 +// en_cmd I 1 +// en_status I 1 +// swd_in I 1 +// +// No combinational paths from inputs to outputs +// +// + +`ifdef BSV_ASSIGNMENT_DELAY +`else + `define BSV_ASSIGNMENT_DELAY +`endif + +`ifdef BSV_POSITIVE_RESET + `define BSV_RESET_VALUE 1'b1 + `define BSV_RESET_EDGE posedge +`else + `define BSV_RESET_VALUE 1'b0 + `define BSV_RESET_EDGE negedge +`endif + +module swd_module(CLK, + RST_N, + + address, + + write_data, + + write, + + read, + + en_rdata, + + en_wdata, + + en_cmd, + + en_status, + + reg_rdata, + + reg_status, + + swclk, + + swd_in, + + swd_out, + + out_en, + + trigger); + input CLK; + input RST_N; + + // action method bus_address + input [15 : 0] address; + + // action method bus_write_data + input [7 : 0] write_data; + + // action method bus_write + input write; + + // action method bus_read + input read; + + // action method bus_en_rdata + input en_rdata; + + // action method bus_en_wdata + input en_wdata; + + // action method bus_en_cmd + input en_cmd; + + // action method bus_en_status + input en_status; + + // value method bus_reg_rdata + output [7 : 0] reg_rdata; + + // value method bus_reg_status + output [7 : 0] reg_status; + + // value method pins_swclk + output swclk; + + // action method pins_swd_in + input swd_in; + + // value method pins_swd_out + output swd_out; + + // value method pins_out_en + output out_en; + + // value method trigger + output trigger; + + // signals for module outputs + wire [7 : 0] reg_rdata, reg_status; + wire out_en, swclk, swd_out, trigger; + + // inlined wires + wire swd_controller_request_in$whas, swd_controller_reset_in$whas; + + // register bus_reg_rdata + reg [7 : 0] bus_reg_rdata; + wire [7 : 0] bus_reg_rdata$D_IN; + wire bus_reg_rdata$EN; + + // register bus_reg_status + reg [7 : 0] bus_reg_status; + wire [7 : 0] bus_reg_status$D_IN; + wire bus_reg_status$EN; + + // register cmd + reg [8 : 0] cmd; + wire [8 : 0] cmd$D_IN; + wire cmd$EN; + + // register rdata + reg [31 : 0] rdata; + wire [31 : 0] rdata$D_IN; + wire rdata$EN; + + // register ready + reg ready; + wire ready$D_IN, ready$EN; + + // register state + reg [1 : 0] state; + reg [1 : 0] state$D_IN; + wire state$EN; + + // register status + reg [1 : 0] status; + wire [1 : 0] status$D_IN; + wire status$EN; + + // register swd_controller_ack + reg [2 : 0] swd_controller_ack; + wire [2 : 0] swd_controller_ack$D_IN; + wire swd_controller_ack$EN; + + // register swd_controller_cnt + reg [6 : 0] swd_controller_cnt; + reg [6 : 0] swd_controller_cnt$D_IN; + wire swd_controller_cnt$EN; + + // register swd_controller_data + reg [32 : 0] swd_controller_data; + reg [32 : 0] swd_controller_data$D_IN; + wire swd_controller_data$EN; + + // register swd_controller_out_en + reg swd_controller_out_en; + wire swd_controller_out_en$D_IN, swd_controller_out_en$EN; + + // register swd_controller_packet + reg [7 : 0] swd_controller_packet; + reg [7 : 0] swd_controller_packet$D_IN; + wire swd_controller_packet$EN; + + // register swd_controller_rnw + reg swd_controller_rnw; + wire swd_controller_rnw$D_IN, swd_controller_rnw$EN; + + // register swd_controller_state + reg [3 : 0] swd_controller_state; + reg [3 : 0] swd_controller_state$D_IN; + wire swd_controller_state$EN; + + // register swd_controller_status + reg [2 : 0] swd_controller_status; + wire [2 : 0] swd_controller_status$D_IN; + wire swd_controller_status$EN; + + // register swd_controller_swclk + reg swd_controller_swclk; + wire swd_controller_swclk$D_IN, swd_controller_swclk$EN; + + // register swd_controller_swd_out + reg swd_controller_swd_out; + reg swd_controller_swd_out$D_IN; + wire swd_controller_swd_out$EN; + + // register wdata + reg [31 : 0] wdata; + wire [31 : 0] wdata$D_IN; + wire wdata$EN; + + // ports of submodule swd_controller_prescaler_ctr + wire [7 : 0] swd_controller_prescaler_ctr$DATA_A, + swd_controller_prescaler_ctr$DATA_B, + swd_controller_prescaler_ctr$DATA_C, + swd_controller_prescaler_ctr$DATA_F, + swd_controller_prescaler_ctr$Q_OUT; + wire swd_controller_prescaler_ctr$ADDA, + swd_controller_prescaler_ctr$ADDB, + swd_controller_prescaler_ctr$SETC, + swd_controller_prescaler_ctr$SETF; + + // rule scheduling signals + wire WILL_FIRE_RL_do_bus_read_rdata, + WILL_FIRE_RL_do_bus_write, + WILL_FIRE_RL_do_cmd, + WILL_FIRE_RL_do_reset, + WILL_FIRE_RL_do_rw; + + // inputs to muxes for submodule ports + reg [2 : 0] MUX_swd_controller_status$write_1__VAL_1; + wire [32 : 0] MUX_swd_controller_data$write_1__VAL_1, + MUX_swd_controller_data$write_1__VAL_2, + MUX_swd_controller_data$write_1__VAL_3; + wire [31 : 0] MUX_rdata$write_1__VAL_1, MUX_rdata$write_1__VAL_2; + wire [8 : 0] MUX_cmd$write_1__VAL_1; + wire [7 : 0] MUX_swd_controller_packet$write_1__VAL_2, + MUX_swd_controller_packet$write_1__VAL_3; + wire [6 : 0] MUX_swd_controller_cnt$write_1__VAL_2, + MUX_swd_controller_cnt$write_1__VAL_4, + MUX_swd_controller_cnt$write_1__VAL_5, + MUX_swd_controller_cnt$write_1__VAL_6; + wire [3 : 0] MUX_swd_controller_state$write_1__VAL_1, + MUX_swd_controller_state$write_1__VAL_3, + MUX_swd_controller_state$write_1__VAL_7; + wire [1 : 0] MUX_state$write_1__VAL_3; + wire MUX_cmd$write_1__SEL_1, + MUX_state$write_1__SEL_1, + MUX_swd_controller_cnt$write_1__PSEL_1, + MUX_swd_controller_cnt$write_1__PSEL_6, + MUX_swd_controller_cnt$write_1__SEL_1, + MUX_swd_controller_cnt$write_1__SEL_2, + MUX_swd_controller_cnt$write_1__SEL_3, + MUX_swd_controller_cnt$write_1__SEL_4, + MUX_swd_controller_cnt$write_1__SEL_5, + MUX_swd_controller_cnt$write_1__SEL_6, + MUX_swd_controller_data$write_1__SEL_1, + MUX_swd_controller_data$write_1__SEL_2, + MUX_swd_controller_data$write_1__SEL_3, + MUX_swd_controller_packet$write_1__SEL_2, + MUX_swd_controller_packet$write_1__SEL_3, + MUX_swd_controller_state$write_1__PSEL_4, + MUX_swd_controller_state$write_1__SEL_3, + MUX_swd_controller_state$write_1__SEL_4, + MUX_swd_controller_state$write_1__SEL_5, + MUX_swd_controller_state$write_1__SEL_6, + MUX_swd_controller_status$write_1__SEL_1, + MUX_swd_controller_swclk$write_1__SEL_1, + MUX_swd_controller_swclk$write_1__SEL_2, + MUX_swd_controller_swd_out$write_1__PSEL_4, + MUX_swd_controller_swd_out$write_1__SEL_2, + MUX_swd_controller_swd_out$write_1__SEL_3, + MUX_swd_controller_swd_out$write_1__SEL_4, + MUX_swd_controller_swd_out$write_1__VAL_2, + MUX_swd_controller_swd_out$write_1__VAL_3; + + // remaining internal signals + wire [15 : 0] _0xE79E__q2; + wire [6 : 0] i__h1457, x__h15006; + wire [1 : 0] cmd_BITS_1_TO_0__q1; + wire swd_controller_cnt_2_ULE_8___d35, + swd_controller_data_2_BIT_0_5_XOR_swd_controll_ETC___d298, + x__h1438, + x__h20247, + x__h20260, + x__h20262, + x__h21446, + x__h21459, + z__h24693, + z__h24700, + z__h24707, + z__h24714, + z__h24721, + z__h24728, + z__h24735, + z__h24742, + z__h24749, + z__h24756, + z__h24763, + z__h24770, + z__h24777, + z__h24784, + z__h24791, + z__h24798, + z__h24805, + z__h24812, + z__h24819, + z__h24826, + z__h24833, + z__h24840, + z__h24847, + z__h24854, + z__h24861, + z__h24868, + z__h24875, + z__h24882, + z__h24889, + z__h24896, + z__h35341, + z__h35348, + z__h35355, + z__h35362, + z__h35369, + z__h35376, + z__h35383, + z__h35390, + z__h35397, + z__h35404, + z__h35411, + z__h35418, + z__h35425, + z__h35432, + z__h35439, + z__h35446, + z__h35453, + z__h35460, + z__h35467, + z__h35474, + z__h35481, + z__h35488, + z__h35495, + z__h35502, + z__h35509, + z__h35516, + z__h35523, + z__h35530, + z__h35537, + z__h35544, + z__h35551; + + // value method bus_reg_rdata + assign reg_rdata = bus_reg_rdata ; + + // value method bus_reg_status + assign reg_status = bus_reg_status ; + + // value method pins_swclk + assign swclk = swd_controller_swclk ; + + // value method pins_swd_out + assign swd_out = swd_controller_swd_out ; + + // value method pins_out_en + assign out_en = swd_controller_out_en ; + + // value method trigger + assign trigger = WILL_FIRE_RL_do_cmd && cmd[6] ; + + // submodule swd_controller_prescaler_ctr + Counter #(.width(32'd8), + .init(8'd99)) swd_controller_prescaler_ctr(.CLK(CLK), + .RST(RST_N), + .DATA_A(swd_controller_prescaler_ctr$DATA_A), + .DATA_B(swd_controller_prescaler_ctr$DATA_B), + .DATA_C(swd_controller_prescaler_ctr$DATA_C), + .DATA_F(swd_controller_prescaler_ctr$DATA_F), + .ADDA(swd_controller_prescaler_ctr$ADDA), + .ADDB(swd_controller_prescaler_ctr$ADDB), + .SETC(swd_controller_prescaler_ctr$SETC), + .SETF(swd_controller_prescaler_ctr$SETF), + .Q_OUT(swd_controller_prescaler_ctr$Q_OUT)); + + // rule RL_do_bus_read_rdata + assign WILL_FIRE_RL_do_bus_read_rdata = read && en_rdata && state != 2'd3 ; + + // rule RL_do_bus_write + assign WILL_FIRE_RL_do_bus_write = write && state == 2'd0 ; + + // rule RL_do_cmd + assign WILL_FIRE_RL_do_cmd = + swd_controller_state == 4'd0 && !swd_controller_status[2] && + state == 2'd1 && + cmd[8] ; + + // rule RL_do_reset + assign WILL_FIRE_RL_do_reset = + swd_controller_state == 4'd0 && !swd_controller_status[2] && + state == 2'd2 ; + + // rule RL_do_rw + assign WILL_FIRE_RL_do_rw = + swd_controller_state == 4'd0 && swd_controller_status[2] && + state == 2'd3 ; + + // inputs to muxes for submodule ports + assign MUX_cmd$write_1__SEL_1 = WILL_FIRE_RL_do_bus_write && en_cmd ; + assign MUX_state$write_1__SEL_1 = WILL_FIRE_RL_do_reset && ready ; + assign MUX_swd_controller_cnt$write_1__PSEL_1 = + swd_controller_state == 4'd7 || swd_controller_state == 4'd1 || + swd_controller_state == 4'd8 ; + assign MUX_swd_controller_cnt$write_1__SEL_1 = + MUX_swd_controller_cnt$write_1__PSEL_1 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 ; + assign MUX_swd_controller_cnt$write_1__SEL_2 = + swd_controller_state == 4'd4 && + swd_controller_prescaler_ctr$Q_OUT == 8'd1 ; + assign MUX_swd_controller_cnt$write_1__SEL_3 = + swd_controller_state == 4'd2 && + swd_controller_prescaler_ctr$Q_OUT == 8'd1 ; + assign MUX_swd_controller_cnt$write_1__SEL_4 = + swd_controller_state == 4'd0 && + (swd_controller_request_in$whas || + swd_controller_reset_in$whas) ; + assign MUX_swd_controller_cnt$write_1__SEL_5 = + swd_controller_state == 4'd3 && + (swd_controller_prescaler_ctr$Q_OUT == 8'd0 || + swd_controller_prescaler_ctr$Q_OUT == 8'd1 && + swd_controller_cnt == 7'd0 && + swd_controller_rnw) ; + assign MUX_swd_controller_cnt$write_1__PSEL_6 = + swd_controller_state == 4'd6 || swd_controller_state == 4'd5 ; + assign MUX_swd_controller_cnt$write_1__SEL_6 = + MUX_swd_controller_cnt$write_1__PSEL_6 && + (swd_controller_prescaler_ctr$Q_OUT == 8'd0 || + swd_controller_prescaler_ctr$Q_OUT == 8'd1 && + swd_controller_cnt == 7'd0) ; + assign MUX_swd_controller_data$write_1__SEL_1 = + swd_controller_state == 4'd5 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 ; + assign MUX_swd_controller_data$write_1__SEL_2 = + swd_controller_state == 4'd6 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 ; + assign MUX_swd_controller_data$write_1__SEL_3 = + WILL_FIRE_RL_do_cmd && !cmd[7] && !cmd[2] ; + assign MUX_swd_controller_packet$write_1__SEL_2 = + WILL_FIRE_RL_do_cmd && !cmd[7] ; + assign MUX_swd_controller_packet$write_1__SEL_3 = + swd_controller_state == 4'd1 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 && + swd_controller_cnt_2_ULE_8___d35 ; + assign MUX_swd_controller_state$write_1__SEL_3 = + swd_controller_state == 4'd3 && + swd_controller_prescaler_ctr$Q_OUT == 8'd1 && + swd_controller_cnt == 7'd0 ; + assign MUX_swd_controller_state$write_1__PSEL_4 = + swd_controller_state == 4'd7 || swd_controller_state == 4'd8 ; + assign MUX_swd_controller_state$write_1__SEL_4 = + MUX_swd_controller_state$write_1__PSEL_4 && + swd_controller_prescaler_ctr$Q_OUT == 8'd1 && + swd_controller_cnt == 7'd0 ; + assign MUX_swd_controller_state$write_1__SEL_5 = + swd_controller_state == 4'd1 && + swd_controller_prescaler_ctr$Q_OUT == 8'd1 && + swd_controller_cnt == 7'd0 ; + assign MUX_swd_controller_state$write_1__SEL_6 = + MUX_swd_controller_cnt$write_1__PSEL_6 && + swd_controller_prescaler_ctr$Q_OUT == 8'd1 && + swd_controller_cnt == 7'd0 ; + assign MUX_swd_controller_status$write_1__SEL_1 = + swd_controller_state == 4'd7 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 ; + assign MUX_swd_controller_swclk$write_1__SEL_1 = + swd_controller_state != 4'd0 && + (swd_controller_prescaler_ctr$Q_OUT == 8'd0 || + swd_controller_prescaler_ctr$Q_OUT == 8'd50) ; + assign MUX_swd_controller_swclk$write_1__SEL_2 = + swd_controller_state == 4'd0 && + !swd_controller_request_in$whas && + !swd_controller_reset_in$whas ; + assign MUX_swd_controller_swd_out$write_1__SEL_2 = + swd_controller_state == 4'd8 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 ; + assign MUX_swd_controller_swd_out$write_1__SEL_3 = + swd_controller_state == 4'd1 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 ; + assign MUX_swd_controller_swd_out$write_1__PSEL_4 = + swd_controller_state == 4'd4 || swd_controller_state == 4'd2 ; + assign MUX_swd_controller_swd_out$write_1__SEL_4 = + MUX_swd_controller_swd_out$write_1__PSEL_4 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 ; + assign MUX_cmd$write_1__VAL_1 = { 1'd1, write_data } ; + assign MUX_rdata$write_1__VAL_1 = { 8'd0, rdata[31:8] } ; + assign MUX_rdata$write_1__VAL_2 = + swd_controller_rnw ? + (swd_controller_data_2_BIT_0_5_XOR_swd_controll_ETC___d298 ? + 32'd0 : + swd_controller_data[31:0]) : + 32'd0 ; + assign MUX_state$write_1__VAL_3 = cmd[7] ? 2'd2 : 2'd3 ; + assign MUX_swd_controller_cnt$write_1__VAL_2 = + (swd_controller_ack == 3'b100) ? 7'd33 : 7'd1 ; + assign MUX_swd_controller_cnt$write_1__VAL_4 = + swd_controller_request_in$whas ? 7'd10 : 7'd126 ; + assign MUX_swd_controller_cnt$write_1__VAL_5 = + (swd_controller_prescaler_ctr$Q_OUT == 8'd0) ? + x__h15006 : + 7'd33 ; + assign MUX_swd_controller_cnt$write_1__VAL_6 = + (swd_controller_prescaler_ctr$Q_OUT == 8'd0) ? x__h15006 : 7'd1 ; + assign MUX_swd_controller_data$write_1__VAL_1 = + { swd_in, swd_controller_data[32:1] } ; + assign MUX_swd_controller_data$write_1__VAL_2 = + { 1'd0, swd_controller_data[32:1] } ; + assign MUX_swd_controller_data$write_1__VAL_3 = + { z__h24896 ^ wdata[7], + wdata[7:0], + wdata[15:8], + wdata[23:16], + wdata[31:24] } ; + assign MUX_swd_controller_packet$write_1__VAL_2 = + { 1'd1, cmd[3:0], cmd[2] ? x__h20247 : x__h21446, 2'd1 } ; + assign MUX_swd_controller_packet$write_1__VAL_3 = + { swd_controller_packet[6:0], 1'd0 } ; + assign MUX_swd_controller_state$write_1__VAL_1 = + (swd_controller_ack == 3'b100) ? 4'd6 : 4'd7 ; + assign MUX_swd_controller_state$write_1__VAL_3 = + swd_controller_rnw ? 4'd5 : 4'd4 ; + assign MUX_swd_controller_state$write_1__VAL_7 = + swd_controller_request_in$whas ? 4'd1 : 4'd8 ; + always@(swd_controller_ack) + begin + case (swd_controller_ack) + 3'b001: MUX_swd_controller_status$write_1__VAL_1 = 3'd6; + 3'b010: MUX_swd_controller_status$write_1__VAL_1 = 3'd5; + 3'b100: MUX_swd_controller_status$write_1__VAL_1 = swd_controller_ack; + default: MUX_swd_controller_status$write_1__VAL_1 = 3'd7; + endcase + end + assign MUX_swd_controller_swd_out$write_1__VAL_2 = + swd_controller_cnt > 7'd71 || swd_controller_cnt <= 7'd55 || + x__h1438 ; + assign MUX_swd_controller_swd_out$write_1__VAL_3 = + swd_controller_cnt_2_ULE_8___d35 && swd_controller_packet[7] ; + + // inlined wires + assign swd_controller_request_in$whas = + WILL_FIRE_RL_do_reset && ready || + WILL_FIRE_RL_do_cmd && !cmd[7] ; + assign swd_controller_reset_in$whas = WILL_FIRE_RL_do_cmd && cmd[7] ; + + // register bus_reg_rdata + assign bus_reg_rdata$D_IN = rdata[7:0] ; + assign bus_reg_rdata$EN = WILL_FIRE_RL_do_bus_read_rdata ; + + // register bus_reg_status + assign bus_reg_status$D_IN = { state == 2'd0, 5'b0, status } ; + assign bus_reg_status$EN = read && en_status ; + + // register cmd + assign cmd$D_IN = MUX_cmd$write_1__SEL_1 ? MUX_cmd$write_1__VAL_1 : 9'd170 ; + assign cmd$EN = WILL_FIRE_RL_do_bus_write && en_cmd || WILL_FIRE_RL_do_rw ; + + // register rdata + assign rdata$D_IN = + WILL_FIRE_RL_do_bus_read_rdata ? + MUX_rdata$write_1__VAL_1 : + MUX_rdata$write_1__VAL_2 ; + assign rdata$EN = WILL_FIRE_RL_do_bus_read_rdata || WILL_FIRE_RL_do_rw ; + + // register ready + assign ready$D_IN = swd_controller_state == 4'd0 ; + assign ready$EN = 1'd1 ; + + // register state + always@(MUX_state$write_1__SEL_1 or + MUX_cmd$write_1__SEL_1 or + WILL_FIRE_RL_do_cmd or + MUX_state$write_1__VAL_3 or WILL_FIRE_RL_do_rw) + begin + case (1'b1) // synopsys parallel_case + MUX_state$write_1__SEL_1: state$D_IN = 2'd3; + MUX_cmd$write_1__SEL_1: state$D_IN = 2'd1; + WILL_FIRE_RL_do_cmd: state$D_IN = MUX_state$write_1__VAL_3; + WILL_FIRE_RL_do_rw: state$D_IN = 2'd0; + default: state$D_IN = 2'b10 /* unspecified value */ ; + endcase + end + assign state$EN = + WILL_FIRE_RL_do_reset && ready || + WILL_FIRE_RL_do_bus_write && en_cmd || + WILL_FIRE_RL_do_cmd || + WILL_FIRE_RL_do_rw ; + + // register status + assign status$D_IN = + swd_controller_rnw ? + (swd_controller_data_2_BIT_0_5_XOR_swd_controll_ETC___d298 ? + 2'd3 : + swd_controller_status[1:0]) : + swd_controller_status[1:0] ; + assign status$EN = WILL_FIRE_RL_do_rw ; + + // register swd_controller_ack + assign swd_controller_ack$D_IN = { swd_controller_ack[1:0], swd_in } ; + assign swd_controller_ack$EN = + swd_controller_state == 4'd3 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 ; + + // register swd_controller_cnt + always@(MUX_swd_controller_cnt$write_1__SEL_1 or + x__h15006 or + MUX_swd_controller_cnt$write_1__SEL_2 or + MUX_swd_controller_cnt$write_1__VAL_2 or + MUX_swd_controller_cnt$write_1__SEL_3 or + MUX_swd_controller_cnt$write_1__SEL_4 or + MUX_swd_controller_cnt$write_1__VAL_4 or + MUX_swd_controller_cnt$write_1__SEL_5 or + MUX_swd_controller_cnt$write_1__VAL_5 or + MUX_swd_controller_cnt$write_1__SEL_6 or + MUX_swd_controller_cnt$write_1__VAL_6) + begin + case (1'b1) // synopsys parallel_case + MUX_swd_controller_cnt$write_1__SEL_1: + swd_controller_cnt$D_IN = x__h15006; + MUX_swd_controller_cnt$write_1__SEL_2: + swd_controller_cnt$D_IN = MUX_swd_controller_cnt$write_1__VAL_2; + MUX_swd_controller_cnt$write_1__SEL_3: swd_controller_cnt$D_IN = 7'd3; + MUX_swd_controller_cnt$write_1__SEL_4: + swd_controller_cnt$D_IN = MUX_swd_controller_cnt$write_1__VAL_4; + MUX_swd_controller_cnt$write_1__SEL_5: + swd_controller_cnt$D_IN = MUX_swd_controller_cnt$write_1__VAL_5; + MUX_swd_controller_cnt$write_1__SEL_6: + swd_controller_cnt$D_IN = MUX_swd_controller_cnt$write_1__VAL_6; + default: swd_controller_cnt$D_IN = 7'b0101010 /* unspecified value */ ; + endcase + end + assign swd_controller_cnt$EN = + (swd_controller_state == 4'd7 || swd_controller_state == 4'd1 || + swd_controller_state == 4'd8) && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 || + swd_controller_state == 4'd4 && + swd_controller_prescaler_ctr$Q_OUT == 8'd1 || + swd_controller_state == 4'd2 && + swd_controller_prescaler_ctr$Q_OUT == 8'd1 || + swd_controller_state == 4'd0 && + (swd_controller_request_in$whas || + swd_controller_reset_in$whas) || + MUX_swd_controller_cnt$write_1__SEL_5 || + (swd_controller_state == 4'd6 || swd_controller_state == 4'd5) && + (swd_controller_prescaler_ctr$Q_OUT == 8'd0 || + swd_controller_prescaler_ctr$Q_OUT == 8'd1 && + swd_controller_cnt == 7'd0) ; + + // register swd_controller_data + always@(MUX_swd_controller_data$write_1__SEL_1 or + MUX_swd_controller_data$write_1__VAL_1 or + MUX_swd_controller_data$write_1__SEL_2 or + MUX_swd_controller_data$write_1__VAL_2 or + MUX_swd_controller_data$write_1__SEL_3 or + MUX_swd_controller_data$write_1__VAL_3 or WILL_FIRE_RL_do_rw) + begin + case (1'b1) // synopsys parallel_case + MUX_swd_controller_data$write_1__SEL_1: + swd_controller_data$D_IN = MUX_swd_controller_data$write_1__VAL_1; + MUX_swd_controller_data$write_1__SEL_2: + swd_controller_data$D_IN = MUX_swd_controller_data$write_1__VAL_2; + MUX_swd_controller_data$write_1__SEL_3: + swd_controller_data$D_IN = MUX_swd_controller_data$write_1__VAL_3; + WILL_FIRE_RL_do_rw: swd_controller_data$D_IN = 33'd0; + default: swd_controller_data$D_IN = + 33'h0AAAAAAAA /* unspecified value */ ; + endcase + end + assign swd_controller_data$EN = + swd_controller_state == 4'd5 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 || + swd_controller_state == 4'd6 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 || + WILL_FIRE_RL_do_cmd && !cmd[7] && !cmd[2] || + WILL_FIRE_RL_do_rw ; + + // register swd_controller_out_en + assign swd_controller_out_en$D_IN = + swd_controller_state == 4'd8 || swd_controller_state == 4'd1 || + swd_controller_state == 4'd6 ; + assign swd_controller_out_en$EN = 1'd1 ; + + // register swd_controller_packet + always@(MUX_state$write_1__SEL_1 or + MUX_swd_controller_packet$write_1__SEL_2 or + MUX_swd_controller_packet$write_1__VAL_2 or + MUX_swd_controller_packet$write_1__SEL_3 or + MUX_swd_controller_packet$write_1__VAL_3 or WILL_FIRE_RL_do_rw) + begin + case (1'b1) // synopsys parallel_case + MUX_state$write_1__SEL_1: swd_controller_packet$D_IN = 8'd165; + MUX_swd_controller_packet$write_1__SEL_2: + swd_controller_packet$D_IN = + MUX_swd_controller_packet$write_1__VAL_2; + MUX_swd_controller_packet$write_1__SEL_3: + swd_controller_packet$D_IN = + MUX_swd_controller_packet$write_1__VAL_3; + WILL_FIRE_RL_do_rw: swd_controller_packet$D_IN = 8'd0; + default: swd_controller_packet$D_IN = + 8'b10101010 /* unspecified value */ ; + endcase + end + assign swd_controller_packet$EN = + WILL_FIRE_RL_do_reset && ready || + WILL_FIRE_RL_do_cmd && !cmd[7] || + swd_controller_state == 4'd1 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 && + swd_controller_cnt_2_ULE_8___d35 || + WILL_FIRE_RL_do_rw ; + + // register swd_controller_rnw + assign swd_controller_rnw$D_IN = MUX_state$write_1__SEL_1 || cmd[2] ; + assign swd_controller_rnw$EN = swd_controller_request_in$whas ; + + // register swd_controller_state + always@(MUX_swd_controller_cnt$write_1__SEL_2 or + MUX_swd_controller_state$write_1__VAL_1 or + MUX_swd_controller_cnt$write_1__SEL_3 or + MUX_swd_controller_state$write_1__SEL_3 or + MUX_swd_controller_state$write_1__VAL_3 or + MUX_swd_controller_state$write_1__SEL_4 or + MUX_swd_controller_state$write_1__SEL_5 or + MUX_swd_controller_state$write_1__SEL_6 or + MUX_swd_controller_cnt$write_1__SEL_4 or + MUX_swd_controller_state$write_1__VAL_7) + begin + case (1'b1) // synopsys parallel_case + MUX_swd_controller_cnt$write_1__SEL_2: + swd_controller_state$D_IN = MUX_swd_controller_state$write_1__VAL_1; + MUX_swd_controller_cnt$write_1__SEL_3: swd_controller_state$D_IN = 4'd3; + MUX_swd_controller_state$write_1__SEL_3: + swd_controller_state$D_IN = MUX_swd_controller_state$write_1__VAL_3; + MUX_swd_controller_state$write_1__SEL_4: + swd_controller_state$D_IN = 4'd0; + MUX_swd_controller_state$write_1__SEL_5: + swd_controller_state$D_IN = 4'd2; + MUX_swd_controller_state$write_1__SEL_6: + swd_controller_state$D_IN = 4'd7; + MUX_swd_controller_cnt$write_1__SEL_4: + swd_controller_state$D_IN = MUX_swd_controller_state$write_1__VAL_7; + default: swd_controller_state$D_IN = 4'b1010 /* unspecified value */ ; + endcase + end + assign swd_controller_state$EN = + swd_controller_state == 4'd4 && + swd_controller_prescaler_ctr$Q_OUT == 8'd1 || + swd_controller_state == 4'd2 && + swd_controller_prescaler_ctr$Q_OUT == 8'd1 || + swd_controller_state == 4'd3 && + swd_controller_prescaler_ctr$Q_OUT == 8'd1 && + swd_controller_cnt == 7'd0 || + (swd_controller_state == 4'd7 || swd_controller_state == 4'd8) && + swd_controller_prescaler_ctr$Q_OUT == 8'd1 && + swd_controller_cnt == 7'd0 || + swd_controller_state == 4'd1 && + swd_controller_prescaler_ctr$Q_OUT == 8'd1 && + swd_controller_cnt == 7'd0 || + (swd_controller_state == 4'd6 || swd_controller_state == 4'd5) && + swd_controller_prescaler_ctr$Q_OUT == 8'd1 && + swd_controller_cnt == 7'd0 || + swd_controller_state == 4'd0 && + (swd_controller_request_in$whas || + swd_controller_reset_in$whas) ; + + // register swd_controller_status + assign swd_controller_status$D_IN = + MUX_swd_controller_status$write_1__SEL_1 ? + MUX_swd_controller_status$write_1__VAL_1 : + 3'd2 ; + assign swd_controller_status$EN = + swd_controller_state == 4'd7 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 || + WILL_FIRE_RL_do_rw ; + + // register swd_controller_swclk + assign swd_controller_swclk$D_IN = + !MUX_swd_controller_swclk$write_1__SEL_1 || + swd_controller_prescaler_ctr$Q_OUT != 8'd0 ; + assign swd_controller_swclk$EN = + swd_controller_state != 4'd0 && + (swd_controller_prescaler_ctr$Q_OUT == 8'd0 || + swd_controller_prescaler_ctr$Q_OUT == 8'd50) || + swd_controller_state == 4'd0 && + !swd_controller_request_in$whas && + !swd_controller_reset_in$whas ; + + // register swd_controller_swd_out + always@(MUX_swd_controller_data$write_1__SEL_2 or + swd_controller_data or + MUX_swd_controller_swd_out$write_1__SEL_2 or + MUX_swd_controller_swd_out$write_1__VAL_2 or + MUX_swd_controller_swd_out$write_1__SEL_3 or + MUX_swd_controller_swd_out$write_1__VAL_3 or + MUX_swd_controller_swd_out$write_1__SEL_4 or + MUX_swd_controller_swclk$write_1__SEL_2) + begin + case (1'b1) // synopsys parallel_case + MUX_swd_controller_data$write_1__SEL_2: + swd_controller_swd_out$D_IN = swd_controller_data[0]; + MUX_swd_controller_swd_out$write_1__SEL_2: + swd_controller_swd_out$D_IN = + MUX_swd_controller_swd_out$write_1__VAL_2; + MUX_swd_controller_swd_out$write_1__SEL_3: + swd_controller_swd_out$D_IN = + MUX_swd_controller_swd_out$write_1__VAL_3; + MUX_swd_controller_swd_out$write_1__SEL_4: + swd_controller_swd_out$D_IN = 1'd0; + MUX_swd_controller_swclk$write_1__SEL_2: + swd_controller_swd_out$D_IN = 1'd1; + default: swd_controller_swd_out$D_IN = 1'b0 /* unspecified value */ ; + endcase + end + assign swd_controller_swd_out$EN = + swd_controller_state == 4'd6 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 || + swd_controller_state == 4'd8 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 || + swd_controller_state == 4'd1 && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 || + (swd_controller_state == 4'd4 || swd_controller_state == 4'd2) && + swd_controller_prescaler_ctr$Q_OUT == 8'd0 || + swd_controller_state == 4'd0 && + !swd_controller_request_in$whas && + !swd_controller_reset_in$whas ; + + // register wdata + assign wdata$D_IN = { wdata[23:0], write_data } ; + assign wdata$EN = WILL_FIRE_RL_do_bus_write && en_wdata ; + + // submodule swd_controller_prescaler_ctr + assign swd_controller_prescaler_ctr$DATA_A = 8'h0 ; + assign swd_controller_prescaler_ctr$DATA_B = 8'd255 ; + assign swd_controller_prescaler_ctr$DATA_C = 8'h0 ; + assign swd_controller_prescaler_ctr$DATA_F = 8'd99 ; + assign swd_controller_prescaler_ctr$ADDA = 1'b0 ; + assign swd_controller_prescaler_ctr$ADDB = + swd_controller_prescaler_ctr$Q_OUT != 8'd0 ; + assign swd_controller_prescaler_ctr$SETC = 1'b0 ; + assign swd_controller_prescaler_ctr$SETF = + swd_controller_request_in$whas || swd_controller_reset_in$whas || + swd_controller_prescaler_ctr$Q_OUT == 8'd0 ; + + // remaining internal signals + assign _0xE79E__q2 = 16'hE79E ; + assign cmd_BITS_1_TO_0__q1 = cmd[1:0] ; + assign i__h1457 = 7'd71 - swd_controller_cnt ; + assign swd_controller_cnt_2_ULE_8___d35 = swd_controller_cnt <= 7'd8 ; + assign swd_controller_data_2_BIT_0_5_XOR_swd_controll_ETC___d298 = + z__h35551 ^ swd_controller_data[32] ; + assign x__h1438 = _0xE79E__q2[i__h1457[3:0]] ; + assign x__h15006 = swd_controller_cnt - 7'd1 ; + assign x__h20247 = x__h20260 ^ cmd_BITS_1_TO_0__q1[1] ; + assign x__h20260 = x__h20262 ^ cmd_BITS_1_TO_0__q1[0] ; + assign x__h20262 = ~cmd[3] ; + assign x__h21446 = x__h21459 ^ cmd_BITS_1_TO_0__q1[1] ; + assign x__h21459 = cmd[3] ^ cmd_BITS_1_TO_0__q1[0] ; + assign z__h24693 = wdata[24] ^ wdata[25] ; + assign z__h24700 = z__h24693 ^ wdata[26] ; + assign z__h24707 = z__h24700 ^ wdata[27] ; + assign z__h24714 = z__h24707 ^ wdata[28] ; + assign z__h24721 = z__h24714 ^ wdata[29] ; + assign z__h24728 = z__h24721 ^ wdata[30] ; + assign z__h24735 = z__h24728 ^ wdata[31] ; + assign z__h24742 = z__h24735 ^ wdata[16] ; + assign z__h24749 = z__h24742 ^ wdata[17] ; + assign z__h24756 = z__h24749 ^ wdata[18] ; + assign z__h24763 = z__h24756 ^ wdata[19] ; + assign z__h24770 = z__h24763 ^ wdata[20] ; + assign z__h24777 = z__h24770 ^ wdata[21] ; + assign z__h24784 = z__h24777 ^ wdata[22] ; + assign z__h24791 = z__h24784 ^ wdata[23] ; + assign z__h24798 = z__h24791 ^ wdata[8] ; + assign z__h24805 = z__h24798 ^ wdata[9] ; + assign z__h24812 = z__h24805 ^ wdata[10] ; + assign z__h24819 = z__h24812 ^ wdata[11] ; + assign z__h24826 = z__h24819 ^ wdata[12] ; + assign z__h24833 = z__h24826 ^ wdata[13] ; + assign z__h24840 = z__h24833 ^ wdata[14] ; + assign z__h24847 = z__h24840 ^ wdata[15] ; + assign z__h24854 = z__h24847 ^ wdata[0] ; + assign z__h24861 = z__h24854 ^ wdata[1] ; + assign z__h24868 = z__h24861 ^ wdata[2] ; + assign z__h24875 = z__h24868 ^ wdata[3] ; + assign z__h24882 = z__h24875 ^ wdata[4] ; + assign z__h24889 = z__h24882 ^ wdata[5] ; + assign z__h24896 = z__h24889 ^ wdata[6] ; + assign z__h35341 = swd_controller_data[0] ^ swd_controller_data[1] ; + assign z__h35348 = z__h35341 ^ swd_controller_data[2] ; + assign z__h35355 = z__h35348 ^ swd_controller_data[3] ; + assign z__h35362 = z__h35355 ^ swd_controller_data[4] ; + assign z__h35369 = z__h35362 ^ swd_controller_data[5] ; + assign z__h35376 = z__h35369 ^ swd_controller_data[6] ; + assign z__h35383 = z__h35376 ^ swd_controller_data[7] ; + assign z__h35390 = z__h35383 ^ swd_controller_data[8] ; + assign z__h35397 = z__h35390 ^ swd_controller_data[9] ; + assign z__h35404 = z__h35397 ^ swd_controller_data[10] ; + assign z__h35411 = z__h35404 ^ swd_controller_data[11] ; + assign z__h35418 = z__h35411 ^ swd_controller_data[12] ; + assign z__h35425 = z__h35418 ^ swd_controller_data[13] ; + assign z__h35432 = z__h35425 ^ swd_controller_data[14] ; + assign z__h35439 = z__h35432 ^ swd_controller_data[15] ; + assign z__h35446 = z__h35439 ^ swd_controller_data[16] ; + assign z__h35453 = z__h35446 ^ swd_controller_data[17] ; + assign z__h35460 = z__h35453 ^ swd_controller_data[18] ; + assign z__h35467 = z__h35460 ^ swd_controller_data[19] ; + assign z__h35474 = z__h35467 ^ swd_controller_data[20] ; + assign z__h35481 = z__h35474 ^ swd_controller_data[21] ; + assign z__h35488 = z__h35481 ^ swd_controller_data[22] ; + assign z__h35495 = z__h35488 ^ swd_controller_data[23] ; + assign z__h35502 = z__h35495 ^ swd_controller_data[24] ; + assign z__h35509 = z__h35502 ^ swd_controller_data[25] ; + assign z__h35516 = z__h35509 ^ swd_controller_data[26] ; + assign z__h35523 = z__h35516 ^ swd_controller_data[27] ; + assign z__h35530 = z__h35523 ^ swd_controller_data[28] ; + assign z__h35537 = z__h35530 ^ swd_controller_data[29] ; + assign z__h35544 = z__h35537 ^ swd_controller_data[30] ; + assign z__h35551 = z__h35544 ^ swd_controller_data[31] ; + + // handling of inlined registers + + always@(posedge CLK) + begin + if (swd_controller_cnt$EN) + swd_controller_cnt <= `BSV_ASSIGNMENT_DELAY swd_controller_cnt$D_IN; + if (swd_controller_data$EN) + swd_controller_data <= `BSV_ASSIGNMENT_DELAY swd_controller_data$D_IN; + if (swd_controller_packet$EN) + swd_controller_packet <= `BSV_ASSIGNMENT_DELAY + swd_controller_packet$D_IN; + if (swd_controller_rnw$EN) + swd_controller_rnw <= `BSV_ASSIGNMENT_DELAY swd_controller_rnw$D_IN; + end + + always@(posedge CLK or `BSV_RESET_EDGE RST_N) + if (RST_N == `BSV_RESET_VALUE) + begin + bus_reg_rdata <= `BSV_ASSIGNMENT_DELAY 8'd0; + bus_reg_status <= `BSV_ASSIGNMENT_DELAY 8'd0; + cmd <= `BSV_ASSIGNMENT_DELAY 9'd170; + rdata <= `BSV_ASSIGNMENT_DELAY 32'd0; + ready <= `BSV_ASSIGNMENT_DELAY 1'd0; + state <= `BSV_ASSIGNMENT_DELAY 2'd0; + status <= `BSV_ASSIGNMENT_DELAY 2'd0; + swd_controller_ack <= `BSV_ASSIGNMENT_DELAY 3'd0; + swd_controller_out_en <= `BSV_ASSIGNMENT_DELAY 1'd1; + swd_controller_state <= `BSV_ASSIGNMENT_DELAY 4'd0; + swd_controller_status <= `BSV_ASSIGNMENT_DELAY 3'd2; + swd_controller_swclk <= `BSV_ASSIGNMENT_DELAY 1'd0; + swd_controller_swd_out <= `BSV_ASSIGNMENT_DELAY 1'd0; + wdata <= `BSV_ASSIGNMENT_DELAY 32'd0; + end + else + begin + if (bus_reg_rdata$EN) + bus_reg_rdata <= `BSV_ASSIGNMENT_DELAY bus_reg_rdata$D_IN; + if (bus_reg_status$EN) + bus_reg_status <= `BSV_ASSIGNMENT_DELAY bus_reg_status$D_IN; + if (cmd$EN) cmd <= `BSV_ASSIGNMENT_DELAY cmd$D_IN; + if (rdata$EN) rdata <= `BSV_ASSIGNMENT_DELAY rdata$D_IN; + if (ready$EN) ready <= `BSV_ASSIGNMENT_DELAY ready$D_IN; + if (state$EN) state <= `BSV_ASSIGNMENT_DELAY state$D_IN; + if (status$EN) status <= `BSV_ASSIGNMENT_DELAY status$D_IN; + if (swd_controller_ack$EN) + swd_controller_ack <= `BSV_ASSIGNMENT_DELAY swd_controller_ack$D_IN; + if (swd_controller_out_en$EN) + swd_controller_out_en <= `BSV_ASSIGNMENT_DELAY + swd_controller_out_en$D_IN; + if (swd_controller_state$EN) + swd_controller_state <= `BSV_ASSIGNMENT_DELAY + swd_controller_state$D_IN; + if (swd_controller_status$EN) + swd_controller_status <= `BSV_ASSIGNMENT_DELAY + swd_controller_status$D_IN; + if (swd_controller_swclk$EN) + swd_controller_swclk <= `BSV_ASSIGNMENT_DELAY + swd_controller_swclk$D_IN; + if (swd_controller_swd_out$EN) + swd_controller_swd_out <= `BSV_ASSIGNMENT_DELAY + swd_controller_swd_out$D_IN; + if (wdata$EN) wdata <= `BSV_ASSIGNMENT_DELAY wdata$D_IN; + end + + // synopsys translate_off + `ifdef BSV_NO_INITIAL_BLOCKS + `else // not BSV_NO_INITIAL_BLOCKS + initial + begin + bus_reg_rdata = 8'hAA; + bus_reg_status = 8'hAA; + cmd = 9'h0AA; + rdata = 32'hAAAAAAAA; + ready = 1'h0; + state = 2'h2; + status = 2'h2; + swd_controller_ack = 3'h2; + swd_controller_cnt = 7'h2A; + swd_controller_data = 33'h0AAAAAAAA; + swd_controller_out_en = 1'h0; + swd_controller_packet = 8'hAA; + swd_controller_rnw = 1'h0; + swd_controller_state = 4'hA; + swd_controller_status = 3'h2; + swd_controller_swclk = 1'h0; + swd_controller_swd_out = 1'h0; + wdata = 32'hAAAAAAAA; + end + `endif // BSV_NO_INITIAL_BLOCKS + // synopsys translate_on + + // handling of system tasks + + // synopsys translate_off + always@(negedge CLK) + begin + #0; + if (RST_N != `BSV_RESET_VALUE) $write("state: "); + if (RST_N != `BSV_RESET_VALUE) + if (swd_controller_state == 4'd0) $write("IDLE"); + if (RST_N != `BSV_RESET_VALUE) + if (swd_controller_state == 4'd1) $write("PACKET"); + if (RST_N != `BSV_RESET_VALUE) + if (swd_controller_state == 4'd2) $write("P_TRN"); + if (RST_N != `BSV_RESET_VALUE) + if (swd_controller_state == 4'd3) $write("ACK"); + if (RST_N != `BSV_RESET_VALUE) + if (swd_controller_state == 4'd4) $write("A_TRN"); + if (RST_N != `BSV_RESET_VALUE) + if (swd_controller_state == 4'd5) $write("RDATA"); + if (RST_N != `BSV_RESET_VALUE) + if (swd_controller_state == 4'd6) $write("WDATA"); + if (RST_N != `BSV_RESET_VALUE) + if (swd_controller_state == 4'd7) $write("DONE"); + if (RST_N != `BSV_RESET_VALUE) + if (swd_controller_state != 4'd0 && swd_controller_state != 4'd1 && + swd_controller_state != 4'd2 && + swd_controller_state != 4'd3 && + swd_controller_state != 4'd4 && + swd_controller_state != 4'd5 && + swd_controller_state != 4'd6 && + swd_controller_state != 4'd7) + $write("RESET"); + if (RST_N != `BSV_RESET_VALUE) + $write(", swclk: %b, swd_out: %b, swd_in: %b, out_en: %b", + swd_controller_swclk, + swd_controller_swd_out, + swd_in, + swd_controller_out_en, + "\n"); + end + // synopsys translate_on +endmodule // swd_module + diff --git a/fpga-arch/system.vhd b/fpga-arch/system.vhd index 4047acb..0d851fd 100644 --- a/fpga-arch/system.vhd +++ b/fpga-arch/system.vhd @@ -109,6 +109,31 @@ architecture behavior of system is -- | | | | | | | | | | -- +----+ +------+ +----------+ +------+ +-----+ + -- Declaration of Verilog module as a component + COMPONENT swd_module + PORT + ( + CLK : IN STD_LOGIC; + RST_N : IN STD_LOGIC; + address : IN STD_LOGIC_VECTOR(15 DOWNTO 0); + write_data : IN STD_LOGIC_VECTOR(7 DOWNTO 0); + write : IN STD_LOGIC; + read : IN STD_LOGIC; + en_rdata : IN STD_LOGIC; + en_wdata : IN STD_LOGIC; + en_cmd : IN STD_LOGIC; + en_status : IN STD_LOGIC; + reg_rdata : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); + reg_status : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); + swclk : OUT STD_LOGIC; + swd_in : IN STD_LOGIC; + swd_out : OUT STD_LOGIC; + out_en : OUT STD_LOGIC; + trigger : OUT STD_LOGIC + ); + END COMPONENT; + + -- Function for easier address decoding. function addr_en ( bus_in: bus_in_t; @@ -150,6 +175,7 @@ architecture behavior of system is + 1 -- ISO7816 trigger + 1 -- I2C trigger + 1 -- SPI trigger + + 1 -- SWD trigger + pulse_gen_count -- Pulse generator outputs + chain_count; -- Chain trigger signal mtxl_in: std_logic_vector(mtxl_in_count-1 downto 0); @@ -161,7 +187,8 @@ architecture behavior of system is + 2 -- I2C + 1 -- SPI + 2 -- SPI slave - + 1; -- Clock + + 1 -- Clock + + 1; -- SWD signal mtxl_out: std_logic_vector(mtxl_out_count-1 downto 0); signal mtxl_out_uart_rx: std_logic_vector(uart_count-1 downto 0); signal mtxl_out_pulse_gen_start: std_logic_vector(pulse_gen_count-1 downto 0); @@ -172,6 +199,7 @@ architecture behavior of system is signal mtxl_out_spi_slave_sck: std_logic; signal mtxl_out_spi_slave_ss: std_logic; signal mtxl_out_clock_glitch_start: std_logic; + signal mtxl_out_swd_swdio: std_logic; signal mtxl_out_chain_events: std_logic_vector_array_t(chain_count-1 downto 0)(chain_size-1 downto 0); @@ -184,7 +212,8 @@ architecture behavior of system is + 3 -- I2C module + 4 -- SPI module + 1 -- SPI slave module - + 1; -- Clock + + 1 -- Clock + + 3; -- SWD signal mtxr_in: tristate_array_t(mtxr_in_count-1 downto 0); signal mtxr_in_uart_tx: std_logic_vector(uart_count-1 downto 0); signal mtxr_in_uart_trigger: std_logic_vector(uart_count-1 downto 0); @@ -203,6 +232,10 @@ architecture behavior of system is signal mtxr_in_spi_trigger: std_logic; signal mtxr_in_spi_slave_miso: std_logic; signal mtxr_in_clock_out: std_logic; + signal mtxr_in_swd_swdio: std_logic; + signal mtxr_in_swd_swdio_en: std_logic; + signal mtxr_in_swd_swclk: std_logic; + signal mtxr_in_swd_trigger: std_logic; signal mtxr_in_chain_out: std_logic_vector(chain_count-1 downto 0); -- Output signals of the output matrix @@ -258,6 +291,10 @@ architecture behavior of system is constant addr_clock_divisor_a: address_t := x"0a01"; constant addr_clock_divisor_b: address_t := x"0a02"; constant addr_clock_count: address_t := x"0a03"; + constant addr_swd_rdata: address_t := x"0b00"; + constant addr_swd_wdata: address_t := x"0b04"; + constant addr_swd_status: address_t := x"0b10"; + constant addr_swd_cmd: address_t := x"0b20"; constant addr_io_value_base: address_t := x"e000"; constant addr_io_config_base: address_t := x"e001"; constant addr_mtxl_base: address_t := x"f000"; @@ -307,6 +344,10 @@ architecture behavior of system is signal en_clock_divisor_a: std_logic; signal en_clock_divisor_b: std_logic; signal en_clock_count: std_logic; + signal en_swd_rdata: std_logic; + signal en_swd_wdata: std_logic; + signal en_swd_cmd: std_logic; + signal en_swd_status: std_logic; signal en_io_value: std_logic_vector(io_count-1 downto 0); signal en_io_config: std_logic_vector(io_count-1 downto 0); signal en_mtxl_sel: std_logic_vector(mtxl_out_count-1 downto 0); @@ -323,7 +364,8 @@ architecture behavior of system is + 1 -- Power control + 2 -- ISO7816 status and data + 4 -- I2C - + 2; -- SPI + + 2 -- SPI + + 2; -- SWD signal reg_io_value: std_logic_vector_array_t(io_count-1 downto 0) (7 downto 0); signal reg_version_data: byte_t; @@ -335,6 +377,7 @@ architecture behavior of system is signal reg_power_control: byte_t; signal reg_i2c_status, reg_i2c_data, reg_i2c_size_h, reg_i2c_size_l: byte_t; signal reg_spi_status, reg_spi_data: byte_t; + signal reg_swd_status, reg_swd_rdata: byte_t; -- State of the LEDs (when override is disabled in LEDs module). signal leds: std_logic_vector(23 downto 0); @@ -434,6 +477,10 @@ begin en_clock_divisor_a <= addr_en(bus_in, addr_clock_divisor_a); en_clock_divisor_b <= addr_en(bus_in, addr_clock_divisor_b); en_clock_count <= addr_en(bus_in, addr_clock_count); + en_swd_rdata <= addr_en(bus_in, addr_swd_rdata); + en_swd_wdata <= addr_en(bus_in, addr_swd_wdata); + en_swd_cmd <= addr_en(bus_in, addr_swd_cmd); + en_swd_status <= addr_en(bus_in, addr_swd_status); en_io_value <= addr_en_loop(bus_in, addr_io_value_base, x"0010", io_count); en_io_config <= addr_en_loop(bus_in, addr_io_config_base, x"0010", io_count); @@ -461,7 +508,9 @@ begin reg_iso7816_status & reg_iso7816_data & reg_spi_status & - reg_spi_data, + reg_spi_data & + reg_swd_rdata & + reg_swd_status, enables => en_io_value & en_pulse_gen_status & @@ -476,7 +525,9 @@ begin en_iso7816_status & en_iso7816_data & en_spi_status & - en_spi_data, + en_spi_data & + en_swd_rdata & + en_swd_status, value => bus_out.read_data ); -- I/O modules @@ -520,7 +571,7 @@ begin -- Version module e_version_module: entity work.version_module - generic map (version => "scaffold-0.9") + generic map (version => "scaffold-0.10") port map ( clock => clock, reset_n => reset_n, @@ -694,6 +745,27 @@ begin output => mtxr_in_clock_out, glitch_start => mtxl_out_clock_glitch_start ); + -- SWD module + c_swd: component swd_module + port map ( + CLK => clock, + RST_N => reset_n, + address => bus_in.address, + write_data => bus_in.write_data, + write => bus_in.write, + read => bus_in.read, + en_rdata => en_swd_rdata, + en_wdata => en_swd_wdata, + en_cmd => en_swd_cmd, + en_status => en_swd_status, + reg_rdata => reg_swd_rdata, + reg_status => reg_swd_status, + swclk => mtxr_in_swd_swclk, + swd_in => mtxl_out_swd_swdio, + swd_out => mtxr_in_swd_swdio, + out_en => mtxr_in_swd_swdio_en, + trigger => mtxr_in_swd_trigger ); + -- Left matrix module e_left_matrix_module: entity work.left_matrix_module generic map ( @@ -733,6 +805,8 @@ begin end loop; mtxl_out_clock_glitch_start <= mtxl_out(i); i := i + 1; + mtxl_out_swd_swdio <= mtxl_out(i); + i := i + 1; assert i = mtxl_out_count; end process; @@ -740,6 +814,7 @@ begin -- mtxr signals are feedback outputs of modules. -- Warning: signals order is inversed regarding Python API code. mtxl_in <= + mtxr_in_swd_trigger & mtxr_in_chain_out & mtxr_in_pulse_gen_out & mtxr_in_spi_trigger & @@ -783,7 +858,12 @@ begin mtxr_in_spi_trigger, mtxr_in_spi_slave_miso, mtxr_in_chain_out, - mtxr_in_clock_out ) + mtxr_in_clock_out, + mtxr_in_swd_swclk, + mtxr_in_swd_swdio, + mtxr_in_swd_swdio_en, + mtxr_in_swd_trigger + ) variable i: integer; begin mtxr_in(0) <= "00"; -- Z @@ -831,6 +911,11 @@ begin -- Clock module mtxr_in(i) <= "1" & mtxr_in_clock_out; i := i + 1; + -- SWD module + mtxr_in(i) <= "1" & mtxr_in_swd_swclk; + mtxr_in(i+1) <= mtxr_in_swd_swdio_en & mtxr_in_swd_swdio; + mtxr_in(i+2) <= "1" & mtxr_in_swd_trigger; + i := i + 3; -- If you add other signals, please dont forget to update the sensivity -- list for simulation support. assert i = mtxr_in_count;