-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathPAWS.ice
415 lines (375 loc) · 13.4 KB
/
PAWS.ice
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
$$if ICARUS or VERILATOR then
// PLL for simulation
algorithm pll(
output uint1 video_clock,
output! uint1 sdram_clock,
output! uint1 clock_decode,
output uint1 compute_clock
) <autorun> {
uint3 counter = 0;
uint8 trigger = 8b11111111;
sdram_clock := clock;
clock_decode := clock;
compute_clock := ~counter[0,1]; // x2 slower
video_clock := counter[1,1]; // x4 slower
while (1) {
counter = counter + 1;
trigger = trigger >> 1;
}
}
$$end
algorithm main(
// LEDS (8 of)
output uint8 leds,
$$if not SIMULATION then
input uint$NUM_BTNS$ btns,
// UART
output uint1 uart_tx,
input uint1 uart_rx,
// GPIO
input uint28 gn,
output uint28 gp,
// USB PS/2
input uint1 us2_bd_dp,
input uint1 us2_bd_dn,
// AUDIO
output uint4 audio_l,
output uint4 audio_r,
// SDCARD
output uint1 sd_clk,
output uint1 sd_mosi,
output uint1 sd_csn,
input uint1 sd_miso,
$$end
$$if HDMI then
// HDMI OUTPUT
output! uint4 gpdi_dp,
$$end
$$if VGA then
// VGA OUTPUT
output! uint$color_depth$ video_r,
output! uint$color_depth$ video_g,
output! uint$color_depth$ video_b,
output uint1 video_hs,
output uint1 video_vs,
$$end
$$if VERILATOR then
output uint1 video_clock,
$$end
// SDRAM
output! uint1 sdram_cle,
output! uint2 sdram_dqm,
output! uint1 sdram_cs,
output! uint1 sdram_we,
output! uint1 sdram_cas,
output! uint1 sdram_ras,
output! uint2 sdram_ba,
output! uint13 sdram_a,
$$if VERILATOR then
output! uint1 sdram_clock, // sdram controller clock
input uint16 sdram_dq_i,
output! uint16 sdram_dq_o,
output! uint1 sdram_dq_en,
$$else
output uint1 sdram_clk, // sdram chip clock != internal sdram_clock
inout uint16 sdram_dq,
$$end
) <@clock_system> {
uint1 clock_system = uninitialized;
uint1 clock_io = uninitialized;
uint1 clock_cpu = uninitialized;
uint1 clock_decode = uninitialized;
$$if VERILATOR then
$$clock_25mhz = 'video_clock'
// --- PLL
pll clockgen<@clock,!reset>(
video_clock :> video_clock,
sdram_clock :> sdram_clock,
clock_decode :> clock_decode,
compute_clock :> clock_system,
compute_clock :> clock_cpu,
compute_clock :> clock_io
);
$$else
$$clock_25mhz = 'clock'
// CLOCK/RESET GENERATION
// CPU + MEMORY
uint1 sdram_clock = uninitialized;
uint1 pll_lock_SYSTEM = uninitialized;
ulx3s_clk_risc_ice_v_SYSTEM clk_gen_SYSTEM (
clkin <: $clock_25mhz$,
clkSYSTEM :> clock_system,
clkIO :> clock_io,
clkSDRAM :> sdram_clock,
clkSDRAMcontrol :> sdram_clk,
locked :> pll_lock_SYSTEM
);
uint1 pll_lock_CPU = uninitialized;
ulx3s_clk_risc_ice_v_CPU clk_gen_CPU (
clkin <: $clock_25mhz$,
clkCPU :> clock_cpu,
clkDECODE :> clock_decode,
locked :> pll_lock_CPU
);
$$end
// SDRAM Reset
uint1 sdram_reset = uninitialized; clean_reset sdram_rstcond<@sdram_clock,!reset> ( out :> sdram_reset );
// SDRAM chip controller by @sylefeb
sdram_r16w16_io sio_fullrate; sdram_r16w16_io sio_halfrate;
sdram_half_speed_access sdaccess <@sdram_clock,!sdram_reset> ( sd <:> sio_fullrate, sdh <:> sio_halfrate );
sdram_controller_autoprecharge_r16_w16 sdram32MB <@sdram_clock,!sdram_reset> (
sd <:> sio_fullrate,
sdram_cle :> sdram_cle,
sdram_dqm :> sdram_dqm,
sdram_cs :> sdram_cs,
sdram_we :> sdram_we,
sdram_cas :> sdram_cas,
sdram_ras :> sdram_ras,
sdram_ba :> sdram_ba,
sdram_a :> sdram_a,
$$if VERILATOR then
dq_i <: sdram_dq_i,
dq_o :> sdram_dq_o,
dq_en :> sdram_dq_en,
$$else
sdram_dq <:> sdram_dq,
$$end
);
// SDRAM ( via CACHE ) and BRAM (for BIOS AND FAST BRAM )
// byteaccess controls byte read/writes
uint1 byteaccess <:: ( ~|CPU.accesssize[0,2] );
cachecontroller DRAM <@clock_system,!reset> (
sio <:> sio_halfrate,
byteaccess <: byteaccess,
address <: CPU.address[0,26],
writedata <: CPU.writedata
);
bramcontroller RAM <@clock_system,!reset> (
byteaccess <: byteaccess,
address <: CPU.address[0,15],
writedata <: CPU.writedata
);
// MEMORY MAPPED I/O + SMT CONTROLS
io_memmap IO_Map <@clock_io,!reset> (
leds :> leds,
$$if not SIMULATION then
gn <: gn,
gp :> gp,
btns <: btns,
uart_tx :> uart_tx,
uart_rx <: uart_rx,
us2_bd_dp <: us2_bd_dp,
us2_bd_dn <: us2_bd_dn,
sd_clk :> sd_clk,
sd_mosi :> sd_mosi,
sd_csn :> sd_csn,
sd_miso <: sd_miso,
$$end
clock_25mhz <: $clock_25mhz$,
memoryAddress <: CPU.address[0,12],
writeData <: CPU.writedata
);
$$if SIMULATION then
uint4 audio_l(0);
uint4 audio_r(0);
$$end
timers_memmap TIMERS_Map <@clock_io,!reset> (
clock_25mhz <: $clock_25mhz$,
memoryAddress <: CPU.address[0,5],
writeData <: CPU.writedata
);
audio_memmap AUDIO_Map <@clock_io,!reset> (
clock_25mhz <: $clock_25mhz$,
memoryAddress <: CPU.address[0,3],
writeData <: CPU.writedata,
audio_l :> audio_l,
audio_r :> audio_r,
static4bit <: TIMERS_Map.static16bit[0,4]
);
video_memmap VIDEO_Map <@clock_io,!reset> (
clock_25mhz <: $clock_25mhz$,
memoryAddress <: CPU.address[0,12],
writeData <: CPU.writedata,
$$if HDMI then
gpdi_dp :> gpdi_dp,
$$end
$$if VGA then
video_r :> video_r,
video_g :> video_g,
video_b :> video_b,
video_hs :> video_hs,
video_vs :> video_vs,
$$end
static6bit <: TIMERS_Map.static16bit[0,6],
blink <: TIMERS_Map.cursor
);
PAWSCPU CPU <@clock_cpu,!reset> (
clock_CPUdecoder <: clock_decode,
SMTRUNNING <: IO_Map.SMTRUNNING,
SMTSTARTPC <: IO_Map.SMTSTARTPC[0,27],
readdata <: readdata
);
// IDENTIFY ADDRESS BLOCK
uint1 SDRAM <: CPU.address[26,1];
uint1 BRAM <: ~SDRAM & ~CPU.address[15,1];
uint1 IOmem <: ~SDRAM & ~BRAM;
uint1 TIMERS <: IOmem & ( ~|CPU.address[12,2] );
uint1 VIDEO <: IOmem & ( CPU.address[12,2] == 2h1 );
uint1 AUDIO <: IOmem & ( CPU.address[12,2] == 2h2 );
uint1 IO <: IOmem & ( &CPU.address[12,2] );
// READ FROM SDRAM / BRAM / IO REGISTERS
uint16 readdata <: SDRAM ? DRAM.readdata :
BRAM ? RAM.readdata :
TIMERS ? TIMERS_Map.readData :
VIDEO ? VIDEO_Map.readData :
AUDIO ? AUDIO_Map.readData :
IO? IO_Map.readData : 0;
// SDRAM -> CPU BUSY STATE
CPU.memorybusy := DRAM.busy | ( ( CPU.readmemory | CPU.writememory ) & ( BRAM | SDRAM ) );
always_before {
DRAM.readflag = SDRAM & CPU.readmemory;
RAM.readflag = BRAM & CPU.readmemory;
AUDIO_Map.memoryRead = AUDIO & CPU.readmemory;
IO_Map.memoryRead = IO & CPU.readmemory;
TIMERS_Map.memoryRead = TIMERS & CPU.readmemory;
VIDEO_Map.memoryRead = VIDEO & CPU.readmemory;
}
always_after {
DRAM.writeflag = SDRAM & CPU.writememory;
RAM.writeflag = BRAM & CPU.writememory;
AUDIO_Map.memoryWrite = AUDIO & CPU.writememory;
IO_Map.memoryWrite = IO & CPU.writememory;
TIMERS_Map.memoryWrite = TIMERS & CPU.writememory;
VIDEO_Map.memoryWrite = VIDEO & CPU.writememory;
}
}
// RAM - BRAM controller
// MEMORY IS 16 BIT, 8 bit WRITES ARE READ MODIFY WRITE
algorithm bramcontroller(
input uint15 address,
input uint1 byteaccess,
input uint1 writeflag,
input uint16 writedata,
input uint1 readflag,
output uint16 readdata
) <autorun,reginputs> {
$$if not SIMULATION then
// RISC-V FAST BRAM and BIOS
bram uint16 ram[16384] = {
$include('ROM/BIOS.inc')
, pad(uninitialized)
};
$$else
// RISC-V FAST BRAM and BIOS FOR VERILATOR - TEST FOR SMT AND FPU
bram uint16 ram[16384] = {
$include('ROM/VBIOS.inc')
, pad(uninitialized)
};
$$end
uint1 update = uninitialized;
// FLAGS FOR BRAM ACCESS
ram.wenable := 0; ram.addr := address[1,14]; readdata := ram.rdata;
ram.wdata := byteaccess ? ( address[0,1] ? { writedata[0,8], ram.rdata[0,8] } : { ram.rdata[8,8], writedata[0,8] } ) : writedata;
always {
if( writeflag ) {
ram.wenable = update | ~byteaccess;
if( byteaccess ) { update = 1; }
} else {
ram.wenable = update;
update = 0;
}
}
}
// RAM - SDRAM CONTROLLER VIA EVICTION CACHE - MEMORY IS 16 BIT
// EVICTION CACHE CONTROLLER - DIRECTLY MAPPED CACHE - WRITE TO SDRAM ONLY IF EVICTING FROM THE CACHE
bitfield cachetag{ uint1 needswrite, uint1 valid, uint12 partaddress }
algorithm cachecontroller(
sdram_user sio,
input uint26 address,
input uint1 byteaccess,
input uint1 writeflag,
input uint16 writedata,
input uint1 readflag,
output uint16 readdata,
output uint1 busy(0)
) <autorun,reginputs> {
// CACHE for SDRAM 16k
// CACHE ADDRESS IS LOWER 14 bits ( 0 - 8191 ) of address, dropping the BYTE address bit
// CACHE TAG IS REMAINING 12 bits of the 26 bit address + 1 bit for valid flag + 1 bit for needwritetosdram flag
simple_dualport_bram uint16 cache[8192] = uninitialized;
simple_dualport_bram uint14 tags[8192] = uninitialized;
// CACHE WRITER
cachewriter CW( cache <:> cache, tags <:> tags, address <: address );
// SDRAM CONTROLLER
sdramcontroller SDRAM(
sio <:> sio,
writedata <: cache.rdata0
);
// CACHE TAG match flag
uint1 cachetagmatch <:: ( { cachetag(tags.rdata0).valid, cachetag(tags.rdata0).partaddress } == { 1b1, address[14,12] } );
// VALUE TO WRITE TO CACHE ( deals with correctly mapping 8 bit writes and 16 bit writes, using sdram or cache as base )
uint16 writethrough <:: ( byteaccess ) ? ( address[0,1] ? { writedata[0,8], cachetagmatch ? cache.rdata0[0,8] : SDRAM.readdata[0,8] } :
{ cachetagmatch ? cache.rdata0[8,8] : SDRAM.readdata[8,8], writedata[0,8] } ) : writedata;
// MEMORY ACCESS FLAGS
uint1 doread = uninitialized; uint1 dowrite = uninitialized;
uint1 doreadsdram <:: ( doread | ( dowrite & byteaccess ) );
// SDRAM ACCESS
SDRAM.readflag := 0; SDRAM.writeflag := 0;
// FLAGS FOR CACHE ACCESS
cache.addr0 := address[1,13]; tags.addr0 := address[1,13];
CW.needwritetosdram := dowrite; CW.writedata := dowrite ? writethrough : SDRAM.readdata; CW.update := 0;
// 16 bit READ
readdata := cachetagmatch ? cache.rdata0 : SDRAM.readdata;
while(1) {
doread = readflag; dowrite = writeflag;
if( doread | dowrite ) {
busy = 1;
++: // WAIT FOR CACHE
if( cachetagmatch ) {
CW.update = dowrite; // IN CACHE, UPDATE IF WRITE
} else {
if( cachetag(tags.rdata0).needswrite ) { // CHECK IF CACHE LINE IS OCCUPIED
while( SDRAM.busy ) {} SDRAM.address = { cachetag(tags.rdata0).partaddress, address[1,13], 1b0 }; SDRAM.writeflag = 1; // EVICT FROM CACHE TO SDRAM
}
if( doreadsdram ) {
while( SDRAM.busy ) {} SDRAM.address = address; SDRAM.readflag = 1; while( SDRAM.busy ) {} // READ FOR READ OR 8 BIT WRITE
CW.update = 1; // UPDATE THE CACHE
} else {
CW.update = dowrite; // UPDATE CACHE FOR 16 BIT WRITE
}
}
busy = 0;
}
}
}
algorithm cachewriter(
input uint26 address,
input uint1 needwritetosdram,
input uint16 writedata,
input uint1 update,
simple_dualport_bram_port1 cache,
simple_dualport_bram_port1 tags
) <autorun,reginputs> {
always_after {
cache.wenable1 = update; tags.wenable1 = update;
cache.addr1 = address[1,13]; cache.wdata1 = writedata;
tags.addr1 = address[1,13]; tags.wdata1 = { needwritetosdram, 1b1, address[14,12] };
}
}
algorithm sdramcontroller(
sdram_user sio,
input uint26 address,
input uint1 writeflag,
input uint16 writedata,
input uint1 readflag,
output uint16 readdata,
output uint1 busy(0)
) <autorun,reginputs> {
// MEMORY ACCESS FLAGS
sio.addr := { address[1,25], 1b0 }; sio.in_valid := ( readflag | writeflag );
sio.data_in := writedata; sio.rw := writeflag;
readdata := sio.data_out;
always_after {
busy = ( sio.done ) ? 0 : ( readflag | writeflag ) ? 1 : busy;
}
}