@@ -11,11 +11,13 @@ export CounterAddress(..);
1111export CounterId ( ..) ;
1212export Counter ( ..) ;
1313export Counters ( ..) ;
14+ export TransmitterOutputEnableMode ( ..) ;
1415
1516export mkController ;
1617export read_controller_register_into ;
1718export clear_controller_counter ;
1819export read_controller_counter_into ;
20+ export transceiver_state_value ;
1921
2022import BRAMCore :: * ;
2123import BRAMFIFO :: * ;
@@ -41,12 +43,14 @@ import IgnitionTransmitter::*;
4143
4244typedef struct {
4345 Integer tick_period;
46+ Integer transmitter_output_disable_timeout;
4447 IgnitionProtocol:: Parameters protocol;
4548} Parameters;
4649
4750instance DefaultValue # ( Parameters) ;
4851 defaultValue = Parameters {
4952 tick_period : 1000 ,
53+ transmitter_output_disable_timeout : 100 ,
5054 protocol : defaultValue} ;
5155endinstance
5256
@@ -121,6 +125,13 @@ typedef UInt#(8) Counter;
121125typedef Server# ( RegisterRequest# ( n) , Bit # ( 8 )) Registers# ( numeric type n) ;
122126typedef Server# ( CounterAddress# ( n) , Counter) Counters# ( numeric type n) ;
123127
128+ typedef enum {
129+ Disabled = 0 ,
130+ EnabledWhenReceiverAligned = 1 ,
131+ EnabledWhenTargetPresent = 2 ,
132+ AlwaysEnabled = 3
133+ } TransmitterOutputEnableMode deriving ( Bits , Eq , FShow ) ;
134+
124135// An interface for a Controller with `n` "channels" which processes events
125136// submitted by a receiver, answers requests from upstack software and generates
126137// events for a transmitter.
@@ -247,7 +258,6 @@ module mkController #(
247258 //
248259 FIFOF # ( Bit # ( 8 )) software_response < - mkFIFOF() ;
249260 FIFOF # ( TransmitterEvent# ( n)) transmitter_events < - mkFIFOF() ;
250- FIFOF # ( Bool ) transmitter_output_enabled_events < - mkFIFOF() ;
251261
252262 let event_handler_idle =
253263 ! ( software_request.notEmpty ||
@@ -899,16 +909,63 @@ module mkController #(
899909 software_request.first.op,
900910 software_request.first.register)) matches
901911 { tagged Read, TransceiverState} :
902- respond_with( transceiver) ;
912+ respond_with( pack ( transceiver) [ 5 : 0 ] ) ;
903913
904914 { tagged Write .b, TransceiverState} : begin
905- let request = TransceiverRegister'( unpack( truncate( b))) ;
915+ TransceiverRegister request = unpack( extend( b)) ;
916+ TransceiverRegister transceiver_ = transceiver;
917+
918+ transceiver_.transmitter_output_enable_mode =
919+ request.transmitter_output_enable_mode;
920+
921+ case ( request.transmitter_output_enable_mode)
922+ Disabled : begin
923+ transceiver_.transmitter_output_disable_timeout_ticks_remaining = 0 ;
924+ transceiver_.transmitter_output_enabled = False ;
925+ end
926+
927+ EnabledWhenReceiverAligned :
928+ if ( transceiver.receiver_status.receiver_aligned) begin
929+ transceiver_.transmitter_output_disable_timeout_ticks_remaining = 0 ;
930+ transceiver_.transmitter_output_enabled = True ;
931+ end
932+ else if ( transceiver.transmitter_output_enabled) begin
933+ transceiver_.transmitter_output_disable_timeout_ticks_remaining =
934+ fromInteger( parameters.transmitter_output_disable_timeout) ;
935+ end
936+
937+ EnabledWhenTargetPresent :
938+ if ( presence.present) begin
939+ transceiver_.transmitter_output_disable_timeout_ticks_remaining = 0 ;
940+ transceiver_.transmitter_output_enabled = True ;
941+ end
942+ else if ( transceiver.transmitter_output_enabled) begin
943+ transceiver_.transmitter_output_disable_timeout_ticks_remaining =
944+ fromInteger( parameters.transmitter_output_disable_timeout) ;
945+ end
946+
947+ AlwaysEnabled : begin
948+ transceiver_.transmitter_output_disable_timeout_ticks_remaining = 0 ;
949+ transceiver_.transmitter_output_enabled = True ;
950+ end
951+ endcase
952+
953+ if ( transceiver.transmitter_output_enabled &&
954+ ! transceiver_.transmitter_output_enabled) begin
955+ $display ( " %5t [Controller %02d] Transmitter output disabled" ,
956+ $time ,
957+ current_controller) ;
958+ end
959+ else if ( ! transceiver.transmitter_output_enabled &&
960+ transceiver_.transmitter_output_enabled) begin
961+ $display ( " %5t [Controller %02d] Transmitter output enabled" ,
962+ $time ,
963+ current_controller) ;
964+ end
906965
907- // Update the transceiver register. A change to the transmitter
908- // output enable mode is applied by on the next tick event. See
909- // `do_handle_tick_event`.
910- transceiver.transmitter_output_mode <=
911- request.transmitter_output_mode;
966+ // Update the transceiver register. Any changes are applied on
967+ // the next tick event. See `do_handle_tick_event`.
968+ transceiver <= transceiver_;
912969 end
913970
914971 { tagged Read, ControllerState} :
@@ -978,9 +1035,10 @@ module mkController #(
9781035 let target_timeout = False ;
9791036 let hello_sent = False ;
9801037
981- // Copy the `presence` register so indiviual fields can be updated as
982- // appropriate.
1038+ // Copy the `presence` and `transceiver` registers so indiviual fields
1039+ // can be updated as appropriate.
9831040 let presence_ = presence;
1041+ let transceiver_ = transceiver;
9841042
9851043 // Update the presence history if a Status message timeout occures.
9861044 if ( presence.status_message_timeout_ticks_remaining == 0 ) begin
@@ -1017,38 +1075,71 @@ module mkController #(
10171075 presence <= presence_;
10181076 presence_summary_r[ current_controller] <= presence_.present;
10191077
1078+ // Count down until the next Hello.
1079+ if ( hello_timer.ticks_remaining == 0 ) begin
1080+ hello_timer.ticks_remaining <=
1081+ fromInteger( parameters.protocol.hello_interval) ;
1082+ end
1083+ else begin
1084+ hello_timer.ticks_remaining <= hello_timer.ticks_remaining - 1 ;
1085+ end
1086+
1087+ // Count down the transmitter disable timeout if the counter is active.
1088+ if ( transceiver.transmitter_output_disable_timeout_ticks_remaining != 0 ) begin
1089+ transceiver_.transmitter_output_disable_timeout_ticks_remaining =
1090+ transceiver.transmitter_output_disable_timeout_ticks_remaining - 1 ;
1091+ end
1092+ // Start the disable timeout counter if the Target has been declared not
1093+ // present.
1094+ else if ( transceiver.transmitter_output_enable_mode ==
1095+ EnabledWhenTargetPresent &&
1096+ presence.present &&
1097+ ! presence_.present) begin
1098+ transceiver_.transmitter_output_disable_timeout_ticks_remaining =
1099+ fromInteger( parameters.transmitter_output_disable_timeout) ;
1100+ end
1101+
1102+ // Disable the transmitter output if the transmitter disable output
1103+ // timer expires. A count of one is used as the timeout here since this
1104+ // does not have to be precise and allows a value of zero to indicate
1105+ // the counter is not active.
1106+ if ( transceiver.transmitter_output_enabled &&
1107+ transceiver.transmitter_output_disable_timeout_ticks_remaining == 1 ) begin
1108+ $display ( " %5t [Controller %02d] Transmitter output disabled" ,
1109+ $time ,
1110+ current_controller) ;
1111+
1112+ transceiver_.transmitter_output_enabled = False ;
1113+ end
1114+
1115+ // Write back the transceiver state.
1116+ transceiver <= transceiver_;
1117+
10201118 // Transmit an Hello message if the Hello timer expires.
10211119 if ( hello_timer.ticks_remaining == 0 ) begin
10221120 $display ( " %5t [Controller %02d] Hello" ,
10231121 $time ,
10241122 current_controller) ;
10251123
1026- hello_timer.ticks_remaining <=
1027- fromInteger( parameters.protocol.hello_interval) ;
1028-
10291124 transmitter_events.enq(
10301125 TransmitterEvent {
10311126 id : current_controller,
10321127 ev : tagged Message tagged Hello} ) ;
10331128
10341129 hello_sent = True ;
10351130 end
1036- // Count down the Hello timer.
1131+ // Transmit an OutputEnable event otherwise. These are sent every tick
1132+ // so that even if a state change in the output enable is requested
1133+ // during the same tick as the Hello message above the state will
1134+ // converge at most one tick later.
10371135 else begin
1038- hello_timer.ticks_remaining <= hello_timer.ticks_remaining - 1 ;
1136+ transmitter_events.enq(
1137+ TransmitterEvent {
1138+ id : current_controller,
1139+ ev : tagged OutputEnabled
1140+ transceiver_.transmitter_output_enabled} ) ;
10391141 end
10401142
1041- // Update the transmitter output enable based on its enable mode and
1042- // Target presence.
1043- case ( transceiver.transmitter_output_mode)
1044- Disabled :
1045- transmitter_output_enabled_events.enq( False ) ;
1046- EnabledWhenTargetPresent :
1047- transmitter_output_enabled_events.enq( presence.present) ;
1048- AlwaysEnabled :
1049- transmitter_output_enabled_events.enq( True ) ;
1050- endcase
1051-
10521143 // Enqueue a request to update the appropriate counters.
10531144 if ( status_timeout || target_timeout || hello_sent) begin
10541145 enq_countable_application_events(
@@ -1106,6 +1197,25 @@ module mkController #(
11061197 presence <= presence_;
11071198 presence_summary_r[ current_controller] <= presence_.present;
11081199
1200+ // Update the transmitter output enabled state if configured.
1201+ // The actual TransmitterEvent will be sent on the next tick.
1202+ // See the Tick handler.
1203+ TransceiverRegister transceiver_ = transceiver;
1204+
1205+ if ( transceiver.transmitter_output_enable_mode ==
1206+ EnabledWhenTargetPresent &&
1207+ ! presence.present &&
1208+ presence_.present) begin
1209+ $display ( " %5t [Controller %02d] Transmitter output enabled" ,
1210+ $time ,
1211+ current_controller) ;
1212+
1213+ transceiver_.transmitter_output_enabled = True ;
1214+ transceiver_.transmitter_output_disable_timeout_ticks_remaining = 0 ;
1215+ end
1216+
1217+ transceiver <= transceiver_;
1218+
11091219 enq_countable_application_events(
11101220 CountableApplicationEvents {
11111221 status_received : True ,
@@ -1216,14 +1326,45 @@ module mkController #(
12161326 $time ,
12171327 current_controller) ;
12181328
1219- transceiver.receiver_status <= link_status_none;
1329+ TransceiverRegister transceiver_ = transceiver;
1330+
1331+ transceiver_.receiver_status = link_status_none;
1332+
1333+ if ( transceiver.transmitter_output_enable_mode ==
1334+ EnabledWhenReceiverAligned &&
1335+ transceiver.transmitter_output_enabled) begin
1336+ // A ReceiverReset means the receiver is not aligned anymore
1337+ // and the disable timeout counter should be started.
1338+ transceiver_.transmitter_output_disable_timeout_ticks_remaining =
1339+ fromInteger( parameters.transmitter_output_disable_timeout) ;
1340+ end
1341+
1342+ // Write back the transceiver state.
1343+ transceiver <= transceiver_;
12201344
12211345 enq_countable_transceiver_events(
12221346 countable_transceiver_events_receiver_reset) ;
12231347 end
12241348
12251349 tagged ReceiverStatusChange .current_status: begin
1226- transceiver.receiver_status <= current_status;
1350+ TransceiverRegister transceiver_ = transceiver;
1351+
1352+ transceiver_.receiver_status = current_status;
1353+
1354+ if ( transceiver.transmitter_output_enable_mode ==
1355+ EnabledWhenReceiverAligned &&
1356+ ! transceiver.transmitter_output_enabled &&
1357+ current_status.receiver_aligned) begin
1358+ $display ( " %5t [Controller %02d] Transmitter output enabled" ,
1359+ $time ,
1360+ current_controller) ;
1361+
1362+ transceiver_.transmitter_output_enabled = True ;
1363+ transceiver_.transmitter_output_disable_timeout_ticks_remaining = 0 ;
1364+ end
1365+
1366+ // Write back the transceiver state.
1367+ transceiver <= transceiver_;
12271368
12281369 enq_countable_transceiver_events(
12291370 determine_transceiver_events(
@@ -1255,11 +1396,6 @@ module mkController #(
12551396 event_handler_state <= AwaitingEvent;
12561397 endrule
12571398
1258- (* fire_when_enabled *)
1259- rule do_discard_transmitter_output_enabled_events;
1260- transmitter_output_enabled_events.deq() ;
1261- endrule
1262-
12631399 interface ControllerTransceiverClient txr;
12641400 interface Get tx = toGet( transmitter_events) ;
12651401 interface Put rx = toPut( receiver_events) ;
@@ -1332,16 +1468,10 @@ typedef struct {
13321468 Maybe # ( t) data;
13331469} RegisterFileRequest# ( numeric type n, type t) deriving ( Bits , Eq , FShow ) ;
13341470
1335- typedef enum {
1336- Disabled = 0 ,
1337- EnabledWhenTargetPresent = 1 ,
1338- AlwaysEnabled = 2
1339- } TransmitterOutputMode deriving ( Bits , Eq , FShow ) ;
1340-
13411471typedef struct {
13421472 ControllerId# ( n) id;
13431473 union tagged {
1344- TransmitterOutputMode SetTransmitterOutputMode ;
1474+ TransmitterOutputEnableMode SetTransmitterOutputEnableMode ;
13451475 SystemPowerRequest SystemPowerRequest;
13461476 } ev;
13471477} SoftwareEvent# ( numeric type n) deriving ( Bits , Eq , FShow ) ;
@@ -1447,8 +1577,9 @@ typedef struct {
14471577} PresenceRegister deriving ( Bits , FShow ) ;
14481578
14491579typedef struct {
1450- TransmitterOutputMode transmitter_output_mode;
1451- Bit # ( 1 ) reserved;
1580+ UInt # ( 8 ) transmitter_output_disable_timeout_ticks_remaining;
1581+ TransmitterOutputEnableMode transmitter_output_enable_mode;
1582+ Bool transmitter_output_enabled;
14521583 LinkStatus receiver_status;
14531584} TransceiverRegister deriving ( Bits , FShow ) ;
14541585
@@ -1522,6 +1653,12 @@ function Stmt read_controller_counter_into(
15221653 endaction
15231654 endseq ;
15241655
1656+ function Bit # ( 8 ) transceiver_state_value(
1657+ TransmitterOutputEnableMode mode,
1658+ Bool transmitter_status,
1659+ LinkStatus receiver_status) =
1660+ { 2'h0 , pack( mode) , pack( transmitter_status) , pack( receiver_status) } ;
1661+
15251662// Given a bit_vector_t with zero or more bits indicating requests and a
15261663// bit_vector_t with exactly one bit set indicating the preferred (next) request
15271664// to select, round-robin select the next request.
0 commit comments