OpenCores
URL https://opencores.org/ocsvn/zap/zap/trunk

Subversion Repositories zap

[/] [zap/] [trunk/] [src/] [rtl/] [cpu/] [zap_cache_fsm.v] - Blame information for rev 51

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 26 Revanth
// -----------------------------------------------------------------------------
2
// --                                                                         --
3
// --                   (C) 2016-2018 Revanth Kamaraj.                        --
4
// --                                                                         -- 
5
// -- --------------------------------------------------------------------------
6
// --                                                                         --
7
// -- This program is free software; you can redistribute it and/or           --
8
// -- modify it under the terms of the GNU General Public License             --
9
// -- as published by the Free Software Foundation; either version 2          --
10
// -- of the License, or (at your option) any later version.                  --
11
// --                                                                         --
12
// -- This program is distributed in the hope that it will be useful,         --
13
// -- but WITHOUT ANY WARRANTY; without even the implied warranty of          --
14
// -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           --
15
// -- GNU General Public License for more details.                            --
16
// --                                                                         --
17
// -- You should have received a copy of the GNU General Public License       --
18
// -- along with this program; if not, write to the Free Software             --
19
// -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA           --
20
// -- 02110-1301, USA.                                                        --
21
// --                                                                         --
22
// -----------------------------------------------------------------------------
23
// --                                                                         --
24
// -- This is the core state machine for the memory subsystem. Talks to both  --
25
// -- processor and the TLB controller. Cache uploads and downloads are done  --
26
// -- using an incrementing burst on the Wishbone bus for maximum efficiency  --
27
// --                                                                         --   
28
// -----------------------------------------------------------------------------
29
 
30
`default_nettype none
31
 
32
`include "zap_defines.vh"
33
 
34
module zap_cache_fsm   #(
35 43 Revanth
        parameter CACHE_SIZE    = 1024  // Bytes.
36
)
37 26 Revanth
 
38 43 Revanth
// ---------------------------------------------- 
39
//  Port List 
40
// ----------------------------------------------        
41
 
42
(
43
 
44 26 Revanth
/* Clock and reset */
45
input   wire                      i_clk,
46
input   wire                      i_reset,
47
 
48
/* From/to processor */
49
input   wire    [31:0]            i_address,
50
input   wire                      i_rd,
51
input   wire                      i_wr,
52
input   wire    [31:0]            i_din,
53
input   wire    [3:0]             i_ben, /* Valid only for writes. */
54
output  reg     [31:0]            o_dat,
55
output  reg                       o_ack,
56
output  reg                       o_err,
57
output  reg     [7:0]             o_fsr,
58
output  reg     [31:0]            o_far,
59
 
60
/* From/To CP15 unit */
61
input   wire                      i_cache_en,
62
input   wire                      i_cache_inv,
63
input   wire                      i_cache_clean,
64
output  reg                       o_cache_inv_done,
65
output  reg                       o_cache_clean_done,
66
 
67
/* From/to cache. */
68
input   wire    [127:0]           i_cache_line,
69
 
70
input   wire                      i_cache_tag_dirty,
71
input   wire  [`CACHE_TAG_WDT-1:0] i_cache_tag, // Tag 
72
input   wire                      i_cache_tag_valid,
73
 
74
output  reg   [`CACHE_TAG_WDT-1:0] o_cache_tag,
75
output  reg                       o_cache_tag_dirty,
76
output  reg                       o_cache_tag_wr_en,
77
 
78
output  reg     [127:0]           o_cache_line,
79
output  reg     [15:0]            o_cache_line_ben,    /* Write + Byte enable */
80
 
81
output  reg                       o_cache_clean_req,
82
input   wire                      i_cache_clean_done,
83
 
84
output  reg                       o_cache_inv_req,
85
input   wire                      i_cache_inv_done,
86
 
87
/* From/to TLB unit */
88
input   wire    [31:0]            i_phy_addr,
89
input   wire    [7:0]             i_fsr,
90
input   wire    [31:0]            i_far,
91
input   wire                      i_fault,
92
input   wire                      i_cacheable,
93
input   wire                      i_busy,
94
 
95
/* Memory access ports, both NXT and FF. Usually you'll be connecting NXT ports */
96
output  reg             o_wb_cyc_ff, o_wb_cyc_nxt,
97
output  reg             o_wb_stb_ff, o_wb_stb_nxt,
98
output  reg     [31:0]  o_wb_adr_ff, o_wb_adr_nxt,
99
output  reg     [31:0]  o_wb_dat_ff, o_wb_dat_nxt,
100
output  reg     [3:0]   o_wb_sel_ff, o_wb_sel_nxt,
101
output  reg             o_wb_wen_ff, o_wb_wen_nxt,
102
output  reg     [2:0]   o_wb_cti_ff, o_wb_cti_nxt,/* Cycle Type Indicator - 010, 111 */
103
input   wire            i_wb_ack,
104
input   wire    [31:0]  i_wb_dat
105
 
106
);
107
 
108 43 Revanth
// -------------------------------------------------------------
109
// Includes and Localparams
110
// -------------------------------------------------------------
111
 
112 26 Revanth
`include "zap_localparams.vh"
113
`include "zap_defines.vh"
114
`include "zap_functions.vh"
115
 
116
/* States */
117
localparam IDLE                 = 0; /* Resting state. */
118
localparam UNCACHEABLE          = 1; /* Uncacheable access. */
119
localparam REFRESH_1            = 2; /* Cache write hit state. Unused. */
120
localparam CLEAN_SINGLE         = 3; /* Ultimately cleans up cache line. Parent state */
121
localparam FETCH_SINGLE         = 4; /* Ultimately validates cache line. Parent state */
122
localparam REFRESH              = 5; /* Cache refresh parent state */
123
localparam INVALIDATE           = 6; /* Cache invalidate parent state */
124
localparam CLEAN                = 7; /* Cache clean parent state */
125
localparam NUMBER_OF_STATES     = 8;
126
 
127 51 Revanth
// ----------------------------------------------------------------------------
128 43 Revanth
// Signal aliases   
129 51 Revanth
// ----------------------------------------------------------------------------
130 26 Revanth
 
131 43 Revanth
wire cache_cmp   = (i_cache_tag[`CACHE_TAG__TAG] == i_address[`VA__CACHE_TAG]);
132
wire cache_dirty = i_cache_tag_dirty;
133 26 Revanth
 
134 51 Revanth
// ----------------------------------------------------------------------------
135 43 Revanth
// Variables
136 51 Revanth
// ----------------------------------------------------------------------------
137 26 Revanth
 
138 43 Revanth
reg [$clog2(NUMBER_OF_STATES)-1:0]      state_ff, state_nxt;
139
reg [31:0]                              buf_ff [3:0];
140
reg [31:0]                              buf_nxt[3:0];
141
reg                                     cache_clean_req_nxt,
142
                                        cache_clean_req_ff;
143
reg                                     cache_inv_req_nxt,
144
                                        cache_inv_req_ff;
145
reg [2:0]                               adr_ctr_ff, adr_ctr_nxt; // Needs to take on 0,1,2,3 AND 4(nxt).
146
reg                                     hit;                     // For debug only.
147
 
148 51 Revanth
// ----------------------------------------------------------------------------
149 43 Revanth
// Logic
150 51 Revanth
// ----------------------------------------------------------------------------
151 43 Revanth
 
152
/* Tie flops to the output */
153 26 Revanth
always @* o_cache_clean_req = cache_clean_req_ff; // Tie req flop to output.
154 51 Revanth
always @* o_cache_inv_req   = cache_inv_req_ff;   // Tie inv flop to output.
155 26 Revanth
 
156 43 Revanth
/* Sequential Block */
157 26 Revanth
always @ (posedge i_clk)
158
begin
159
        if ( i_reset )
160
        begin
161 43 Revanth
                o_wb_cyc_ff             <= 0;
162
                o_wb_stb_ff             <= 0;
163
                o_wb_wen_ff             <= 0;
164
                o_wb_sel_ff             <= 0;
165
                o_wb_dat_ff             <= 0;
166
                o_wb_cti_ff             <= CTI_CLASSIC;
167
                o_wb_adr_ff             <= 0;
168
                cache_clean_req_ff      <= 0;
169
                cache_inv_req_ff        <= 0;
170
                adr_ctr_ff              <= 0;
171
                state_ff                <= IDLE;
172 26 Revanth
        end
173
        else
174
        begin
175
                o_wb_cyc_ff             <= o_wb_cyc_nxt;
176
                o_wb_stb_ff             <= o_wb_stb_nxt;
177
                o_wb_wen_ff             <= o_wb_wen_nxt;
178
                o_wb_sel_ff             <= o_wb_sel_nxt;
179
                o_wb_dat_ff             <= o_wb_dat_nxt;
180
                o_wb_cti_ff             <= o_wb_cti_nxt;
181
                o_wb_adr_ff             <= o_wb_adr_nxt;
182
                cache_clean_req_ff      <= cache_clean_req_nxt;
183
                cache_inv_req_ff        <= cache_inv_req_nxt;
184
                adr_ctr_ff              <= adr_ctr_nxt;
185
                state_ff                <= state_nxt;
186
                buf_ff[0]               <= buf_nxt[0];
187
                buf_ff[1]               <= buf_nxt[1];
188
                buf_ff[2]               <= buf_nxt[2];
189 29 Revanth
                buf_ff[3]               <= buf_nxt[3];
190 26 Revanth
        end
191
end
192
 
193 43 Revanth
/* Combo block */
194 26 Revanth
always @*
195
begin
196
        /* Default values */
197
        state_nxt               = state_ff;
198
        adr_ctr_nxt             = adr_ctr_ff;
199
        o_wb_cyc_nxt            = o_wb_cyc_ff;
200
        o_wb_stb_nxt            = o_wb_stb_ff;
201
        o_wb_adr_nxt            = o_wb_adr_ff;
202
        o_wb_dat_nxt            = o_wb_dat_ff;
203
        o_wb_cti_nxt            = o_wb_cti_ff;
204
        o_wb_wen_nxt            = o_wb_wen_ff;
205
        o_wb_sel_nxt            = o_wb_sel_ff;
206
        cache_clean_req_nxt     = cache_clean_req_ff;
207
        cache_inv_req_nxt       = cache_clean_req_ff;
208 43 Revanth
        o_fsr                   = 0;
209
        o_far                   = 0;
210
        o_cache_tag             = 0;
211
        o_cache_inv_done        = 0;
212
        o_cache_clean_done      = 0;
213
        o_cache_tag_dirty       = 0;
214
        o_cache_tag_wr_en       = 0;
215
        o_cache_line            = 0;
216
        o_cache_line_ben        = 0;
217
        o_dat                   = 0;
218
        o_ack                   = 0;
219
        o_err                   = 0;
220
        buf_nxt[0]              = buf_ff[0];
221
        buf_nxt[1]              = buf_ff[1];
222
        buf_nxt[2]              = buf_ff[2];
223
        buf_nxt[3]              = buf_ff[3];
224
        hit                     = 0;
225 26 Revanth
 
226
        case(state_ff)
227
 
228
        IDLE:
229
        begin
230
                kill_access;
231
 
232
                if ( i_cache_inv )
233
                begin
234
                        o_ack     = 1'd0;
235
                        state_nxt = INVALIDATE;
236
                end
237
                else if ( i_cache_clean )
238
                begin
239
                        o_ack     = 1'd0;
240
                        state_nxt = CLEAN;
241
                end
242
                else if ( i_fault )
243
                begin
244
                        /* MMU access fault. */
245
                        o_err = 1'd1;
246
                        o_ack = 1'd1;
247 29 Revanth
                        o_fsr = i_fsr;
248
                        o_far = i_far;
249 26 Revanth
                end
250
                else if ( i_busy )
251
                begin
252
                        /* Wait it out */
253
                end
254
                else if ( i_rd || i_wr )
255
                begin
256
                        if ( i_cacheable && i_cache_en )
257
                        begin
258
                                case ({cache_cmp,i_cache_tag_valid})
259
 
260
                                2'b11: /* Cache hit */
261
                                begin
262
                                        if ( i_rd ) /* Read request. */
263
                                        begin
264
                                                /* Accelerate performance */
265
                                                o_dat   = adapt_cache_data(i_address[3:2], i_cache_line);
266
 
267
                                                hit = 1'd1;
268
 
269
 
270
                                                o_ack   = 1'd1;
271
                                        end
272
                                        else if ( i_wr ) /* Write request */
273
                                        begin
274
                                                state_nxt    = REFRESH_1;
275
                                                o_ack        = 1'd0;
276
 
277
                                                /* Accelerate performance */
278
                                                o_cache_line =
279
                                                {i_din,i_din,i_din,i_din};
280
 
281
                                                o_cache_line_ben  = ben_comp ( i_address[3:2], i_ben );
282
 
283
                                                /* Write to tag and also write out physical address. */
284
                                                o_cache_tag_wr_en               = 1'd1;
285
                                                o_cache_tag[`CACHE_TAG__TAG]    = i_address[`VA__CACHE_TAG];
286
                                                o_cache_tag_dirty               = 1'd1;
287
                                                o_cache_tag[`CACHE_TAG__PA]     = i_phy_addr >> 4;
288
 
289
 
290
                                        end
291
                                end
292
 
293
                                2'b01: /* Unrelated tag, possibly dirty. */
294
                                begin
295
                                        /* CPU should wait */
296
                                        o_ack = 1'd0;
297
 
298
                                        if ( cache_dirty )
299
                                        begin
300
                                                /* Set up counter */
301
                                                adr_ctr_nxt = 0;
302
 
303
                                                /* Clean a single cache line */
304
                                                state_nxt = CLEAN_SINGLE;
305
                                        end
306
                                        else if ( i_rd | i_wr )
307
                                        begin
308
                                                /* Set up counter */
309
                                                adr_ctr_nxt = 0;
310
 
311
                                                /* Fetch a single cache line */
312
                                                state_nxt = FETCH_SINGLE;
313
                                        end
314
                                end
315
 
316
                                default: /* Need to generate a new tag. */
317
                                begin
318
                                                /* CPU should wait. */
319
                                                o_ack = 1'd0;
320
 
321
                                                /* Set up counter */
322
                                                adr_ctr_nxt = 0;
323
 
324
                                                /* Fetch a single cache line */
325
                                                state_nxt = FETCH_SINGLE;
326
                                end
327
                                endcase
328
                        end
329
                        else /* Decidedly non cacheable. */
330
                        begin
331
                                state_nxt       = UNCACHEABLE;
332
                                o_ack           = 1'd0; /* Wait...*/
333
                                o_wb_stb_nxt    = 1'd1;
334
                                o_wb_cyc_nxt    = 1'd1;
335
                                o_wb_adr_nxt    = i_phy_addr;
336
                                o_wb_dat_nxt    = i_din;
337
                                o_wb_wen_nxt    = i_wr;
338 29 Revanth
                                o_wb_sel_nxt    = i_ben; // Was i_wr ? i_ben : 4'b1111
339 26 Revanth
                                o_wb_cti_nxt    = CTI_CLASSIC;
340
                        end
341
                end
342
        end
343
 
344
        UNCACHEABLE: /* Uncacheable reads and writes definitely go through this. */
345
        begin
346
                if ( i_wb_ack )
347
                begin
348
                        o_dat           = i_wb_dat;
349
                        o_ack           = 1'd1;
350
                        state_nxt       = IDLE;
351
                        kill_access;
352
                end
353
        end
354
 
355
        REFRESH_1: /* A single wait state is needed to handle B2B write-read */
356
        begin
357
                kill_access;
358
                state_nxt = REFRESH;
359
                o_ack     = 1'd0;
360
        end
361
 
362
        CLEAN_SINGLE: /* Clean single cache line */
363
        begin
364
                o_ack = 1'd0;
365
 
366
                /* Generate address */
367
                adr_ctr_nxt = adr_ctr_ff + (o_wb_stb_ff && i_wb_ack);
368
 
369
                if ( adr_ctr_nxt <= 3 )
370
                begin
371
                        /* Sync up with memory. Use PA in cache tag itself. */
372
                        wb_prpr_write( clean_single_d (i_cache_line, adr_ctr_nxt),
373
                                      {i_cache_tag[`CACHE_TAG__PA], 4'd0} + (adr_ctr_nxt << 2),
374
                                      adr_ctr_nxt != 3 ? CTI_BURST : CTI_EOB, 4'b1111);
375
                end
376
                else
377
                begin
378
                        /* Move to wait state */
379
                        kill_access;
380
                        state_nxt = REFRESH_1;
381
 
382
                        /* Update tag. Remove dirty bit. */
383
                        o_cache_tag_wr_en                      = 1'd1; // Implicitly sets valid (redundant).
384
                        o_cache_tag[`CACHE_TAG__TAG]           = i_cache_tag[`VA__CACHE_TAG]; // Preserve.
385
                        o_cache_tag_dirty                      = 1'd0;
386
                        o_cache_tag[`CACHE_TAG__PA]            = i_cache_tag[`CACHE_TAG__PA]; // Preserve.
387
                end
388
        end
389
 
390
        FETCH_SINGLE: /* Fetch a single cache line */
391
        begin
392
 
393
                o_ack = 1'd0;
394
 
395
                /* Generate address */
396
                adr_ctr_nxt = adr_ctr_ff + (o_wb_stb_ff && i_wb_ack);
397
 
398
                /* Write to buffer */
399
                buf_nxt[adr_ctr_ff] = i_wb_ack ? i_wb_dat : buf_ff[adr_ctr_ff];
400
 
401
                /* Manipulate buffer as needed */
402
                if ( i_wr )
403
                begin
404
                        buf_nxt[i_address[3:2]][7:0]   = i_ben[0] ? i_din[7:0]   : buf_nxt[i_address[3:2]][7:0];
405
                        buf_nxt[i_address[3:2]][15:8]  = i_ben[1] ? i_din[15:8]  : buf_nxt[i_address[3:2]][15:8];
406
                        buf_nxt[i_address[3:2]][23:16] = i_ben[2] ? i_din[23:16] : buf_nxt[i_address[3:2]][23:16];
407
                        buf_nxt[i_address[3:2]][31:24] = i_ben[3] ? i_din[31:24] : buf_nxt[i_address[3:2]][31:24];
408
                end
409
 
410
                if ( adr_ctr_nxt <= 3 )
411
                begin
412
 
413
                        /* Fetch line from memory */
414
                        wb_prpr_read({i_phy_addr[31:4], 4'd0} + (adr_ctr_nxt << 2),
415
                                     adr_ctr_nxt != 3 ? CTI_BURST : CTI_EOB);
416
                end
417
                else
418
                begin
419
 
420
                        /* Update cache */
421
                        o_cache_line = {buf_nxt[3], buf_ff[2], buf_ff[1], buf_ff[0]};
422
                        o_cache_line_ben  = 16'b1111111111111111;
423
 
424
                        /* Update tag. Remove dirty and set valid */
425
                        o_cache_tag_wr_en                       = 1'd1; // Implicitly sets valid.
426
                        o_cache_tag[`CACHE_TAG__TAG]            = i_address[`VA__CACHE_TAG];
427
                        o_cache_tag[`CACHE_TAG__PA]             = i_phy_addr >> 4;
428
                        o_cache_tag_dirty                       = !i_wr ? 1'd0 : 1'd1; // BUG FIX.
429
 
430
                        /* Move to wait state */
431
                        kill_access;
432
                        state_nxt = REFRESH_1;
433
                end
434
        end
435
 
436
        REFRESH: /* One extra cycle for cache and tag to update. */
437
        begin
438
                kill_access;
439
                o_ack     = i_wr && cache_cmp;
440
                state_nxt = IDLE;
441
        end
442
 
443
        INVALIDATE: /* Invalidate the cache - Almost Single Cycle */
444
        begin
445
                cache_inv_req_nxt = 1'd1;
446
                cache_clean_req_nxt = 1'd0;
447
 
448
                if ( i_cache_inv_done )
449
                begin
450
                        cache_inv_req_nxt    = 1'd0;
451
                        state_nxt            = IDLE;
452
                        o_cache_inv_done = 1'd1;
453
                end
454
        end
455
 
456
        CLEAN:  /* Force cache to clean itself */
457
        begin
458
                cache_clean_req_nxt = 1'd1;
459
                cache_inv_req_nxt   = 1'd0;
460
 
461
                if ( i_cache_clean_done )
462
                begin
463
                        cache_clean_req_nxt  = 1'd0;
464
                        state_nxt            = IDLE;
465
                        o_cache_clean_done   = 1'd1;
466
                end
467
        end
468
 
469
        endcase
470
end
471
 
472 51 Revanth
// ----------------------------------------------------------------------------
473 43 Revanth
// Tasks and functions.
474 51 Revanth
// ----------------------------------------------------------------------------
475 43 Revanth
 
476 26 Revanth
function [31:0] adapt_cache_data
477
(input [1:0] shift, input [127:0] cd);
478
begin: blk1
479
        reg [31:0] shamt;
480
        shamt = shift << 5;
481
        adapt_cache_data = cd >> shamt;
482
end
483
endfunction
484
 
485
function [15:0] ben_comp ( input [1:0] shift, input [3:0] bv );
486
begin:fblk2
487
        reg [31:0] shamt;
488
        shamt = shift << 2;
489
        ben_comp = bv << shamt;
490
end
491
endfunction
492
 
493
function [31:0] clean_single_d ( input [127:0] cl, input [31:0] sh );
494
reg [31:0] shamt;
495
begin
496
        shamt = sh << 5;
497
        clean_single_d = cl >> shamt; // Select specific 32-bit.
498
end
499
endfunction
500
 
501
/* Function to generate Wishbone read signals. */
502
task  wb_prpr_read;
503
input [31:0] i_address;
504
input [2:0]  i_cti;
505
begin
506
        o_wb_cyc_nxt = 1'd1;
507
        o_wb_stb_nxt = 1'd1;
508
        o_wb_wen_nxt = 1'd0;
509
        o_wb_sel_nxt = 4'b1111;
510
        o_wb_adr_nxt = i_address;
511
        o_wb_cti_nxt = i_cti;
512
        o_wb_dat_nxt = 0;
513
end
514
endtask
515
 
516
/* Function to generate Wishbone write signals */
517
task  wb_prpr_write;
518
input   [31:0]  i_data;
519
input   [31:0]  i_address;
520
input   [2:0]   i_cti;
521
input   [3:0]   i_ben;
522
begin
523
        o_wb_cyc_nxt = 1'd1;
524
        o_wb_stb_nxt = 1'd1;
525
        o_wb_wen_nxt = 1'd1;
526
        o_wb_sel_nxt = i_ben;
527
        o_wb_adr_nxt = i_address;
528
        o_wb_cti_nxt = i_cti;
529
        o_wb_dat_nxt = i_data;
530
end
531
endtask
532
 
533
/* Disables Wishbone */
534
task  kill_access;
535
begin
536
        o_wb_cyc_nxt = 0;
537
        o_wb_stb_nxt = 0;
538
        o_wb_wen_nxt = 0;
539
        o_wb_adr_nxt = 0;
540
        o_wb_dat_nxt = 0;
541
        o_wb_sel_nxt = 0;
542
        o_wb_cti_nxt = CTI_CLASSIC;
543
end
544
endtask
545
 
546
// ----------------------------------------------------------------------------
547
 
548
wire [31:0] buf0_ff, buf1_ff, buf2_ff;
549 43 Revanth
 
550 26 Revanth
assign buf0_ff = buf_ff[0];
551
assign buf1_ff = buf_ff[1];
552
assign buf2_ff = buf_ff[2];
553 43 Revanth
 
554 26 Revanth
wire [31:0] buf3_ff = buf_ff[3];
555
wire [31:0] buf0_nxt = buf_nxt[0];
556
wire [31:0] buf1_nxt = buf_nxt[1];
557
wire [31:0] buf2_nxt = buf_nxt[2];
558
wire [31:0] buf3_nxt = buf_nxt[3];
559
 
560
wire [31:0] dbg_addr_tag = i_address[`VA__CACHE_TAG];
561
wire [31:0] dbg_addr_pa  = i_phy_addr >> 4;
562
wire [31:0] dbg_ct_tag   = o_cache_tag[`CACHE_TAG__TAG];
563
wire [31:0] dbg_ct_pa    = o_cache_tag[`CACHE_TAG__PA];
564
 
565 43 Revanth
endmodule // zap_cache_fsm
566
 
567 26 Revanth
`default_nettype wire
568 51 Revanth
 
569
// ----------------------------------------------------------------------------
570
// END OF FILE
571
// ----------------------------------------------------------------------------

powered by: WebSVN 2.1.0

© copyright 1999-2022 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.