Files
fpga6502/fpga/source/design_modules.v
2026-04-14 21:34:37 -07:00

1495 lines
37 KiB
Verilog

////////////////////////////////////////////////////////////////////////////
// _____
// / _______ Copyright (C) 2013-2022 Efinix Inc. All rights reserved.
// / / \
// / / .. / design_modules.v
// / / .' /
// __/ /.' / Description:
// __ \ / Modules for SapphireSoC example design
// /_/ /\ \_____/ /
// ____/ \_______/
//
// ***********************************************************************
// Revisions:
// 1.0 Initial rev
// 1.1 Added Custom ALU
// 1.2 Fixed AXI4 slave read first issue
// 1.3 Added axi full-duplex to half-duplex converter
// ***********************************************************************
`timescale 1ns/1ps
module apb3_slave #(
// user parameter starts here
//
parameter ADDR_WIDTH = 16,
parameter DATA_WIDTH = 32,
parameter NUM_REG = 4
) (
// user logic starts here
input clk,
input resetn,
input [ADDR_WIDTH-1:0] PADDR,
input PSEL,
input PENABLE,
output PREADY,
input PWRITE,
input [DATA_WIDTH-1:0] PWDATA,
output [DATA_WIDTH-1:0] PRDATA,
output PSLVERROR
);
///////////////////////////////////////////////////////////////////////////////
localparam [1:0] IDLE = 2'b00,
SETUP = 2'b01,
ACCESS = 2'b10;
integer byteIndex;
reg [DATA_WIDTH-1:0] slaveReg [0:NUM_REG-1];
reg [DATA_WIDTH-1:0] slaveRegOut;
reg [1:0] busState,
busNext;
reg slaveReady;
wire actWrite,
actRead;
reg [31:0] lfsr;
wire lfsr_stop;
///////////////////////////////////////////////////////////////////////////////
always@(posedge clk or negedge resetn)
begin
if(!resetn)
busState <= IDLE;
else
busState <= busNext;
end
always@(*)
begin
busNext = busState;
case(busState)
IDLE:
begin
if(PSEL && !PENABLE)
busNext = SETUP;
else
busNext = IDLE;
end
SETUP:
begin
if(PSEL && PENABLE)
busNext = ACCESS;
else
busNext = IDLE;
end
ACCESS:
begin
if(PREADY)
busNext = IDLE;
else
busNext = ACCESS;
end
default:
begin
busNext = IDLE;
end
endcase
end
assign actWrite = PWRITE & (busState == ACCESS);
assign actRead = !PWRITE & (busState == ACCESS);
assign PSLVERROR = 1'b0;
assign PRDATA = slaveRegOut;
assign PREADY = slaveReady & & (busState !== IDLE);
always@ (posedge clk)
begin
slaveReady <= actWrite | actRead;
end
always@ (posedge clk or negedge resetn)
begin
if(!resetn)
for(byteIndex = 0; byteIndex < NUM_REG; byteIndex = byteIndex + 1)
slaveReg[byteIndex] <= {DATA_WIDTH{1'b0}};
else
begin
if(actWrite)
begin
for(byteIndex = 0; byteIndex < NUM_REG; byteIndex = byteIndex + 1)
if (PADDR[3:0] == (byteIndex*4))
slaveReg[byteIndex] <= PWDATA;
end
else
begin
slaveReg[0] <= lfsr;
for(byteIndex = 1; byteIndex < NUM_REG; byteIndex = byteIndex + 1)
slaveReg[byteIndex] <= slaveReg[byteIndex];
end
end
end
always@ (posedge clk or negedge resetn)
begin
if(!resetn)
slaveRegOut <= {DATA_WIDTH{1'b0}};
else begin
if(actRead)
slaveRegOut <= slaveReg[PADDR[7:2]];
else
slaveRegOut <= slaveRegOut;
end
end
assign lfsr_stop = slaveReg[1][0];
//custom logics
always@(posedge clk or negedge resetn)
begin
if (!resetn)
lfsr <= 'd1;
else
begin
if(!lfsr_stop)
begin
lfsr[31] <= lfsr[0];
lfsr[30] <= lfsr[31];
lfsr[29] <= lfsr[30];
lfsr[28] <= lfsr[29];
lfsr[27] <= lfsr[28];
lfsr[26] <= lfsr[27];
lfsr[25] <= lfsr[26];
lfsr[24] <= lfsr[25];
lfsr[23] <= lfsr[24];
lfsr[22] <= lfsr[23];
lfsr[21] <= lfsr[22];
lfsr[20] <= lfsr[21];
lfsr[19] <= lfsr[20];
lfsr[18] <= lfsr[19];
lfsr[17] <= lfsr[18];
lfsr[16] <= lfsr[17];
lfsr[15] <= lfsr[16];
lfsr[14] <= lfsr[15];
lfsr[13] <= lfsr[14];
lfsr[12] <= lfsr[13];
lfsr[11] <= lfsr[12];
lfsr[10] <= lfsr[11];
lfsr[9 ] <= lfsr[10];
lfsr[8 ] <= lfsr[9 ];
lfsr[7 ] <= lfsr[8 ];
lfsr[6 ] <= lfsr[7 ];
lfsr[5 ] <= lfsr[6 ];
lfsr[4 ] <= lfsr[5 ];
lfsr[3 ] <= lfsr[4 ] ^ lfsr[0];
lfsr[2 ] <= lfsr[3 ];
lfsr[1 ] <= lfsr[2 ];
lfsr[0 ] <= lfsr[1 ] ^ lfsr[0];
end
else
begin
lfsr <= lfsr;
end
end
end
endmodule
// ***********************************************************************
module axi4_slave #(
parameter ADDR_WIDTH = 32,
parameter DATA_WIDTH = 32
) (
//custom logic starts here
output axi_interrupt,
//
input axi_aclk,
input axi_resetn,
//AW
input [7:0] axi_awid,
input [ADDR_WIDTH-1:0] axi_awaddr,
input [7:0] axi_awlen,
input [2:0] axi_awsize,
input [1:0] axi_awburst,
input axi_awlock,
input [3:0] axi_awcache,
input [2:0] axi_awprot,
input [3:0] axi_awqos,
input [3:0] axi_awregion,
input axi_awvalid,
output axi_awready,
//W
input [DATA_WIDTH-1:0] axi_wdata,
input [(DATA_WIDTH/8)-1:0]
axi_wstrb,
input axi_wlast,
input axi_wvalid,
output axi_wready,
//B
output [7:0] axi_bid,
output [1:0] axi_bresp,
output axi_bvalid,
input axi_bready,
//AR
input [7:0] axi_arid,
input [ADDR_WIDTH-1:0] axi_araddr,
input [7:0] axi_arlen,
input [2:0] axi_arsize,
input [1:0] axi_arburst,
input axi_arlock,
input [3:0] axi_arcache,
input [2:0] axi_arprot,
input [3:0] axi_arqos,
input [3:0] axi_arregion,
input axi_arvalid,
output axi_arready,
//R
output [7:0] axi_rid,
output [DATA_WIDTH-1:0] axi_rdata,
output [1:0] axi_rresp,
output axi_rlast,
output axi_rvalid,
input axi_rready
);
///////////////////////////////////////////////////////////////////////////////
localparam RAM_SIZE = 2048;
localparam RAMW = $clog2(RAM_SIZE);
localparam [2:0] IDLE = 3'h0,
PRE_WR = 3'h1,
WR = 3'h2,
WR_RESP = 3'h3,
PRE_RD = 3'h4,
RD = 3'h5;
reg [2:0] busState,
busNext;
wire busReady,
busPreWrite,
busWrite,
busWriteResp,
busPreRead,
busRead;
wire awWrap,
arWrap;
reg [7:0] awidReg;
reg [ADDR_WIDTH-1:0] awaddrReg;
reg [7:0] awlenReg;
reg [2:0] awsizeReg;
reg [1:0] awburstReg,
awlockReg;
reg [3:0] awcacheReg;
reg [2:0] awprotReg;
reg [3:0] awqosReg;
reg [3:0] awregionReg;
reg [7:0] aridReg;
reg [ADDR_WIDTH-1:0] araddrReg;
reg [7:0] arlenReg;
reg [2:0] arsizeReg;
reg [1:0] arburstReg,
arlockReg;
reg [3:0] arcacheReg;
reg [2:0] arprotReg;
reg [3:0] arqosReg;
reg [3:0] arregionReg;
reg [31:0] awaddr_base;
wire [31:0] awWrapSize;
reg [7:0] decodeAwsize;
wire [31:0] araddr_wrap;
reg [7:0] decodeArsize;
reg [31:0] araddr_base;
wire [31:0] arWrapSize;
reg [7:0] ridReg;
reg [1:0] rrespReg;
reg [1:0] rlastReg;
wire pWr_done;
wire pRd_done;
wire awaddr_ext;
wire araddr_ext;
wire [(DATA_WIDTH/8)-1:0]
rlast;
wire [(DATA_WIDTH/8)-1:0]
rvalid;
//custom logic
wire [9:0] wdata [0:3];
wire wEnable[0:3];
wire [9:0] rdata [0:3];
wire [31:0] data_o;
wire rEnable;
reg r_axi_interrupt;
///////////////////////////////////////////////////////////////////////////////
always@ (posedge axi_aclk or negedge axi_resetn)
begin
if(!axi_resetn)
busState <= IDLE;
else
busState <= busNext;
end
always@ (*)
begin
busNext = busState;
case(busState)
IDLE:
begin
if(axi_awvalid)
busNext = PRE_WR;
else if(axi_arvalid)
busNext = PRE_RD;
else
busNext = IDLE;
end
PRE_WR:
begin
if(pWr_done)
busNext = WR;
else
busNext = PRE_WR;
end
WR:
begin
if(axi_wlast)
busNext = WR_RESP;
else
busNext = WR;
end
WR_RESP:
begin
if(axi_bready)
busNext = IDLE;
else
busNext = WR_RESP;
end
PRE_RD:
begin
if(pRd_done)
busNext = RD;
else
busNext = PRE_RD;
end
RD:
begin
if(axi_rlast && axi_rready)
busNext = IDLE;
else
busNext = RD;
end
default:
busNext = IDLE;
endcase
end
assign busReady = (busState == IDLE);
assign busPreWrite = (busState == PRE_WR);
assign busWrite = (busState == WR);
assign busWriteResp = (busState == WR_RESP);
assign busPreRead = (busState == PRE_RD);
assign busRead = (busState == RD);
//PRE_WRITE
assign pWr_done = (awburstReg == 2'b10)? awaddr_ext : 1'b1;
//AW Control
assign axi_awready = busReady;
//Wrap Control
always@ (posedge axi_aclk or negedge axi_resetn)
begin
if (!axi_resetn)
awaddr_base <= 'h0;
else begin
if(busReady)
awaddr_base <= 'h0;
else if(busPreWrite && !awaddr_ext)
awaddr_base <= awaddr_base + awWrapSize;
else
awaddr_base <= awaddr_base;
end
end
assign awaddr_ext = busPreWrite ? (awaddr_base[RAMW:0] > awaddrReg[RAMW:0]) : 1'b0;
assign awWrap = busWrite && (axi_awburst == 2'b10) ? (awaddrReg[RAMW:0] == awaddr_base - 4) : 1'b0;
assign awWrapSize = (DATA_WIDTH/8) * awlenReg;
//AW Info
always@ (posedge axi_aclk)
begin
if(axi_awvalid) begin
awidReg <= axi_awid;
awlenReg <= axi_awlen + 1'b1;
awsizeReg <= axi_awsize;
awburstReg <= axi_awburst;
awlockReg <= axi_awlock;
awcacheReg <= axi_awcache;
awprotReg <= axi_awprot;
awqosReg <= axi_awqos;
awregionReg <= axi_awregion;
end
else begin
awidReg <= awidReg;
awlenReg <= awlenReg;
awsizeReg <= awsizeReg;
awburstReg <= awburstReg;
awlockReg <= awlockReg;
awcacheReg <= awcacheReg;
awprotReg <= awprotReg;
awqosReg <= awqosReg;
awregionReg <= awregionReg;
end
end
always@ (awsizeReg)
begin
case(awsizeReg)
3'h0:decodeAwsize <= 8'd1;
3'h1:decodeAwsize <= 8'd2;
3'h2:decodeAwsize <= 8'd4;
3'h3:decodeAwsize <= 8'd8;
3'h4:decodeAwsize <= 8'd16;
3'h5:decodeAwsize <= 8'd32;
3'h6:decodeAwsize <= 8'd64;
3'h7:decodeAwsize <= 8'd128;
default:decodeAwsize <= 8'd1;
endcase
end
always@ (posedge axi_aclk)
begin
if(axi_awvalid)
awaddrReg <= axi_awaddr;
else if (busWrite) begin
case(awburstReg)
2'b00://fixed burst
awaddrReg <= awaddrReg;
2'b01://incremental burst
awaddrReg <= awaddrReg + decodeAwsize;
2'b10://wrap burst
begin
if(awWrap)
awaddrReg <= awaddrReg - awWrapSize;
else
awaddrReg <= awaddrReg + decodeAwsize;
end
default:
awaddrReg <= awaddrReg;
endcase
end
end
//W operation
assign axi_wready = busWrite;
//B Response
assign axi_bid = awidReg;
assign axi_bresp = 2'b00;
assign axi_bvalid = busWriteResp;
//PRE_READ
assign pRd_done = (arburstReg == 2'b10)? araddr_ext : 1'b1;
//AR Control
assign axi_arready = busReady;
//Wrap Control
always@ (posedge axi_aclk or negedge axi_resetn)
begin
if (!axi_resetn)
araddr_base <= 'h0;
else begin
if(busReady)
araddr_base <= 'h0;
else if(busPreRead && !araddr_ext)
araddr_base <= araddr_base + arWrapSize;
else
araddr_base <= araddr_base;
end
end
assign araddr_ext = busPreRead ? (araddr_base[RAMW:0] > araddrReg[RAMW:0]) : 1'b0;
assign arWrap = (busRead && axi_arburst == 2'b10) ? (araddrReg[RAMW:0] == araddr_base - 4) : 1'b0;
assign arWrapSize = (DATA_WIDTH/8) * arlenReg;
//AR Info
always@ (posedge axi_aclk)
begin
if(axi_arvalid) begin
aridReg <= axi_arid;
arlenReg <= axi_arlen + 1'b1;
arsizeReg <= axi_arsize;
arburstReg <= axi_arburst;
arlockReg <= axi_arlock;
arcacheReg <= axi_arcache;
arprotReg <= axi_arprot;
arqosReg <= axi_arqos;
arregionReg <= axi_arregion;
end
else begin
aridReg <= aridReg;
arlenReg <= arlenReg;
arsizeReg <= arsizeReg;
arburstReg <= arburstReg;
arlockReg <= arlockReg;
arcacheReg <= arcacheReg;
arprotReg <= arprotReg;
arqosReg <= arqosReg;
arregionReg <= arregionReg;
end
end
always@ (arsizeReg)
begin
case(arsizeReg)
3'h0:decodeArsize <= 8'd1;
3'h1:decodeArsize <= 8'd2;
3'h2:decodeArsize <= 8'd4;
3'h3:decodeArsize <= 8'd8;
3'h4:decodeArsize <= 8'd16;
3'h5:decodeArsize <= 8'd32;
3'h6:decodeArsize <= 8'd64;
3'h7:decodeArsize <= 8'd128;
default:decodeArsize <= 8'd1;
endcase
end
always@ (posedge axi_aclk)
begin
if(axi_arvalid)
araddrReg <= axi_araddr;
else if (rEnable && axi_rready) begin
case(arburstReg)
2'b00://fixed burst
araddrReg <= araddrReg;
2'b01://incremental burst
araddrReg <= araddrReg + decodeArsize;
2'b10://wrap burst
begin
if(arWrap)
araddrReg <= araddrReg - arWrapSize;
else
araddrReg <= araddrReg + decodeArsize;
end
default:
araddrReg <= araddrReg;
endcase
end
end
// R Operation
assign axi_rdata = data_o;
// R Response
assign axi_rvalid = busRead? |rvalid : 1'b0 ;
assign axi_rlast = busRead? |rlast : 1'b0 ;
assign axi_rresp = 2'b00;
assign axi_rid = aridReg;
//custom logic starts here
assign axi_interrupt = r_axi_interrupt;
assign rEnable = (axi_arburst == 2'b10)? busRead : busPreRead;
always@ (posedge axi_aclk)
begin
if (!axi_resetn)
begin
r_axi_interrupt <= 1'b0;
end
else
begin
if((axi_wvalid) && (axi_wdata == 16'hABCD))
r_axi_interrupt <= 1'b1;
else
r_axi_interrupt <= 1'b0;
end
end
genvar i;
generate
for(i=0;i < (DATA_WIDTH/8); i = i + 1) begin
assign rvalid[i] = (arlenReg != 'h1)? rdata[i][8] : 1'b1;
assign rlast[i] = (arlenReg != 'h1)? rdata[i][9] : 1'b1;
assign wdata[i] = {axi_wlast, axi_wvalid, axi_wdata[(i*8+7) -: 8]} ;
assign data_o[(i*8+7) -: 8] = rdata[i];
assign wEnable[i] = axi_wready & axi_wvalid & axi_wstrb[i];
ext_mem #(
.DATA_WIDTH (10),
.ADDR_WIDTH (RAMW-2),
.OUTPUT_REG ("TRUE")
) user_ram (
.wdata (wdata[i]),
.waddr (awaddrReg[RAMW-1:2]),
.raddr (araddrReg[RAMW-1:2]),
.we (wEnable[i]),
.wclk (axi_aclk),
.re (rEnable),
.rclk (axi_aclk),
.rdata (rdata[i])
);
end
endgenerate
endmodule
// ***********************************************************************
module memory_checker #(
parameter WIDTH = 32,
parameter ALEN = 23,
parameter START_ADDR = 32'h00000000,
parameter STOP_ADDR = 32'h00100000,
parameter ADDR_OFFSET = (ALEN + 1)*(WIDTH/8)
) (
input axi_clk,
input rstn,
input start,
output [7:0] aid,
output reg [31:0] aaddr,
output reg [7:0] alen,
output reg [2:0] asize,
output reg [1:0] aburst,
output reg [1:0] alock,
output reg avalid,
input aready,
output reg atype,
output [7:0] wid,
output reg [WIDTH-1:0] wdata,
output [WIDTH/8-1:0] wstrb,
output reg wlast,
output reg wvalid,
input wready,
input [3:0] rid,
input [WIDTH-1:0] rdata,
input rlast,
input rvalid,
output reg rready,
input [1:0] rresp,
input [7:0] bid,
input bvalid,
output reg bready,
output pass
);
///////////////////////////////////////////////////////////////////////////////
localparam ASIZE = (WIDTH == 512)? 6 :
(WIDTH == 256)? 5 :
(WIDTH == 128)? 4 :
(WIDTH == 64)? 3 : 2;
//Main states
localparam COMPARE_WIDTH = WIDTH;
localparam IDLE = 4'b0000,
WRITE_ADDR = 4'b0001,
PRE_WRITE = 4'b0010,
WRITE = 4'b0011,
POST_WRITE = 4'b0100,
READ_ADDR = 4'b0101,
PRE_READ = 4'b0110,
READ_COMPARE = 4'b0111,
POST_READ = 4'b1000,
DONE = 4'b1001;
//reg [3:0] states, nstates;
reg fail;
reg done;
reg [3:0] states;
reg [3:0] nstates;
reg bvalid_done;
reg [1:0] start_sync;
reg [8:0] write_cnt, read_cnt;
reg [WIDTH-1:0] rdata_store;
reg wburst_done,
rburst_done,
write_done,
read_done;
///////////////////////////////////////////////////////////////////////////////
assign aid = 8'h00;
assign wstrb = {WIDTH/8{1'b1}};
assign wid = 8'h00;
assign pass = done & ~fail;
always @(posedge axi_clk or negedge rstn)
begin
if (!rstn) begin
start_sync <= 2'b00;
end else begin
start_sync[0] <= start;
start_sync[1] <= start_sync[0];
end
end
always @(posedge axi_clk or negedge rstn)
begin
if (!rstn) begin
states <= IDLE;
end else begin
states <= nstates;
end
end
always @(states or start_sync[1] or write_cnt or rburst_done or write_done or read_done or bvalid_done or aready)
begin
case(states)
IDLE :
if (start_sync[1])
nstates = WRITE_ADDR;
else
nstates = IDLE;
WRITE_ADDR :
if (aready)
nstates = PRE_WRITE;
else
nstates = WRITE_ADDR;
PRE_WRITE :
nstates = WRITE;
WRITE :
if (write_cnt == 9'd0)
nstates = POST_WRITE;
else
nstates = WRITE;
POST_WRITE :
if (write_done & bvalid_done)
nstates = READ_ADDR;
else if (bvalid_done)
nstates = WRITE_ADDR;
else
nstates = POST_WRITE;
READ_ADDR :
if (aready)
nstates = PRE_READ;
else
nstates = READ_ADDR;
PRE_READ :
nstates = READ_COMPARE;
READ_COMPARE :
if (rburst_done)
nstates = POST_READ;
else
nstates = READ_COMPARE;
POST_READ :
if (read_done)
nstates = DONE;
else
nstates = READ_ADDR;
DONE :
nstates = DONE;
default :
nstates = IDLE;
endcase
end
always @(posedge axi_clk or negedge rstn)
begin
if (!rstn) begin
aaddr <= START_ADDR;
avalid <= 1'b0;
atype <= 1'b0;
aburst <= 2'b00;
asize <= 3'b000;
alen <= 8'd0;
alock <= 2'b00;
wvalid <= 1'b0;
write_cnt <= ALEN + 1;
write_done <= 1'b0;
wdata <= {WIDTH{1'b0}};
wburst_done <= 1'b0;
wlast <= 1'b0;
bready <= 1'b0;
fail <= 1'b0;
done <= 1'b0;
rready <= 1'b0;
bvalid_done <=1'b0;
end
else
begin
if (states == IDLE)
begin
aaddr <= START_ADDR;
avalid <= 1'b0;
atype <= 1'b0;
aburst <= 2'b00;
asize <= 3'b000;
alen <= 8'd0;
alock <= 2'b00;
wvalid <= 1'b0;
write_cnt <= ALEN + 1;
wdata <= {WIDTH{1'b0}};
wburst_done <= 1'b0;
wlast <= 1'b0;
bready <= 1'b0;
rready <= 1'b0;
bvalid_done <= 1'b0;
fail <= 1'b0;
done <= 1'b0;
end
if (states == WRITE_ADDR)
begin
avalid <= 1'b1;
atype <= 1'b1;
asize <= ASIZE;
alen <= ALEN;
aburst <= 2'b01;
alock <= 2'b00;
wvalid <= 1'b0;
write_cnt <= ALEN + 1;
wburst_done <= 1'b0;
bvalid_done <= 1'b0;
bready <= 1'b0;
rready <= 1'b0;
done <= 1'b0;
fail <= 1'b0;
end
if (states == PRE_WRITE)
begin
avalid <= 1'b0;
atype <= 1'b0;
wvalid <= 1'b1;
wdata <= {{WIDTH/32{~aaddr[7:0]}},{WIDTH/32{~write_cnt[7:0]}},{WIDTH/32{aaddr[7:0]}},{WIDTH/32{write_cnt[7:0]}}};
bready <= 1'b1;
write_cnt <= write_cnt - 1;
if(alen == 'd0)
begin
wlast <= 1'b1;
end
end
if (states == WRITE)
begin
if (wready == 1'b1)
begin
wdata <= {{WIDTH/32{~aaddr[7:0]}},{WIDTH/32{~write_cnt[7:0]}},{WIDTH/32{aaddr[7:0]}},{WIDTH/32{write_cnt[7:0]}}};
if (write_cnt == 9'd0)
begin
wburst_done <= 1'b1;
wlast <= 1'b0;
wvalid <= 1'b0;
if (aaddr >= STOP_ADDR)
begin
write_done <= 1'b1;
end else
begin
write_done <= 1'b0;
end
end if (write_cnt == 9'd1)
begin
wlast <= 1'b1;
write_cnt <= write_cnt - 1;
end
else
begin
write_cnt <= write_cnt - 1;
end
end
end
if (states == POST_WRITE)
begin
if (write_done)
begin
aaddr <= START_ADDR;
end
else
begin
if (bvalid) begin
aaddr <= aaddr + ADDR_OFFSET;
end
end
if (wready == 1'b1)
begin
wlast <= 1'b0;
wvalid <= 1'b0;
end
if (bvalid)
begin
bvalid_done <= 1'b1;
bready <= 1'b0;
end
end
if (states == READ_ADDR)
begin
avalid <= 1'b1;
read_cnt <= ALEN + 1;
end
if (states == PRE_READ)
begin
avalid <= 1'b0;
rburst_done <= 1'b0;
rdata_store <= {{WIDTH/32{~aaddr[7:0]}},{WIDTH/32{~read_cnt[7:0]}},{WIDTH/32{aaddr[7:0]}},{WIDTH/32{read_cnt[7:0]}}};
read_cnt <= read_cnt - 1'b1;
end
if (states == READ_COMPARE)
begin
rready <= 1'b1;
if (read_cnt != 9'd0)
begin
if (rvalid == 1'b1)
begin
rdata_store <= {{WIDTH/32{~aaddr[7:0]}},{WIDTH/32{~read_cnt[7:0]}},{WIDTH/32{aaddr[7:0]}},{WIDTH/32{read_cnt[7:0]}}};
read_cnt <= read_cnt - 1'b1;
if (rdata[COMPARE_WIDTH-1:0] != rdata_store[COMPARE_WIDTH-1:0])
fail <= 1'b1;
else
fail <= 1'b0;
end
end
end
if (read_cnt == 9'd0)
begin
if (rvalid == 1'b1)
begin
if (rdata[COMPARE_WIDTH-1:0] != rdata_store[COMPARE_WIDTH-1:0])
begin
fail <= 1'b1;
end
else
begin
fail <= 1'b0;
end
if (aaddr >= STOP_ADDR)
begin
read_done <= 1'b1;
end
else
begin
read_done <= 1'b0;
end
rburst_done <= 1'b1;
end
end
if (states == POST_READ)
begin
aaddr <= aaddr + ADDR_OFFSET;
rready <= 1'b1;
end
if (states == DONE)
begin
done <= 1'b1;
end
end
end
endmodule
// ***********************************************************************
module timer_start #(
parameter MHZ = 50,
parameter SECOND = 3,
parameter PULSE = 0
) (
input clk,
input rst_n,
output start
);
reg [35:0] delay_cnt;
wire second_tick;
reg [4:0] second_cnt;
reg [3:0] pulse_reg;
wire start_reg;
///////////////////////////////////////////////////////////////////////////////
`ifndef EFX_SIM
localparam tick_cnt = (MHZ * 1000000) >> 1;
`else
localparam tick_cnt = MHZ * 200;
`endif
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
delay_cnt <= 'd0;
else
begin
if(delay_cnt == tick_cnt || start_reg == 1'b1)
delay_cnt <= 'd0;
else
delay_cnt <= delay_cnt + 1'b1;
end
end
assign second_tick = ((delay_cnt) == (tick_cnt - 1));
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
second_cnt <= 'd0;
else
begin
if(second_tick)
second_cnt <= second_cnt + 1'b1;
else
second_cnt <= second_cnt;
end
end
assign start_reg = (second_cnt == SECOND);
always@(posedge clk)
begin
pulse_reg <= {pulse_reg[2:0],start_reg};
end
generate
if(PULSE == 1)
assign start = ~pulse_reg[3] & start_reg;
else
assign start = start_reg;
endgenerate
endmodule
// ***********************************************************************
module ext_mem #(
parameter DATA_WIDTH = 8,
parameter ADDR_WIDTH = 9,
parameter OUTPUT_REG = "TRUE",
parameter RAM_INIT_FILE = ""
) (
input [DATA_WIDTH-1:0] wdata,
input [ADDR_WIDTH-1:0] waddr,
input [ADDR_WIDTH-1:0] raddr,
input we,
input wclk,
input re,
input rclk,
output [DATA_WIDTH-1:0] rdata
);
/////////////////////////////////////////////////////////////////////////////
localparam MEMORY_DEPTH = 2**ADDR_WIDTH;
localparam MAX_DATA = (1<<ADDR_WIDTH)-1;
reg [DATA_WIDTH-1:0]ram [MEMORY_DEPTH-1:0];
wire [DATA_WIDTH-1:0] r_rdata_1P;
reg [DATA_WIDTH-1:0] r_rdata_2P = 'h0;
/////////////////////////////////////////////////////////////////////////////
initial
begin
if (RAM_INIT_FILE != "")
begin
$readmemh(RAM_INIT_FILE, ram);
end
end
always @ (posedge wclk)
if (we)
ram[waddr] <= wdata;
assign r_rdata_1P = re? ram[raddr] : 'hZ;
always @ (posedge rclk)
begin
if (re)
r_rdata_2P <= r_rdata_1P;
end
generate
if (OUTPUT_REG == "TRUE")
assign rdata = r_rdata_2P;
else
assign rdata = r_rdata_1P;
endgenerate
endmodule
// ***********************************************************************
module custom_instruction_tea (
input clk,
input reset,
input cmd_valid,
output cmd_ready,
input [9:0] cmd_function_id,
input [31:0] cmd_inputs_0,
input [31:0] cmd_inputs_1,
output reg rsp_valid,
input rsp_ready,
output [31:0] rsp_outputs_0
);
/////////////////////////////////////////////////////////////////////////////
reg [31:0] raw_data0;
reg [31:0] raw_data1;
reg raw_valid;
reg raw_valid_upper;
reg [1:0] valid_upper_r1;
wire [63:0] enc_out;
wire enc_valid;
wire enc_valid_upper;
reg enc_busy;
/////////////////////////////////////////////////////////////////////////////
always@(posedge clk or posedge reset)
begin
if(reset)
begin
raw_data0 <= 32'd0;
raw_data1 <= 32'd0;
raw_valid <= 1'b0;
raw_valid_upper <= raw_valid_upper;
end
else
begin
if (cmd_ready & cmd_valid)
begin
case (cmd_function_id[1:0])
2'd0:
begin
raw_data0 <= cmd_inputs_0;
raw_data1 <= cmd_inputs_1;
raw_valid <= 1'b1;
raw_valid_upper <= 1'b0;
end
2'd1:
begin
raw_data0 <= raw_data0;
raw_data1 <= raw_data1;
raw_valid <= 1'b0;
raw_valid_upper <= 1'b1;
end
default:
begin
raw_data0 <= raw_data0;
raw_data1 <= raw_data1;
raw_valid <= 1'b0;
raw_valid_upper <= raw_valid_upper;
end
endcase
end
else
begin
raw_data0 <= raw_data0;
raw_data1 <= raw_data1;
raw_valid <= 1'b0;
raw_valid_upper <= raw_valid_upper;
end
end
end
always@(posedge clk or posedge reset)
begin
if(reset)
enc_busy <= 1'b0;
else
begin
if(rsp_valid && rsp_ready)
enc_busy <= 1'b0;
else if(cmd_valid)
begin
case (cmd_function_id[1:0])
2'd0,2'd1:
enc_busy <= 1'b1;
default:
enc_busy <= 1'b0;
endcase
end
else
enc_busy <= enc_busy;
end
end
always@(posedge clk)
begin
valid_upper_r1 <= {valid_upper_r1[0], raw_valid_upper};
end
assign enc_valid_upper = valid_upper_r1[0] & ~valid_upper_r1[1];
always@(posedge clk or posedge reset)
begin
if(reset)
rsp_valid <= 1'b0;
else
begin
if(enc_valid | enc_valid_upper)
rsp_valid <= 1'b1;
else if(rsp_ready)
rsp_valid <= 1'b0;
else
rsp_valid <= rsp_valid;
end
end
assign rsp_outputs_0 = raw_valid_upper ? enc_out[63:32]:enc_out[31:0];
assign cmd_ready = !enc_busy;
tiny_encrytion #(
.ITER(1024)
) tea (
.clk (clk),
.reset (reset),
.raw0 (raw_data0),
.raw1 (raw_data1),
.rawEn (raw_valid),
.busy (),
.enc_out (enc_out),
.enc_valid (enc_valid)
);
endmodule
/////////////////////////////////////////////////////////////////////////////
module tiny_encrytion #(
parameter ITER = 1024
) (
clk,
reset,
raw0,
raw1,
rawEn,
busy,
enc_out,
enc_valid
);
input clk;
input reset;
input [31:0] raw0;
input [31:0] raw1;
input rawEn;
output busy;
output reg [63:0] enc_out;
output enc_valid;
/////////////////////////////////////////////////////////////////////////////
localparam deltaConstant = 32'h9E3779B9;
localparam enckey0 = 32'h01234567;
localparam enckey1 = 32'h89abcdef;
localparam enckey2 = 32'h13579248;
localparam enckey3 = 32'h248a0135;
localparam CW = $clog2(ITER);
reg [31:0] raw_r0,
raw_r1;
reg [CW-1:0] iteration_cnt;
reg [2:0] iteration_start;
wire iteration_stop;
reg iteration_act;
reg [1:0] data_tick;
reg data_tick_r1;
reg [31:0] delta_r1;
wire [31:0] cal0_top;
wire [31:0] cal0_mid;
wire [31:0] cal0_bot;
wire [31:0] cal0;
wire [31:0] cal1_top;
wire [31:0] cal1_mid;
wire [31:0] cal1_bot;
wire [31:0] cal1;
/////////////////////////////////////////////////////////////////////////////
always@(posedge clk)
begin
if(data_tick[0])
enc_out <= {raw_r1, raw_r0};
else
enc_out <= enc_out;
end
assign busy = iteration_act;
assign enc_valid = data_tick[1];
always@(posedge clk)
begin
iteration_start <= {iteration_start[1:0], rawEn};
data_tick <= {data_tick[0], iteration_stop};
end
assign iteration_stop = (iteration_cnt == {CW{1'b1}});
always@(posedge clk or posedge reset)
begin
if(reset)
iteration_act <= 'b0;
else
begin
if(iteration_start[2])
iteration_act <= 1'b1;
else if(iteration_stop)
iteration_act <= 1'b0;
else
iteration_act <= iteration_act;
end
end
always@(posedge clk or posedge reset)
begin
if(reset)
iteration_cnt <= 'd0;
else
begin
if(iteration_act)
iteration_cnt <= iteration_cnt + 1'b1;
else
iteration_cnt <= 'd0;
end
end
always@(posedge clk)
begin
if(iteration_start[1] && !iteration_act)
begin
raw_r0 <= raw0;
raw_r1 <= raw1;
delta_r1 <= deltaConstant;
end
else
if(iteration_act)
begin
raw_r0 <= cal1 + raw_r0;
raw_r1 <= cal0 + raw_r1;
delta_r1 <= delta_r1 + deltaConstant;
end
else
begin
raw_r0 <= raw_r0;
raw_r1 <= raw_r1;
delta_r1 <= delta_r1;
end
end
assign cal0_top = ((raw_r0 + cal1) << 4) + enckey2;
assign cal0_mid = (raw_r0 + cal1) + delta_r1;
assign cal0_bot = ((raw_r0 + cal1) >> 5) + enckey3;
assign cal0 = cal0_top ^ cal0_mid ^ cal0_bot;
assign cal1_top = (raw_r1 << 4) + enckey0;
assign cal1_mid = raw_r1 + delta_r1;
assign cal1_bot = (raw_r1 >> 5) + enckey1;
assign cal1 = cal1_top ^ cal1_mid ^ cal1_bot;
endmodule
/////////////////////////////////////////////////////////////////////////////
module fd_to_hd_wrapper (
input clk,
input reset,
output wire io_ddrA_arw_valid,
input io_ddrA_arw_ready,
output wire [31:0] io_ddrA_arw_payload_addr,
output wire [7:0] io_ddrA_arw_payload_id,
output wire [7:0] io_ddrA_arw_payload_len,
output wire [2:0] io_ddrA_arw_payload_size,
output wire [1:0] io_ddrA_arw_payload_burst,
output wire [1:0] io_ddrA_arw_payload_lock,
output wire io_ddrA_arw_payload_write,
input io_ddrA_aw_valid,
output wire io_ddrA_aw_ready,
input [31:0] io_ddrA_aw_payload_addr,
input [7:0] io_ddrA_aw_payload_id,
input [7:0] io_ddrA_aw_payload_len,
input [2:0] io_ddrA_aw_payload_size,
input [1:0] io_ddrA_aw_payload_burst,
input [1:0] io_ddrA_aw_payload_lock,
input io_ddrA_ar_valid,
output wire io_ddrA_ar_ready,
input [31:0] io_ddrA_ar_payload_addr,
input [7:0] io_ddrA_ar_payload_id,
input [7:0] io_ddrA_ar_payload_len,
input [2:0] io_ddrA_ar_payload_size,
input [1:0] io_ddrA_ar_payload_burst,
input [1:0] io_ddrA_ar_payload_lock
);
/////////////////////////////////////////////////////////////////////////////
localparam [1:0] IDLE = 2'h0,
WRITE = 2'h1,
READ = 2'h2;
reg [1:0] st_cur,
st_next;
wire op_write,
op_read;
/////////////////////////////////////////////////////////////////////////////
always@(posedge clk or posedge reset)
begin
if(reset)
st_cur <= IDLE;
else
st_cur <= st_next;
end
always@*
begin
st_next = st_cur;
case(st_cur)
IDLE:
begin
if(io_ddrA_aw_valid)
st_next = WRITE;
else if (io_ddrA_ar_valid)
st_next = READ;
else
st_next = IDLE;
end
WRITE:
begin
if(io_ddrA_aw_ready)
st_next = IDLE;
else
st_next = WRITE;
end
READ:
begin
if(io_ddrA_ar_ready)
st_next = IDLE;
else
st_next = READ;
end
default: st_next = IDLE;
endcase
end
assign op_write = (st_cur == WRITE);
assign op_read = (st_cur == READ);
assign io_ddrA_arw_valid = op_write ? io_ddrA_aw_valid : op_read ? io_ddrA_ar_valid : 1'b0;
assign io_ddrA_arw_payload_addr = op_write ? io_ddrA_aw_payload_addr : io_ddrA_ar_payload_addr;
assign io_ddrA_arw_payload_id = op_write ? io_ddrA_aw_payload_id : io_ddrA_ar_payload_id;
assign io_ddrA_arw_payload_len = op_write ? io_ddrA_aw_payload_len : io_ddrA_ar_payload_len;
assign io_ddrA_arw_payload_size = op_write ? io_ddrA_aw_payload_size : io_ddrA_ar_payload_size;
assign io_ddrA_arw_payload_burst = op_write ? io_ddrA_aw_payload_burst : io_ddrA_ar_payload_burst;
assign io_ddrA_arw_payload_lock = op_write ? io_ddrA_aw_payload_lock : io_ddrA_ar_payload_lock;
assign io_ddrA_arw_payload_write = op_write;
assign io_ddrA_aw_ready = op_write ? io_ddrA_arw_ready : 1'b0;
assign io_ddrA_ar_ready = op_read ? io_ddrA_arw_ready : 1'b0;
endmodule