URL
https://opencores.org/ocsvn/amber/amber/trunk
Subversion Repositories amber
Compare Revisions
- This comparison shows the changes necessary to convert path
/amber
- from Rev 78 to Rev 77
- ↔ Reverse comparison
Rev 78 → Rev 77
/trunk/hw/fpga/bin/Makefile
38,9 → 38,9
# // |
# ---------------------------------------------------------------- |
|
# ---------------------------------------------------- |
# ---------------------------------------------------- |
# Environment Configuration |
# ---------------------------------------------------- |
# ---------------------------------------------------- |
|
# Directories |
BIN_FOLDER = ../bin |
61,7 → 61,7
BOOT_LOADER_DEF = BOOT_LOADER_ETHMAC |
else |
BOOT_LOADER_DIR = ../../../sw/boot-loader-serial |
BOOT_LOADER_DEF = |
BOOT_LOADER_DEF = |
endif |
|
VERILOG_INCLUDE_PATH = ../../vlog/lib ../../vlog/tb $(BOOT_LOADER_DIR) |
71,9 → 71,9
|
|
|
# ---------------------------------------------------- |
# ---------------------------------------------------- |
# Build Configuration |
# ---------------------------------------------------- |
# ---------------------------------------------------- |
|
# AMBER_CLK_DIVIDER |
# Sets the system clock frequency |
86,7 → 86,7
ifdef A25 |
AMBER_CORE = AMBER_A25_CORE |
else |
AMBER_CORE = AMBER_A23_CORE |
AMBER_CORE = AMBER_A23_CORE |
endif |
|
|
93,7 → 93,7
|
# The spartan6 device used on SP605 Development board |
XILINX_FPGA = xc6slx45tfgg484-3 |
XST_DEFINES = XILINX_FPGA XILINX_SPARTAN6_FPGA $(AMBER_CORE) AMBER_CLK_DIVIDER=21 $(BOOT_LOADER_DEF) |
XST_DEFINES = XILINX_FPGA XILINX_SPARTAN6_FPGA $(AMBER_CORE) AMBER_CLK_DIVIDER=20 $(BOOT_LOADER_DEF) |
# Xilinx placement and timing constraints |
XST_CONST_FILE = xs6_constraints.ucf |
# List of verilog source files for Xilinx Spartan-6 device |
101,14 → 101,14
|
|
|
# ---------------------------------------------------- |
# Focus on speed or area |
# ---------------------------------------------------- |
# ---------------------------------------------------- |
# Focus on speed or area |
# ---------------------------------------------------- |
#OPT = area |
OPT = speed |
|
|
# ---------------------------------------------------- |
# ---------------------------------------------------- |
# Xilinx XST Compile Options |
# ---------------------------------------------------- |
|
203,10 → 203,10
cd $(WORK_FOLDER); \ |
trce -v 5 -l 5 -n 5 -xml $(RTL_TOP) $(RTL_TOP).ncd \ |
-o $(WORK_FOLDER)/$(RTL_TOP).trc.twr \ |
$(RTL_TOP).pcf |
$(RTL_TOP).pcf |
cp $(WORK_FOLDER)/$(RTL_TOP).trc.twr $(LOG_FOLDER)/$(RTL_TOP).trc.$(RUN_ID).twr |
|
|
|
# ---------------------------------------------------- |
# bitgen |
# ---------------------------------------------------- |
252,8 → 252,8
$(RTL_TOP).ngd \ |
$(RTL_TOP).pcf |
cp $(WORK_FOLDER)/$(RTL_TOP).map.mrp $(LOG_FOLDER)/$(RTL_TOP).map.$(RUN_ID).mrp |
|
|
|
# ---------------------------------------------------- |
# ngdbuild |
# ---------------------------------------------------- |
261,7 → 261,7
cd $(WORK_FOLDER); \ |
ngdbuild -intstyle xflow -verbose -p $(XILINX_FPGA) \ |
-dd _ngo -nt on \ |
-uc $(BIN_FOLDER)/$(XST_CONST_FILE) $(RTL_TOP).ngc $(RTL_TOP).ngd |
-uc $(BIN_FOLDER)/$(XST_CONST_FILE) $(RTL_TOP).ngc $(RTL_TOP).ngd |
|
|
# ---------------------------------------------------- |
/trunk/hw/vlog/system/system.v
41,11 → 41,11
////////////////////////////////////////////////////////////////// |
|
|
module system |
module system |
( |
input brd_rst, |
input brd_clk_n, |
input brd_clk_p, |
input brd_clk_n, |
input brd_clk_p, |
|
|
// UART 0 Interface |
70,14 → 70,15
output ddr3_ck_p, |
output ddr3_ck_n, |
|
`ifdef XILINX_SPARTAN6_FPGA |
`ifdef XILINX_SPARTAN6_FPGA |
inout mcb3_rzq, |
//inout mcb3_zio, |
`endif |
|
|
// Ethmac B100 MAC to PHY Interface |
input mtx_clk_pad_i, |
output [3:0] mtxd_pad_o, |
output [3:0] mtxd_pad_o, |
output mtxen_pad_o, |
output mtxerr_pad_o, |
input mrx_clk_pad_i, |
87,7 → 88,7
input mcoll_pad_i, |
input mcrs_pad_i, |
inout md_pad_io, |
output mdc_pad_o, |
output mdc_pad_o, |
output phy_reset_n, |
|
output [3:0] led |
95,7 → 96,7
|
|
wire sys_clk; // System clock |
wire sys_rst; // Active high reset, synchronous to sys_clk |
wire sys_rst; // Active low reset, synchronous to sys_clk |
wire clk_200; // 200MHz from board |
|
|
102,7 → 103,7
// ====================================== |
// Xilinx MCB DDR3 Controller connections |
// ====================================== |
`ifdef XILINX_SPARTAN6_FPGA |
`ifdef XILINX_SPARTAN6_FPGA |
wire c3_p0_cmd_en; |
wire [2:0] c3_p0_cmd_instr; |
wire [29:0] c3_p0_cmd_byte_addr; |
166,25 → 167,25
wire [WB_SLAVES-1:0] s_wb_ack ; |
wire [WB_SLAVES-1:0] s_wb_err ; |
|
wire [31:0] emm_wb_adr; |
wire [3:0] emm_wb_sel; |
wire emm_wb_we; |
wire [31:0] emm_wb_rdat; |
wire [31:0] emm_wb_wdat; |
wire emm_wb_cyc; |
wire emm_wb_stb; |
wire emm_wb_ack; |
wire emm_wb_err; |
wire [31:0] emm_wb_adr; |
wire [3:0] emm_wb_sel; |
wire emm_wb_we; |
wire [31:0] emm_wb_rdat; |
wire [31:0] emm_wb_wdat; |
wire emm_wb_cyc; |
wire emm_wb_stb; |
wire emm_wb_ack; |
wire emm_wb_err; |
|
wire [31:0] ems_wb_adr; |
wire [3:0] ems_wb_sel; |
wire ems_wb_we; |
wire [31:0] ems_wb_rdat; |
wire [31:0] ems_wb_wdat; |
wire ems_wb_cyc; |
wire ems_wb_stb; |
wire ems_wb_ack; |
wire ems_wb_err; |
wire [31:0] ems_wb_adr; |
wire [3:0] ems_wb_sel; |
wire ems_wb_we; |
wire [31:0] ems_wb_rdat; |
wire [31:0] ems_wb_wdat; |
wire ems_wb_cyc; |
wire ems_wb_stb; |
wire ems_wb_ack; |
wire ems_wb_err; |
|
|
// ====================================== |
205,15 → 206,15
// ====================================== |
clocks_resets u_clocks_resets ( |
.i_brd_rst ( brd_rst ), |
.i_brd_clk_n ( brd_clk_n ), |
.i_brd_clk_p ( brd_clk_p ), |
.i_brd_clk_n ( brd_clk_n ), |
.i_brd_clk_p ( brd_clk_p ), |
.i_ddr_calib_done ( phy_init_done ), |
.o_sys_rst ( sys_rst ), |
.o_sys_clk ( sys_clk ), |
.o_clk_200 ( clk_200 ) |
); |
|
|
|
// ------------------------------------------------------------- |
// Instantiate Amber Processor Core |
// ------------------------------------------------------------- |
223,12 → 224,12
a23_core u_amber ( |
`endif |
.i_clk ( sys_clk ), |
|
|
.i_irq ( amber_irq ), |
.i_firq ( amber_firq ), |
|
.i_system_rdy ( system_rdy ), |
|
|
.o_wb_adr ( m_wb_adr [1] ), |
.o_wb_sel ( m_wb_sel [1] ), |
.o_wb_we ( m_wb_we [1] ), |
244,31 → 245,32
// ------------------------------------------------------------- |
// Instantiate B100 Ethernet MAC |
// ------------------------------------------------------------- |
|
eth_top u_eth_top ( |
.wb_clk_i ( sys_clk ), |
.wb_rst_i ( sys_rst ), |
|
// WISHBONE slave |
.wb_adr_i ( ems_wb_adr [11:2] ), |
.wb_sel_i ( ems_wb_sel ), |
.wb_we_i ( ems_wb_we ), |
.wb_cyc_i ( ems_wb_cyc ), |
.wb_stb_i ( ems_wb_stb ), |
.wb_ack_o ( ems_wb_ack ), |
.wb_dat_i ( ems_wb_wdat ), |
.wb_dat_o ( ems_wb_rdat ), |
.wb_err_o ( ems_wb_err ), |
.wb_adr_i ( ems_wb_adr [11:2] ), |
.wb_sel_i ( ems_wb_sel ), |
.wb_we_i ( ems_wb_we ), |
.wb_cyc_i ( ems_wb_cyc ), |
.wb_stb_i ( ems_wb_stb ), |
.wb_ack_o ( ems_wb_ack ), |
.wb_dat_i ( ems_wb_wdat ), |
.wb_dat_o ( ems_wb_rdat ), |
.wb_err_o ( ems_wb_err ), |
|
// WISHBONE master |
.m_wb_adr_o ( emm_wb_adr ), |
.m_wb_sel_o ( emm_wb_sel ), |
.m_wb_we_o ( emm_wb_we ), |
.m_wb_dat_i ( emm_wb_rdat ), |
.m_wb_dat_o ( emm_wb_wdat ), |
.m_wb_cyc_o ( emm_wb_cyc ), |
.m_wb_stb_o ( emm_wb_stb ), |
.m_wb_ack_i ( emm_wb_ack ), |
.m_wb_err_i ( emm_wb_err ), |
.m_wb_adr_o ( emm_wb_adr ), |
.m_wb_sel_o ( emm_wb_sel ), |
.m_wb_we_o ( emm_wb_we ), |
.m_wb_dat_i ( emm_wb_rdat ), |
.m_wb_dat_o ( emm_wb_wdat ), |
.m_wb_cyc_o ( emm_wb_cyc ), |
.m_wb_stb_o ( emm_wb_stb ), |
.m_wb_ack_i ( emm_wb_ack ), |
.m_wb_err_i ( emm_wb_err ), |
|
// MAC to PHY I/F |
.mtx_clk_pad_i ( mtx_clk_pad_i ), |
278,13 → 280,13
.mrx_clk_pad_i ( mrx_clk_pad_i ), |
.mrxd_pad_i ( mrxd_pad_i ), |
.mrxdv_pad_i ( mrxdv_pad_i ), |
.mrxerr_pad_i ( mrxerr_pad_i ), |
.mcoll_pad_i ( mcoll_pad_i ), |
.mcrs_pad_i ( mcrs_pad_i ), |
.md_pad_i ( md_pad_i ), |
.mdc_pad_o ( mdc_pad_o ), |
.md_pad_o ( md_pad_o ), |
.md_padoe_o ( md_padoe_o ), |
.mrxerr_pad_i ( mrxerr_pad_i ), |
.mcoll_pad_i ( mcoll_pad_i ), |
.mcrs_pad_i ( mcrs_pad_i ), |
.md_pad_i ( md_pad_i ), |
.mdc_pad_o ( mdc_pad_o ), |
.md_pad_o ( md_pad_o ), |
.md_padoe_o ( md_padoe_o ), |
|
// Interrupt |
.int_o ( ethmac_int ) |
299,14 → 301,16
`else |
generic_iobuf u_iobuf ( |
`endif |
.O ( md_pad_i ), |
.IO ( md_pad_io ), |
.I ( md_pad_o ), |
.O ( md_pad_i ), |
.IO ( md_pad_io ), |
.I ( md_pad_o ), |
// T is high for tri-state output |
.T ( ~md_padoe_o ) |
.T ( ~md_padoe_o ) |
); |
|
// Ethernet MII PHY reset |
//assign phy_reset_n = !sys_rst; |
|
// Halt core until system is ready |
assign system_rdy = phy_init_done && !sys_rst; |
|
357,12 → 361,12
.i_clk ( sys_clk ), |
|
.o_uart_int ( uart0_int ), |
|
|
.i_uart_cts_n ( i_uart0_rts ), |
.o_uart_txd ( o_uart0_rx ), |
.o_uart_rts_n ( o_uart0_cts ), |
.i_uart_rxd ( i_uart0_tx ), |
|
|
.i_wb_adr ( s_wb_adr [3] ), |
.i_wb_sel ( s_wb_sel [3] ), |
.i_wb_we ( s_wb_we [3] ), |
381,12 → 385,12
uart #( |
.WB_DWIDTH ( WB_DWIDTH ), |
.WB_SWIDTH ( WB_SWIDTH ) |
) |
) |
u_uart1 ( |
.i_clk ( sys_clk ), |
|
.o_uart_int ( uart1_int ), |
|
|
// These are not connected. ONly pins for 1 UART |
// on my development board |
.i_uart_cts_n ( 1'd1 ), |
393,7 → 397,7
.o_uart_txd ( ), |
.o_uart_rts_n ( ), |
.i_uart_rxd ( 1'd1 ), |
|
|
.i_wb_adr ( s_wb_adr [4] ), |
.i_wb_sel ( s_wb_sel [4] ), |
.i_wb_we ( s_wb_we [4] ), |
413,10 → 417,10
test_module #( |
.WB_DWIDTH ( WB_DWIDTH ), |
.WB_SWIDTH ( WB_SWIDTH ) |
) |
) |
u_test_module ( |
.i_clk ( sys_clk ), |
|
|
.o_irq ( test_reg_irq ), |
.o_firq ( test_reg_firq ), |
.o_mem_ctrl ( test_mem_ctrl ), |
440,13 → 444,13
timer_module #( |
.WB_DWIDTH ( WB_DWIDTH ), |
.WB_SWIDTH ( WB_SWIDTH ) |
) |
) |
u_timer_module ( |
.i_clk ( sys_clk ), |
|
|
// Interrupt outputs |
.o_timer_int ( timer_int ), |
|
|
// Wishbone interface |
.i_wb_adr ( s_wb_adr [6] ), |
.i_wb_sel ( s_wb_sel [6] ), |
469,11 → 473,11
) |
u_interrupt_controller ( |
.i_clk ( sys_clk ), |
|
|
// Interrupt outputs |
.o_irq ( amber_irq ), |
.o_firq ( amber_firq ), |
|
|
// Interrupt inputs |
.i_uart0_int ( uart0_int ), |
.i_uart1_int ( uart1_int ), |
481,7 → 485,7
.i_test_reg_irq ( test_reg_irq ), |
.i_test_reg_firq ( test_reg_firq ), |
.i_tm_timer_int ( timer_int ), |
|
|
// Wishbone interface |
.i_wb_adr ( s_wb_adr [7] ), |
.i_wb_sel ( s_wb_sel [7] ), |
501,31 → 505,31
// ====================================== |
// Instantiate non-synthesizable main memory model |
// ====================================== |
|
|
assign phy_init_done = 1'd1; |
|
|
main_mem #( |
.WB_DWIDTH ( WB_DWIDTH ), |
.WB_SWIDTH ( WB_SWIDTH ) |
) |
) |
u_main_mem ( |
.i_clk ( sys_clk ), |
.i_mem_ctrl ( test_mem_ctrl ), |
.i_wb_adr ( s_wb_adr [2] ), |
.i_wb_sel ( s_wb_sel [2] ), |
.i_wb_we ( s_wb_we [2] ), |
.o_wb_dat ( s_wb_dat_r[2] ), |
.i_wb_dat ( s_wb_dat_w[2] ), |
.i_wb_cyc ( s_wb_cyc [2] ), |
.i_wb_stb ( s_wb_stb [2] ), |
.o_wb_ack ( s_wb_ack [2] ), |
.o_wb_err ( s_wb_err [2] ) |
.i_wb_adr ( s_wb_adr [2] ), |
.i_wb_sel ( s_wb_sel [2] ), |
.i_wb_we ( s_wb_we [2] ), |
.o_wb_dat ( s_wb_dat_r[2] ), |
.i_wb_dat ( s_wb_dat_w[2] ), |
.i_wb_cyc ( s_wb_cyc [2] ), |
.i_wb_stb ( s_wb_stb [2] ), |
.o_wb_ack ( s_wb_ack [2] ), |
.o_wb_err ( s_wb_err [2] ) |
); |
|
`endif |
|
|
`ifdef XILINX_SPARTAN6_FPGA |
`ifdef XILINX_SPARTAN6_FPGA |
// ------------------------------------------------------------- |
// Instantiate Wishbone to Xilinx Spartan-6 DDR3 Bridge |
// ------------------------------------------------------------- |
537,30 → 541,30
u_wb_xs6_ddr3_bridge( |
.i_clk ( sys_clk ), |
|
.o_cmd_en ( c3_p0_cmd_en ), |
.o_cmd_instr ( c3_p0_cmd_instr ), |
.o_cmd_byte_addr ( c3_p0_cmd_byte_addr ), |
.i_cmd_full ( c3_p0_cmd_full ), |
.i_wr_full ( c3_p0_wr_full ), |
.o_wr_en ( c3_p0_wr_en ), |
.o_wr_mask ( c3_p0_wr_mask ), |
.o_wr_data ( c3_p0_wr_data ), |
.i_rd_data ( c3_p0_rd_data ), |
.o_cmd_en ( c3_p0_cmd_en ), |
.o_cmd_instr ( c3_p0_cmd_instr ), |
.o_cmd_byte_addr ( c3_p0_cmd_byte_addr ), |
.i_cmd_full ( c3_p0_cmd_full ), |
.i_wr_full ( c3_p0_wr_full ), |
.o_wr_en ( c3_p0_wr_en ), |
.o_wr_mask ( c3_p0_wr_mask ), |
.o_wr_data ( c3_p0_wr_data ), |
.i_rd_data ( c3_p0_rd_data ), |
.i_rd_empty ( c3_p0_rd_empty ), |
|
|
.i_mem_ctrl ( test_mem_ctrl ), |
.i_wb_adr ( s_wb_adr [2] ), |
.i_wb_sel ( s_wb_sel [2] ), |
.i_wb_we ( s_wb_we [2] ), |
.o_wb_dat ( s_wb_dat_r[2] ), |
.i_wb_dat ( s_wb_dat_w[2] ), |
.i_wb_cyc ( s_wb_cyc [2] ), |
.i_wb_stb ( s_wb_stb [2] ), |
.o_wb_ack ( s_wb_ack [2] ), |
.o_wb_err ( s_wb_err [2] ) |
.i_wb_adr ( s_wb_adr [2] ), |
.i_wb_sel ( s_wb_sel [2] ), |
.i_wb_we ( s_wb_we [2] ), |
.o_wb_dat ( s_wb_dat_r[2] ), |
.i_wb_dat ( s_wb_dat_w[2] ), |
.i_wb_cyc ( s_wb_cyc [2] ), |
.i_wb_stb ( s_wb_stb [2] ), |
.o_wb_ack ( s_wb_ack [2] ), |
.o_wb_err ( s_wb_err [2] ) |
); |
|
|
|
// ------------------------------------------------------------- |
// Instantiate Xilinx Spartan-6 FPGA MCB-DDR3 Controller |
// ------------------------------------------------------------- |
579,6 → 583,7
.mcb3_dram_udm ( ddr3_dm[1] ), |
.mcb3_dram_dm ( ddr3_dm[0] ), |
.mcb3_rzq ( mcb3_rzq ), |
// .mcb3_zio ( mcb3_zio ), |
.mcb3_dram_udqs ( ddr3_dqs_p[1] ), |
.mcb3_dram_dqs ( ddr3_dqs_p[0] ), |
.mcb3_dram_udqs_n ( ddr3_dqs_n[1] ), |
585,15 → 590,15
.mcb3_dram_dqs_n ( ddr3_dqs_n[0] ), |
.mcb3_dram_ck ( ddr3_ck_p ), |
.mcb3_dram_ck_n ( ddr3_ck_n ), |
|
.c3_sys_clk ( clk_200 ), |
|
.c3_sys_clk ( clk_200 ), |
.c3_sys_rst_i ( brd_rst ), // active-high |
.c3_clk0 ( ), |
.c3_rst0 ( ), |
.c3_calib_done ( phy_init_done ), |
|
|
.c3_p0_cmd_clk ( sys_clk ), |
|
|
.c3_p0_cmd_en ( c3_p0_cmd_en ), |
.c3_p0_cmd_instr ( c3_p0_cmd_instr ), |
.c3_p0_cmd_bl ( 6'd0 ), |
600,9 → 605,9
.c3_p0_cmd_byte_addr ( c3_p0_cmd_byte_addr ), |
.c3_p0_cmd_empty ( ), |
.c3_p0_cmd_full ( c3_p0_cmd_full ), |
|
|
.c3_p0_wr_clk ( sys_clk ), |
|
|
.c3_p0_wr_en ( c3_p0_wr_en ), |
.c3_p0_wr_mask ( c3_p0_wr_mask ), |
.c3_p0_wr_data ( c3_p0_wr_data ), |
611,9 → 616,9
.c3_p0_wr_count ( ), |
.c3_p0_wr_underrun ( ), |
.c3_p0_wr_error ( ), |
|
|
.c3_p0_rd_clk ( sys_clk ), |
|
|
.c3_p0_rd_en ( 1'd1 ), |
.c3_p0_rd_data ( c3_p0_rd_data ), |
.c3_p0_rd_full ( ), |
/trunk/hw/vlog/system/register_addresses.v
78,26 → 78,26
|
|
// Interrupt Controller |
localparam AMBER_IC_IRQ0_STATUS = 16'h0000; |
localparam AMBER_IC_IRQ0_RAWSTAT = 16'h0004; |
localparam AMBER_IC_IRQ0_ENABLESET = 16'h0008; |
localparam AMBER_IC_IRQ0_ENABLECLR = 16'h000c; |
localparam AMBER_IC_IRQ0_STATUS = 16'h0000; |
localparam AMBER_IC_IRQ0_RAWSTAT = 16'h0004; |
localparam AMBER_IC_IRQ0_ENABLESET = 16'h0008; |
localparam AMBER_IC_IRQ0_ENABLECLR = 16'h000c; |
localparam AMBER_IC_INT_SOFTSET_0 = 16'h0010; |
localparam AMBER_IC_INT_SOFTCLEAR_0 = 16'h0014; |
localparam AMBER_IC_FIRQ0_STATUS = 16'h0020; |
localparam AMBER_IC_FIRQ0_RAWSTAT = 16'h0024; |
localparam AMBER_IC_FIRQ0_ENABLESET = 16'h0028; |
localparam AMBER_IC_FIRQ0_ENABLECLR = 16'h002c; |
localparam AMBER_IC_IRQ1_STATUS = 16'h0040; |
localparam AMBER_IC_IRQ1_RAWSTAT = 16'h0044; |
localparam AMBER_IC_IRQ1_ENABLESET = 16'h0048; |
localparam AMBER_IC_IRQ1_ENABLECLR = 16'h004c; |
localparam AMBER_IC_FIRQ0_STATUS = 16'h0020; |
localparam AMBER_IC_FIRQ0_RAWSTAT = 16'h0024; |
localparam AMBER_IC_FIRQ0_ENABLESET = 16'h0028; |
localparam AMBER_IC_FIRQ0_ENABLECLR = 16'h002c; |
localparam AMBER_IC_IRQ1_STATUS = 16'h0040; |
localparam AMBER_IC_IRQ1_RAWSTAT = 16'h0044; |
localparam AMBER_IC_IRQ1_ENABLESET = 16'h0048; |
localparam AMBER_IC_IRQ1_ENABLECLR = 16'h004c; |
localparam AMBER_IC_INT_SOFTSET_1 = 16'h0050; |
localparam AMBER_IC_INT_SOFTCLEAR_1 = 16'h0054; |
localparam AMBER_IC_FIRQ1_STATUS = 16'h0060; |
localparam AMBER_IC_FIRQ1_RAWSTAT = 16'h0064; |
localparam AMBER_IC_FIRQ1_ENABLESET = 16'h0068; |
localparam AMBER_IC_FIRQ1_ENABLECLR = 16'h006c; |
localparam AMBER_IC_FIRQ1_STATUS = 16'h0060; |
localparam AMBER_IC_FIRQ1_RAWSTAT = 16'h0064; |
localparam AMBER_IC_FIRQ1_ENABLESET = 16'h0068; |
localparam AMBER_IC_FIRQ1_ENABLECLR = 16'h006c; |
localparam AMBER_IC_INT_SOFTSET_2 = 16'h0090; |
localparam AMBER_IC_INT_SOFTCLEAR_2 = 16'h0094; |
localparam AMBER_IC_INT_SOFTSET_3 = 16'h00d0; |
/trunk/hw/vlog/system/interrupt_controller.v
116,13 → 116,13
assign o_wb_ack = i_wb_stb && ( wb_start_write || wb_start_read_d1 ); |
|
generate |
if (WB_DWIDTH == 128) |
if (WB_DWIDTH == 128) |
begin : wb128 |
assign wb_wdata32 = i_wb_adr[3:2] == 2'd3 ? i_wb_dat[127:96] : |
i_wb_adr[3:2] == 2'd2 ? i_wb_dat[ 95:64] : |
i_wb_adr[3:2] == 2'd1 ? i_wb_dat[ 63:32] : |
i_wb_dat[ 31: 0] ; |
|
|
assign o_wb_dat = {4{wb_rdata32}}; |
end |
else |
136,28 → 136,28
// ====================================== |
// Interrupts |
// ====================================== |
assign raw_interrupts = {23'd0, |
assign raw_interrupts = {23'd0, |
i_ethmac_int, // 8: Ethernet MAC interrupt |
|
|
i_tm_timer_int[2], // 7: Timer Module Interrupt 2 |
i_tm_timer_int[1], // 6: Timer Module Interrupt 1 |
i_tm_timer_int[0], // 5: Timer Module Interrupt 0 |
1'd0, |
|
|
1'd0, |
i_uart1_int, // 2: Uart 1 interrupt |
i_uart0_int, // 1: Uart 0 interrupt |
1'd0 // 0: Software interrupt not |
1'd0 // 0: Software interrupt not |
}; // here because its not maskable |
|
assign irq0_interrupts = {raw_interrupts[31:1], softint_0_reg} & irq0_enable_reg; |
assign firq0_interrupts = raw_interrupts & firq0_enable_reg; |
assign firq0_interrupts = raw_interrupts & firq0_enable_reg; |
assign irq1_interrupts = {raw_interrupts[31:1], softint_1_reg} & irq1_enable_reg; |
assign firq1_interrupts = raw_interrupts & firq1_enable_reg; |
assign firq1_interrupts = raw_interrupts & firq1_enable_reg; |
|
// The interrupts from the test registers module are not masked, |
// just to keep their usage really simple |
assign irq_0 = |{irq0_interrupts, i_test_reg_irq}; |
assign irq_0 = |{irq0_interrupts, i_test_reg_irq}; |
assign firq_0 = |{firq0_interrupts, i_test_reg_firq}; |
assign irq_1 = |irq1_interrupts; |
assign firq_1 = |firq1_interrupts; |
165,7 → 165,6
assign o_irq = irq_0 | irq_1; |
assign o_firq = firq_0 | firq_1; |
|
|
// ======================================================== |
// Register Writes |
// ======================================================== |
176,15 → 175,15
AMBER_IC_IRQ0_ENABLECLR: irq0_enable_reg <= irq0_enable_reg & (~i_wb_dat); |
AMBER_IC_FIRQ0_ENABLESET: firq0_enable_reg <= firq0_enable_reg | ( i_wb_dat); |
AMBER_IC_FIRQ0_ENABLECLR: firq0_enable_reg <= firq0_enable_reg & (~i_wb_dat); |
|
|
AMBER_IC_INT_SOFTSET_0: softint_0_reg <= softint_0_reg | ( i_wb_dat[0]); |
AMBER_IC_INT_SOFTCLEAR_0: softint_0_reg <= softint_0_reg & (~i_wb_dat[0]); |
|
|
AMBER_IC_IRQ1_ENABLESET: irq1_enable_reg <= irq1_enable_reg | ( i_wb_dat); |
AMBER_IC_IRQ1_ENABLECLR: irq1_enable_reg <= irq1_enable_reg & (~i_wb_dat); |
AMBER_IC_FIRQ1_ENABLESET: firq1_enable_reg <= firq1_enable_reg | ( i_wb_dat); |
AMBER_IC_FIRQ1_ENABLECLR: firq1_enable_reg <= firq1_enable_reg & (~i_wb_dat); |
|
|
AMBER_IC_INT_SOFTSET_1: softint_1_reg <= softint_1_reg | ( i_wb_dat[0]); |
AMBER_IC_INT_SOFTCLEAR_1: softint_1_reg <= softint_1_reg & (~i_wb_dat[0]); |
endcase |
196,9 → 195,9
always @( posedge i_clk ) |
if ( wb_start_read ) |
case ( i_wb_adr[15:0] ) |
|
AMBER_IC_IRQ0_ENABLESET: wb_rdata32 <= irq0_enable_reg; |
AMBER_IC_FIRQ0_ENABLESET: wb_rdata32 <= firq0_enable_reg; |
|
AMBER_IC_IRQ0_ENABLESET: wb_rdata32 <= irq0_enable_reg; |
AMBER_IC_FIRQ0_ENABLESET: wb_rdata32 <= firq0_enable_reg; |
AMBER_IC_IRQ0_RAWSTAT: wb_rdata32 <= raw_interrupts; |
AMBER_IC_IRQ0_STATUS: wb_rdata32 <= irq0_interrupts; |
AMBER_IC_FIRQ0_RAWSTAT: wb_rdata32 <= raw_interrupts; |
205,10 → 204,10
AMBER_IC_FIRQ0_STATUS: wb_rdata32 <= firq0_interrupts; |
|
AMBER_IC_INT_SOFTSET_0: wb_rdata32 <= {31'd0, softint_0_reg}; |
AMBER_IC_INT_SOFTCLEAR_0: wb_rdata32 <= {31'd0, softint_0_reg}; |
AMBER_IC_INT_SOFTCLEAR_0: wb_rdata32 <= {31'd0, softint_0_reg}; |
|
AMBER_IC_IRQ1_ENABLESET: wb_rdata32 <= irq1_enable_reg; |
AMBER_IC_FIRQ1_ENABLESET: wb_rdata32 <= firq1_enable_reg; |
AMBER_IC_IRQ1_ENABLESET: wb_rdata32 <= irq1_enable_reg; |
AMBER_IC_FIRQ1_ENABLESET: wb_rdata32 <= firq1_enable_reg; |
AMBER_IC_IRQ1_RAWSTAT: wb_rdata32 <= raw_interrupts; |
AMBER_IC_IRQ1_STATUS: wb_rdata32 <= irq1_interrupts; |
AMBER_IC_FIRQ1_RAWSTAT: wb_rdata32 <= raw_interrupts; |
215,10 → 214,10
AMBER_IC_FIRQ1_STATUS: wb_rdata32 <= firq1_interrupts; |
|
AMBER_IC_INT_SOFTSET_1: wb_rdata32 <= {31'd0, softint_1_reg}; |
AMBER_IC_INT_SOFTCLEAR_1: wb_rdata32 <= {31'd0, softint_1_reg}; |
|
AMBER_IC_INT_SOFTCLEAR_1: wb_rdata32 <= {31'd0, softint_1_reg}; |
|
default: wb_rdata32 <= 32'h22334455; |
|
|
endcase |
|
|
231,74 → 230,74
|
|
//synopsys translate_off |
`ifdef AMBER_IC_DEBUG |
`ifdef AMBER_IC_DEBUG |
|
wire wb_read_ack = i_wb_stb && ( wb_start_write || wb_start_read_d1 ); |
|
// ----------------------------------------------- |
// Report Interrupt Controller Register accesses |
// ----------------------------------------------- |
// ----------------------------------------------- |
always @(posedge i_clk) |
if ( wb_read_ack || wb_start_write ) |
begin |
`TB_DEBUG_MESSAGE |
|
|
if ( wb_start_write ) |
$write("Write 0x%08x to ", i_wb_dat); |
else |
$write("Read 0x%08x from ", o_wb_dat); |
|
|
case ( i_wb_adr[15:0] ) |
AMBER_IC_IRQ0_STATUS: |
$write(" Interrupt Controller module IRQ0 Status"); |
$write(" Interrupt Controller module IRQ0 Status"); |
AMBER_IC_IRQ0_RAWSTAT: |
$write(" Interrupt Controller module IRQ0 Raw Status"); |
$write(" Interrupt Controller module IRQ0 Raw Status"); |
AMBER_IC_IRQ0_ENABLESET: |
$write(" Interrupt Controller module IRQ0 Enable Set"); |
$write(" Interrupt Controller module IRQ0 Enable Set"); |
AMBER_IC_IRQ0_ENABLECLR: |
$write(" Interrupt Controller module IRQ0 Enable Clear"); |
$write(" Interrupt Controller module IRQ0 Enable Clear"); |
AMBER_IC_FIRQ0_STATUS: |
$write(" Interrupt Controller module FIRQ0 Status"); |
$write(" Interrupt Controller module FIRQ0 Status"); |
AMBER_IC_FIRQ0_RAWSTAT: |
$write(" Interrupt Controller module FIRQ0 Raw Status"); |
$write(" Interrupt Controller module FIRQ0 Raw Status"); |
AMBER_IC_FIRQ0_ENABLESET: |
$write(" Interrupt Controller module FIRQ0 Enable set"); |
$write(" Interrupt Controller module FIRQ0 Enable set"); |
AMBER_IC_FIRQ0_ENABLECLR: |
$write(" Interrupt Controller module FIRQ0 Enable Clear"); |
AMBER_IC_INT_SOFTSET_0: |
$write(" Interrupt Controller module SoftInt 0 Set"); |
$write(" Interrupt Controller module FIRQ0 Enable Clear"); |
AMBER_IC_INT_SOFTSET_0: |
$write(" Interrupt Controller module SoftInt 0 Set"); |
AMBER_IC_INT_SOFTCLEAR_0: |
$write(" Interrupt Controller module SoftInt 0 Clear"); |
$write(" Interrupt Controller module SoftInt 0 Clear"); |
AMBER_IC_IRQ1_STATUS: |
$write(" Interrupt Controller module IRQ1 Status"); |
$write(" Interrupt Controller module IRQ1 Status"); |
AMBER_IC_IRQ1_RAWSTAT: |
$write(" Interrupt Controller module IRQ1 Raw Status"); |
$write(" Interrupt Controller module IRQ1 Raw Status"); |
AMBER_IC_IRQ1_ENABLESET: |
$write(" Interrupt Controller module IRQ1 Enable Set"); |
$write(" Interrupt Controller module IRQ1 Enable Set"); |
AMBER_IC_IRQ1_ENABLECLR: |
$write(" Interrupt Controller module IRQ1 Enable Clear"); |
$write(" Interrupt Controller module IRQ1 Enable Clear"); |
AMBER_IC_FIRQ1_STATUS: |
$write(" Interrupt Controller module FIRQ1 Status"); |
$write(" Interrupt Controller module FIRQ1 Status"); |
AMBER_IC_FIRQ1_RAWSTAT: |
$write(" Interrupt Controller module FIRQ1 Raw Status"); |
$write(" Interrupt Controller module FIRQ1 Raw Status"); |
AMBER_IC_FIRQ1_ENABLESET: |
$write(" Interrupt Controller module FIRQ1 Enable set"); |
$write(" Interrupt Controller module FIRQ1 Enable set"); |
AMBER_IC_FIRQ1_ENABLECLR: |
$write(" Interrupt Controller module FIRQ1 Enable Clear"); |
AMBER_IC_INT_SOFTSET_1: |
$write(" Interrupt Controller module SoftInt 1 Set"); |
$write(" Interrupt Controller module FIRQ1 Enable Clear"); |
AMBER_IC_INT_SOFTSET_1: |
$write(" Interrupt Controller module SoftInt 1 Set"); |
AMBER_IC_INT_SOFTCLEAR_1: |
$write(" Interrupt Controller module SoftInt 1 Clear"); |
$write(" Interrupt Controller module SoftInt 1 Clear"); |
|
default: |
begin |
$write(" unknown Amber IC Register region"); |
$write(", Address 0x%08h\n", i_wb_adr); |
$write(", Address 0x%08h\n", i_wb_adr); |
`TB_ERROR_MESSAGE |
end |
endcase |
|
$write(", Address 0x%08h\n", i_wb_adr); |
|
$write(", Address 0x%08h\n", i_wb_adr); |
end |
`endif |
|
/trunk/sw/boot-loader-serial/fpga-version.h
1,74 → 230,74
#define AMBER_FPGA_VERSION "20130506123001" |
#define AMBER_FPGA_VERSION "20130428184629" |
/trunk/sw/boot-loader-ethmac/serial.h
File deleted
/trunk/sw/boot-loader-ethmac/serial.c
File deleted
/trunk/sw/boot-loader-ethmac/telnet.h
42,6 → 42,11
#define MAX_TELNET_TX 1024 |
|
|
#define telnet_broadcast(args ...) \ |
do { put_line (socket0_g->telnet_txbuf, args); \ |
put_line (socket1_g->telnet_txbuf, args); } while (0) |
|
|
void parse_telnet_options (char *, socket_t*); |
void parse_telnet_payload (char *, socket_t*); |
void telnet_options (socket_t*); |
/trunk/sw/boot-loader-ethmac/ethmac.c
7,7 → 7,7
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
55,10 → 55,10
{ |
/* Disable EthMac interrupts in Ethmac core */ |
*(unsigned int *) ( ADR_ETHMAC_INT_MASK ) = 0x0; |
|
|
/* Disable Ethmac interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100; |
|
|
/* Disable Rx & Tx - MODER Register |
[15] = Add pads to short frames |
[13] = CRCEN |
67,8 → 67,8
[5] = 1 for promiscuous, 0 rx only frames that match mac address |
[1] = txen |
[0] = rxen */ |
*(unsigned int *) ( ADR_ETHMAC_MODER ) = 0xa420; |
|
*(unsigned int *) ( ADR_ETHMAC_MODER ) = 0xa420; |
|
/* Put the PHY into reset */ |
phy_rst(0); /* reset is active low */ |
|
81,7 → 81,7
int packet; |
int n; |
unsigned int d32; |
|
|
/* Disable Ethmac interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100; |
|
88,10 → 88,10
/* Set my MAC address */ |
d32 = self_g.mac[2]<<24|self_g.mac[3]<<16|self_g.mac[4]<<8|self_g.mac[5]; |
*(unsigned int *) ( ADR_ETHMAC_MAC_ADDR0 ) = d32; |
|
|
d32 = self_g.mac[0]<<8|self_g.mac[1]; |
*(unsigned int *) ( ADR_ETHMAC_MAC_ADDR1 ) = d32; |
|
|
if (!config_phy()) return 0; |
|
/* Write the Receive Packet Buffer Descriptor */ |
98,32 → 98,31
/* Buffer Pointer */ |
for (packet=0; packet<ETHMAC_RX_BUFFERS; packet++) { |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x204 + packet*8 ) = ETHMAC_RX_BUFFER + packet * 0x1000; |
/* Ready Rx buffer |
[31:16] = length in bytes, |
/* Ready Rx buffer |
[31:16] = length in bytes, |
[15] = empty |
[14] = Enable IRQ |
[13] = wrap bit */ |
/* set empty flag again */ |
if (packet == ETHMAC_RX_BUFFERS-1) /* last receive buffer ? */ |
/* Set wrap bit is last buffer */ |
/* Set wrap bit is last buffer */ |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + packet*8 ) = 0x0000e000; |
else |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + packet*8 ) = 0x0000c000; |
} |
|
|
/* Enable EthMac interrupts in Ethmac core */ |
/* Receive frame and receive error botgh enabled */ |
/* When a bad frame is received is still gets written to a buffer |
so needs to be dealt with */ |
*(unsigned int *) ( ADR_ETHMAC_INT_MASK ) = 0xc; |
|
|
/* Enable Ethmac interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100; |
|
|
/* Set transmit packet buffer location */ |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 4 ) = ETHMAC_TX_BUFFER; |
|
|
/* Set the ready bit, bit 15, low */ |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 0 ) = 0x7800; |
|
136,7 → 135,7
[1] = txen |
[0] = rxen */ |
*(unsigned int *) ( ADR_ETHMAC_MODER ) = 0xa423; |
|
|
return 1; |
} |
|
144,8 → 143,8
void tx_packet(int len) |
{ |
unsigned int status = 0; |
|
|
|
|
/* Poll the ready bit. |
Wait until the ready bit is cleared by the ethmac hardware |
This holds everything up while the packet is being transmitted, but |
158,10 → 157,10
|
|
/* Enable packet tx |
[31:16] = length in bytes, |
[31:16] = length in bytes, |
[15] = ready |
[14] = tx int |
[13] = wrap bit |
[13] = wrap bit |
[12] = pad enable for short packets |
[11] = crc en |
*/ |
177,13 → 176,14
int stat; |
int phy_id; |
int link_up = 1; |
|
time_t* link_timer; |
|
|
link_timer = init_timer(); |
|
|
/* Bring PHY out of reset */ |
phy_rst(1); /* reset is active low */ |
|
|
/* Discover phy addr by searching addrs in order {1,0,2,..., 31} */ |
for(addr = 0; addr < 32; addr++) { |
phy_id = (addr == 0) ? 1 : (addr == 1) ? 0 : addr; |
191,12 → 191,9
stat = mdio_read(phy_id, MII_BMSR); |
stat = mdio_read(phy_id, MII_BMSR); |
if(!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0)))) |
break; |
break; |
} |
/* Failed to find a PHY on the md bus */ |
if (addr == 32) |
return 0; |
|
|
/* Reset PHY */ |
bmcr = mdio_read(phy_id, MII_BMCR); |
mdio_write(phy_id, MII_BMCR, bmcr | BMCR_RESET); |
205,23 → 202,22
/* Set bits 9.8, 9.9 to 0 */ |
bmcr = mdio_read(phy_id, MII_CTRL1000); |
mdio_write(phy_id, MII_CTRL1000, bmcr & 0xfcff ); |
|
|
/* Restart autoneg */ |
bmcr = mdio_read(phy_id, MII_BMCR); |
mdio_write(phy_id, MII_BMCR, bmcr | BMCR_ANRESTART); |
|
|
/* Wait for link up */ |
/* Print PHY status MII_BMSR = Basic Mode Status Register*/ |
/* allow a few seconds for the link to come up before giving up */ |
set_timer(link_timer, 5000); |
|
/* allow 2 seconds for the link to come up before giving up */ |
set_timer(link_timer, 5000); |
while (!((stat = mdio_read(phy_id, MII_BMSR)) & BMSR_LSTATUS)) { |
if (timer_expired(link_timer)) { |
link_up = 0; |
break; |
link_up = 0; |
break; |
} |
} |
|
|
return link_up; |
} |
|
240,7 → 236,7
|
/* |
addr = PHY address |
reg = register address within PHY |
reg = register address within PHY |
*/ |
unsigned short mdio_ctrl(unsigned int addr, unsigned int dir, unsigned int reg, unsigned short data) |
{ |
247,23 → 243,23
unsigned int data_out = 0; |
unsigned int i; |
unsigned long flags; |
|
mdio_ready(); |
|
mdio_ready(); |
|
*(volatile unsigned int *)(ADR_ETHMAC_MIIADDRESS) = (reg << 8) | (addr & 0x1f); |
|
if (dir == mdi_write) { |
*(volatile unsigned int *)(ADR_ETHMAC_MIITXDATA) = data; |
/* Execute Write ! */ |
*(volatile unsigned int *)(ADR_ETHMAC_MIICOMMAND) = 0x4; |
} |
else { |
/* Execute Read ! */ |
*(volatile unsigned int *)(ADR_ETHMAC_MIICOMMAND) = 0x2; |
mdio_ready(); |
data_out = *(volatile unsigned int *)(ADR_ETHMAC_MIIRXDATA); |
} |
|
if (dir == mdi_write) { |
*(volatile unsigned int *)(ADR_ETHMAC_MIITXDATA) = data; |
/* Execute Write ! */ |
*(volatile unsigned int *)(ADR_ETHMAC_MIICOMMAND) = 0x4; |
} |
else { |
/* Execute Read ! */ |
*(volatile unsigned int *)(ADR_ETHMAC_MIICOMMAND) = 0x2; |
mdio_ready(); |
data_out = *(volatile unsigned int *)(ADR_ETHMAC_MIIRXDATA); |
} |
|
return (unsigned short) data_out; |
} |
|
270,13 → 266,13
|
/* Wait until its ready */ |
void mdio_ready() |
{ |
{ |
int i; |
for (;;) { |
/* Bit 1 is high when the MD i/f is busy */ |
if ((*(volatile unsigned int *)(ADR_ETHMAC_MIISTATUS) & 0x2) == 0x0) |
/* Bit 1 is high when the MD i/f is busy */ |
if ((*(volatile unsigned int *)(ADR_ETHMAC_MIISTATUS) & 0x2) == 0x0) |
break; |
|
|
i++; |
if (i==10000000) { |
i=0; |
287,31 → 283,29
|
|
void ethmac_interrupt(void) |
{ |
{ |
int buffer; |
unsigned int int_src; |
unsigned int rx_buf_status; |
|
|
/* Mask ethmac interrupts */ |
*(volatile unsigned int *) ( ADR_ETHMAC_INT_MASK ) = 0; |
|
|
int_src = *(volatile unsigned int *) ( ADR_ETHMAC_INT_SOURCE ); |
|
if (int_src) { |
for (buffer=0; buffer<ETHMAC_RX_BUFFERS; buffer++) { |
|
rx_buf_status = *(volatile unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 ); |
|
if ((rx_buf_status & 0x8000) == 0) { |
|
parse_rx_packet((char*)(ETHMAC_RX_BUFFER+buffer*0x1000), rx_packet_g); |
|
/* set empty flag again */ |
if (buffer == ETHMAC_RX_BUFFERS-1) /* last receive buffer ? */ |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 ) = 0x0000e000; |
else |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 ) = 0x0000c000; |
} |
|
for (buffer=0; buffer<ETHMAC_RX_BUFFERS; buffer++) { |
|
rx_buf_status = *(volatile unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 ); |
|
if ((rx_buf_status & 0x8000) == 0) { |
|
parse_rx_packet((char*)(ETHMAC_RX_BUFFER+buffer*0x1000), rx_packet_g); |
|
/* set empty flag again */ |
if (buffer == ETHMAC_RX_BUFFERS-1) /* last receive buffer ? */ |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 ) = 0x0000e000; |
else |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 ) = 0x0000c000; |
} |
} |
|
/trunk/sw/boot-loader-ethmac/boot-loader-ethmac.c
7,7 → 7,7
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
41,23 → 41,29
// // |
----------------------------------------------------------------*/ |
|
// TODO list |
// tcp.c clean up |
// Cleanup self_g structure and usage |
// tcp window - what is it, whats it set to? Add it to status stuff |
// Get A25 version working |
// test with booting linux |
|
#include "amber_registers.h" |
#include "address_map.h" |
#include "line-buffer.h" |
#include "timer.h" |
#include "utilities.h" |
|
#include "ethmac.h" |
#include "packet.h" |
#include "tcp.h" |
#include "udp.h" |
#include "telnet.h" |
#include "serial.h" |
|
#include "elfsplitter.h" |
#include "boot-loader-ethmac.h" |
|
|
|
int main ( void ) { |
char* line; |
time_t* led_flash_timer; |
64,52 → 70,41
time_t* reboot_timer; |
socket_t* socket = socket0_g; |
int reboot_stage = 0; |
|
|
/* Enable the serial debug port */ |
init_serial(); |
print_serial("Amber debug port\n\r"); |
|
|
/* Turn off all LEDs */ |
|
/* Turn off all LEDs as a starting point */ |
led_clear(); |
|
|
/* initialize the memory allocation system */ |
/* this must be first, because all the other init functions call malloc */ |
init_malloc(); |
|
|
|
/* Initialize current time and some timers */ |
init_current_time(); |
led_flash_timer = init_timer(); |
set_timer(led_flash_timer, 500); |
set_timer(led_flash_timer, 500); |
reboot_timer = init_timer(); |
|
|
|
|
/* receive packet buffer */ |
rx_packet_g = malloc(sizeof(packet_t)); |
|
|
/* initialize two tcp sockets */ |
|
/* socket init */ |
socket0_g = init_socket(0); |
socket1_g = init_socket(1); |
|
|
/* open ethernet port and wait for connection requests |
|
/* open ethernet port and wait for connection requests |
keep trying forever */ |
while (!open_link()); |
|
|
|
/* infinite loop. Everything is timer, interrupt and queue driven from here on down */ |
while (1) { |
|
|
/* Flash a heartbeat LED */ |
if (timer_expired(led_flash_timer)) { |
led_flip(0); |
set_timer(led_flash_timer, 500); |
} |
|
|
|
|
/* Check for newly downloaded tftp file. Add to all tx buffers */ |
/* Has a file been uploaded via tftp ? */ |
if (udp_file_g != NULL) { |
116,24 → 111,17
/* Notify telnet clients that file has been received */ |
if (udp_file_g->ready) { |
udp_file_g->ready = 0; |
|
print_serial("Received file %s, %d bytes", |
udp_file_g->filename, udp_file_g->total_bytes); |
if (udp_file_g->linux_boot) |
print_serial(", linux image detected\r\n"); |
else |
print_serial("\r\n"); |
|
if (process_file(socket0_g) == 0) { |
telnet_broadcast("Received file %s, %d bytes, linux %d\r\n", |
udp_file_g->filename, udp_file_g->total_bytes, udp_file_g->linux_boot); |
if (process_file(socket0_g) == 0) |
/* Disconnect in 1 second */ |
set_timer(reboot_timer, 1000); |
} |
else |
print_serial("Not an elf file\r\n"); |
telnet_broadcast("Not an elf file\r\n"); |
} |
} |
|
|
|
|
/* reboot timer expired */ |
if (timer_expired(reboot_timer)) { |
/* First stage of reboot sequence is to nicely disconnect */ |
142,7 → 130,7
reboot_stage = 1; |
socket0_g->tcp_disconnect = 1; |
socket1_g->tcp_disconnect = 1; |
} |
} |
else { |
/* Second stage of reboot sequence is to turn off ethmac and then jump to restart vector */ |
close_link(); |
156,8 → 144,8
socket = socket1_g; |
else |
socket = socket0_g; |
|
|
|
|
/* Check if any tcp packets need to be re-transmitted */ |
tcp_retransmit(socket); |
|
166,8 → 154,8
if (socket->tcp_disconnect && socket->tcp_connection_state == TCP_OPEN) { |
tcp_disconnect(socket); |
} |
|
|
|
/* Reset connection */ |
if (socket->tcp_reset) { |
socket->tcp_connection_state = TCP_CLOSED; |
176,15 → 164,15
tcp_reply(socket, NULL, 0); |
socket->tcp_reset = 0; |
} |
|
|
/* Send telnet options */ |
|
|
/* Send telnet options */ |
if (socket->tcp_connection_state == TCP_OPEN && !socket->telnet_options_sent){ |
telnet_options(socket); |
socket->telnet_options_sent = 1; |
} |
|
/* telnet connection open |
|
/* telnet connection open |
Communicate with client */ |
else if (socket->telnet_connection_state == TELNET_OPEN) { |
/* Send telnet greeting */ |
192,9 → 180,9
put_line (socket->telnet_txbuf, "Amber Processor Boot Loader\r\n> "); |
socket->telnet_sent_opening_message = 1; |
} |
|
|
/* Parse telnet rx buffer */ |
if (get_line(socket->telnet_rxbuf, &line)) |
if (get_line(socket->telnet_rxbuf, &line)) |
parse_command (socket, line); |
|
/* Transmit text from telnet tx buffer */ |
207,13 → 195,13
|
/* Parse a command line passed from main and execute the command */ |
/* returns the length of the reply string */ |
int parse_command (socket_t* socket, char* line) |
{ |
int parse_command (socket_t* socket, char* line) |
{ |
unsigned int start_addr; |
unsigned int address; |
unsigned int range; |
int len, error = 0; |
|
|
/* All commands are just a single character. |
Just ignore anything else */ |
switch (line[0]) { |
220,52 → 208,52
/* Disconnect */ |
case 'e': |
case 'x': |
case 'q': |
case 'q': |
socket->tcp_disconnect = 1; |
return 0; |
|
case 'r': /* Read mem */ |
|
case 'r': /* Read mem */ |
{ |
if (len = get_hex (&line[2], &start_addr)) { |
if (len = get_hex (&line[2], &start_addr)) { |
if (len = get_hex (&line[3+len], &range)) { |
for (address=start_addr; address<start_addr+range; address+=4) { |
put_line (socket->telnet_txbuf, "0x%08x 0x%08x\r\n", |
put_line (socket->telnet_txbuf, "0x%08x 0x%08x\r\n", |
address, *(unsigned int *)address); |
} |
} |
else { |
put_line (socket->telnet_txbuf, "0x%08x 0x%08x\r\n", |
put_line (socket->telnet_txbuf, "0x%08x 0x%08x\r\n", |
start_addr, *(unsigned int *)start_addr); |
} |
} |
else |
else |
error=1; |
break; |
break; |
} |
|
|
|
case 'h': {/* Help */ |
case 'h': {/* Help */ |
put_line (socket->telnet_txbuf, "You need help alright\r\n"); |
break; |
break; |
} |
|
|
case 's': {/* Status */ |
|
case 's': {/* Status */ |
put_line (socket->telnet_txbuf, "Socket ID %d\r\n", socket->id); |
put_line (socket->telnet_txbuf, "Packets received %d\r\n", socket->packets_received); |
put_line (socket->telnet_txbuf, "Packets transmitted %d\r\n", socket->packets_sent); |
put_line (socket->telnet_txbuf, "Packets resent %d\r\n", socket->packets_resent); |
put_line (socket->telnet_txbuf, "TCP checksum errors %d\r\n", tcp_checksum_errors_g); |
|
|
put_line (socket->telnet_txbuf, "Counterparty IP %d.%d.%d.%d\r\n", |
socket->rx_packet->src_ip[0], |
socket->rx_packet->src_ip[1], |
socket->rx_packet->src_ip[2], |
socket->rx_packet->src_ip[3]); |
|
|
put_line (socket->telnet_txbuf, "Counterparty Port %d\r\n", |
socket->rx_packet->tcp_src_port); |
|
|
put_line (socket->telnet_txbuf, "Malloc pointer 0x%08x\r\n", |
*(unsigned int *)(ADR_MALLOC_POINTER)); |
put_line (socket->telnet_txbuf, "Malloc count %d\r\n", |
273,18 → 261,18
put_line (socket->telnet_txbuf, "Uptime %d seconds\r\n", current_time_g->seconds); |
break; |
} |
|
|
|
|
default: { |
error=1; break; |
} |
} |
} |
|
|
|
|
if (error) |
put_line (socket->telnet_txbuf, "You're not making any sense\r\n", |
put_line (socket->telnet_txbuf, "You're not making any sense\r\n", |
line[0], line[1], line[2]); |
|
|
put_line (socket->telnet_txbuf, "> "); |
return 0; |
} |
293,7 → 281,7
/* copy tftp file into a single contiguous buffer so |
if can be processed by elf splitter */ |
int process_file(socket_t* socket) |
{ |
{ |
block_t* block; |
char* buf512; |
char* tftp_file; |
300,12 → 288,12
char* line; |
int line_len; |
int ret; |
|
|
tftp_file = malloc(udp_file_g->total_bytes); |
|
|
block = udp_file_g; |
buf512= tftp_file; |
|
|
while (block->next) { |
memcpy(buf512, block->buf512, block->bytes); |
buf512=&buf512[512]; |
313,7 → 301,7
} |
memcpy(buf512, block->buf512, block->bytes); |
buf512=&buf512[512]; |
|
|
return elfsplitter(tftp_file, socket); |
} |
|
325,9 → 313,9
void reboot() |
{ |
int i; |
|
|
/* Disable all interrupts */ |
/* Disable ethmac_int interrupt */ |
/* Disable ethmac_int interrupt */ |
/* Disable timer 0 interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x120; |
|
334,14 → 322,10
for(i=0;i<MEM_BUF_ENTRIES;i++) |
if (elf_mem0_g->entry[i].valid) |
*(char *)(i) = elf_mem0_g->entry[i].data; |
|
if (udp_file_g->linux_boot) { |
print_serial("linux reboot\n\r"); |
_jump_to_program(LINUX_JUMP_ADR); |
} |
else { |
print_serial("normal reboot\n\r"); |
_restart(); |
} |
|
if (udp_file_g->linux_boot) |
_jump_to_program(LINUX_JUMP_ADR); |
else |
_restart(); |
} |
|
/trunk/sw/boot-loader-ethmac/start.S
66,31 → 66,31
|
|
.section .text |
.globl start |
start: |
.globl start |
start: |
/* 0x00 Reset Interrupt vector address */ |
b startup |
|
/* 0x04 Undefined Instruction Interrupt vector address */ |
b _testfail |
|
|
/* 0x08 SWI Interrupt vector address */ |
b _testfail |
|
|
/* 0x0c Prefetch abort Interrupt vector address */ |
b _testfail |
|
|
/* 0x10 Data abort Interrupt vector address */ |
b _testfail |
b _testfail |
|
|
/* 0x18 IRQ vector address */ |
b service_irq |
|
|
/* 0x1c FIRQ vector address */ |
b _testfail |
|
|
|
.global _restart |
_restart: |
@ jump to address 0 in irq mode |
105,23 → 105,23
mov r0, #0 |
ldr r1, AdrExecBase |
1: ldm r0!, {r2-r9} |
stm r1!, {r2-r9} |
stm r1!, {r2-r9} |
cmp r0, #0x4000 |
bne 1b |
|
/* Fix the interrupt jump pointers */ |
ldr r0, AdrExecBase |
ldr r0, AdrExecBase |
mov r1, r0, lsr #2 |
mov r2, #0 |
|
|
2: ldr r3, [r2] |
orr r3, r3, r1 |
str r3, [r2], #4 |
cmp r2, #0x1c |
bne 2b |
|
|
/* Jump to 2f but offset from ExecBase not current location */ |
3: ldr r0, AdrExecBase |
3: ldr r0, AdrExecBase |
ldr r1, AdrJumpPoint |
orr r0, r0, r1 |
mov pc, r0 |
130,21 → 130,21
|
/* Switch to IRQ Mode */ |
mov r0, #0x00000002 |
teqp pc, r0 |
teqp pc, r0 |
/* Set IRQ Mode stack pointer */ |
ldr sp, AdrIRQStack |
|
/* Switch to SVC mode and Unset interrupt mask bits */ |
mov r0, #0x00000003 |
teqp pc, r0 |
|
teqp pc, r0 |
|
@ Enable the cache |
@ set region 24 to be uncached. Used for packet buffers |
mov r0, #0xfeffffff |
mcr 15, 0, r0, cr3, cr0, 0 @ cacheable area |
mcr 15, 0, r0, cr3, cr0, 0 @ cacheable area |
mov r0, #1 |
mcr 15, 0, r0, cr2, cr0, 0 @ cache enable |
|
mcr 15, 0, r0, cr2, cr0, 0 @ cache enable |
|
@ init SP |
ldr sp, AdrStack |
|
152,15 → 152,15
ldr r0, AdrMemCtrl |
mov r1, #1 |
str r1, [r0] |
|
|
.extern main |
bl main |
|
|
@ jump to program at r0 |
.globl _jump_to_program |
.globl _jump_to_program |
_jump_to_program: |
|
|
|
@ ---------------------------------------------- |
@ Copy ATAG structure to AdrBootParams |
@ ---------------------------------------------- |
167,54 → 167,52
ldr r1, AdrBootParams |
ldr r2, AdrATAGBase |
ldr r3, AdeEndATAG |
|
|
1: cmp r2, r3 |
beq 2f |
ldr r4, [r2], #4 |
str r4, [r1], #4 |
b 1b |
|
|
@ Set memc page tables |
2: ldr r2, AdrPageTabes |
2: ldr r2, AdrPageTabes |
mov r3, #0 |
mov r4, #40 |
3: str r3,[r2],#4 |
subs r4, r4, #1 |
bne 3b |
|
|
@ ---------------------------------------------- |
@ jump to start of program in svc mode with interrupts disabled |
@ ---------------------------------------------- |
mov r4, r0 |
orr r4, #0x0c000003 |
mov r0, #0 |
mov r0, #0 |
mov pc, r4 |
|
|
|
service_irq: |
@ As this is an interrupt, need tp save all registers to the stack |
stmfd sp!, {r0-r3, lr} |
@ Save all registers to the stack |
stmfd sp!, {r0-r12, lr} |
|
@ is it a timer interrupt ? |
ldr r0, AdrInterruptStatus |
ldr r3, [r0] |
ands r2, r3, #0x20 |
ldr r1, [r0] |
ands r2, r1, #0x20 |
beq 1f @ not timer int, jump |
@ Remember that registers r0 to r2 can be changed by this function |
.extern timer_interrupt |
bl timer_interrupt |
|
bl timer_interrupt |
|
@ is it an ethernet interrupt ? |
1: ands r2, r3, #0x100 |
beq 2f @ not ethmac int, jump |
1: ands r2, r1, #0x100 |
beq 2f @ not ethmac int, jump |
.extern ethmac_interrupt |
@ Remember that registers r0 to r2 can be changed by this function |
bl ethmac_interrupt |
|
|
|
2: @ Restore all registers from the stack |
ldmfd sp!, {r0-r3, lr} |
|
ldmfd sp!, {r0-r12, lr} |
|
@ Jump straight back to normal execution |
subs pc, lr, #4 |
|
222,17 → 220,17
|
/* _testfail: Used to terminate execution in Verilog simulations */ |
/* On the board just puts the processor into an infinite loop */ |
.globl _testfail |
.globl _testfail |
_testfail: |
ldr r11, AdrTestStatus |
str r0, [r11] |
b _testfail |
|
|
|
/* _testpass: Used to terminate execution in Verilog simulations */ |
/* On the board just puts the processor into an infinite loop */ |
.globl _testpass |
_testpass: |
.globl _testpass |
_testpass: |
ldr r11, AdrTestStatus |
mov r10, #17 |
str r10, [r11] |
239,8 → 237,8
b _testpass |
|
|
|
|
|
/* _div: Integer division function */ |
@ Divide r0 by r1 |
@ Answer returned in r1 |
258,22 → 256,22
@ Invert negative numbers |
tst r0, #0x80000000 |
mvnne r0, r0 |
addne r0, r0, #1 |
addne r0, r0, #1 |
|
tst r1, #0x80000000 |
mvnne r1, r1 |
addne r1, r1, #1 |
addne r1, r1, #1 |
|
@ divide r1 by r2, also use registers r0 and r4 |
mov r2, r1 |
mov r1, r0 |
|
|
cmp r2, #0 |
beq 3f |
|
@ In order to divide r1 by r2, the first thing we need to do is to shift r2 |
@ left by the necessary number of places. The easiest method of doing this |
@ is simply by trial and error - shift until we discover that r2 has become |
@ In order to divide r1 by r2, the first thing we need to do is to shift r2 |
@ left by the necessary number of places. The easiest method of doing this |
@ is simply by trial and error - shift until we discover that r2 has become |
@ too big, then stop. |
mov r0,#0 @ clear r0 to accumulate result |
mov r3,#1 @ set bit 0 in r3, which will be |
290,14 → 288,14
@ shift r3 left in parallel in order to flag how far we have to go |
|
@ r0 will be used to hold the result. The role of r3 is more complicated. |
@ In effect, we are using r3 to mark where the right-hand end of r2 has got to |
@ - if we shift r2 three places left, this will be indicated by a value of %1000 |
@ in r3. However, we also add it to r0 every time we manage a successful subtraction, |
@ since it marks the position of the digit currently being calculated in the answer. |
|
@ so at the time of the first subtraction, r3 would have been %100, at the time |
@ of the second (which failed) it would have been %10, and at the time of the |
@ third %1. Adding it to r0 after each successful subtraction would have |
@ In effect, we are using r3 to mark where the right-hand end of r2 has got to |
@ - if we shift r2 three places left, this will be indicated by a value of %1000 |
@ in r3. However, we also add it to r0 every time we manage a successful subtraction, |
@ since it marks the position of the digit currently being calculated in the answer. |
|
@ so at the time of the first subtraction, r3 would have been %100, at the time |
@ of the second (which failed) it would have been %10, and at the time of the |
@ third %1. Adding it to r0 after each successful subtraction would have |
@ given us, once again, the answer of %101! |
|
@ Now for the loop that actually does the work: |
307,19 → 305,19
addcs r0,r0,r3 @ and add the current bit in r3 to |
@ the accumulating answer in r0 |
|
@ In subtraction (a cmp instruction simulates a subtraction in |
@ order to set the flags), if r1 - r2 gives a positive answer and no 'borrow' |
@ is required, the carry flag is set. This is required in order to make SBC |
@ (Subtract with Carry) work properly when used to carry out a 64-bit subtraction, |
@ In subtraction (a cmp instruction simulates a subtraction in |
@ order to set the flags), if r1 - r2 gives a positive answer and no 'borrow' |
@ is required, the carry flag is set. This is required in order to make SBC |
@ (Subtract with Carry) work properly when used to carry out a 64-bit subtraction, |
@ but it is confusing! |
|
@ In this case, we are turning it to our advantage. The carry flag is set to |
@ indicate that a successful subtraction is possible, i.e. one that doesn't |
@ generate a negative result, and the two following instructions are carried |
@ out only when the condition Carry Set applies. Note that the 'S' on the end |
@ of these instructions is part of the 'CS' condition code and does not mean |
|
@ In this case, we are turning it to our advantage. The carry flag is set to |
@ indicate that a successful subtraction is possible, i.e. one that doesn't |
@ generate a negative result, and the two following instructions are carried |
@ out only when the condition Carry Set applies. Note that the 'S' on the end |
@ of these instructions is part of the 'CS' condition code and does not mean |
@ that they set the flags! |
|
|
movs r3,r3,lsr #1 @ Shift r3 right into carry flag |
movcc r2,r2,lsr #1 @ and if bit 0 of r3 was zero, also |
@ shift r2 right |
326,20 → 324,20
bcc 2b @ If carry not clear, r3 has shifted |
@ back to where it started, and we |
@ can end |
|
@ if one of the inputs is negetive then return a negative result |
|
@ if one of the inputs is negetive then return a negative result |
tst r4, #0x80000000 |
mvnne r0, r0 |
addne r0, r0, #1 |
addne r0, r0, #1 |
3: ldmia sp!, {r4, pc}^ |
|
|
/* strcpy: String copy function |
/* strcpy: String copy function |
char * strcpy ( char * destination, const char * source ); |
destination is returned |
*/ |
*/ |
@ r0 points to destination |
@ r1 points to source string which terminates with a 0 |
@ r1 points to source string which terminates with a 0 |
.globl strcpy |
strcpy: |
stmdb sp!, {r4-r6, lr} |
353,22 → 351,22
strb r3, [r6], #1 |
cmp r3, #0 |
ldmeqia sp!, {r4-r6, pc}^ |
|
|
ldrb r3, [r1], #1 |
strb r3, [r6], #1 |
cmp r3, #0 |
ldmeqia sp!, {r4-r6, pc}^ |
|
|
ldrb r3, [r1], #1 |
strb r3, [r6], #1 |
cmp r3, #0 |
ldmeqia sp!, {r4-r6, pc}^ |
|
|
ldrb r3, [r1], #1 |
strb r3, [r6], #1 |
cmp r3, #0 |
ldmeqia sp!, {r4-r6, pc}^ |
|
|
b strcpy_main |
|
|
378,7 → 376,7
@ r1 points to source string |
@ r2 is the number of bytes to copy |
.globl strncpy |
strncpy: |
strncpy: |
stmdb sp!, {r4, lr} |
cmp r2, #0 |
beq 2f |
399,26 → 397,26
.globl strncmp |
strncmp: |
stmdb sp!, {r4, r5, r6, lr} |
|
|
@ check for 0 length |
cmp r2, #0 |
moveq r0, #1 |
beq 2f |
|
|
mov r3, #0 |
|
|
1: add r3, r3, #1 |
ldrb r4, [r0], #1 |
ldrb r5, [r1], #1 |
|
|
subs r6, r4, r5 |
movne r0, r6 |
bne 2f |
|
|
cmp r3, r2 |
moveq r0, #0 |
beq 2f |
|
|
b 1b |
2: ldmia sp!, {r4, r5, r6, pc}^ |
|
429,12 → 427,12
ldr r0, AdrMallocBase |
ldr r1, AdrMallocPointer |
str r0, [r1] |
|
|
@ initialize the counter to 0 |
ldr r1, AdrMallocCount |
mov r2, #0 |
str r2, [r1] |
|
|
mov pc, lr |
|
|
445,38 → 443,25
ldr r1, AdrMallocPointer |
ldr r2, [r1] /* r2 now containts the starting address of the next memory block to use */ |
add r3, r0, r2 /* r3 contains the address after the end of the new object */ |
|
|
/* Round r3 up to the nearest 0x100 to keep memory aligned */ |
tst r3, #0xff |
beq 1f |
bic r3, r3, #0xff |
add r3, r3, #0x100 |
|
|
1: str r3, [r1] /* Update the malloc pointer */ |
mov r0, r2 /* Return the address from before the pointer was updated */ |
|
|
@ Update the block count |
ldr r1, AdrMallocCount |
ldr r2, [r1] |
add r2, r2, #1 |
str r2, [r1] |
|
|
mov pc, lr |
|
|
.global serial_putchar_ |
serial_putchar_: |
ldr r1, AdrUARTDR |
ldr r3, AdrUARTFR |
@ Check the tx_full flag |
1: ldr r2, [r3] |
and r2, r2, #0x20 |
cmp r2, #0 |
streqb r0, [r1] |
moveqs pc, lr @ return |
bne 1b |
|
|
/* stack at top of ddr3 memory space */ |
AdrJumpPoint: .word _jump_point |
AdrExecBase: .word ADR_EXEC_BASE |
490,9 → 475,6
AdrTestStatus: .word ADR_AMBER_TEST_STATUS |
AdrInterruptStatus: .word ADR_AMBER_IC_IRQ0_STATUS |
|
AdrUARTDR: .word ADR_AMBER_UART0_DR |
AdrUARTFR: .word ADR_AMBER_UART0_FR |
|
.align 2 |
AdrATAGBase: .word ATAGBase |
AdeEndATAG: .word EndATAG |
502,7 → 484,7
.word FLAG_READONLY @ flags |
.word 4096 @ page size |
.word 0x0 @ rootdev |
|
|
.word ATAG_MEM_SIZE |
.word ATAG_MEM |
.word 32*1024*1024 @ size - 32MB |
518,7 → 500,7
.word ATAG_INITRD |
.word 0x02800000 @ virtual address of start of initrd image |
.word 0x00032000 @ size = 200k |
|
|
.word ATAG_NONE |
.word 0x0 |
EndATAG: .word 0x0 |
/trunk/sw/boot-loader-ethmac/utilities.h
44,7 → 44,6
int get_hex (char*, unsigned int*); |
int next_string (char*); |
int strcmp (char*, char*); |
int serial_putchar_ (char *); |
|
void led_clear (void); |
void led_flip (int); |
/trunk/sw/boot-loader-ethmac/timer.c
7,7 → 7,7
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
62,7 → 62,7
|
|
/*Initialize a global variable that keeps |
track of the current up time. Timers are |
track of the current up time. Timers are |
compared against this running value. |
*/ |
void init_current_time() |
70,7 → 70,7
/* Configure timer 0 */ |
/* Counts down from this value and generates an interrupt every 1/100 seconds */ |
*(unsigned int *) ( ADR_AMBER_TM_TIMER0_LOAD ) = 1562; // 16-bit, x 256 |
*(unsigned int *) ( ADR_AMBER_TM_TIMER0_CTRL ) = 0xc8; // enable[7], periodic[6], |
*(unsigned int *) ( ADR_AMBER_TM_TIMER0_CTRL ) = 0xc8; // enable[7], periodic[6], |
|
/* Enable timer 0 interrupt */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x020; |
86,7 → 86,7
{ |
/* Clear timer 0 interrupt in timer */ |
*(unsigned int *) ( ADR_AMBER_TM_TIMER0_CLR ) = 1; |
|
|
/* Disable timer 0 interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x020; |
|
98,9 → 98,9
else { |
current_time_g->milliseconds+=10; |
} |
|
|
/* Enable timer 0 interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x020; |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x020; |
} |
|
|
109,13 → 109,13
{ |
if (!expiry_time->seconds && !expiry_time->milliseconds) |
/* timer is not set */ |
return 0; |
return 0; |
else if (expiry_time->seconds < current_time_g->seconds) |
return 1; |
else if ((expiry_time->seconds == current_time_g->seconds) && |
else if ((expiry_time->seconds == current_time_g->seconds) && |
(expiry_time->milliseconds < current_time_g->milliseconds)) |
return 1; |
else |
else |
return 0; |
} |
|
125,8 → 125,8
{ |
int seconds = _div(milliseconds, 1000); |
int mseconds = milliseconds - seconds*1000; /* milliseconds % 1000 */ |
|
|
|
|
if (current_time_g->milliseconds >= (1000 - mseconds)) { |
timer->seconds = current_time_g->seconds + 1; |
timer->milliseconds = current_time_g->milliseconds + mseconds - 1000; |
135,7 → 135,7
timer->seconds = current_time_g->seconds; |
timer->milliseconds = current_time_g->milliseconds + mseconds; |
} |
|
|
timer->seconds += seconds; |
} |
|
/trunk/sw/boot-loader-ethmac/udp.c
7,7 → 7,7
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
60,58 → 60,59
unsigned int udp_src_port = buf[0]<<8|buf[1]; |
unsigned int udp_dst_port = buf[2]<<8|buf[3]; |
unsigned int udp_len = buf[4]<<8|buf[5]; |
|
|
unsigned short prot_udp=17; |
unsigned short word16; |
unsigned long sum = 0; |
unsigned long sum = 0; |
unsigned int checksum; |
int mode_offset; |
int binary_mode; |
int i; |
|
|
|
|
for (i=0;i<4;i=i+2){ |
word16 =((rx_packet->src_ip[i]<<8)&0xFF00)+(rx_packet->src_ip[i+1]&0xFF); |
sum=sum+word16; |
sum=sum+word16; |
} |
for (i=0;i<4;i=i+2){ |
word16 =((rx_packet->dst_ip[i]<<8)&0xFF00)+(rx_packet->dst_ip[i+1]&0xFF); |
sum=sum+word16; |
sum=sum+word16; |
} |
// the protocol number and the length of the TCP packet |
sum = sum + prot_udp + udp_len; |
|
checksum = header_checksum16(buf, udp_len, sum); |
|
if (checksum) |
udp_checksum_errors_g++; |
|
|
/* TFTP */ |
|
if (checksum) |
udp_checksum_errors_g++; |
|
|
/* TFTP */ |
if (udp_dst_port == 69 && !checksum) { |
unsigned int opcode = buf[8]<<8|buf[9]; |
unsigned int block = buf[10]<<8|buf[11]; |
int tftp_len = udp_len - 12; |
|
|
mode_offset = next_string(&buf[10]); |
binary_mode = strcmp("octet", &buf[10+mode_offset]); |
|
|
switch (opcode) { |
|
|
case UDP_READ: |
udp_reply(rx_packet, udp_dst_port, udp_src_port, 0, UDP_ERROR); |
break; |
|
|
case UDP_WRITE: |
udp_file_g = init_buffer_512(); |
udp_file_g->filename = malloc(256); |
strcpy(udp_file_g->filename, &buf[10]); |
|
if (strncmp(&buf[10], "vmlinux", 7) == 0) |
udp_file_g->linux_boot = 1; |
|
|
if (strncmp(&buf[10], "vmlinux") == 0) |
udp_file_g->linux_boot == 1; |
|
udp_current_block_g = udp_file_g; |
|
|
|
if (binary_mode) |
udp_reply(rx_packet, udp_dst_port, udp_src_port, 0, UDP_ACK); |
else |
121,21 → 122,21
|
case UDP_DATA: |
udp_reply(rx_packet, udp_dst_port, udp_src_port, block, UDP_ACK); |
|
|
if (block > udp_file_g->last_block) { |
// Have not already received this block |
udp_file_g->last_block = block; |
|
|
/* receive and save a block */ |
udp_current_block_g->bytes = tftp_len; |
udp_file_g->total_bytes += tftp_len; |
udp_file_g->total_blocks++; |
|
|
memcpy(udp_current_block_g->buf512, &buf[12], tftp_len); |
|
|
/* Prepare the next block */ |
if (tftp_len == 512) { |
udp_current_block_g->next = init_buffer_512(); |
udp_current_block_g->next = init_buffer_512(); |
udp_current_block_g = udp_current_block_g->next; |
} |
else { /* Last block */ |
143,8 → 144,8
} |
} |
break; |
|
|
|
|
default: break; |
} |
} |
159,10 → 160,10
unsigned short prot_udp=17; |
unsigned short udp_len; |
unsigned short word16; |
unsigned long sum = 0; |
unsigned long sum = 0; |
int i; |
mac_ip_t target; |
|
|
target.mac[0] = rx_packet->src_mac[0]; |
target.mac[1] = rx_packet->src_mac[1]; |
target.mac[2] = rx_packet->src_mac[2]; |
179,8 → 180,8
buf[35] = udp_src_port & 0xff; |
buf[36] = (udp_dst_port & 0xff00)>>8; |
buf[37] = udp_dst_port & 0xff; |
|
if (reply_type == UDP_ACK) |
|
if (reply_type == UDP_ACK) |
udp_len = 8+4; |
else /* error */ |
udp_len = 8+2+2+14; |
188,17 → 189,17
|
buf[38] = (udp_len & 0xff00)>>8; |
buf[39] = udp_len & 0xff; |
|
|
buf[40] = 0; // checksum |
buf[41] = 0; // checksum |
|
|
// ------------------------------------- |
// tftf payload |
// tftf payload |
// ------------------------------------- |
// Opcode |
buf[42] = 0; |
buf[43] = reply_type & 0xff; // Acknowledgment |
|
buf[42] = 0; |
buf[43] = reply_type & 0xff; // Acknowledgment |
|
if (reply_type == UDP_ACK) { |
// block |
buf[44] = (block & 0xff00)>>8; |
211,18 → 212,18
// 46 to 59 |
strncpy(&buf[46], "Not supported", 14); |
} |
|
|
|
|
// ------------------------------------- |
// UDP Checksum calculation |
// ------------------------------------- |
for (i=0;i<4;i=i+2){ |
word16 =((rx_packet->src_ip[i]<<8)&0xFF00)+(rx_packet->src_ip[i+1]&0xFF); |
sum=sum+word16; |
sum=sum+word16; |
} |
for (i=0;i<4;i=i+2){ |
word16 =((rx_packet->dst_ip[i]<<8)&0xFF00)+(rx_packet->dst_ip[i+1]&0xFF); |
sum=sum+word16; |
sum=sum+word16; |
} |
// the protocol number and the length of the TCP packet |
sum = sum + prot_udp + udp_len; |
230,7 → 231,7
checksum = header_checksum16(&buf[34], udp_len, sum); |
buf[40] = (checksum & 0xff00)>>8; // checksum |
buf[41] = checksum & 0xff; // checksum |
|
|
ip_header(&buf[14], &target, 20+udp_len, 17); /* 20 byes of tcp options, bytes 14 to 33, ip_proto = 17, UDP */ |
ethernet_header(buf, &target, 0x0800); /*bytes 0 to 13*/ |
tx_packet(34+udp_len); // packet length in bytes |
248,7 → 249,6
block->total_blocks = 0; |
block->ready = 0; |
block->filename = NULL; |
block->linux_boot = 0; |
return block; |
} |
|
/trunk/sw/boot-loader-ethmac/telnet.c
7,7 → 7,7
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
53,22 → 53,22
int i; |
int stage = 0; |
char stage1; |
|
|
for (i=0;i<socket->rx_packet->tcp_payload_len;i++) { |
|
|
if (stage == 0) { |
switch (buf[i]) { |
case 241: stage = 0; break; // NOP |
case 255: stage = 1; |
case 255: stage = 1; |
if (socket->telnet_connection_state == TELNET_CLOSED) { |
socket->telnet_connection_state = TELNET_OPEN; |
} |
break; // IAC |
|
default: if (buf[i] < 128) |
|
default: if (buf[i] < 128) |
goto telnet_payload; |
} |
|
|
} else if (stage == 1) { |
stage1 = buf[i]; |
switch (buf[i]) { |
80,9 → 80,9
case TELNET_DONT: stage = 2; break; // 0xfe DONT |
default : stage = 2; break; |
} |
|
|
} else { // stage = 2 |
stage = 0; |
stage = 0; |
switch (buf[i]) { |
case 1: // echo |
/* Client request that server echos stuff back to client */ |
92,7 → 92,7
else if (stage1 == TELNET_DONT) |
socket->telnet_echo_mode = 0; |
break; |
|
|
case 3: break; // suppress go ahead |
case 5: break; // status |
case 6: break; // time mark |
108,8 → 108,8
} |
} |
|
return; |
|
return; |
|
telnet_payload: |
socket->rx_packet->telnet_payload_len = socket->rx_packet->tcp_payload_len - i; |
parse_telnet_payload(&buf[i], socket); |
122,7 → 122,7
int cr = 0; |
int windows = 0; |
for (i=0;i<socket->rx_packet->telnet_payload_len;i++) { |
if (buf[i] == '\n') |
if (buf[i] == '\n') |
windows = 1; |
else if (buf[i] < 128 && buf[i] != 0) { |
/* end of a line */ |
130,13 → 130,13
if (buf[i] == '\r') { |
cr=1; |
put_byte(socket->telnet_rxbuf, buf[i], 1); /* last byte of line */ |
} |
} |
else { |
put_byte(socket->telnet_rxbuf, buf[i], 0); /* not last byte of line */ |
} |
} |
} |
} |
|
|
if (socket->telnet_echo_mode) { |
if (cr && !windows) { |
buf[socket->rx_packet->telnet_payload_len] = '\n'; |
153,7 → 153,7
|
// telnet options |
// Will echo - advertise that I have the ability to echo back commands to the client |
buf[0] = 0xff; buf[1] = TELNET_WILL; buf[2] = 0x01; |
buf[0] = 0xff; buf[1] = TELNET_WILL; buf[2] = 0x01; |
tcp_reply(socket, buf, 3); |
|
} |
165,17 → 165,27
int total_line_len; |
char* line; |
char* first_line; |
|
/* Parse telnet tx buffer |
Grab as many lines as possible to stuff into a packet to transmit */ |
line_len = get_line(txbuf, &first_line); |
if (line_len) { |
total_line_len = line_len; |
while (total_line_len < MAX_TELNET_TX && line_len) { |
line_len = get_line(txbuf, &line); |
total_line_len += line_len; |
} |
tcp_tx(socket, first_line, total_line_len); |
} |
} |
|
/* Parse telnet tx buffer |
Grab as many lines as possible to stuff into a packet to transmit */ |
line_len = get_line(txbuf, &first_line); |
if (line_len) { |
total_line_len = line_len; |
while (total_line_len < MAX_TELNET_TX && line_len) { |
line_len = get_line(txbuf, &line); |
total_line_len += line_len; |
} |
tcp_tx(socket, first_line, total_line_len); |
} |
/* |
void telnet_broadcast (const char *fmt, ...) |
{ |
register unsigned long *varg = (unsigned long *)(&fmt); |
*varg++; |
|
put_line (socket0_g->telnet_txbuf, fmt, varg); |
put_line (socket1_g->telnet_txbuf, fmt, varg); |
} |
|
*/ |
/trunk/sw/boot-loader-ethmac/Makefile
41,9 → 41,9
# Assembly source files |
|
SRC = boot-loader-ethmac.c line-buffer.c timer.c print.c elfsplitter.c utilities.c \ |
serial.c ethmac.c packet.c tcp.c udp.c telnet.c start.S ../mini-libc/memcpy.c |
ethmac.c packet.c tcp.c udp.c telnet.c start.S ../mini-libc/memcpy.c |
DEP = address_map.h boot-loader-ethmac.h line-buffer.h timer.h utilities.h \ |
serial.h ethmac.h tcp.h udp.h telnet.h packet.h elfsplitter.h |
ethmac.h tcp.h udp.h telnet.h packet.h elfsplitter.h |
TGT = boot-loader-ethmac.elf |
LDS = sections.lds |
|
55,5 → 55,5
|
all : debug |
../tools/check_mem_size.sh $(MEM) "@000040" |
|
|
include ../include/common.mk |
/trunk/sw/boot-loader-ethmac/print.c
48,16 → 48,13
#define PRINT_BUF_LEN 16 |
|
|
/* format and print a string, inserting variables, to dst char buffer, |
return the number of characters printed. If dst is 0, the string is |
sent to the serial output |
*/ |
|
int print(char** dst, const char *format, unsigned long *varg) |
{ |
register int width, pad; |
register int pc = 0; |
char scr[2]; |
|
|
for (; *format != 0; ++format) { |
if (*format == '%') { |
++format; |
107,10 → 104,8
} |
else { |
out: |
if (dst) |
*(*dst)++ = *format; |
else |
serial_putchar_(*format); |
//outbyte (dst, *format); |
*(*dst)++ = *format; |
++pc; |
} |
} |
124,39 → 119,33
{ |
register int pc = 0, padchar = ' '; |
|
if (width > 0) { |
register int len = 0; |
register const char *ptr; |
for (ptr = string; *ptr; ++ptr) ++len; |
if (len >= width) width = 0; |
else width -= len; |
if (pad & PAD_ZERO) padchar = '0'; |
} |
if (!(pad & PAD_RIGHT)) { |
for ( ; width > 0; --width) { |
if (dst) |
*(*dst)++ = padchar; |
else |
serial_putchar_(padchar); |
++pc; |
} |
} |
for ( ; *string ; ++string) { |
if (dst) |
*(*dst)++ = *string; |
else |
serial_putchar_(*string); |
++pc; |
} |
for ( ; width > 0; --width) { |
if (dst) |
if (width > 0) { |
register int len = 0; |
register const char *ptr; |
for (ptr = string; *ptr; ++ptr) ++len; |
if (len >= width) width = 0; |
else width -= len; |
if (pad & PAD_ZERO) padchar = '0'; |
} |
if (!(pad & PAD_RIGHT)) { |
for ( ; width > 0; --width) { |
//outbyte(dst, padchar); |
*(*dst)++ = padchar; |
else |
serial_putchar_(padchar); |
++pc; |
} |
++pc; |
} |
} |
for ( ; *string ; ++string) { |
//outbyte(dst, *string); |
*(*dst)++ = *string; |
++pc; |
} |
for ( ; width > 0; --width) { |
//outbyte(dst, padchar); |
*(*dst)++ = padchar; |
++pc; |
} |
|
return pc; |
return pc; |
} |
|
|
185,11 → 174,11
while (u) { |
if ( b == 16 ) t = u & 0xf; /* hex modulous */ |
else t = u - ( _div (u, b) * b ); /* Modulous */ |
|
|
if( t >= 10 ) |
t += letbase - '0' - 10; |
*--s = t + '0'; |
|
|
/* u /= b; */ |
if ( b == 16) u = u >> 4; /* divide by 16 */ |
else u = _div(u, b); |
197,10 → 186,8
|
if (neg) { |
if( width && (pad & PAD_ZERO) ) { |
if (dst) |
*(*dst)++ = '-'; |
else |
serial_putchar_('-'); |
//outbyte(dst,'-'); |
*(*dst)++ = '-'; |
++pc; |
--width; |
} |
/trunk/sw/boot-loader-ethmac/elfsplitter.c
59,7 → 59,8
unsigned int outP; |
int interrupt_table_written = 0; |
int interrupt_table_zero_written = 0; |
|
|
|
/* Create buffer to hold interrupt vector memory values |
Can't copy these into mem0 locations until ready to pass control |
t new program |
67,8 → 68,8
elf_mem0_g = malloc(sizeof(mem_buf_t)); |
for(i=0;i<MEM_BUF_ENTRIES;i++) |
elf_mem0_g->entry[i].valid = 0; |
|
|
|
|
elfHeader=(ElfHeader*)inbuf; |
|
|
75,54 → 76,60
if (strncmp((char*)elfHeader->e_ident+1,"ELF",3)) { |
return(1); |
} |
|
|
if (elfHeader->e_machine != 40) { |
print_serial ("%s:L%d ERROR: ELF file not targetting correct processor type.\r\n", |
__FILE__, __LINE__); |
telnet_broadcast ("%s ERROR: ELF file not targetting correct processor type.\r\n", |
__func__); |
return(1); |
} |
|
|
for (i=0;i<elfHeader->e_shnum;++i) { |
elfSection=(Elf32_Shdr*)(inbuf+elfHeader->e_shoff+elfHeader->e_shentsize*i); |
|
for (i=0;i<elfHeader->e_shnum;++i) { |
elfSection=(Elf32_Shdr*)(inbuf+elfHeader->e_shoff+elfHeader->e_shentsize*i); |
|
/* section with non-zero bits, can be either text or data */ |
if (elfSection->sh_type == SHT_PROGBITS && elfSection->sh_size != 0) { |
for (j=0; j<elfSection->sh_size; j++) { |
k = j + elfSection->sh_offset; |
outP = elfSection->sh_addr + j; |
|
/* debug */ |
if (outP >= ADR_EXEC_BASE) |
print_serial("%s:L%d ERROR: 1 outP value 0x%08x\r\n",__FILE__, __LINE__, outP); |
else if (outP > MEM_BUF_ENTRIES) |
outbuf[outP] = inbuf[k]; |
else { |
elf_mem0_g->entry[outP].valid = 1; |
elf_mem0_g->entry[outP].data = inbuf[k]; |
/* section with non-zero bits, can be either text or data */ |
if (elfSection->sh_type == SHT_PROGBITS && elfSection->sh_size != 0) { |
for (j=0; j<elfSection->sh_size; j++) { |
k = j + elfSection->sh_offset; |
outP = elfSection->sh_addr + j; |
|
/* debug */ |
if (outP >= ADR_EXEC_BASE) |
telnet_broadcast("%s ERROR: 1 outP value 0x%08x\r\n",__func__, outP); |
else if (outP > MEM_BUF_ENTRIES) |
outbuf[outP] = inbuf[k]; |
else { |
elf_mem0_g->entry[outP].valid = 1; |
elf_mem0_g->entry[outP].data = inbuf[k]; |
interrupt_table_written = 1; |
} |
} |
} |
|
if (elfSection->sh_type == SHT_NOBITS && elfSection->sh_size != 0) { |
for (j=0; j<elfSection->sh_size; j++) { |
outP = j + elfSection->sh_addr; |
|
/* debug */ |
if (outP >= ADR_EXEC_BASE) |
print_serial("%s:L%d ERROR: 2 outP value 0x%08x\r\n",__FILE__, __LINE__, outP); |
else if (outP > MEM_BUF_ENTRIES) |
outbuf[outP] = 0; |
else { |
elf_mem0_g->entry[outP].valid = 1; |
elf_mem0_g->entry[outP].data = 0; |
} |
} |
|
if (elfSection->sh_type == SHT_NOBITS && elfSection->sh_size != 0) { |
for (j=0; j<elfSection->sh_size; j++) { |
outP = j + elfSection->sh_addr; |
|
/* debug */ |
if (outP >= ADR_EXEC_BASE) |
telnet_broadcast("%s ERROR: 2 outP value 0x%08x\r\n",__func__, outP); |
else if (outP > MEM_BUF_ENTRIES) |
outbuf[outP] = 0; |
else { |
elf_mem0_g->entry[outP].valid = 1; |
elf_mem0_g->entry[outP].data = 0; |
interrupt_table_zero_written = 1; |
} |
} |
} |
} |
|
} |
} |
} |
|
/* |
if (interrupt_table_written) |
telnet_broadcast ("%s WARNING: Interrupt table writes\r\n",__func__); |
if (interrupt_table_zero_written) |
telnet_broadcast ("%s WARNING: Interrupt table ZERO writes\r\n",__func__); |
*/ |
return 0; |
} |
|