Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
X
x393_sata
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
x393_sata
Commits
e94b62c6
Commit
e94b62c6
authored
Feb 08, 2016
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added modupe to abort/recover AXI HP port after SATA errors, more debugging of the hardware
parent
50ca592a
Changes
15
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
1207 additions
and
312 deletions
+1207
-312
.project
.project
+17
-17
ahci_dma.v
ahci/ahci_dma.v
+211
-28
ahci_fsm.v
ahci/ahci_fsm.v
+21
-6
ahci_sata_layers.v
ahci/ahci_sata_layers.v
+7
-5
ahci_top.v
ahci/ahci_top.v
+109
-74
axi_ahci_regs.v
ahci/axi_ahci_regs.v
+15
-7
axi_hp_abort.v
ahci/axi_hp_abort.v
+142
-0
sata_ahci_top.v
ahci/sata_ahci_top.v
+6
-3
action_decoder.v
generated/action_decoder.v
+1
-1
condition_mux.v
generated/condition_mux.v
+93
-45
ahci_fsm_sequence.py
helpers/ahci_fsm_sequence.py
+16
-9
ahxi_fsm_code.vh
includes/ahxi_fsm_code.vh
+1
-1
x393sata.py
py393sata/x393sata.py
+321
-15
tb_ahci.tf
tb/tb_ahci.tf
+62
-8
tb_ahci_01.sav
tb_ahci_01.sav
+185
-93
No files found.
.project
View file @
e94b62c6
...
...
@@ -52,87 +52,87 @@
<link>
<name>
vivado_logs/VivadoBitstream.log
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoBitstream-2016020
5231700944
.log
</location>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoBitstream-2016020
8095350202
.log
</location>
</link>
<link>
<name>
vivado_logs/VivadoOpt.log
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoOpt-2016020
5231700944
.log
</location>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoOpt-2016020
8095350202
.log
</location>
</link>
<link>
<name>
vivado_logs/VivadoOptPhys.log
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoOptPhys-2016020
5231700944
.log
</location>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoOptPhys-2016020
8095350202
.log
</location>
</link>
<link>
<name>
vivado_logs/VivadoOptPower.log
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoOptPower-2016020
5231700944
.log
</location>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoOptPower-2016020
8095350202
.log
</location>
</link>
<link>
<name>
vivado_logs/VivadoPlace.log
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoPlace-2016020
5231700944
.log
</location>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoPlace-2016020
8095350202
.log
</location>
</link>
<link>
<name>
vivado_logs/VivadoRoute.log
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoRoute-2016020
5231700944
.log
</location>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoRoute-2016020
8095350202
.log
</location>
</link>
<link>
<name>
vivado_logs/VivadoSynthesis.log
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoSynthesis-2016020
5231700944
.log
</location>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoSynthesis-2016020
8095139740
.log
</location>
</link>
<link>
<name>
vivado_logs/VivadoTimimgSummaryReportImplemented.log
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoTimimgSummaryReportImplemented-2016020
5231700944
.log
</location>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoTimimgSummaryReportImplemented-2016020
8095350202
.log
</location>
</link>
<link>
<name>
vivado_logs/VivadoTimimgSummaryReportSynthesis.log
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoTimimgSummaryReportSynthesis-2016020
5231700944
.log
</location>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoTimimgSummaryReportSynthesis-2016020
8095139740
.log
</location>
</link>
<link>
<name>
vivado_logs/VivadoTimingReportImplemented.log
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoTimingReportImplemented-2016020
5231700944
.log
</location>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoTimingReportImplemented-2016020
8095350202
.log
</location>
</link>
<link>
<name>
vivado_logs/VivadoTimingReportSynthesis.log
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoTimingReportSynthesis-2016020
5231700944
.log
</location>
<location>
/home/andrey/git/x393_sata/vivado_logs/VivadoTimingReportSynthesis-2016020
8095139740
.log
</location>
</link>
<link>
<name>
vivado_state/x393_sata-opt-phys.dcp
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_state/x393_sata-opt-phys-2016020
5231700944
.dcp
</location>
<location>
/home/andrey/git/x393_sata/vivado_state/x393_sata-opt-phys-2016020
8095350202
.dcp
</location>
</link>
<link>
<name>
vivado_state/x393_sata-opt-power.dcp
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_state/x393_sata-opt-power-2016020
5231700944
.dcp
</location>
<location>
/home/andrey/git/x393_sata/vivado_state/x393_sata-opt-power-2016020
8095350202
.dcp
</location>
</link>
<link>
<name>
vivado_state/x393_sata-opt.dcp
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_state/x393_sata-opt-2016020
5231700944
.dcp
</location>
<location>
/home/andrey/git/x393_sata/vivado_state/x393_sata-opt-2016020
8095350202
.dcp
</location>
</link>
<link>
<name>
vivado_state/x393_sata-place.dcp
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_state/x393_sata-place-2016020
5231700944
.dcp
</location>
<location>
/home/andrey/git/x393_sata/vivado_state/x393_sata-place-2016020
8095350202
.dcp
</location>
</link>
<link>
<name>
vivado_state/x393_sata-route.dcp
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_state/x393_sata-route-2016020
5231700944
.dcp
</location>
<location>
/home/andrey/git/x393_sata/vivado_state/x393_sata-route-2016020
8095350202
.dcp
</location>
</link>
<link>
<name>
vivado_state/x393_sata-synth.dcp
</name>
<type>
1
</type>
<location>
/home/andrey/git/x393_sata/vivado_state/x393_sata-synth-2016020
5231700944
.dcp
</location>
<location>
/home/andrey/git/x393_sata/vivado_state/x393_sata-synth-2016020
8095139740
.dcp
</location>
</link>
</linkedResources>
</projectDescription>
ahci/ahci_dma.v
View file @
e94b62c6
This diff is collapsed.
Click to expand it.
ahci/ahci_fsm.v
View file @
e94b62c6
...
...
@@ -144,7 +144,7 @@ module ahci_fsm
input
dma_cmd_busy
,
// output reg (DMA engine is processing PRDs)
/// input dma_cmd_done, // output (last PRD is over)
output
dma_cmd_abort
,
// try to abort a command
input
dma_abort_done
,
// if abort is not needed, will generate dma_abort_done just next cycle
// Communication with ahci_fis_receive (some are unused)
// Debug features
...
...
@@ -257,15 +257,20 @@ module ahci_fsm
// reg jump_r;
reg
[
2
:
0
]
fsm_jump
;
wire
fsm_next
;
reg
fsm_next_r
;
//
reg fsm_next_r;
reg
fsm_actions
;
// processing actions
reg
fsm_act_busy
;
reg
[
1
:
0
]
fsm_transitions
;
// processing transitions
reg
fsm_preload
;
// read first sequence data (2 cycles for regen)
// wire [7:0] precond_w = pgm_data[17:10]; // select what to use - cond_met_w valis after precond_w, same time as conditions
// reg [7:0] conditions;
wire
pre_jump_w
=
(
|
async_pend_r
)
?
async_ackn
:
|
(
cond_met_w
&
fsm_transitions
[
1
])
;
wire
fsm_act_done
=
get_fis_done
||
xmit_done
||
(
syncesc_send_pend
&&
syncesc_send_done
)
;
// wire pre_jump_w = (|async_pend_r) ? async_ackn : |(cond_met_w & fsm_transitions[1]);
wire
pre_jump_w
=
(
|
async_pend_r
)
?
async_ackn
:
(
cond_met_w
&
fsm_transitions
[
1
])
;
wire
fsm_act_done
=
get_fis_done
||
xmit_done
||
(
syncesc_send_pend
&&
syncesc_send_done
)
||
dma_abort_done
||
asynq_rq
;
// cominit_got || pcmd_st_cleared
wire
fsm_wait_act_w
=
pgm_data
[
16
]
;
// this action requires waiting for done
wire
fsm_last_act_w
=
pgm_data
[
17
]
;
...
...
@@ -283,6 +288,14 @@ module ahci_fsm
wire
phy_ready_chng_w
=
!
hba_rst
&&
!
was_rst
&&
(
phy_ready
!=
phy_ready_prev
)
;
reg
was_last_action_r
;
// delay last action if it was fsm_wait_act;
wire
fsm_transitions_w
=
// next will be transitions processing
(
fsm_last_act_w
&&
fsm_actions
&&
fsm_next
&&
!
fsm_wait_act_w
)
||
(
fsm_act_busy
&&
fsm_act_done
&&
was_last_action_r
)
;
wire
conditions_ce
=
// copy all conditions to the register so they will not change while iterating through them
!
fsm_transitions_w
&&
!
fsm_transitions
[
0
]
;
assign
fsm_next
=
(
fsm_preload
||
(
fsm_actions
&&
!
update_busy
&&
!
fsm_act_busy
)
||
fsm_transitions
[
0
])
&&
!
async_pend_r
[
0
]
;
// quiet if received cominit is pending
assign
update_all
=
fsm_jump
[
0
]
;
...
...
@@ -344,8 +357,9 @@ module ahci_fsm
if
(
fsm_actions
&&
fsm_next
)
was_last_action_r
<=
fsm_last_act_w
;
if
(
hba_rst
||
pre_jump_w
)
fsm_transitions
<=
0
;
else
if
((
fsm_last_act_w
&&
fsm_actions
&&
fsm_next
&&
!
fsm_wait_act_w
)
||
(
fsm_act_busy
&&
fsm_act_done
&&
was_last_action_r
)
)
fsm_transitions
<=
1
;
else
if
(
fsm_transitions_w
)
fsm_transitions
<=
1
;
// else if ((fsm_last_act_w && fsm_actions && fsm_next && !fsm_wait_act_w) ||
// (fsm_act_busy && fsm_act_done && was_last_action_r) ) fsm_transitions <= 1;
else
fsm_transitions
<=
{
fsm_transitions
[
0
]
,
fsm_transitions
[
0
]
};
if
(
hba_rst
)
fsm_preload
<=
0
;
...
...
@@ -460,6 +474,7 @@ module ahci_fsm
// Condition inputs may be registered if needed
condition_mux
condition_mux_i
(
.
clk
(
mclk
)
,
// input
.
ce
(
conditions_ce
)
,
// input
.
sel
(
pgm_data
[
17
:
10
])
,
// input[7:0]
.
condition
(
cond_met_w
)
,
// output
//COMPOSITE
...
...
ahci/ahci_sata_layers.v
View file @
e94b62c6
...
...
@@ -92,7 +92,9 @@ module ahci_sata_layers #(
input
wire
rxp_in
,
input
wire
rxn_in
,
output
[
31
:
0
]
debug_sata
output
[
31
:
0
]
debug_phy
,
output
[
31
:
0
]
debug_link
)
;
localparam
PHY_SPEED
=
2
;
// SATA2
...
...
@@ -169,8 +171,8 @@ module ahci_sata_layers #(
wire
d2h_fifo_wr
=
ll_d2h_valid
||
fis_over_r
;
// fis_over_r will push FIS end to FIFO
reg
h2d_pending
;
// HBA started sending FIS to fifo
wire
[
31
:
0
]
debug_phy
;
wire
[
31
:
0
]
debug_link
;
//
wire [31:0] debug_phy;
//
wire [31:0] debug_link;
wire
rxelsfull
;
wire
rxelsempty
;
...
...
@@ -184,7 +186,7 @@ module ahci_sata_layers #(
// assign debug_sata = {debug_link[31:4],debug_phy[3:0]} ; //
// assign debug_sata = {debug_link[31:8],debug_phy[7:0]} ; //
assign
debug_sata
=
{
debug_link
[
27
:
20
]
,
debug_phy
[
23
:
0
]
}
;
//
//
assign debug_sata = {debug_link[27:20],debug_phy[23:0]} ; //
assign
ll_h2d_last
=
(
h2d_type_out
==
H2D_TYPE_FIS_LAST
)
;
assign
d2h_valid
=
d2h_nempty
;
...
...
@@ -260,7 +262,7 @@ module ahci_sata_layers #(
.
link_reset
(
ll_link_reset
)
,
// input wire // oob sequence is reinitiated and link now is not established or rxelecidle
.
sync_escape_req
(
syncesc_send
)
,
// input wire // TL demands to brutally cancel current transaction
.
sync_escape_ack
(
syncesc_send_done
)
,
// output wire // acknowlegement of a successful reception?
.
incom_stop_req
(
pcmd_st_cleared
)
,
// input wire // TL demands to stop current recieving session
.
incom_stop_req
(
pcmd_st_cleared
)
,
// input wire // TL demands to stop current recieving session
.
link_established
(
link_established
)
,
// inputs from phy
.
phy_ready
(
phy_ready
)
,
// input wire // phy is ready - link is established
...
...
ahci/ahci_top.v
View file @
e94b62c6
This diff is collapsed.
Click to expand it.
ahci/axi_ahci_regs.v
View file @
e94b62c6
...
...
@@ -115,7 +115,10 @@ module axi_ahci_regs#(
output
afi_cache_set
,
output
was_hba_rst
,
// last reset was hba reset (not counting system reset)
output
was_port_rst
,
// last reset was port reset
input
[
31
:
0
]
debug_in
input
[
31
:
0
]
debug_in0
,
input
[
31
:
0
]
debug_in1
,
input
[
31
:
0
]
debug_in2
,
input
[
31
:
0
]
debug_in3
`ifdef
USE_DATASCOPE
// Datascope interface (write to memory that can be software-read)
,
input
datascope_clk
,
...
...
@@ -188,6 +191,7 @@ module axi_ahci_regs#(
reg
wait_first_access
=
RESET_TO_FIRST_ACCESS
;
// keep port reset until first access
wire
any_access
=
bram_wen_r
||
bram_ren
[
0
]
;
reg
debug_rd_r
;
reg
[
31
:
0
]
debug_r
;
assign
bram_addr
=
bram_ren
[
0
]
?
bram_raddr
[
ADDRESS_BITS
-
1
:
0
]
:
(
bram_wen_r
?
bram_waddr_r
:
bram_waddr
[
ADDRESS_BITS
-
1
:
0
])
;
...
...
@@ -198,7 +202,6 @@ module axi_ahci_regs#(
assign
was_hba_rst
=
was_hba_rst_r
[
0
]
;
assign
was_port_rst
=
was_port_rst_r
[
0
]
;
always
@
(
posedge
aclk
)
begin
if
(
arst
)
write_busy_r
<=
0
;
...
...
@@ -207,7 +210,7 @@ module axi_ahci_regs#(
if
(
bram_wen
)
bram_wdata_r
<=
bram_wdata
;
if
(
bram_ren
[
1
])
bram_rdata_r
<=
debug_rd_r
?
debug_in
:
bram_rdata
;
//
if (bram_ren[1]) bram_rdata_r <= debug_rd_r? debug_in : bram_rdata;
bram_wstb_r
<=
{
4
{
bram_wen
}}
&
bram_wstb
;
...
...
@@ -215,8 +218,17 @@ module axi_ahci_regs#(
if
(
bram_wen
)
bram_waddr_r
<=
bram_waddr
[
ADDRESS_BITS
-
1
:
0
]
;
if
(
bram_ren
[
0
])
debug_rd_r
<=
&
bram_raddr
[
ADDRESS_BITS
-
1
:
4
]
;
// last 16 DWORDs (With AXIBRAM_BITS will be duplicated)
if
(
bram_ren
[
0
])
debug_r
<=
bram_raddr
[
1
]
?
(
bram_raddr
[
0
]
?
debug_in3
:
debug_in2
)
:
(
bram_raddr
[
0
]
?
debug_in1
:
debug_in0
)
;
if
(
bram_ren
[
1
])
bram_rdata_r
<=
debug_rd_r
?
debug_r
:
bram_rdata
;
end
//debug_rd_r
generate
genvar
i
;
for
(
i
=
0
;
i
<
32
;
i
=
i
+
1
)
begin
:
bit_type_block
...
...
@@ -281,10 +293,6 @@ module axi_ahci_regs#(
if
(
pgm_fsm_set_w
)
pgm_ad
<=
ahci_regs_di
[
17
:
0
]
;
end
always
@
(
posedge
aclk
)
begin
if
(
bram_ren
[
0
])
debug_rd_r
<=
&
bram_raddr
[
ADDRESS_BITS
-
1
:
4
]
;
// last 16 DWORDs (With AXIBRAM_BITS will be duplicated)
end
//debug_rd_r
/*
...
...
ahci/axi_hp_abort.v
0 → 100644
View file @
e94b62c6
/*******************************************************************************
* Module: axi_hp_abort
* Date:2016-02-07
* Author: andrey
* Description: Trying to gracefully reset AXI HP after aborted transmission
* For read channel - just keep afi_rready on until RD FIFO is empty (afi_rcount ==0)
* For write - keep track aof all what was sent so far, assuming aw is always ahead of w
* Reset only by global reset (system POR) - probably it is not possible to just
* reset PL or relaod bitfile,
*
* Copyright (c) 2016 Elphel, Inc .
* axi_hp_abort.v is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* axi_hp_abort.v 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> .
*******************************************************************************/
`timescale
1
ns
/
1
ps
module
axi_hp_abort
(
input
hclk
,
input
hrst
,
// just disables processing inputs
input
abort
,
output
busy
,
// should disable control of afi_wvalid, afi_awid
output
reg
done
,
input
afi_awvalid
,
// afi_awready is supposed to be always on when afi_awvalid (caller uses fifo counetrs) ?
input
afi_awready
,
//
input
[
5
:
0
]
afi_awid
,
input
[
3
:
0
]
afi_awlen
,
input
afi_wvalid_in
,
input
afi_wready
,
output
afi_wvalid
,
output
reg
[
5
:
0
]
afi_wid
,
input
afi_arvalid
,
input
afi_arready
,
input
[
3
:
0
]
afi_arlen
,
input
afi_rready_in
,
input
afi_rvalid
,
output
afi_rready
,
output
afi_wlast
,
// TODO: Try to resolve problems when afi_racount, afi_wacount afi_wcount do not match expected
input
[
2
:
0
]
afi_racount
,
input
[
7
:
0
]
afi_rcount
,
input
[
5
:
0
]
afi_wacount
,
input
[
7
:
0
]
afi_wcount
,
output
reg
dirty
,
// single bit to be sampled in different clock domain to see if flushing is needed
output
reg
axi_mismatch
,
// calculated as 'dirty' but axi hp counters are 0
output
[
21
:
0
]
debug
)
;
reg
busy_r
;
wire
done_w
=
busy_r
&&
!
dirty
;
reg
[
3
:
0
]
aw_lengths_ram
[
0
:
31
]
;
reg
[
4
:
0
]
aw_lengths_waddr
=
0
;
reg
[
4
:
0
]
aw_lengths_raddr
=
0
;
reg
[
5
:
0
]
aw_count
=
0
;
reg
[
7
:
0
]
w_count
=
0
;
reg
[
7
:
0
]
r_count
=
0
;
reg
adav
=
0
;
wire
arwr
=
!
hrst
&&
afi_arvalid
&&
afi_arready
;
wire
drd
=
!
hrst
&&
afi_rvalid
&&
afi_rready_in
;
wire
awr
=
!
hrst
&&
afi_awvalid
&&
afi_awready
;
reg
ard_r
=
0
;
// additional length read if not much data
wire
ard
=
adav
&&
((
|
w_count
[
7
:
4
])
||
ard_r
)
;
wire
wwr
=
!
hrst
&&
afi_wready
&&
afi_wvalid_in
;
reg
afi_rready_r
;
reg
afi_wlast_r
;
// wait one cycle after last in each burst (just to ease timing)
reg
busy_aborting
;
// actually aborting
wire
reset_counters
=
busy_r
&&
!
busy_aborting
;
assign
busy
=
busy_r
;
assign
afi_rready
=
busy_aborting
&&
(
|
r_count
)
&&
((
|
afi_rcount
[
7
:
1
])
||
(
!
afi_rready_r
&&
afi_rcount
[
0
]))
;
assign
afi_wlast
=
busy_aborting
&&
adav
&&
(
w_count
[
3
:
0
]
==
aw_lengths_ram
[
aw_lengths_raddr
])
;
assign
afi_wvalid
=
busy_aborting
&&
adav
&&
!
afi_wlast_r
;
assign
debug
=
{
aw_count
[
5
:
0
]
,
w_count
[
7
:
0
]
,
r_count
[
7
:
0
]
};
// Watch for transactios performed by others (and this one too)
always
@
(
posedge
hclk
)
begin
// read channel
if
(
reset_counters
)
r_count
<=
0
;
else
if
(
drd
)
if
(
arwr
)
r_count
<=
r_count
+
{
4'b0
,
afi_arlen
};
else
r_count
<=
r_count
-
1
;
else
if
(
arwr
)
r_count
<=
w_count
+
{
4'b0
,
afi_arlen
}
+
1
;
// write channel
if
(
awr
)
afi_wid
<=
afi_awid
;
// one command is supposed to use just one awid/wid
if
(
awr
)
aw_lengths_ram
[
aw_lengths_waddr
]
<=
afi_awlen
;
if
(
reset_counters
)
aw_lengths_waddr
<=
0
;
else
if
(
awr
)
aw_lengths_waddr
<=
aw_lengths_waddr
+
1
;
if
(
reset_counters
)
aw_lengths_raddr
<=
0
;
else
if
(
ard
)
aw_lengths_raddr
<=
aw_lengths_raddr
+
1
;
if
(
reset_counters
)
aw_count
<=
0
;
else
if
(
awr
&&
!
ard
)
aw_count
<=
aw_count
+
1
;
else
if
(
!
awr
&&
ard
)
aw_count
<=
aw_count
-
1
;
adav
<=
!
reset_counters
&&
(
|
aw_count
[
5
:
1
])
||
((
awr
||
aw_count
[
0
])
&&
!
ard
)
||
(
awr
&&
aw_count
[
0
])
;
ard_r
<=
!
ard
&&
adav
&&
(
w_count
[
3
:
0
]
>
aw_lengths_ram
[
aw_lengths_raddr
])
;
if
(
reset_counters
)
w_count
<=
0
;
else
if
(
wwr
)
if
(
ard
)
w_count
<=
w_count
-
{
4'b0
,
aw_lengths_ram
[
aw_lengths_raddr
]
};
else
w_count
<=
w_count
+
1
;
else
if
(
ard
)
w_count
<=
w_count
-
{
4'b0
,
aw_lengths_ram
[
aw_lengths_raddr
]
}
-
1
;
dirty
<=
(
|
r_count
)
||
(
|
aw_count
)
;
// assuming w_count can never be non-zero? - no
end
// flushing part
always
@
(
posedge
hclk
)
begin
if
(
abort
)
busy_r
<=
1
;
else
if
(
done_w
)
busy_r
<=
0
;
if
(
abort
&&
((
|
afi_racount
)
||
(
|
afi_rcount
)
||
(
|
afi_wacount
)
||
(
|
afi_wcount
)))
busy_aborting
<=
1
;
else
if
(
done_w
)
busy_aborting
<=
0
;
done
<=
done_w
;
afi_rready_r
<=
afi_rready
;
afi_wlast_r
<=
afi_wlast
;
axi_mismatch
<=
busy
&&
!
busy_aborting
&&
dirty
;
//
end
endmodule
ahci/sata_ahci_top.v
View file @
e94b62c6
...
...
@@ -224,7 +224,8 @@
reg
[
2
:
0
]
nhrst_r
;
wire
hrst
=
!
nhrst_r
[
2
]
;
wire
[
31
:
0
]
debug_sata
;
wire
[
31
:
0
]
debug_phy
;
wire
[
31
:
0
]
debug_link
;
always
@
(
posedge
hclk
or
posedge
arst
)
begin
if
(
arst
)
nhrst_r
<=
0
;
...
...
@@ -365,7 +366,8 @@
.
sctl_ipm
(
sctl_ipm
)
,
// output[3:0]
.
sctl_spd
(
sctl_spd
)
,
// output[3:0]
.
irq
(
irq
)
,
// output
.
debug_in
(
debug_sata
)
// input[31:0]
.
debug_in_phy
(
debug_phy
)
,
// input[31:0]
.
debug_in_link
(
debug_link
)
// input[31:0]
)
;
ahci_sata_layers
#(
...
...
@@ -424,7 +426,8 @@
.
txn_out
(
TXN
)
,
// output wire
.
rxp_in
(
RXP
)
,
// input wire
.
rxn_in
(
RXN
)
,
// input wire
.
debug_sata
(
debug_sata
)
// output[31:0]
.
debug_phy
(
debug_phy
)
,
// output[31:0]
.
debug_link
(
debug_link
)
// output[31:0]
)
;
...
...
generated/action_decoder.v
View file @
e94b62c6
/*******************************************************************************
* Module: action_decoder
* Date:2016-0
1-2
7
* Date:2016-0
2-0
7
* Author: auto-generated file, see ahci_fsm_sequence.py
* Description: Decode sequencer code to 1-hot actions
*******************************************************************************/
...
...
generated/condition_mux.v
View file @
e94b62c6
/*******************************************************************************
* Module: condition_mux
* Date:2016-0
1-2
7
* Date:2016-0
2-0
7
* Author: auto-generated file, see ahci_fsm_sequence.py
* Description: Select condition
*******************************************************************************/
...
...
@@ -9,6 +9,7 @@
module
condition_mux
(
input
clk
,
input
ce
,
// enable recording all conditions
input
[
7
:
0
]
sel
,
output
condition
,
input
ST_NB_ND
,
...
...
@@ -57,57 +58,104 @@ module condition_mux (
input
X_RDY_COLLISION
)
;
wire
[
44
:
0
]
masked
;
reg
[
43
:
0
]
registered
;
reg
[
5
:
0
]
cond_r
;
assign
condition
=
|
cond_r
;
assign
masked
[
0
]
=
ST_NB_ND
&&
sel
[
2
]
&&
sel
[
1
]
&&
sel
[
0
]
;
assign
masked
[
1
]
=
PXCI0_NOT_CMDTOISSUE
&&
sel
[
3
]
&&
sel
[
1
]
&&
sel
[
0
]
;
assign
masked
[
2
]
=
PCTI_CTBAR_XCZ
&&
sel
[
4
]
&&
sel
[
1
]
&&
sel
[
0
]
;
assign
masked
[
3
]
=
PCTI_XCZ
&&
sel
[
5
]
&&
sel
[
1
]
&&
sel
[
0
]
;
assign
masked
[
4
]
=
NST_D2HR
&&
sel
[
6
]
&&
sel
[
1
]
&&
sel
[
0
]
;
assign
masked
[
5
]
=
NPD_NCA
&&
sel
[
7
]
&&
sel
[
1
]
&&
sel
[
0
]
;
assign
masked
[
6
]
=
CHW_DMAA
&&
sel
[
3
]
&&
sel
[
2
]
&&
sel
[
0
]
;
assign
masked
[
7
]
=
SCTL_DET_CHANGED_TO_4
&&
sel
[
4
]
&&
sel
[
2
]
&&
sel
[
0
]
;
assign
masked
[
8
]
=
SCTL_DET_CHANGED_TO_1
&&
sel
[
5
]
&&
sel
[
2
]
&&
sel
[
0
]
;
assign
masked
[
9
]
=
PXSSTS_DET_NE_3
&&
sel
[
6
]
&&
sel
[
2
]
&&
sel
[
0
]
;
assign
masked
[
10
]
=
PXSSTS_DET_EQ_1
&&
sel
[
7
]
&&
sel
[
2
]
&&
sel
[
0
]
;
assign
masked
[
11
]
=
NPCMD_FRE
&&
sel
[
4
]
&&
sel
[
3
]
&&
sel
[
0
]
;
assign
masked
[
12
]
=
FIS_OK
&&
sel
[
5
]
&&
sel
[
3
]
&&
sel
[
0
]
;
assign
masked
[
13
]
=
FIS_ERR
&&
sel
[
6
]
&&
sel
[
3
]
&&
sel
[
0
]
;
assign
masked
[
14
]
=
FIS_FERR
&&
sel
[
7
]
&&
sel
[
3
]
&&
sel
[
0
]
;
assign
masked
[
15
]
=
FIS_EXTRA
&&
sel
[
5
]
&&
sel
[
4
]
&&
sel
[
0
]
;
assign
masked
[
16
]
=
FIS_FIRST_INVALID
&&
sel
[
6
]
&&
sel
[
4
]
&&
sel
[
0
]
;
assign
masked
[
17
]
=
FR_D2HR
&&
sel
[
7
]
&&
sel
[
4
]
&&
sel
[
0
]
;
assign
masked
[
18
]
=
FIS_DATA
&&
sel
[
6
]
&&
sel
[
5
]
&&
sel
[
0
]
;
assign
masked
[
19
]
=
FIS_ANY
&&
sel
[
7
]
&&
sel
[
5
]
&&
sel
[
0
]
;
assign
masked
[
20
]
=
NB_ND_D2HR_PIO
&&
sel
[
7
]
&&
sel
[
6
]
&&
sel
[
0
]
;
assign
masked
[
21
]
=
D2HR
&&
sel
[
3
]
&&
sel
[
2
]
&&
sel
[
1
]
;
assign
masked
[
22
]
=
SDB
&&
sel
[
4
]
&&
sel
[
2
]
&&
sel
[
1
]
;
assign
masked
[
23
]
=
DMA_ACT
&&
sel
[
5
]
&&
sel
[
2
]
&&
sel
[
1
]
;
assign
masked
[
24
]
=
DMA_SETUP
&&
sel
[
6
]
&&
sel
[
2
]
&&
sel
[
1
]
;
assign
masked
[
25
]
=
BIST_ACT_FE
&&
sel
[
7
]
&&
sel
[
2
]
&&
sel
[
1
]
;
assign
masked
[
26
]
=
BIST_ACT
&&
sel
[
4
]
&&
sel
[
3
]
&&
sel
[
1
]
;
assign
masked
[
27
]
=
PIO_SETUP
&&
sel
[
5
]
&&
sel
[
3
]
&&
sel
[
1
]
;
assign
masked
[
28
]
=
NB_ND
&&
sel
[
6
]
&&
sel
[
3
]
&&
sel
[
1
]
;
assign
masked
[
29
]
=
TFD_STS_ERR
&&
sel
[
7
]
&&
sel
[
3
]
&&
sel
[
1
]
;
assign
masked
[
30
]
=
FIS_I
&&
sel
[
5
]
&&
sel
[
4
]
&&
sel
[
1
]
;
assign
masked
[
31
]
=
PIO_I
&&
sel
[
6
]
&&
sel
[
4
]
&&
sel
[
1
]
;
assign
masked
[
32
]
=
NPD
&&
sel
[
7
]
&&
sel
[
4
]
&&
sel
[
1
]
;
assign
masked
[
33
]
=
PIOX
&&
sel
[
6
]
&&
sel
[
5
]
&&
sel
[
1
]
;
assign
masked
[
34
]
=
XFER0
&&
sel
[
7
]
&&
sel
[
5
]
&&
sel
[
1
]
;
assign
masked
[
35
]
=
PIOX_XFER0
&&
sel
[
7
]
&&
sel
[
6
]
&&
sel
[
1
]
;
assign
masked
[
36
]
=
CTBAA_CTBAP
&&
sel
[
4
]
&&
sel
[
3
]
&&
sel
[
2
]
;
assign
masked
[
37
]
=
CTBAP
&&
sel
[
5
]
&&
sel
[
3
]
&&
sel
[
2
]
;
assign
masked
[
38
]
=
CTBA_B
&&
sel
[
6
]
&&
sel
[
3
]
&&
sel
[
2
]
;
assign
masked
[
39
]
=
CTBA_C
&&
sel
[
7
]
&&
sel
[
3
]
&&
sel
[
2
]
;
assign
masked
[
40
]
=
TX_ERR
&&
sel
[
5
]
&&
sel
[
4
]
&&
sel
[
2
]
;
assign
masked
[
41
]
=
SYNCESC_ERR
&&
sel
[
6
]
&&
sel
[
4
]
&&
sel
[
2
]
;
assign
masked
[
42
]
=
DMA_PRD_IRQ_PEND
&&
sel
[
7
]
&&
sel
[
4
]
&&
sel
[
2
]
;
assign
masked
[
43
]
=
X_RDY_COLLISION
&&
sel
[
6
]
&&
sel
[
5
]
&&
sel
[
2
]
;
assign
masked
[
0
]
=
registered
[
0
]
&&
sel
[
2
]
&&
sel
[
1
]
&&
sel
[
0
]
;
assign
masked
[
1
]
=
registered
[
1
]
&&
sel
[
3
]
&&
sel
[
1
]
&&
sel
[
0
]
;
assign
masked
[
2
]
=
registered
[
2
]
&&
sel
[
4
]
&&
sel
[
1
]
&&
sel
[
0
]
;
assign
masked
[
3
]
=
registered
[
3
]
&&
sel
[
5
]
&&
sel
[
1
]
&&
sel
[
0
]
;
assign
masked
[
4
]
=
registered
[
4
]
&&
sel
[
6
]
&&
sel
[
1
]
&&
sel
[
0
]
;
assign
masked
[
5
]
=
registered
[
5
]
&&
sel
[
7
]
&&
sel
[
1
]
&&
sel
[
0
]
;
assign
masked
[
6
]
=
registered
[
6
]
&&
sel
[
3
]
&&
sel
[
2
]
&&
sel
[
0
]
;
assign
masked
[
7
]
=
registered
[
7
]
&&
sel
[
4
]
&&
sel
[
2
]
&&
sel
[
0
]
;
assign
masked
[
8
]
=
registered
[
8
]
&&
sel
[
5
]
&&
sel
[
2
]
&&
sel
[
0
]
;
assign
masked
[
9
]
=
registered
[
9
]
&&
sel
[
6
]
&&
sel
[
2
]
&&
sel
[
0
]
;
assign
masked
[
10
]
=
registered
[
10
]
&&
sel
[
7
]
&&
sel
[
2
]
&&
sel
[
0
]
;
assign
masked
[
11
]
=
registered
[
11
]
&&
sel
[
4
]
&&
sel
[
3
]
&&
sel
[
0
]
;
assign
masked
[
12
]
=
registered
[
12
]
&&
sel
[
5
]
&&
sel
[
3
]
&&
sel
[
0
]
;
assign
masked
[
13
]
=
registered
[
13
]
&&
sel
[
6
]
&&
sel
[
3
]
&&
sel
[
0
]
;
assign
masked
[
14
]
=
registered
[
14
]
&&
sel
[
7
]
&&
sel
[
3
]
&&
sel
[
0
]
;
assign
masked
[
15
]
=
registered
[
15
]
&&
sel
[
5
]
&&
sel
[
4
]
&&
sel
[
0
]
;
assign
masked
[
16
]
=
registered
[
16
]
&&
sel
[
6
]
&&
sel
[
4
]
&&
sel
[
0
]
;
assign
masked
[
17
]
=
registered
[
17
]
&&
sel
[
7
]
&&
sel
[
4
]
&&
sel
[
0
]
;
assign
masked
[
18
]
=
registered
[
18
]
&&
sel
[
6
]
&&
sel
[
5
]
&&
sel
[
0
]
;
assign
masked
[
19
]
=
registered
[
19
]
&&
sel
[
7
]
&&
sel
[
5
]
&&
sel
[
0
]
;
assign
masked
[
20
]
=
registered
[
20
]
&&
sel
[
7
]
&&
sel
[
6
]
&&
sel
[
0
]
;
assign
masked
[
21
]
=
registered
[
21
]
&&
sel
[
3
]
&&
sel
[
2
]
&&
sel
[
1
]
;
assign
masked
[
22
]
=
registered
[
22
]
&&
sel
[
4
]
&&
sel
[
2
]
&&
sel
[
1
]
;
assign
masked
[
23
]
=
registered
[
23
]
&&
sel
[
5
]
&&
sel
[
2
]
&&
sel
[
1
]
;
assign
masked
[
24
]
=
registered
[
24
]
&&
sel
[
6
]
&&
sel
[
2
]
&&
sel
[
1
]
;
assign
masked
[
25
]
=
registered
[
25
]
&&
sel
[
7
]
&&
sel
[
2
]
&&
sel
[
1
]
;
assign
masked
[
26
]
=
registered
[
26
]
&&
sel
[
4
]
&&
sel
[
3
]
&&
sel
[
1
]
;
assign
masked
[
27
]
=
registered
[
27
]
&&
sel
[
5
]
&&
sel
[
3
]
&&
sel
[
1
]
;
assign
masked
[
28
]
=
registered
[
28
]
&&
sel
[
6
]
&&
sel
[
3
]
&&
sel
[
1
]
;
assign
masked
[
29
]
=
registered
[
29
]
&&
sel
[
7
]
&&
sel
[
3
]
&&
sel
[
1
]
;
assign
masked
[
30
]
=
registered
[
30
]
&&
sel
[
5
]
&&
sel
[
4
]
&&
sel
[
1
]
;
assign
masked
[
31
]
=
registered
[
31
]
&&
sel
[
6
]
&&
sel
[
4
]
&&
sel
[
1
]
;
assign
masked
[
32
]
=
registered
[
32
]
&&
sel
[
7
]
&&
sel
[
4
]
&&
sel
[
1
]
;
assign
masked
[
33
]
=
registered
[
33
]
&&
sel
[
6
]
&&
sel
[
5
]
&&
sel
[
1
]
;
assign
masked
[
34
]
=
registered
[
34
]
&&
sel
[
7
]
&&
sel
[
5
]
&&
sel
[
1
]
;
assign
masked
[
35
]
=
registered
[
35
]
&&
sel
[
7
]
&&
sel
[
6
]
&&
sel
[
1
]
;
assign
masked
[
36
]
=
registered
[
36
]
&&
sel
[
4
]
&&
sel
[
3
]
&&
sel
[
2
]
;
assign
masked
[
37
]
=
registered
[
37
]
&&
sel
[
5
]
&&
sel
[
3
]
&&
sel
[
2
]
;
assign
masked
[
38
]
=
registered
[
38
]
&&
sel
[
6
]
&&
sel
[
3
]
&&
sel
[
2
]
;
assign
masked
[
39
]
=
registered
[
39
]
&&
sel
[
7
]
&&
sel
[
3
]
&&
sel
[
2
]
;
assign
masked
[
40
]
=
registered
[
40
]
&&
sel
[
5
]
&&
sel
[
4
]
&&
sel
[
2
]
;
assign
masked
[
41
]
=
registered
[
41
]
&&
sel
[
6
]
&&
sel
[
4
]
&&
sel
[
2
]
;
assign
masked
[
42
]
=
registered
[
42
]
&&
sel
[
7
]
&&
sel
[
4
]
&&
sel
[
2
]
;
assign
masked
[
43
]
=
registered
[
43
]
&&
sel
[
6
]
&&
sel
[
5
]
&&
sel
[
2
]
;
assign
masked
[
44
]
=
!
(
|
sel
)
;
// always TRUE condition (sel ==0)
always
@
(
posedge
clk
)
begin
if
(
ce
)
begin
registered
[
0
]
<=
ST_NB_ND
;
registered
[
1
]
<=
PXCI0_NOT_CMDTOISSUE
;
registered
[
2
]
<=
PCTI_CTBAR_XCZ
;
registered
[
3
]
<=
PCTI_XCZ
;
registered
[
4
]
<=
NST_D2HR
;
registered
[
5
]
<=
NPD_NCA
;
registered
[
6
]
<=
CHW_DMAA
;
registered
[
7
]
<=
SCTL_DET_CHANGED_TO_4
;
registered
[
8
]
<=
SCTL_DET_CHANGED_TO_1
;
registered
[
9
]
<=
PXSSTS_DET_NE_3
;
registered
[
10
]
<=
PXSSTS_DET_EQ_1
;
registered
[
11
]
<=
NPCMD_FRE
;
registered
[
12
]
<=
FIS_OK
;
registered
[
13
]
<=
FIS_ERR
;
registered
[
14
]
<=
FIS_FERR
;
registered
[
15
]
<=
FIS_EXTRA
;
registered
[
16
]
<=
FIS_FIRST_INVALID
;
registered
[
17
]
<=
FR_D2HR
;
registered
[
18
]
<=
FIS_DATA
;
registered
[
19
]
<=
FIS_ANY
;
registered
[
20
]
<=
NB_ND_D2HR_PIO
;
registered
[
21
]
<=
D2HR
;
registered
[
22
]
<=
SDB
;
registered
[
23
]
<=
DMA_ACT
;
registered
[
24
]
<=
DMA_SETUP
;
registered
[
25
]
<=
BIST_ACT_FE
;
registered
[
26
]
<=
BIST_ACT
;
registered
[
27
]
<=
PIO_SETUP
;
registered
[
28
]
<=
NB_ND
;
registered
[
29
]
<=
TFD_STS_ERR
;
registered
[
30
]
<=
FIS_I
;
registered
[
31
]
<=
PIO_I
;
registered
[
32
]
<=
NPD
;
registered
[
33
]
<=
PIOX
;
registered
[
34
]
<=
XFER0
;
registered
[
35
]
<=
PIOX_XFER0
;
registered
[
36
]
<=
CTBAA_CTBAP
;
registered
[
37
]
<=
CTBAP
;
registered
[
38
]
<=
CTBA_B
;
registered
[
39
]
<=
CTBA_C
;
registered
[
40
]
<=
TX_ERR
;
registered
[
41
]
<=
SYNCESC_ERR
;
registered
[
42
]
<=
DMA_PRD_IRQ_PEND
;
registered
[
43
]
<=
X_RDY_COLLISION
;
end
cond_r
[
0
]
<=
|
masked
[
7
:
0
]
;
cond_r
[
1
]
<=
|
masked
[
15
:
8
]
;
cond_r
[
2
]
<=
|
masked
[
23
:
16
]
;
...
...
helpers/ahci_fsm_sequence.py
View file @
e94b62c6
...
...
@@ -53,7 +53,7 @@ actions = ['NOP',
# FIS_TRANSMIT
'CLEAR_CMD_TO_ISSUE'
,
# DMA
'DMA_ABORT'
,
'DMA_PRD_IRQ_CLEAR'
,
'DMA_ABORT
*
'
,
'DMA_PRD_IRQ_CLEAR'
,
# SATA TRANSPORT/LINK/PHY
'XMIT_COMRESET'
,
'SEND_SYNC_ESC*'
,
'SET_OFFLINE'
,
'R_OK'
,
'R_ERR'
,
# FIS TRANSMIT/WAIT DONE
...
...
@@ -158,7 +158,7 @@ sequence = [{LBL:'POR', ADDR: 0x0, ACT: NOP},
{
GOTO
:
'P:NotRunning'
},
{
LBL
:
'P:StartBitCleared'
,
ACT
:
'PXCI0_CLEAR'
},
# pxci0_clear
{
ACT
:
'DMA_ABORT
'
},
# dma_cmd_abort (should eventually clear PxCMD.CR)?
{
ACT
:
'DMA_ABORT
*'
},
# dma_cmd_abort (should eventually clear PxCMD.CR)?
{
ACT
:
'PCMD_CR_CLEAR'
},
# pcmd_cr_reset
{
ACT
:
'XFER_CNTR_CLEAR'
},
# clear_xfer_cntr
...
...
@@ -477,6 +477,7 @@ def condition_mux_verilog(conditions, condition_vals, module_name, fanout, file=
module
%
s (
input clk,
input ce, // enable recording all conditions
input [
%2
d:0] sel,
output condition,"""
v
=
max
(
condition_vals
.
values
())
...
...
@@ -485,15 +486,14 @@ module %s (
num_inputs
+=
1
v
>>=
1
maximal_length
=
max
([
len
(
n
)
for
n
in
conditions
])
# numregs = (len(conditions) + fanout - 1) // fanout
numregs
=
(
len
(
conditions
)
+
fanout
)
//
fanout
# one more bit for 'always' (sel == 0)
header
=
header_template
%
(
module_name
,
datetime
.
date
.
today
()
.
isoformat
(),
os
.
path
.
basename
(
__file__
),
module_name
,
num_inputs
-
1
)
print
(
header
,
file
=
file
)
for
input_name
in
conditions
[:
len
(
conditions
)
-
1
]:
print
(
" input
%
s,"
%
(
input_name
),
file
=
file
)
print
(
" input
%
s);
\n
"
%
(
conditions
[
-
1
]),
file
=
file
)
# print(" wire [%2d:0] masked;"%(len(conditions)-1),
file=file)
print
(
"
wire [
%2
d:0] masked;"
%
(
len
(
conditions
)
),
file
=
file
)
print
(
" input
%
s,"
%
(
input_name
),
file
=
file
)
print
(
" input
%
s);
\n
"
%
(
conditions
[
-
1
]),
file
=
file
)
print
(
" wire [
%2
d:0] masked;"
%
(
len
(
conditions
)),
file
=
file
)
print
(
"
reg [
%2
d:0] registered;"
%
(
len
(
conditions
)
-
1
),
file
=
file
)
if
numregs
>
1
:
print
(
" reg [
%2
d:0] cond_r;
\n
"
%
(
numregs
-
1
),
file
=
file
)
else
:
...
...
@@ -505,7 +505,8 @@ module %s (
print
(
" assign condition = cond_r;
\n
"
,
file
=
file
)
for
b
in
range
(
len
(
conditions
)):
print
(
" assign masked[
%2
d] =
%
s
%
s"
%
(
b
,
conditions
[
b
]
,
" "
*
(
maximal_length
-
len
(
conditions
[
b
]))),
end
=
""
,
file
=
file
)
# print(" assign masked[%2d] = %s %s"%(b, conditions[b] , " "*(maximal_length - len(conditions[b]))),end="",file=file)
print
(
" assign masked[
%2
d] = registered[
%2
d] "
%
(
b
,
b
),
end
=
""
,
file
=
file
)
d
=
condition_vals
[
conditions
[
b
]]
for
nb
in
range
(
num_inputs
-
1
,
-
1
,
-
1
):
...
...
@@ -514,7 +515,13 @@ module %s (
print
(
";"
,
file
=
file
)
print
(
" assign masked[
%2
d] = !(|sel); // always TRUE condition (sel ==0)"
%
(
len
(
conditions
)),
file
=
file
)
print
(
"
\n
always @(posedge clk) begin"
,
file
=
file
)
print
(
"
\n
always @(posedge clk) begin"
,
file
=
file
)
print
(
" if (ce) begin"
,
file
=
file
)
for
b
in
range
(
len
(
conditions
)):
print
(
" registered[
%2
d] <=
%
s;"
%
(
b
,
conditions
[
b
]),
file
=
file
)
print
(
" end"
,
file
=
file
)