demo: basic lm32 design

parent aa250eba
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_include.v
// Title : CPU global macros
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// Version : 3.2
// : No Change
// Version : 3.3
// : Support for extended configuration register
// =============================================================================
`ifdef LM32_INCLUDE_V
`else
`define LM32_INCLUDE_V
//
// Common configuration options
//
`define CFG_EBA_RESET 32'h0
`define CFG_DEBA_RESET 32'h0
//`define CFG_PL_MULTIPLY_ENABLED
//`define CFG_PL_BARREL_SHIFT_ENABLED
//`define CFG_SIGN_EXTEND_ENABLED
//`define CFG_MC_DIVIDE_ENABLED
//`define CFG_ICACHE_ENABLED
`define CFG_ICACHE_ASSOCIATIVITY 2
`define CFG_ICACHE_SETS 256
`define CFG_ICACHE_BYTES_PER_LINE 16
`define CFG_ICACHE_BASE_ADDRESS 32'h0
`define CFG_ICACHE_LIMIT 32'h7fffffff
//`define CFG_DCACHE_ENABLED
`define CFG_DCACHE_ASSOCIATIVITY 2
`define CFG_DCACHE_SETS 512
`define CFG_DCACHE_BYTES_PER_LINE 16
`define CFG_DCACHE_BASE_ADDRESS 32'h0
`define CFG_DCACHE_LIMIT 32'h7fffffff
//
// End of common configuration options
//
`ifdef TRUE
`else
`define TRUE 1'b1
`define FALSE 1'b0
`define TRUE_N 1'b0
`define FALSE_N 1'b1
`endif
// Wishbone configuration
`define CFG_IWB_ENABLED
`define CFG_DWB_ENABLED
// Data-path width
`define LM32_WORD_WIDTH 32
`define LM32_WORD_RNG (`LM32_WORD_WIDTH-1):0
`define LM32_SHIFT_WIDTH 5
`define LM32_SHIFT_RNG (`LM32_SHIFT_WIDTH-1):0
`define LM32_BYTE_SELECT_WIDTH 4
`define LM32_BYTE_SELECT_RNG (`LM32_BYTE_SELECT_WIDTH-1):0
// Register file size
`define LM32_REGISTERS 32
`define LM32_REG_IDX_WIDTH 5
`define LM32_REG_IDX_RNG (`LM32_REG_IDX_WIDTH-1):0
// Standard register numbers
`define LM32_RA_REG `LM32_REG_IDX_WIDTH'd29
`define LM32_EA_REG `LM32_REG_IDX_WIDTH'd30
`define LM32_BA_REG `LM32_REG_IDX_WIDTH'd31
// Range of Program Counter. Two LSBs are always 0.
// `ifdef CFG_ICACHE_ENABLED
// `define LM32_PC_WIDTH (clogb2(`CFG_ICACHE_LIMIT-`CFG_ICACHE_BASE_ADDRESS)-2)
// `else
// `ifdef CFG_IWB_ENABLED
`define LM32_PC_WIDTH (`LM32_WORD_WIDTH-2)
// `else
// `define LM32_PC_WIDTH `LM32_IROM_ADDRESS_WIDTH
// `endif
// `endif
`define LM32_PC_RNG (`LM32_PC_WIDTH+2-1):2
// Range of an instruction
`define LM32_INSTRUCTION_WIDTH 32
`define LM32_INSTRUCTION_RNG (`LM32_INSTRUCTION_WIDTH-1):0
// Adder operation
`define LM32_ADDER_OP_ADD 1'b0
`define LM32_ADDER_OP_SUBTRACT 1'b1
// Shift direction
`define LM32_SHIFT_OP_RIGHT 1'b0
`define LM32_SHIFT_OP_LEFT 1'b1
// Currently always enabled
`define CFG_BUS_ERRORS_ENABLED
// Derive macro that indicates whether we have single-stepping or not
`ifdef CFG_ROM_DEBUG_ENABLED
`define LM32_SINGLE_STEP_ENABLED
`else
`ifdef CFG_HW_DEBUG_ENABLED
`define LM32_SINGLE_STEP_ENABLED
`endif
`endif
// Derive macro that indicates whether JTAG interface is required
`ifdef CFG_JTAG_UART_ENABLED
`define LM32_JTAG_ENABLED
`else
`ifdef CFG_DEBUG_ENABLED
`define LM32_JTAG_ENABLED
`else
`endif
`endif
// Derive macro that indicates whether we have a barrel-shifter or not
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
`define LM32_BARREL_SHIFT_ENABLED
`else // CFG_PL_BARREL_SHIFT_ENABLED
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
`define LM32_BARREL_SHIFT_ENABLED
`else
`define LM32_NO_BARREL_SHIFT
`endif
`endif // CFG_PL_BARREL_SHIFT_ENABLED
// Derive macro that indicates whether we have a multiplier or not
`ifdef CFG_PL_MULTIPLY_ENABLED
`define LM32_MULTIPLY_ENABLED
`else
`ifdef CFG_MC_MULTIPLY_ENABLED
`define LM32_MULTIPLY_ENABLED
`endif
`endif
// Derive a macro that indicates whether or not the multi-cycle arithmetic unit is required
`ifdef CFG_MC_DIVIDE_ENABLED
`define LM32_MC_ARITHMETIC_ENABLED
`endif
`ifdef CFG_MC_MULTIPLY_ENABLED
`define LM32_MC_ARITHMETIC_ENABLED
`endif
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
`define LM32_MC_ARITHMETIC_ENABLED
`endif
// Derive macro that indicates if we are using an EBR register file
`ifdef CFG_EBR_POSEDGE_REGISTER_FILE
`define LM32_EBR_REGISTER_FILE
`endif
`ifdef CFG_EBR_NEGEDGE_REGISTER_FILE
`define LM32_EBR_REGISTER_FILE
`endif
// Revision number
`define LM32_REVISION 6'h02
// Logical operations - Function encoded directly in instruction
`define LM32_LOGIC_OP_RNG 3:0
// Conditions for conditional branches
`define LM32_CONDITION_WIDTH 3
`define LM32_CONDITION_RNG (`LM32_CONDITION_WIDTH-1):0
`define LM32_CONDITION_E 3'b001
`define LM32_CONDITION_G 3'b010
`define LM32_CONDITION_GE 3'b011
`define LM32_CONDITION_GEU 3'b100
`define LM32_CONDITION_GU 3'b101
`define LM32_CONDITION_NE 3'b111
`define LM32_CONDITION_U1 3'b000
`define LM32_CONDITION_U2 3'b110
// Size of load or store instruction - Encoding corresponds to opcode
`define LM32_SIZE_WIDTH 2
`define LM32_SIZE_RNG 1:0
`define LM32_SIZE_BYTE 2'b00
`define LM32_SIZE_HWORD 2'b11
`define LM32_SIZE_WORD 2'b10
`define LM32_ADDRESS_LSBS_WIDTH 2
// Width and range of a CSR index
`ifdef CFG_DEBUG_ENABLED
`define LM32_CSR_WIDTH 5
`define LM32_CSR_RNG (`LM32_CSR_WIDTH-1):0
`else
`ifdef CFG_JTAG_ENABLED
`define LM32_CSR_WIDTH 4
`define LM32_CSR_RNG (`LM32_CSR_WIDTH-1):0
`else
`define LM32_CSR_WIDTH 3
`define LM32_CSR_RNG (`LM32_CSR_WIDTH-1):0
`endif
`endif
// CSR indices
`define LM32_CSR_IE `LM32_CSR_WIDTH'h0
`define LM32_CSR_IM `LM32_CSR_WIDTH'h1
`define LM32_CSR_IP `LM32_CSR_WIDTH'h2
`define LM32_CSR_ICC `LM32_CSR_WIDTH'h3
`define LM32_CSR_DCC `LM32_CSR_WIDTH'h4
`define LM32_CSR_CC `LM32_CSR_WIDTH'h5
`define LM32_CSR_CFG `LM32_CSR_WIDTH'h6
`define LM32_CSR_EBA `LM32_CSR_WIDTH'h7
`ifdef CFG_DEBUG_ENABLED
`define LM32_CSR_DC `LM32_CSR_WIDTH'h8
`define LM32_CSR_DEBA `LM32_CSR_WIDTH'h9
`endif
`define LM32_CSR_CFG2 `LM32_CSR_WIDTH'ha
`ifdef CFG_JTAG_ENABLED
`define LM32_CSR_JTX `LM32_CSR_WIDTH'he
`define LM32_CSR_JRX `LM32_CSR_WIDTH'hf
`endif
`ifdef CFG_DEBUG_ENABLED
`define LM32_CSR_BP0 `LM32_CSR_WIDTH'h10
`define LM32_CSR_BP1 `LM32_CSR_WIDTH'h11
`define LM32_CSR_BP2 `LM32_CSR_WIDTH'h12
`define LM32_CSR_BP3 `LM32_CSR_WIDTH'h13
`define LM32_CSR_WP0 `LM32_CSR_WIDTH'h18
`define LM32_CSR_WP1 `LM32_CSR_WIDTH'h19
`define LM32_CSR_WP2 `LM32_CSR_WIDTH'h1a
`define LM32_CSR_WP3 `LM32_CSR_WIDTH'h1b
`endif
// Values for WPC CSR
`define LM32_WPC_C_RNG 1:0
`define LM32_WPC_C_DISABLED 2'b00
`define LM32_WPC_C_READ 2'b01
`define LM32_WPC_C_WRITE 2'b10
`define LM32_WPC_C_READ_WRITE 2'b11
// Exception IDs
`define LM32_EID_WIDTH 3
`define LM32_EID_RNG (`LM32_EID_WIDTH-1):0
`define LM32_EID_RESET 3'h0
`define LM32_EID_BREAKPOINT 3'd1
`define LM32_EID_INST_BUS_ERROR 3'h2
`define LM32_EID_WATCHPOINT 3'd3
`define LM32_EID_DATA_BUS_ERROR 3'h4
`define LM32_EID_DIVIDE_BY_ZERO 3'h5
`define LM32_EID_INTERRUPT 3'h6
`define LM32_EID_SCALL 3'h7
// Pipeline result selection mux controls
`define LM32_D_RESULT_SEL_0_RNG 0:0
`define LM32_D_RESULT_SEL_0_REG_0 1'b0
`define LM32_D_RESULT_SEL_0_NEXT_PC 1'b1
`define LM32_D_RESULT_SEL_1_RNG 1:0
`define LM32_D_RESULT_SEL_1_ZERO 2'b00
`define LM32_D_RESULT_SEL_1_REG_1 2'b01
`define LM32_D_RESULT_SEL_1_IMMEDIATE 2'b10
`define LM32_USER_OPCODE_WIDTH 11
`define LM32_USER_OPCODE_RNG (`LM32_USER_OPCODE_WIDTH-1):0
// Derive a macro to indicate if either of the caches are implemented
`ifdef CFG_ICACHE_ENABLED
`define LM32_CACHE_ENABLED
`else
`ifdef CFG_DCACHE_ENABLED
`define LM32_CACHE_ENABLED
`endif
`endif
/////////////////////////////////////////////////////
// Interrupts
/////////////////////////////////////////////////////
// Always enable interrupts
`define CFG_INTERRUPTS_ENABLED
// Currently this is fixed to 32 and should not be changed
`define CFG_INTERRUPTS 32
`define LM32_INTERRUPT_WIDTH `CFG_INTERRUPTS
`define LM32_INTERRUPT_RNG (`LM32_INTERRUPT_WIDTH-1):0
/////////////////////////////////////////////////////
// General
/////////////////////////////////////////////////////
// Sub-word range types
`define LM32_BYTE_WIDTH 8
`define LM32_BYTE_RNG 7:0
`define LM32_HWORD_WIDTH 16
`define LM32_HWORD_RNG 15:0
// Word sub-byte indicies
`define LM32_BYTE_0_RNG 7:0
`define LM32_BYTE_1_RNG 15:8
`define LM32_BYTE_2_RNG 23:16
`define LM32_BYTE_3_RNG 31:24
// Word sub-halfword indices
`define LM32_HWORD_0_RNG 15:0
`define LM32_HWORD_1_RNG 31:16
// Use a synchronous reset
`define CFG_RESET_SENSITIVITY
// V.T. Srce
`define SRCE
// Whether to include context registers for debug exceptions
// in addition to standard exception handling registers
// Bizarre - Removing this increases LUT count!
`define CFG_DEBUG_EXCEPTIONS_ENABLED
// Wishbone defines
// Refer to Wishbone System-on-Chip Interconnection Architecture
// These should probably be moved to a Wishbone common file
// Wishbone cycle types
`define LM32_CTYPE_WIDTH 3
`define LM32_CTYPE_RNG (`LM32_CTYPE_WIDTH-1):0
`define LM32_CTYPE_CLASSIC 3'b000
`define LM32_CTYPE_CONSTANT 3'b001
`define LM32_CTYPE_INCREMENTING 3'b010
`define LM32_CTYPE_END 3'b111
// Wishbone burst types
`define LM32_BTYPE_WIDTH 2
`define LM32_BTYPE_RNG (`LM32_BTYPE_WIDTH-1):0
`define LM32_BTYPE_LINEAR 2'b00
`define LM32_BTYPE_4_BEAT 2'b01
`define LM32_BTYPE_8_BEAT 2'b10
`define LM32_BTYPE_16_BEAT 2'b11
`endif
/*
* Milkymist VJ SoC
* Copyright (C) 2007, 2008, 2009, 2011 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* System clock frequency in Hz.
*/
`define CLOCK_FREQUENCY 125000000
/*
* System clock period in ns (must be in sync with CLOCK_FREQUENCY).
*/
`define CLOCK_PERIOD 8
/*
* Default baudrate for the debug UART.
*/
`define BAUD_RATE 115200
/*
* Milkymist VJ SoC
* Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
* Copyright (C) 2011 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
`include "setup.v"
module system(
input clkin,
input resetin,
// UART
input uart_rxd,
output uart_txd,
// GPIO
input [2:0] btn,
output [1:0] led
);
//------------------------------------------------------------------
// Clock and Reset Generation
//------------------------------------------------------------------
wire sys_clk;
wire hard_reset;
assign sys_clk = clkin;
`ifndef SIMULATION
/* Synchronize the reset input */
reg rst0;
reg rst1;
always @(posedge sys_clk) rst0 <= resetin;
always @(posedge sys_clk) rst1 <= rst0;
/* Debounce it
* and generate power-on reset.
*/
reg [19:0] rst_debounce;
reg sys_rst;
initial rst_debounce <= 20'hFFFFF;
initial sys_rst <= 1'b1;
always @(posedge sys_clk) begin
if(rst1 | hard_reset)
rst_debounce <= 20'hFFFFF;
else if(rst_debounce != 20'd0)
rst_debounce <= rst_debounce - 20'd1;
sys_rst <= rst_debounce != 20'd0;
end
`else
wire sys_rst;
assign sys_rst = resetin;
`endif
//------------------------------------------------------------------
// Wishbone master wires
//------------------------------------------------------------------
wire [31:0] cpuibus_adr,
cpudbus_adr;
wire [2:0] cpuibus_cti,
cpudbus_cti;
wire [31:0] cpuibus_dat_r,
cpudbus_dat_r,
cpudbus_dat_w;
wire [3:0] cpudbus_sel;
wire cpudbus_we;
wire cpuibus_cyc,
cpudbus_cyc;
wire cpuibus_stb,
cpudbus_stb;
wire cpuibus_ack,
cpudbus_ack;
//------------------------------------------------------------------
// Wishbone slave wires
//------------------------------------------------------------------
wire [31:0] brg_adr,
bram_adr,
csrbrg_adr;
wire [2:0] brg_cti,
bram_cti;
wire [31:0] bram_dat_r,
bram_dat_w,
csrbrg_dat_r,
csrbrg_dat_w;
wire [3:0] bram_sel;
wire bram_we,
csrbrg_we,
aceusb_we;
wire bram_cyc,
csrbrg_cyc;
wire bram_stb,
csrbrg_stb;
wire bram_ack,
csrbrg_ack;
//---------------------------------------------------------------------------
// Wishbone switch
//---------------------------------------------------------------------------
conbus #(
.s_addr_w(3),
.s0_addr(3'b000), // bram 0x00000000
.s1_addr(3'b001), // free 0x20000000
.s2_addr(3'b010), // free 0x40000000
.s3_addr(3'b100), // CSR bridge 0x80000000
.s4_addr(3'b101) // free 0xa0000000
) conbus (
.sys_clk(sys_clk),
.sys_rst(sys_rst),
// Master 0
.m0_dat_i(32'hx),
.m0_dat_o(cpuibus_dat_r),
.m0_adr_i(cpuibus_adr),
.m0_cti_i(cpuibus_cti),
.m0_we_i(1'b0),
.m0_sel_i(4'hf),
.m0_cyc_i(cpuibus_cyc),
.m0_stb_i(cpuibus_stb),
.m0_ack_o(cpuibus_ack),
// Master 1
.m1_dat_i(cpudbus_dat_w),
.m1_dat_o(cpudbus_dat_r),
.m1_adr_i(cpudbus_adr),
.m1_cti_i(cpudbus_cti),
.m1_we_i(cpudbus_we),
.m1_sel_i(cpudbus_sel),
.m1_cyc_i(cpudbus_cyc),
.m1_stb_i(cpudbus_stb),
.m1_ack_o(cpudbus_ack),
// Master 2
.m2_dat_i(32'bx),
.m2_dat_o(),
.m2_adr_i(32'bx),
.m2_cti_i(3'bx),
.m2_we_i(1'bx),
.m2_sel_i(4'bx),
.m2_cyc_i(1'b0),
.m2_stb_i(1'b0),
.m2_ack_o(),
// Master 3
.m3_dat_i(32'bx),
.m3_dat_o(),
.m3_adr_i(32'bx),
.m3_cti_i(3'bx),
.m3_we_i(1'bx),
.m3_sel_i(4'bx),
.m3_cyc_i(1'b0),
.m3_stb_i(1'b0),
.m3_ack_o(),
// Master 4
.m4_dat_i(32'bx),
.m4_dat_o(),
.m4_adr_i(32'bx),
.m4_cti_i(3'bx),
.m4_we_i(1'bx),
.m4_sel_i(4'bx),
.m4_cyc_i(1'b0),
.m4_stb_i(1'b0),
.m4_ack_o(),
// Slave 0
.s0_dat_i(bram_dat_r),
.s0_dat_o(bram_dat_w),
.s0_adr_o(bram_adr),
.s0_cti_o(bram_cti),
.s0_sel_o(bram_sel),
.s0_we_o(bram_we),
.s0_cyc_o(bram_cyc),
.s0_stb_o(bram_stb),
.s0_ack_i(bram_ack),
// Slave 1
.s1_dat_i(32'bx),
.s1_adr_o(),
.s1_cyc_o(),
.s1_stb_o(),
.s1_ack_i(1'b0),
// Slave 2
.s2_dat_i(32'bx),
.s2_dat_o(),
.s2_adr_o(),
.s2_cti_o(),
.s2_sel_o(),
.s2_we_o(),
.s2_cyc_o(),
.s2_stb_o(),
.s2_ack_i(1'b0),
// Slave 3
.s3_dat_i(csrbrg_dat_r),
.s3_dat_o(csrbrg_dat_w),
.s3_adr_o(csrbrg_adr),
.s3_we_o(csrbrg_we),
.s3_cyc_o(csrbrg_cyc),
.s3_stb_o(csrbrg_stb),
.s3_ack_i(csrbrg_ack),
// Slave 4
.s4_dat_i(32'bx),
.s4_dat_o(),
.s4_adr_o(),
.s4_we_o(),
.s4_cyc_o(),
.s4_stb_o(),
.s4_ack_i(1'b0)
);
//------------------------------------------------------------------
// CSR bus
//------------------------------------------------------------------
wire [13:0] csr_a;
wire csr_we;
wire [31:0] csr_dw;
wire [31:0] csr_dr_uart,
csr_dr_sysctl;
//---------------------------------------------------------------------------
// WISHBONE to CSR bridge
//---------------------------------------------------------------------------
csrbrg csrbrg(
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.wb_adr_i(csrbrg_adr),
.wb_dat_i(csrbrg_dat_w),
.wb_dat_o(csrbrg_dat_r),
.wb_cyc_i(csrbrg_cyc),
.wb_stb_i(csrbrg_stb),
.wb_we_i(csrbrg_we),
.wb_ack_o(csrbrg_ack),
.csr_a(csr_a),
.csr_we(csr_we),
.csr_do(csr_dw),
/* combine all slave->master data lines with an OR */
.csr_di(
csr_dr_uart
|csr_dr_sysctl
)
);
//---------------------------------------------------------------------------
// Interrupts
//---------------------------------------------------------------------------
wire gpio_irq;
wire timer0_irq;
wire timer1_irq;
wire uartrx_irq;
wire uarttx_irq;
wire [31:0] cpu_interrupt;
assign cpu_interrupt = {27'd0,
uarttx_irq,
uartrx_irq,
timer1_irq,
timer0_irq,
gpio_irq
};
//---------------------------------------------------------------------------
// LM32 CPU
//---------------------------------------------------------------------------
lm32_top cpu(
.clk_i(sys_clk),
.rst_i(sys_rst),
.interrupt(cpu_interrupt),
.I_ADR_O(cpuibus_adr),
.I_DAT_I(cpuibus_dat_r),
.I_DAT_O(),
.I_SEL_O(),
.I_CYC_O(cpuibus_cyc),
.I_STB_O(cpuibus_stb),
.I_ACK_I(cpuibus_ack),
.I_WE_O(),
.I_CTI_O(cpuibus_cti),
.I_LOCK_O(),
.I_BTE_O(),
.I_ERR_I(1'b0),
.I_RTY_I(1'b0),
.D_ADR_O(cpudbus_adr),
.D_DAT_I(cpudbus_dat_r),
.D_DAT_O(cpudbus_dat_w),
.D_SEL_O(cpudbus_sel),
.D_CYC_O(cpudbus_cyc),
.D_STB_O(cpudbus_stb),
.D_ACK_I(cpudbus_ack),
.D_WE_O (cpudbus_we),
.D_CTI_O(cpudbus_cti),
.D_LOCK_O(),
.D_BTE_O(),
.D_ERR_I(1'b0),
.D_RTY_I(1'b0)
);
//---------------------------------------------------------------------------
// BRAM
//---------------------------------------------------------------------------
bram #(
.adr_width(14)
) bram (
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.wb_adr_i(bram_adr),
.wb_dat_o(bram_dat_r),
.wb_dat_i(bram_dat_w),
.wb_sel_i(bram_sel),
.wb_stb_i(bram_stb),
.wb_cyc_i(bram_cyc),
.wb_ack_o(bram_ack),
.wb_we_i(bram_we)
);
//---------------------------------------------------------------------------
// UART
//---------------------------------------------------------------------------
uart #(
.csr_addr(4'h0),
.clk_freq(`CLOCK_FREQUENCY),
.baud(`BAUD_RATE)
) uart (
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.csr_a(csr_a),
.csr_we(csr_we),
.csr_di(csr_dw),
.csr_do(csr_dr_uart),
.rx_irq(uartrx_irq),
.tx_irq(uarttx_irq),
.uart_rxd(uart_rxd),
.uart_txd(uart_txd)
);
//---------------------------------------------------------------------------
// System Controller
//---------------------------------------------------------------------------
wire [13:0] gpio_outputs;
sysctl #(
.csr_addr(4'h1),
.ninputs(3),
.noutputs(2),
.systemid(32'h53504543) /* SPEC */
) sysctl (
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.gpio_irq(gpio_irq),
.timer0_irq(timer0_irq),
.timer1_irq(timer1_irq),
.csr_a(csr_a),
.csr_we(csr_we),
.csr_di(csr_dw),
.csr_do(csr_dr_sysctl),
.gpio_inputs(btn),
.gpio_outputs(led),
.hard_reset(hard_reset)
);
endmodule
BOARD_SRC=$(wildcard $(BOARD_DIR)/*.v)
CONBUS_SRC=$(wildcard $(CORES_DIR)/conbus/rtl/*.v)
LM32_SRC= \
$(CORES_DIR)/lm32/rtl/lm32_cpu.v \
$(CORES_DIR)/lm32/rtl/lm32_instruction_unit.v \
$(CORES_DIR)/lm32/rtl/lm32_decoder.v \
$(CORES_DIR)/lm32/rtl/lm32_load_store_unit.v \
$(CORES_DIR)/lm32/rtl/lm32_adder.v \
$(CORES_DIR)/lm32/rtl/lm32_addsub.v \
$(CORES_DIR)/lm32/rtl/lm32_logic_op.v \
$(CORES_DIR)/lm32/rtl/lm32_shifter.v \
$(CORES_DIR)/lm32/rtl/lm32_interrupt.v \
$(CORES_DIR)/lm32/rtl/lm32_top.v
CSRBRG_SRC=$(wildcard $(CORES_DIR)/csrbrg/rtl/*.v)
BRAM_SRC=$(wildcard $(CORES_DIR)/bram/rtl/*.v)
UART_SRC=$(wildcard $(CORES_DIR)/uart/rtl/*.v)
SYSCTL_SRC=$(wildcard $(CORES_DIR)/sysctl/rtl/*.v)
CORES_SRC=$(CONBUS_SRC) $(LM32_SRC) $(CSRBRG_SRC) $(BRAM_SRC) $(UART_SRC) $(SYSCTL_SRC)
BOARD_DIR=../rtl
CORES_DIR=../../../cores
include ../sources.mak
SRC=$(BOARD_SRC) $(CORES_SRC)
all: build/system.bit
build/system.ucf: common.ucf xst.ucf
cat common.ucf xst.ucf > build/system.ucf
build/system.prj: $(SRC)
rm -f build/system.prj
for i in `echo $^`; do \
echo "verilog work ../$$i" >> build/system.prj; \
done
build/system.ngc: build/system.prj
cd build && xst -ifn ../system.xst
build/system.ngd: build/system.ngc build/system.ucf
cd build && ngdbuild -uc system.ucf system.ngc
include common.mak
timing: build/system-routed.twr
load: build/system.bit
cd build && impact -batch ../load.cmd
build/system.ncd: build/system.ngd
cd build && map -ol high -w system.ngd
build/system-routed.ncd: build/system.ncd
cd build && par -ol high -w system.ncd system-routed.ncd
build/system.bit: build/system-routed.ncd
cd build && bitgen -w system-routed.ncd system.bit
build/system-routed.twr: build/system-routed.ncd
cd build && trce -v 10 system-routed.ncd system.pcf
clean:
rm -rf build/*
.PHONY: timing usage load clean
# ==== Clock input ====
NET "clkin" TNM_NET = CLK_125MHZ;
TIMESPEC TS_CLK_125MHZ = PERIOD CLK_125MHZ 8 ns;
setMode -bscan
setCable -p auto
identify
assignfile -p 1 -file system.bit
program -p 1
quit
run
-ifn system.prj
-top system
-ifmt MIXED
-opt_mode SPEED
-opt_level 2
-ofn system.ngc
-p xc6slx45t-fgg484-2
TEX=bram.tex
DVI=$(TEX:.tex=.dvi)
PS=$(TEX:.tex=.ps)
PDF=$(TEX:.tex=.pdf)
AUX=$(TEX:.tex=.aux)
LOG=$(TEX:.tex=.log)
all: $(PDF)
%.dvi: %.tex
latex $<
%.ps: %.dvi
dvips $<
%.pdf: %.ps
ps2pdf $<
clean:
rm -f $(DVI) $(PS) $(PDF) $(AUX) $(LOG)
.PHONY: clean
\documentclass[a4paper,11pt]{article}
\usepackage{fullpage}
\usepackage[latin1]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[normalem]{ulem}
\usepackage[english]{babel}
\usepackage{listings,babel}
\lstset{breaklines=true,basicstyle=\ttfamily}
\usepackage{graphicx}
\usepackage{moreverb}
\usepackage{url}
\title{Wishbone Block RAM}
\author{S\'ebastien Bourdeauducq}
\date{December 2009}
\begin{document}
\setlength{\parindent}{0pt}
\setlength{\parskip}{5pt}
\maketitle{}
\section{Specifications}
This core creates 32-bit storage RAM on the Wishbone bus by using FPGA Block RAM.
Byte-wide writes are supported. Burst access is not supported.
The typical use case is to provide initial memory for softcore CPUs.
\section{Using the core}
You should specify the block RAM storage depth, in bytes, by using the \verb!adr_width! parameter.
\section*{Copyright notice}
Copyright \copyright 2007-2009 S\'ebastien Bourdeauducq. \\
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the LICENSE.FDL file at the root of the Milkymist source distribution.
\end{document}
/*
* Milkymist VJ SoC
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
module bram #(
parameter adr_width = 11 // in bytes
) (
input sys_clk,
input sys_rst,
input wb_stb_i,
input wb_cyc_i,
input wb_we_i,
output reg wb_ack_o,
input [31:0] wb_adr_i,
output [31:0] wb_dat_o,
input [31:0] wb_dat_i,
input [3:0] wb_sel_i
);
//-----------------------------------------------------------------
// Storage depth in 32 bit words
//-----------------------------------------------------------------
parameter word_width = adr_width - 2;
parameter word_depth = (1 << word_width);
//-----------------------------------------------------------------
// Actual RAM
//-----------------------------------------------------------------
reg [7:0] ram0 [0:word_depth-1];
reg [7:0] ram1 [0:word_depth-1];
reg [7:0] ram2 [0:word_depth-1];
reg [7:0] ram3 [0:word_depth-1];
wire [word_width-1:0] adr;
wire [7:0] ram0di;
wire ram0we;
wire [7:0] ram1di;
wire ram1we;
wire [7:0] ram2di;
wire ram2we;
wire [7:0] ram3di;
wire ram3we;
reg [7:0] ram0do;
reg [7:0] ram1do;
reg [7:0] ram2do;
reg [7:0] ram3do;
always @(posedge sys_clk) begin
if(ram0we)
ram0[adr] <= ram0di;
ram0do <= ram0[adr];
end
always @(posedge sys_clk) begin
if(ram1we)
ram1[adr] <= ram1di;
ram1do <= ram1[adr];
end
always @(posedge sys_clk) begin
if(ram2we)
ram2[adr] <= ram2di;
ram2do <= ram2[adr];
end
always @(posedge sys_clk) begin
if(ram3we)
ram3[adr] <= ram3di;
ram3do <= ram3[adr];
end
assign ram0we = wb_cyc_i & wb_stb_i & wb_we_i & wb_sel_i[0];
assign ram1we = wb_cyc_i & wb_stb_i & wb_we_i & wb_sel_i[1];
assign ram2we = wb_cyc_i & wb_stb_i & wb_we_i & wb_sel_i[2];
assign ram3we = wb_cyc_i & wb_stb_i & wb_we_i & wb_sel_i[3];
assign ram0di = wb_dat_i[7:0];
assign ram1di = wb_dat_i[15:8];
assign ram2di = wb_dat_i[23:16];
assign ram3di = wb_dat_i[31:24];
assign wb_dat_o = {ram3do, ram2do, ram1do, ram0do};
assign adr = wb_adr_i[adr_width-1:2];
always @(posedge sys_clk) begin
if(sys_rst)
wb_ack_o <= 1'b0;
else begin
if(wb_cyc_i & wb_stb_i)
wb_ack_o <= ~wb_ack_o;
else
wb_ack_o <= 1'b0;
end
end
endmodule
TEX=conbus.tex
DVI=$(TEX:.tex=.dvi)
PS=$(TEX:.tex=.ps)
PDF=$(TEX:.tex=.pdf)
AUX=$(TEX:.tex=.aux)
LOG=$(TEX:.tex=.log)
all: $(PDF)
%.dvi: %.tex
latex $<
%.ps: %.dvi
dvips $<
%.pdf: %.ps
ps2pdf $<
clean:
rm -f $(DVI) $(PS) $(PDF) $(AUX) $(LOG)
.PHONY: clean
\documentclass[a4paper,11pt]{article}
\usepackage{fullpage}
\usepackage[latin1]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[normalem]{ulem}
\usepackage[english]{babel}
\usepackage{listings,babel}
\lstset{breaklines=true,basicstyle=\ttfamily}
\usepackage{graphicx}
\usepackage{moreverb}
\usepackage{url}
\title{Wishbone bus arbiter and address decoder}
\author{S\'ebastien Bourdeauducq}
\date{December 2009}
\begin{document}
\setlength{\parindent}{0pt}
\setlength{\parskip}{5pt}
\maketitle{}
\section{Specifications}
This core allows up to several masters to communicate with up to several slaves on a shared Wishbone bus.
It takes care of bus arbitration and remapping of the slave base addresses. It is very simple and does not take care of priorities. Scheduling occurs when a master releases the bus, and then the next master which requested the bus takes ownership.
It is based on \verb!wb_conbus! from OpenCores.
\section{Using the core}
All parameters and ports should be self-explanatory. No special care should be taken.
\section*{Copyright notice}
Copyright \copyright 2007-2009 S\'ebastien Bourdeauducq. \\
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the LICENSE.FDL file at the root of the Milkymist source distribution.
\end{document}
/*
* Wishbone Arbiter and Address Decoder
* Copyright (C) 2008, 2009, 2010 Sebastien Bourdeauducq
* Copyright (C) 2000 Johny Chi - chisuhua@yahoo.com.cn
* This file is part of Milkymist.
*
* This source file may be used and distributed without
* restriction provided that this copyright statement is not
* removed from the file and that any derivative work contains
* the original copyright notice and the associated disclaimer.
*
* This source file is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any
* later version.
*
* This source is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this source; if not, download it
* from http://www.opencores.org/lgpl.shtml.
*/
module conbus #(
parameter s_addr_w = 4,
parameter s0_addr = 4'h0,
parameter s1_addr = 4'h1,
parameter s2_addr = 4'h2,
parameter s3_addr = 4'h3,
parameter s4_addr = 4'h4,
parameter s5_addr = 4'h5
) (
input sys_clk,
input sys_rst,
// Master 0 Interface
input [31:0] m0_dat_i,
output [31:0] m0_dat_o,
input [31:0] m0_adr_i,
input [2:0] m0_cti_i,
input [3:0] m0_sel_i,
input m0_we_i,
input m0_cyc_i,
input m0_stb_i,
output m0_ack_o,
// Master 1 Interface
input [31:0] m1_dat_i,
output [31:0] m1_dat_o,
input [31:0] m1_adr_i,
input [2:0] m1_cti_i,
input [3:0] m1_sel_i,
input m1_we_i,
input m1_cyc_i,
input m1_stb_i,
output m1_ack_o,
// Master 2 Interface
input [31:0] m2_dat_i,
output [31:0] m2_dat_o,
input [31:0] m2_adr_i,
input [2:0] m2_cti_i,
input [3:0] m2_sel_i,
input m2_we_i,
input m2_cyc_i,
input m2_stb_i,
output m2_ack_o,
// Master 3 Interface
input [31:0] m3_dat_i,
output [31:0] m3_dat_o,
input [31:0] m3_adr_i,
input [2:0] m3_cti_i,
input [3:0] m3_sel_i,
input m3_we_i,
input m3_cyc_i,
input m3_stb_i,
output m3_ack_o,
// Master 4 Interface
input [31:0] m4_dat_i,
output [31:0] m4_dat_o,
input [31:0] m4_adr_i,
input [2:0] m4_cti_i,
input [3:0] m4_sel_i,
input m4_we_i,
input m4_cyc_i,
input m4_stb_i,
output m4_ack_o,
// Master 5 Interface
input [31:0] m5_dat_i,
output [31:0] m5_dat_o,
input [31:0] m5_adr_i,
input [2:0] m5_cti_i,
input [3:0] m5_sel_i,
input m5_we_i,
input m5_cyc_i,
input m5_stb_i,
output m5_ack_o,
// Slave 0 Interface
input [31:0] s0_dat_i,
output [31:0] s0_dat_o,
output [31:0] s0_adr_o,
output [2:0] s0_cti_o,
output [3:0] s0_sel_o,
output s0_we_o,
output s0_cyc_o,
output s0_stb_o,
input s0_ack_i,
// Slave 1 Interface
input [31:0] s1_dat_i,
output [31:0] s1_dat_o,
output [31:0] s1_adr_o,
output [2:0] s1_cti_o,
output [3:0] s1_sel_o,
output s1_we_o,
output s1_cyc_o,
output s1_stb_o,
input s1_ack_i,
// Slave 2 Interface
input [31:0] s2_dat_i,
output [31:0] s2_dat_o,
output [31:0] s2_adr_o,
output [2:0] s2_cti_o,
output [3:0] s2_sel_o,
output s2_we_o,
output s2_cyc_o,
output s2_stb_o,
input s2_ack_i,
// Slave 3 Interface
input [31:0] s3_dat_i,
output [31:0] s3_dat_o,
output [31:0] s3_adr_o,
output [2:0] s3_cti_o,
output [3:0] s3_sel_o,
output s3_we_o,
output s3_cyc_o,
output s3_stb_o,
input s3_ack_i,
// Slave 4 Interface
input [31:0] s4_dat_i,
output [31:0] s4_dat_o,
output [31:0] s4_adr_o,
output [2:0] s4_cti_o,
output [3:0] s4_sel_o,
output s4_we_o,
output s4_cyc_o,
output s4_stb_o,
input s4_ack_i,
// Slave 5 Interface
input [31:0] s5_dat_i,
output [31:0] s5_dat_o,
output [31:0] s5_adr_o,
output [2:0] s5_cti_o,
output [3:0] s5_sel_o,
output s5_we_o,
output s5_cyc_o,
output s5_stb_o,
input s5_ack_i
);
// address + CTI + data + byte select
// + cyc + we + stb
`define mbusw_ls 32 + 3 + 32 + 4 + 3
wire [5:0] slave_sel;
wire [5:0] gnt;
wire [`mbusw_ls -1:0] i_bus_m; // internal shared bus, master data and control to slave
wire [31:0] i_dat_s; // internal shared bus, slave data to master
wire i_bus_ack; // internal shared bus, ack signal
// master 0
assign m0_dat_o = i_dat_s;
assign m0_ack_o = i_bus_ack & gnt[0];
// master 1
assign m1_dat_o = i_dat_s;
assign m1_ack_o = i_bus_ack & gnt[1];
// master 2
assign m2_dat_o = i_dat_s;
assign m2_ack_o = i_bus_ack & gnt[2];
// master 3
assign m3_dat_o = i_dat_s;
assign m3_ack_o = i_bus_ack & gnt[3];
// master 4
assign m4_dat_o = i_dat_s;
assign m4_ack_o = i_bus_ack & gnt[4];
// master 5
assign m5_dat_o = i_dat_s;
assign m5_ack_o = i_bus_ack & gnt[5];
assign i_bus_ack = s0_ack_i | s1_ack_i | s2_ack_i | s3_ack_i | s4_ack_i | s5_ack_i;
// slave 0
assign {s0_adr_o, s0_cti_o, s0_sel_o, s0_dat_o, s0_we_o, s0_cyc_o} = i_bus_m[`mbusw_ls -1:1];
assign s0_stb_o = i_bus_m[1] & i_bus_m[0] & slave_sel[0]; // stb_o = cyc_i & stb_i & slave_sel
// slave 1
assign {s1_adr_o, s1_cti_o, s1_sel_o, s1_dat_o, s1_we_o, s1_cyc_o} = i_bus_m[`mbusw_ls -1:1];
assign s1_stb_o = i_bus_m[1] & i_bus_m[0] & slave_sel[1];
// slave 2
assign {s2_adr_o, s2_cti_o, s2_sel_o, s2_dat_o, s2_we_o, s2_cyc_o} = i_bus_m[`mbusw_ls -1:1];
assign s2_stb_o = i_bus_m[1] & i_bus_m[0] & slave_sel[2];
// slave 3
assign {s3_adr_o, s3_cti_o, s3_sel_o, s3_dat_o, s3_we_o, s3_cyc_o} = i_bus_m[`mbusw_ls -1:1];
assign s3_stb_o = i_bus_m[1] & i_bus_m[0] & slave_sel[3];
// slave 4
assign {s4_adr_o, s4_cti_o, s4_sel_o, s4_dat_o, s4_we_o, s4_cyc_o} = i_bus_m[`mbusw_ls -1:1];
assign s4_stb_o = i_bus_m[1] & i_bus_m[0] & slave_sel[4];
// slave 5
assign {s5_adr_o, s5_cti_o, s5_sel_o, s5_dat_o, s5_we_o, s5_cyc_o} = i_bus_m[`mbusw_ls -1:1];
assign s5_stb_o = i_bus_m[1] & i_bus_m[0] & slave_sel[5];
assign i_bus_m =
({`mbusw_ls{gnt[0]}} & {m0_adr_i, m0_cti_i, m0_sel_i, m0_dat_i, m0_we_i, m0_cyc_i, m0_stb_i})
|({`mbusw_ls{gnt[1]}} & {m1_adr_i, m1_cti_i, m1_sel_i, m1_dat_i, m1_we_i, m1_cyc_i, m1_stb_i})
|({`mbusw_ls{gnt[2]}} & {m2_adr_i, m2_cti_i, m2_sel_i, m2_dat_i, m2_we_i, m2_cyc_i, m2_stb_i})
|({`mbusw_ls{gnt[3]}} & {m3_adr_i, m3_cti_i, m3_sel_i, m3_dat_i, m3_we_i, m3_cyc_i, m3_stb_i})
|({`mbusw_ls{gnt[4]}} & {m4_adr_i, m4_cti_i, m4_sel_i, m4_dat_i, m4_we_i, m4_cyc_i, m4_stb_i})
|({`mbusw_ls{gnt[5]}} & {m5_adr_i, m5_cti_i, m5_sel_i, m5_dat_i, m5_we_i, m5_cyc_i, m5_stb_i});
assign i_dat_s =
({32{slave_sel[ 0]}} & s0_dat_i)
|({32{slave_sel[ 1]}} & s1_dat_i)
|({32{slave_sel[ 2]}} & s2_dat_i)
|({32{slave_sel[ 3]}} & s3_dat_i)
|({32{slave_sel[ 4]}} & s4_dat_i)
|({32{slave_sel[ 5]}} & s5_dat_i);
wire [5:0] req = {m5_cyc_i, m4_cyc_i, m3_cyc_i, m2_cyc_i, m1_cyc_i, m0_cyc_i};
conbus_arb conbus_arb(
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.req(req),
.gnt(gnt)
);
assign slave_sel[0] = (i_bus_m[`mbusw_ls-1 : `mbusw_ls-s_addr_w] == s0_addr);
assign slave_sel[1] = (i_bus_m[`mbusw_ls-1 : `mbusw_ls-s_addr_w] == s1_addr);
assign slave_sel[2] = (i_bus_m[`mbusw_ls-1 : `mbusw_ls-s_addr_w] == s2_addr);
assign slave_sel[3] = (i_bus_m[`mbusw_ls-1 : `mbusw_ls-s_addr_w] == s3_addr);
assign slave_sel[4] = (i_bus_m[`mbusw_ls-1 : `mbusw_ls-s_addr_w] == s4_addr);
assign slave_sel[5] = (i_bus_m[`mbusw_ls-1 : `mbusw_ls-s_addr_w] == s5_addr);
endmodule
/*
* Milkymist VJ SoC
* Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
module conbus_arb(
input sys_clk,
input sys_rst,
input [5:0] req,
output [5:0] gnt
);
parameter [5:0] grant0 = 6'b000001,
grant1 = 6'b000010,
grant2 = 6'b000100,
grant3 = 6'b001000,
grant4 = 6'b010000,
grant5 = 6'b100000;
reg [5:0] state;
reg [5:0] next_state;
assign gnt = state;
always @(posedge sys_clk) begin
if(sys_rst)
state <= grant0;
else
state <= next_state;
end
always @(*) begin
next_state = state;
case(state)
grant0: begin
if(~req[0]) begin
if(req[1]) next_state = grant1;
else if(req[2]) next_state = grant2;
else if(req[3]) next_state = grant3;
else if(req[4]) next_state = grant4;
else if(req[5]) next_state = grant5;
end
end
grant1: begin
if(~req[1]) begin
if(req[2]) next_state = grant2;
else if(req[3]) next_state = grant3;
else if(req[4]) next_state = grant4;
else if(req[5]) next_state = grant5;
else if(req[0]) next_state = grant0;
end
end
grant2: begin
if(~req[2]) begin
if(req[3]) next_state = grant3;
else if(req[4]) next_state = grant4;
else if(req[5]) next_state = grant5;
else if(req[0]) next_state = grant0;
else if(req[1]) next_state = grant1;
end
end
grant3: begin
if(~req[3]) begin
if(req[4]) next_state = grant4;
else if(req[5]) next_state = grant5;
else if(req[0]) next_state = grant0;
else if(req[1]) next_state = grant1;
else if(req[2]) next_state = grant2;
end
end
grant4: begin
if(~req[4]) begin
if(req[5]) next_state = grant5;
else if(req[0]) next_state = grant0;
else if(req[1]) next_state = grant1;
else if(req[2]) next_state = grant2;
else if(req[3]) next_state = grant3;
end
end
grant5: begin
if(~req[5]) begin
if(req[0]) next_state = grant0;
else if(req[1]) next_state = grant1;
else if(req[2]) next_state = grant2;
else if(req[3]) next_state = grant3;
else if(req[4]) next_state = grant4;
end
end
endcase
end
endmodule
SOURCES=tb_conbus.v master.v slave.v $(wildcard ../rtl/*.v)
all: tb_conbus
sim: tb_conbus
./tb_conbus
cversim: $(SOURCES)
cver $(SOURCES)
clean:
rm -f tb_conbus verilog.log
tb_conbus: $(SOURCES)
iverilog -o tb_conbus $(SOURCES)
.PHONY: clean sim cversim
/*
* Milkymist VJ SoC
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
module master #(
parameter id = 0,
parameter nreads = 128,
parameter nwrites = 128,
parameter p = 4
) (
input sys_clk,
input sys_rst,
output reg [31:0] dat_w,
input [31:0] dat_r,
output reg [31:0] adr,
output [2:0] cti,
output reg we,
output reg [3:0] sel,
output cyc,
output stb,
input ack,
output reg tend
);
integer rcounter;
integer wcounter;
reg active;
assign cyc = active;
assign stb = active;
assign cti = 0;
always @(posedge sys_clk) begin
if(sys_rst) begin
dat_w = 0;
adr = 0;
we = 0;
sel = 0;
active = 0;
rcounter = 0;
wcounter = 0;
tend = 0;
end else begin
if(ack) begin
if(~active)
$display("[M%d] Spurious ack", id);
else begin
if(we)
$display("[M%d] Ack W: %x:%x [%x]", id, adr, dat_w, sel);
else
$display("[M%d] Ack R: %x:%x [%x]", id, adr, dat_r, sel);
end
active = 1'b0;
end else if(~active) begin
if(($random % p) == 0) begin
adr = $random;
adr = adr % 5;
adr = (adr << (32-3)) + id;
sel = sel + 1;
active = 1'b1;
if(($random % 2) == 0) begin
/* Read */
we = 1'b0;
rcounter = rcounter + 1;
end else begin
/* Write */
we = 1'b1;
dat_w = ($random << 16) + id;
wcounter = wcounter + 1;
end
end
end
tend = (rcounter >= nreads) && (wcounter >= nwrites);
end
end
endmodule
/*
* Milkymist VJ SoC
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
module slave #(
parameter id = 0,
parameter p = 3
) (
input sys_clk,
input sys_rst,
input [31:0] dat_w,
output reg [31:0] dat_r,
input [31:0] adr,
input [2:0] cti,
input we,
input [3:0] sel,
input cyc,
input stb,
output reg ack
);
always @(posedge sys_clk) begin
if(sys_rst) begin
dat_r = 0;
ack = 0;
end else begin
if(cyc & stb & ~ack) begin
if(($random % p) == 0) begin
ack = 1;
if(~we)
dat_r = ($random << 16) + id;
if(we)
$display("[S%d] Ack W: %x:%x [%x]", id, adr, dat_w, sel);
else
$display("[S%d] Ack R: %x:%x [%x]", id, adr, dat_r, sel);
end
end else
ack = 0;
end
end
endmodule
/*
* Milkymist VJ SoC
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
module tb_conbus();
reg sys_rst;
reg sys_clk;
//------------------------------------------------------------------
// Wishbone master wires
//------------------------------------------------------------------
wire [31:0] m0_adr,
m1_adr,
m2_adr,
m3_adr,
m4_adr;
wire [2:0] m0_cti,
m1_cti,
m2_cti,
m3_cti,
m4_cti;
wire [31:0] m0_dat_r,
m0_dat_w,
m1_dat_r,
m1_dat_w,
m2_dat_r,
m2_dat_w,
m3_dat_r,
m3_dat_w,
m4_dat_r,
m4_dat_w;
wire [3:0] m0_sel,
m1_sel,
m2_sel,
m3_sel,
m4_sel;
wire m0_we,
m1_we,
m2_we,
m3_we,
m4_we;
wire m0_cyc,
m1_cyc,
m2_cyc,
m3_cyc,
m4_cyc;
wire m0_stb,
m1_stb,
m2_stb,
m3_stb,
m4_stb;
wire m0_ack,
m1_ack,
m2_ack,
m3_ack,
m4_ack;
//------------------------------------------------------------------
// Wishbone slave wires
//------------------------------------------------------------------
wire [31:0] s0_adr,
s1_adr,
s2_adr,
s3_adr,
s4_adr;
wire [2:0] s0_cti,
s1_cti,
s2_cti,
s3_cti,
s4_cti;
wire [31:0] s0_dat_r,
s0_dat_w,
s1_dat_r,
s1_dat_w,
s2_dat_r,
s2_dat_w,
s3_dat_r,
s3_dat_w,
s4_dat_r,
s4_dat_w;
wire [3:0] s0_sel,
s1_sel,
s2_sel,
s3_sel,
s4_sel;
wire s0_we,
s1_we,
s2_we,
s3_we,
s4_we;
wire s0_cyc,
s1_cyc,
s2_cyc,
s3_cyc,
s4_cyc;
wire s0_stb,
s1_stb,
s2_stb,
s3_stb,
s4_stb;
wire s0_ack,
s1_ack,
s2_ack,
s3_ack,
s4_ack;
//---------------------------------------------------------------------------
// Wishbone switch
//---------------------------------------------------------------------------
conbus #(
.s_addr_w(3),
.s0_addr(3'b000), // 0x00000000
.s1_addr(3'b001), // 0x20000000
.s2_addr(3'b010), // 0x40000000
.s3_addr(3'b011), // 0x60000000
.s4_addr(3'b100) // 0x80000000
) dut (
.sys_clk(sys_clk),
.sys_rst(sys_rst),
// Master 0
.m0_dat_i(m0_dat_w),
.m0_dat_o(m0_dat_r),
.m0_adr_i(m0_adr),
.m0_cti_i(m0_cti),
.m0_we_i(m0_we),
.m0_sel_i(m0_sel),
.m0_cyc_i(m0_cyc),
.m0_stb_i(m0_stb),
.m0_ack_o(m0_ack),
// Master 1
.m1_dat_i(m1_dat_w),
.m1_dat_o(m1_dat_r),
.m1_adr_i(m1_adr),
.m1_cti_i(m1_cti),
.m1_we_i(m1_we),
.m1_sel_i(m1_sel),
.m1_cyc_i(m1_cyc),
.m1_stb_i(m1_stb),
.m1_ack_o(m1_ack),
// Master 2
.m2_dat_i(m2_dat_w),
.m2_dat_o(m2_dat_r),
.m2_adr_i(m2_adr),
.m2_cti_i(m2_cti),
.m2_we_i(m2_we),
.m2_sel_i(m2_sel),
.m2_cyc_i(m2_cyc),
.m2_stb_i(m2_stb),
.m2_ack_o(m2_ack),
// Master 3
.m3_dat_i(m3_dat_w),
.m3_dat_o(m3_dat_r),
.m3_adr_i(m3_adr),
.m3_cti_i(m3_cti),
.m3_we_i(m3_we),
.m3_sel_i(m3_sel),
.m3_cyc_i(m3_cyc),
.m3_stb_i(m3_stb),
.m3_ack_o(m3_ack),
// Master 4
.m4_dat_i(m4_dat_w),
.m4_dat_o(m4_dat_r),
.m4_adr_i(m4_adr),
.m4_cti_i(m4_cti),
.m4_we_i(m4_we),
.m4_sel_i(m4_sel),
.m4_cyc_i(m4_cyc),
.m4_stb_i(m4_stb),
.m4_ack_o(m4_ack),
// Slave 0
.s0_dat_i(s0_dat_r),
.s0_dat_o(s0_dat_w),
.s0_adr_o(s0_adr),
.s0_cti_o(s0_cti),
.s0_sel_o(s0_sel),
.s0_we_o(s0_we),
.s0_cyc_o(s0_cyc),
.s0_stb_o(s0_stb),
.s0_ack_i(s0_ack),
// Slave 1
.s1_dat_i(s1_dat_r),
.s1_dat_o(s1_dat_w),
.s1_adr_o(s1_adr),
.s1_cti_o(s1_cti),
.s1_sel_o(s1_sel),
.s1_we_o(s1_we),
.s1_cyc_o(s1_cyc),
.s1_stb_o(s1_stb),
.s1_ack_i(s1_ack),
// Slave 2
.s2_dat_i(s2_dat_r),
.s2_dat_o(s2_dat_w),
.s2_adr_o(s2_adr),
.s2_cti_o(s2_cti),
.s2_sel_o(s2_sel),
.s2_we_o(s2_we),
.s2_cyc_o(s2_cyc),
.s2_stb_o(s2_stb),
.s2_ack_i(s2_ack),
// Slave 3
.s3_dat_i(s3_dat_r),
.s3_dat_o(s3_dat_w),
.s3_adr_o(s3_adr),
.s3_cti_o(s3_cti),
.s3_sel_o(s3_sel),
.s3_we_o(s3_we),
.s3_cyc_o(s3_cyc),
.s3_stb_o(s3_stb),
.s3_ack_i(s3_ack),
// Slave 4
.s4_dat_i(s4_dat_r),
.s4_dat_o(s4_dat_w),
.s4_adr_o(s4_adr),
.s4_cti_o(s4_cti),
.s4_sel_o(s4_sel),
.s4_we_o(s4_we),
.s4_cyc_o(s4_cyc),
.s4_stb_o(s4_stb),
.s4_ack_i(s4_ack)
);
//---------------------------------------------------------------------------
// Masters
//---------------------------------------------------------------------------
wire m0_end;
master #(
.id(0)
) m0 (
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.dat_w(m0_dat_w),
.dat_r(m0_dat_r),
.adr(m0_adr),
.cti(m0_cti),
.we(m0_we),
.sel(m0_sel),
.cyc(m0_cyc),
.stb(m0_stb),
.ack(m0_ack),
.tend(m0_end)
);
wire m1_end;
master #(
.id(1)
) m1 (
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.dat_w(m1_dat_w),
.dat_r(m1_dat_r),
.adr(m1_adr),
.cti(m1_cti),
.we(m1_we),
.sel(m1_sel),
.cyc(m1_cyc),
.stb(m1_stb),
.ack(m1_ack),
.tend(m1_end)
);
wire m2_end;
master #(
.id(2)
) m2 (
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.dat_w(m2_dat_w),
.dat_r(m2_dat_r),
.adr(m2_adr),
.cti(m2_cti),
.we(m2_we),
.sel(m2_sel),
.cyc(m2_cyc),
.stb(m2_stb),
.ack(m2_ack),
.tend(m2_end)
);
wire m3_end;
master #(
.id(3)
) m3 (
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.dat_w(m3_dat_w),
.dat_r(m3_dat_r),
.adr(m3_adr),
.cti(m3_cti),
.we(m3_we),
.sel(m3_sel),
.cyc(m3_cyc),
.stb(m3_stb),
.ack(m3_ack),
.tend(m3_end)
);
wire m4_end;
master #(
.id(4)
) m4 (
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.dat_w(m4_dat_w),
.dat_r(m4_dat_r),
.adr(m4_adr),
.cti(m4_cti),
.we(m4_we),
.sel(m4_sel),
.cyc(m4_cyc),
.stb(m4_stb),
.ack(m4_ack),
.tend(m4_end)
);
//---------------------------------------------------------------------------
// Slaves
//---------------------------------------------------------------------------
slave #(
.id(0)
) s0 (
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.dat_w(s0_dat_w),
.dat_r(s0_dat_r),
.adr(s0_adr),
.cti(s0_cti),
.we(s0_we),
.sel(s0_sel),
.cyc(s0_cyc),
.stb(s0_stb),
.ack(s0_ack)
);
slave #(
.id(1)
) s1 (
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.dat_w(s1_dat_w),
.dat_r(s1_dat_r),
.adr(s1_adr),
.cti(s1_cti),
.we(s1_we),
.sel(s1_sel),
.cyc(s1_cyc),
.stb(s1_stb),
.ack(s1_ack)
);
slave #(
.id(2)
) s2 (
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.dat_w(s2_dat_w),
.dat_r(s2_dat_r),
.adr(s2_adr),
.cti(s2_cti),
.we(s2_we),
.sel(s2_sel),
.cyc(s2_cyc),
.stb(s2_stb),
.ack(s2_ack)
);
slave #(
.id(3)
) s3 (
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.dat_w(s3_dat_w),
.dat_r(s3_dat_r),
.adr(s3_adr),
.cti(s3_cti),
.we(s3_we),
.sel(s3_sel),
.cyc(s3_cyc),
.stb(s3_stb),
.ack(s3_ack)
);
slave #(
.id(4)
) s4 (
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.dat_w(s4_dat_w),
.dat_r(s4_dat_r),
.adr(s4_adr),
.cti(s4_cti),
.we(s4_we),
.sel(s4_sel),
.cyc(s4_cyc),
.stb(s4_stb),
.ack(s4_ack)
);
initial sys_clk = 1'b0;
always #5 sys_clk = ~sys_clk;
wire all_end = m0_end & m1_end & m2_end & m3_end & m4_end;
always begin
sys_rst = 1'b1;
@(posedge sys_clk);
#1 sys_rst = 1'b0;
@(posedge all_end);
$finish;
end
endmodule
/*
* Milkymist VJ SoC
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
module csrbrg(
input sys_clk,
input sys_rst,
/* WB */
input [31:0] wb_adr_i,
input [31:0] wb_dat_i,
output reg [31:0] wb_dat_o,
input wb_cyc_i,
input wb_stb_i,
input wb_we_i,
output reg wb_ack_o,
/* CSR */
output reg [13:0] csr_a,
output reg csr_we,
output reg [31:0] csr_do,
input [31:0] csr_di
);
/* Datapath: WB <- CSR */
always @(posedge sys_clk) begin
wb_dat_o <= csr_di;
end
/* Datapath: CSR -> WB */
reg next_csr_we;
always @(posedge sys_clk) begin
csr_a <= wb_adr_i[15:2];
csr_we <= next_csr_we;
csr_do <= wb_dat_i;
end
/* Controller */
reg [1:0] state;
reg [1:0] next_state;
parameter IDLE = 2'd0;
parameter DELAYACK1 = 2'd1;
parameter DELAYACK2 = 2'd2;
parameter ACK = 2'd3;
always @(posedge sys_clk) begin
if(sys_rst)
state <= IDLE;
else
state <= next_state;
end
always @(*) begin
next_state = state;
wb_ack_o = 1'b0;
next_csr_we = 1'b0;
case(state)
IDLE: begin
if(wb_cyc_i & wb_stb_i) begin
/* We have a request for us */
next_csr_we = wb_we_i;
if(wb_we_i)
next_state = ACK;
else
next_state = DELAYACK1;
end
end
DELAYACK1: next_state = DELAYACK2;
DELAYACK2: next_state = ACK;
ACK: begin
wb_ack_o = 1'b1;
next_state = IDLE;
end
endcase
end
endmodule
SOURCES=tb_csrbrg.v $(wildcard ../rtl/*.v)
all: sim
sim:
cver $(SOURCES)
clean:
rm -f verilog.log
.PHONY: clean sim
/*
* Milkymist VJ SoC
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
module tb_csrbrg();
reg sys_clk;
reg sys_rst;
reg [31:0] wb_adr_i;
reg [31:0] wb_dat_i;
wire [31:0] wb_dat_o;
reg wb_cyc_i;
reg wb_stb_i;
reg wb_we_i;
wire wb_ack_o;
wire [13:0] csr_a;
wire csr_we;
wire [31:0] csr_do;
reg [31:0] csr_di;
/* 100MHz system clock */
initial sys_clk = 1'b0;
always #5 sys_clk = ~sys_clk;
csrbrg dut(
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.wb_adr_i(wb_adr_i),
.wb_dat_i(wb_dat_i),
.wb_dat_o(wb_dat_o),
.wb_cyc_i(wb_cyc_i),
.wb_stb_i(wb_stb_i),
.wb_we_i(wb_we_i),
.wb_ack_o(wb_ack_o),
/* CSR bus master */
.csr_a(csr_a),
.csr_we(csr_we),
.csr_do(csr_do),
.csr_di(csr_di)
);
task waitclock;
begin
@(posedge sys_clk);
#1;
end
endtask
task wbwrite;
input [31:0] address;
input [31:0] data;
integer i;
begin
wb_adr_i = address;
wb_dat_i = data;
wb_cyc_i = 1'b1;
wb_stb_i = 1'b1;
wb_we_i = 1'b1;
i = 0;
while(~wb_ack_o) begin
i = i+1;
waitclock;
end
waitclock;
$display("WB Write: %x=%x acked in %d clocks", address, data, i);
wb_cyc_i = 1'b0;
wb_stb_i = 1'b0;
wb_we_i = 1'b0;
end
endtask
task wbread;
input [31:0] address;
integer i;
begin
wb_adr_i = address;
wb_cyc_i = 1'b1;
wb_stb_i = 1'b1;
wb_we_i = 1'b0;
i = 0;
while(~wb_ack_o) begin
i = i+1;
waitclock;
end
$display("WB Read : %x=%x acked in %d clocks", address, wb_dat_o, i);
waitclock;
wb_cyc_i = 1'b0;
wb_stb_i = 1'b0;
wb_we_i = 1'b0;
end
endtask
/* Simulate CSR slave */
reg [31:0] csr1;
reg [31:0] csr2;
wire csr_selected = (csr_a[13:10] == 4'ha);
always @(posedge sys_clk) begin
if(csr_selected) begin
if(csr_we) begin
$display("Writing %x to CSR %x", csr_do, csr_a[0]);
case(csr_a[0])
1'b0: csr1 <= csr_do;
1'b1: csr2 <= csr_do;
endcase
end
case(csr_a[0])
1'b0: csr_di <= csr1;
1'b1: csr_di <= csr2;
endcase
end else
/* we must set data to 0 to be able to use a distributed OR topology
* in the slaves->master datapath.
*/
csr_di <= 32'd0;
end
always begin
/* Reset / Initialize our logic */
sys_rst = 1'b1;
wb_adr_i = 32'd0;
wb_dat_i = 32'd0;
wb_cyc_i = 1'b0;
wb_stb_i = 1'b0;
wb_we_i = 1'b0;
waitclock;
sys_rst = 1'b0;
waitclock;
/* Try some transfers */
wbwrite(32'h0000a000, 32'hcafebabe);
wbwrite(32'h0000a004, 32'habadface);
wbread(32'h0000a000);
wbread(32'h0000a004);
$finish;
end
endmodule
* 2009-12-21 Upgrade to LatticeMico32 3.5.
* 2009-11-12 Active-high interrupts (lekernel)
* 2009-07-01 Based on LatticeMico32 core from mico32_72_linux.tar.
(LatticeMico32 v3.3)
H1 {
font-weight:bold;
border-top-style:none;
font-family:Arial, helvetica, sans-serif;
color:#ea6d23;
margin-left:15px;
margin-top:3px;
margin-bottom:10px;
border-bottom-style:Solid;
border-bottom-width:2px;
border-bottom-color:#dbdbdb;
margin-right:0px;
line-height:Normal;
font-size:1em; }
LI.kadov-H1 {
font-weight:bold;
font-family:Arial, helvetica, sans-serif;
color:#ea6d23;
line-height:Normal;
font-size:1em; }
H2 {
font-weight:bold;
x-text-underline:Off;
border-top-style:none;
border-bottom-style:none;
font-family:Arial, helvetica, sans-serif;
color:#ea6d23;
margin-left:15px;
margin-top:12px;
margin-bottom:5px;
font-size:0.84em;
margin-right:0px;
text-decoration:none; }
LI.kadov-H2 {
font-weight:bold;
x-text-underline:Off;
font-family:Arial, helvetica, sans-serif;
color:#ea6d23;
font-size:0.84em;
text-decoration:none; }
P {
margin-top:0pt;
font-family:Verdana, Arial, helvetica, sans-serif;
color:#323232;
font-size:71%;
margin-bottom:8px;
line-height:1.4em;
margin-right:0px;
margin-left:15px; }
LI.kadov-P {
font-family:Verdana, Arial, helvetica, sans-serif;
color:#323232;
font-size:71%;
line-height:1.4em; }
p.Step {
list-style:decimal;
margin-left:0px;
font-size:100%;
margin-bottom:7px;
margin-top:0px; }
LI.kadov-p-CStep {
list-style:decimal;
font-size:100%; }
P.Bullet {
font-size:100%;
list-style:url("image/top-bullet.gif");
margin-bottom:7px;
margin-left:0px;
margin-top:0px; }
LI.kadov-P-CBullet {
font-size:100%;
list-style:url("image/top-bullet.gif"); }
P.NormalIndent {
margin-left:40px; }
LI.kadov-P-CNormalIndent { }
P.BulletIndent {
margin-bottom:2px;
font-size:100%;
margin-left:15pt;
list-style:url("image/secondary-bullet.gif"); }
LI.kadov-P-CBulletIndent {
font-size:100%;
list-style:url("image/secondary-bullet.gif"); }
P.Procedure {
font-style:italic;
font-weight:normal;
x-next-class:Step;
x-next-type:p;
margin-top:12pt;
margin-bottom:5px; }
LI.kadov-P-CProcedure {
font-style:italic;
font-weight:normal; }
P.Note {
margin-top:8pt;
margin-bottom:8pt;
border-top-style:Solid;
border-bottom-style:Solid;
padding-top:4px;
padding-bottom:4px;
border-top-width:1px;
border-bottom-width:1px;
background-color:#ffffff; }
LI.kadov-P-CNote { }
P.NoteIndent {
margin-top:8pt;
margin-bottom:8pt;
border-top-style:Solid;
border-bottom-style:Solid;
padding-top:4px;
padding-bottom:4px;
border-top-width:1px;
border-bottom-width:1px;
background-color:#ffffff;
margin-left:40px; }
LI.kadov-P-CNoteIndent { }
P.Table {
margin-top:4px;
margin-bottom:4px;
margin-right:4px;
margin-left:4px; }
LI.kadov-P-CTable { }
P.Code {
margin-bottom:0px;
line-height:Normal;
font-family:"Courier New" , Courier, monospace; }
LI.kadov-P-CCode {
line-height:Normal;
font-family:"Courier New" , Courier, monospace; }
P.StepBulletFirst {
font-size:100%;
margin-left:15px;
margin-bottom:2px;
list-style:url("image/secondary-bullet.gif"); }
LI.kadov-P-CStepBulletFirst {
font-size:100%;
list-style:url("image/secondary-bullet.gif"); }
BODY {
background-color:#ffffff;
color:#000080;
font-family:Arial, sans-serif; }
P.SeeAlso {
font-weight:bold;
font-style:normal;
x-next-type:P;
color:#ea6d23;
font-family:Arial, helvetica, sans-serif;
margin-left:15px;
margin-top:12px;
margin-bottom:5px;
font-size:0.84em; }
LI.kadov-P-CSeeAlso {
font-weight:bold;
font-style:normal;
color:#ea6d23;
font-family:Arial, helvetica, sans-serif;
font-size:0.84em; }
A:link {
font-weight:bold;
font-style:normal;
color:#003a98;
x-text-underline:Off;
text-decoration:none; }
A:hover {
x-text-underline:Normal;
color:#59add3;
text-decoration:underline; }
A:active {
color:#59add3; }
A:visited {
x-text-underline:Off;
color:#385689;
font-weight:bold;
font-style:normal;
text-decoration:none; }
H1.Home {
x-next-type:P;
border-top-style:none;
border-bottom-style:none;
x-text-underline:Off;
font-size:15pt;
color:#ea6d23;
text-decoration:none; }
LI.kadov-H1-CHome {
x-text-underline:Off;
font-size:15pt;
color:#ea6d23;
text-decoration:none; }
H3 {
margin-left:15px;
margin-top:12px;
margin-bottom:5px;
color:#323232;
font-size:71%;
font-family:Verdana, Arial, helvetica, sans-serif;
margin-right:0px; }
LI.kadov-H3 {
color:#323232;
font-size:71%;
font-family:Verdana, Arial, helvetica, sans-serif; }
P.Title {
font-weight:bold;
font-style:normal;
x-next-type:P;
font-family:Arial, helvetica, sans-serif;
color:#ea6d23;
margin-bottom:10px;
font-size:1.4em;
line-height:Normal;
border-bottom-style:Solid;
border-bottom-width:2px;
border-bottom-color:#dbdbdb;
margin-top:0px; }
LI.kadov-P-CTitle {
font-weight:bold;
font-style:normal;
font-family:Arial, helvetica, sans-serif;
color:#ea6d23;
font-size:1.4em;
line-height:Normal; }
P.Supra {
font-weight:bold;
font-style:normal;
margin-bottom:6pt;
font-family:Arial, helvetica, sans-serif; }
LI.kadov-P-CSupra {
font-weight:bold;
font-style:normal;
font-family:Arial, helvetica, sans-serif; }
OL {
font-size:71%;
font-family:Verdana, Arial, helvetica, sans-serif;
color:#323232; }
UL {
font-size:71%;
font-family:Verdana, Arial, helvetica, sans-serif;
color:#323232; }
P.CodeIndent {
font-family:"Courier New" , Courier, monospace;
margin-left:40px;
margin-bottom:0px;
line-height:Normal; }
LI.kadov-P-CCodeIndent {
font-family:"Courier New" , Courier, monospace;
line-height:Normal; }
H1 {
font-weight:bold;
border-top-style:none;
font-family:Arial, helvetica, sans-serif;
color:#ea6d23;
margin-left:15px;
margin-top:3px;
margin-bottom:10px;
border-bottom-style:Solid;
border-bottom-width:2px;
border-bottom-color:#dbdbdb;
margin-right:1pt;
line-height:Normal;
font-size:1em; }
LI.kadov-H1 {
font-weight:bold;
font-family:Arial, helvetica, sans-serif;
color:#ea6d23;
line-height:Normal;
font-size:1em; }
H2 {
font-weight:bold;
x-text-underline:Off;
border-top-style:none;
border-bottom-style:none;
font-family:Arial, helvetica, sans-serif;
color:#ea6d23;
margin-left:15px;
margin-top:12px;
margin-bottom:5px;
font-size:0.84em;
margin-right:1pt;
text-decoration:none; }
LI.kadov-H2 {
font-weight:bold;
x-text-underline:Off;
font-family:Arial, helvetica, sans-serif;
color:#ea6d23;
font-size:0.84em;
text-decoration:none; }
P {
margin-top:1pt;
font-family:Verdana, Arial, helvetica, sans-serif;
color:#323232;
font-size:71%;
margin-bottom:8px;
line-height:1.4em;
margin-right:1pt;
margin-left:15px; }
LI.kadov-P {
font-family:Verdana, Arial, helvetica, sans-serif;
color:#323232;
font-size:71%;
line-height:1.4em; }
p.Step {
list-style:decimal;
margin-left:1pt;
font-size:100%;
margin-bottom:7px;
margin-top:1pt; }
LI.kadov-p-CStep {
list-style:decimal;
font-size:100%; }
P.Bullet {
font-size:100%;
margin-bottom:7px;
margin-left:1pt;
margin-top:1pt; }
LI.kadov-P-CBullet {
font-size:100%; }
P.NormalIndent {
margin-left:40px; }
LI.kadov-P-CNormalIndent { }
P.BulletIndent {
margin-bottom:2px;
font-size:100%;
margin-left:15pt; }
LI.kadov-P-CBulletIndent {
font-size:100%; }
P.Procedure {
font-style:italic;
font-weight:normal;
x-next-class:Step;
x-next-type:p;
margin-top:12pt;
margin-bottom:5px; }
LI.kadov-P-CProcedure {
font-style:italic;
font-weight:normal; }
P.Note {
margin-top:8pt;
margin-bottom:8pt;
border-top-style:Solid;
border-bottom-style:Solid;
padding-top:4px;
padding-bottom:4px;
border-top-width:1px;
border-bottom-width:1px;
background-color:#ffffff; }
LI.kadov-P-CNote { }
P.NoteIndent {
margin-top:8pt;
margin-bottom:8pt;
border-top-style:Solid;
border-bottom-style:Solid;
padding-top:4px;
padding-bottom:4px;
border-top-width:1px;
border-bottom-width:1px;
background-color:#ffffff;
margin-left:40px; }
LI.kadov-P-CNoteIndent { }
P.Table {
margin-top:4px;
margin-bottom:4px;
margin-right:4px;
margin-left:4px; }
LI.kadov-P-CTable { }
P.Code {
margin-bottom:1pt;
line-height:Normal;
font-family:"Courier New" , Courier, monospace; }
LI.kadov-P-CCode {
line-height:Normal;
font-family:"Courier New" , Courier, monospace; }
P.StepBulletFirst {
font-size:100%;
margin-left:15px;
margin-bottom:2px; }
LI.kadov-P-CStepBulletFirst {
font-size:100%; }
BODY {
background-color:#ffffff;
color:#000080;
font-family:Arial, sans-serif; }
P.SeeAlso {
font-weight:bold;
font-style:normal;
x-next-type:P;
color:#ea6d23;
font-family:Arial, helvetica, sans-serif;
margin-left:15px;
margin-top:12px;
margin-bottom:5px;
font-size:0.84em; }
LI.kadov-P-CSeeAlso {
font-weight:bold;
font-style:normal;
color:#ea6d23;
font-family:Arial, helvetica, sans-serif;
font-size:0.84em; }
A:link {
font-weight:bold;
font-style:normal;
color:#003a98;
x-text-underline:Off;
text-decoration:none; }
A:hover {
x-text-underline:Normal;
color:#59add3;
text-decoration:underline; }
A:active {
color:#59add3; }
A:visited {
x-text-underline:Off;
color:#385689;
font-weight:bold;
font-style:normal;
text-decoration:none; }
H1.Home {
x-next-type:P;
border-top-style:none;
border-bottom-style:none;
x-text-underline:Off;
font-size:15pt;
color:#ea6d23;
text-decoration:none; }
LI.kadov-H1-CHome {
x-text-underline:Off;
font-size:15pt;
color:#ea6d23;
text-decoration:none; }
H3 {
margin-left:15px;
margin-top:12px;
margin-bottom:5px;
color:#323232;
font-size:71%;
font-family:Verdana, Arial, helvetica, sans-serif;
margin-right:1pt;
font-weight:bold; }
LI.kadov-H3 {
color:#323232;
font-size:71%;
font-family:Verdana, Arial, helvetica, sans-serif; }
P.Title {
font-weight:bold;
font-style:normal;
x-next-type:P;
font-family:Arial, helvetica, sans-serif;
color:#ea6d23;
margin-bottom:10px;
font-size:1.4em;
line-height:Normal;
border-bottom-style:Solid;
border-bottom-width:2px;
border-bottom-color:#dbdbdb;
margin-top:1pt; }
LI.kadov-P-CTitle {
font-weight:bold;
font-style:normal;
font-family:Arial, helvetica, sans-serif;
color:#ea6d23;
font-size:1.4em;
line-height:Normal; }
P.Supra {
font-weight:bold;
font-style:normal;
margin-bottom:6pt;
font-family:Arial, helvetica, sans-serif; }
LI.kadov-P-CSupra {
font-weight:bold;
font-style:normal;
font-family:Arial, helvetica, sans-serif; }
OL {
font-size:71%;
font-family:Verdana, Arial, helvetica, sans-serif;
color:#323232; }
UL {
font-size:71%;
font-family:Verdana, Arial, helvetica, sans-serif;
color:#323232; }
P.CodeIndent {
font-family:"Courier New" , Courier, monospace;
margin-left:40px;
margin-bottom:1pt;
line-height:Normal; }
LI.kadov-P-CCodeIndent {
font-family:"Courier New" , Courier, monospace;
line-height:Normal; }
ol ol {
margin-top:1px; }
ol ul {
margin-top:1px; }
ul ul {
margin-top:1px; }
ul ol {
margin-top:1px; }
<!doctype HTML public "-//W3C//DTD HTML 4.0 Frameset//EN">
<html>
<head>
<title>LatticeMico32 processor</title>
<meta http-equiv="content-type" content="text/html; charset=windows-1252">
<meta name="generator" content="RoboHelp by eHelp Corporation www.ehelp.com">
<link rel="stylesheet" href="lever40_ns.css"><script type="text/javascript" language="JavaScript" title="WebHelpSplitCss">
<!--
if (navigator.appName !="Netscape")
{ document.write("<link rel='stylesheet' href='lever40.css'>");}
//-->
</script>
<style>
<!--
body { border-left-style:None; border-right-style:None; border-top-style:None; border-bottom-style:None; }
-->
</style><style type="text/css">
<!--
img_whs1 { border:none; width:29px; height:31px; float:none; border-style:none; }
p.whs2 { font-style:italic; }
table.whs3 { x-cell-content-align:top; height:84px; left:0px; top:114px; width:738px; margin-left:15px; border-spacing:0px; }
col.whs4 { width:93px; }
col.whs5 { width:598px; }
tr.whs6 { x-cell-content-align:top; height:22px; }
td.whs7 { width:93px; padding-right:10px; padding-left:10px; border-left-style:Solid; border-left-color:#c0c0c0; border-top-style:Solid; border-top-color:#c0c0c0; border-right-color:#c0c0c0; border-right-style:Solid; border-bottom-color:#c0c0c0; border-bottom-style:Solid; border-right-width:1px; border-left-width:1px; border-top-width:1px; border-bottom-width:1px; background-color:#dee8f4; }
td.whs8 { width:598px; padding-right:10px; padding-left:10px; border-top-style:Solid; border-top-color:#c0c0c0; border-right-color:#c0c0c0; border-right-style:Solid; border-bottom-color:#c0c0c0; border-bottom-style:Solid; border-top-width:1px; border-bottom-width:1px; border-right-width:1px; background-color:#dee8f4; }
td.whs9 { width:93px; padding-right:10px; padding-left:10px; border-left-color:#c0c0c0; border-left-width:1px; border-left-style:Solid; border-right-color:#c0c0c0; border-right-style:Solid; border-right-width:1px; border-bottom-color:#c0c0c0; border-bottom-style:Solid; border-bottom-width:1px; }
td.whs10 { width:598px; padding-right:10px; padding-left:10px; border-right-color:#c0c0c0; border-right-style:Solid; border-right-width:1px; border-bottom-color:#c0c0c0; border-bottom-style:Solid; border-bottom-width:1px; }
p.whs11 { margin-left:4px; }
table.whs12 { x-cell-content-align:top; margin-left:15px; border-spacing:0px; }
col.whs13 { width:167px; }
col.whs14 { width:524px; }
tr.whs15 { x-cell-content-align:top; }
td.whs16 { width:167px; padding-right:10px; padding-left:10px; background-color:#dee8f4; border-left-color:#c0c0c0; border-top-color:#c0c0c0; border-top-style:Solid; border-bottom-color:#c0c0c0; border-bottom-width:1px; border-bottom-style:Solid; border-right-color:#c0c0c0; border-right-width:1px; border-right-style:Solid; border-left-width:1px; border-left-style:solid; border-top-width:1px; }
td.whs17 { width:524px; padding-right:10px; padding-left:10px; background-color:#dee8f4; border-top-style:Solid; border-top-color:#c0c0c0; border-right-style:Solid; border-right-color:#c0c0c0; border-bottom-color:#c0c0c0; border-bottom-width:1px; border-bottom-style:Solid; border-top-width:1px; border-right-width:1px; }
td.whs18 { width:167px; padding-right:10px; padding-left:10px; border-left-color:#c0c0c0; border-bottom-color:#c0c0c0; border-bottom-width:1px; border-bottom-style:Solid; border-right-color:#c0c0c0; border-right-width:1px; border-right-style:Solid; border-left-width:1px; border-left-style:solid; }
td.whs19 { width:524px; border-right-style:Solid; border-right-color:#c0c0c0; border-bottom-color:#c0c0c0; border-bottom-width:1px; border-bottom-style:Solid; border-right-width:1px; }
td.whs20 { width:691px; padding-right:10px; padding-left:10px; border-left-color:#c0c0c0; border-right-style:Solid; border-right-color:#c0c0c0; border-bottom-color:#c0c0c0; border-bottom-width:1px; border-bottom-style:Solid; border-left-width:1px; border-left-style:solid; border-right-width:1px; }
td.whs21 { width:524px; padding-right:10px; padding-left:10px; border-right-style:Solid; border-right-color:#c0c0c0; border-bottom-color:#c0c0c0; border-bottom-width:1px; border-bottom-style:Solid; border-right-width:1px; }
ul.whs22 { list-style:disc; }
td.whs23 { width:167px; padding-right:10px; padding-left:10px; border-left-color:#c0c0c0; border-bottom-color:#c0c0c0; border-bottom-style:Solid; border-right-color:#c0c0c0; border-right-width:1px; border-right-style:Solid; border-left-width:1px; border-left-style:solid; border-bottom-width:1px; }
td.whs24 { width:524px; padding-right:10px; padding-left:10px; border-right-style:Solid; border-right-color:#c0c0c0; border-bottom-style:Solid; border-bottom-color:#c0c0c0; border-bottom-width:1px; border-right-width:1px; }
td.whs25 { width:167px; padding-right:10px; padding-left:10px; background-color:#dee8f4; border-left-color:#c0c0c0; border-top-style:Solid; border-top-color:#c0c0c0; border-right-color:#c0c0c0; border-right-style:Solid; border-bottom-color:#c0c0c0; border-bottom-width:1px; border-bottom-style:Solid; border-right-width:1px; border-left-width:1px; border-left-style:Solid; border-top-width:1px; }
td.whs26 { width:524px; padding-right:10px; padding-left:10px; background-color:#dee8f4; border-top-style:Solid; border-top-color:#c0c0c0; border-bottom-color:#c0c0c0; border-bottom-width:1px; border-bottom-style:Solid; border-top-width:1px; border-right-color:#c0c0c0; border-right-width:1px; border-right-style:Solid; }
td.whs27 { width:691px; padding-right:10px; padding-left:10px; border-left-color:#c0c0c0; border-bottom-color:#c0c0c0; border-bottom-width:1px; border-bottom-style:Solid; border-left-width:1px; border-left-style:Solid; border-right-color:#c0c0c0; border-right-width:1px; border-right-style:Solid; }
td.whs28 { width:167px; padding-right:10px; padding-left:10px; border-left-color:#c0c0c0; border-right-color:#c0c0c0; border-right-style:Solid; border-bottom-color:#c0c0c0; border-bottom-width:1px; border-bottom-style:Solid; border-right-width:1px; border-left-width:1px; border-left-style:Solid; }
td.whs29 { width:524px; padding-right:10px; padding-left:10px; border-bottom-color:#c0c0c0; border-bottom-width:1px; border-bottom-style:Solid; border-right-color:#c0c0c0; border-right-width:1px; border-right-style:Solid; }
td.whs30 { width:167px; padding-right:10px; padding-left:10px; border-left-color:#c0c0c0; border-right-color:#c0c0c0; border-right-style:Solid; border-bottom-color:#c0c0c0; border-bottom-style:Solid; border-right-width:1px; border-left-width:1px; border-left-style:Solid; border-bottom-width:1px; }
td.whs31 { width:524px; padding-right:10px; padding-left:10px; border-bottom-color:#c0c0c0; border-bottom-style:Solid; border-bottom-width:1px; border-right-color:#c0c0c0; border-right-width:1px; border-right-style:Solid; }
img_whs32 { border:none; width:14px; height:16px; float:none; border-style:none; }
-->
</style><script type="text/javascript" language="JavaScript">
<!--
function ehlp_showtip(current,e,text)
{
if ((parseInt(navigator.appVersion) == 4) && (navigator.appName == 'Netscape'))
{
document.tooltip.document.write("<layer bgColor='yellow' style='border:1px solid black;font-size:12px;'>"+ text + "</layer>");
document.tooltip.document.close();
document.tooltip.left=e.pageX+5;
document.tooltip.top=e.pageY+5;
document.tooltip.visibility="show";
}
}
function ehlp_hidetip()
{
document.tooltip.visibility="hidden";
}
//-->
</script>
<script type="text/javascript" language="JavaScript" title="WebHelpInlineScript">
<!--
function reDo() {
if (innerWidth != origWidth || innerHeight != origHeight)
location.reload();
}
if ((parseInt(navigator.appVersion) == 4) && (navigator.appName == "Netscape")) {
origWidth = innerWidth;
origHeight = innerHeight;
onresize = reDo;
}
onerror = null;
//-->
</script>
<style type="text/css">
<!--
div.WebHelpPopupMenu { position:absolute; left:0px; top:0px; z-index:4; visibility:hidden; }
p.WebHelpNavBar { text-align:right; }
-->
</style><script type="text/javascript" language="javascript1.2" src="whmsg.js"></script>
<script type="text/javascript" language="javascript" src="whver.js"></script>
<script type="text/javascript" language="javascript1.2" src="whproxy.js"></script>
<script type="text/javascript" language="javascript1.2" src="whutils.js"></script>
<script type="text/javascript" language="javascript1.2" src="whtopic.js"></script>
<script type="text/javascript" language="javascript1.2">
<!--
if (window.gbWhTopic)
{
if (window.setRelStartPage)
{
addTocInfo("LM32");
}
if (window.setRelStartPage)
{
setRelStartPage("msb_peripherals.htm");
autoSync(0);
sendSyncInfo();
sendAveInfoOut();
}
}
else
if (window.gbIE4)
document.location.reload();
//-->
</script>
</head>
<body><script type="text/javascript" language="javascript1.2">
<!--
if (window.writeIntopicBar)
writeIntopicBar(4);
//-->
</script>
<h1>LatticeMico32 Processor &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a title="View Reference Manual" href="lm32_archman.pdf" target="_blank" onmouseover="if ((parseInt(navigator.appVersion) == 4) && (navigator.appName == 'Netscape')) ehlp_showtip(this,event,'View Reference Manual');" onmouseout="if ((parseInt(navigator.appVersion) == 4) && (navigator.appName == 'Netscape')) ehlp_hidetip();"><img src="ds_icon_ast.jpg" x-maintain-ratio="TRUE" width="29px" height="31px" border="0" class="img_whs1"></a></h1>
<p>The LatticeMico32 processor is a high-performance 32-bit microprocessor
optimized for Lattice Semiconductor field-programmable gate arrays. </p>
<p class="whs2"><span style="font-style: italic;"><I>*If the
processor manual fails to open, see the note at the bottom of this page.</I></span></p>
<h2>Revision History</h2>
<table x-use-null-cells cellspacing="0" width="738" height="84" class="whs3">
<script language='JavaScript'><!--
if ((navigator.appName == "Netscape") && (parseInt(navigator.appVersion) == 4)) document.write("</table><table x-use-null-cells cellspacing='0' width='738' height='84' border='1' bordercolor='silver' bordercolorlight='silver' bordercolordark='silver'>");
//--></script>
<col class="whs4">
<col class="whs5">
<tr valign="top" class="whs6">
<td bgcolor="#DEE8F4" width="93px" class="whs7">
<p class=Table
style="font-weight: bold;">Version</td>
<td bgcolor="#DEE8F4" width="598px" class="whs8">
<p class=Table
style="font-weight: bold;">Description</td></tr>
<tr valign="top" class="whs6">
<td colspan="1" rowspan="1" width="93px" class="whs9">
<p class=Table
style="font-weight: normal;">3.5</td>
<td colspan="1" rowspan="1" width="598px" class="whs10">
<p class=whs10
style="margin-left: 0px;">Support added to allow Inline Memories to
be generated as non-power-of-two, as long as they are a multiple of 1024
bytes</td></tr>
<tr valign="top" class="whs6">
<td colspan="1" rowspan="1" width="93px" class="whs9">
<p class=Table
style="font-weight: normal;">3.4</td>
<td colspan="1" rowspan="1" width="598px" class="whs10">
<p class=whs10
style="margin-left: 0px;">Updated to support ispLEVER 7.2 SP1.</td></tr>
<tr valign="top" class="whs6">
<td colspan="1" rowspan="1" width="93px" class="whs9">
<p class=Table
style="font-weight: normal;">3.3</td>
<td colspan="1" rowspan="1" width="598px" class="whs10">
<p class=whs10
style="margin-left: 0px;">Updated to support ispLEVER 7.2.</p>
<p class=whs10
style="margin-left: 0px;">Added Inline Memory to support on-chip memory
connected through a local bus.</td></tr>
<tr valign="top" class="whs6">
<td colspan="1" rowspan="1" width="93px" class="whs9">
<p class=Table
style="font-weight: normal;">3.2</td>
<td colspan="1" rowspan="1" width="598px" class="whs10">
<p class=whs10
style="margin-left: 0px;">Updated to support ispLEVER 7.1 SP1</p>
<p class=whs10
style="margin-left: 0px;">Added Memory Type to instruction cache and
data cache.</td></tr>
<tr valign="top" class="whs6">
<td colspan="1" rowspan="1" width="93px" class="whs9">
<p class=Table
style="font-weight: normal;">3.1</td>
<td colspan="1" rowspan="1" width="598px" class="whs10">
<p class="whs11">Updated to support ispLEVER 7.1.</p>
<p class="whs11">Added static predictor to improve the behavior
of branches.</p>
<p class="whs11">Added support for optionally mapping the register
file to EBRs (on-chip memory).</p>
<p class="whs11">Added support for selecting between distributed
RAM and EBRs (pseudo-dual port or true-dual port) for instruction and
data caches.</td></tr>
<tr valign="top" class="whs6">
<td colspan="1" rowspan="1" width="93px" class="whs9">
<p class=Table
style="font-weight: normal;"><span style="font-weight: normal;">3.0
(7.0 SP2)</span></td>
<td colspan="1" rowspan="1" width="598px" class="whs10">
<p class="whs11">Updated to support ispLEVER 7.0 SP2.</p>
<p class="whs11">Fixed incorrect handling of data cache miss
in the presence of an instruction cache miss.</td></tr>
<tr valign="top" class="whs6">
<td colspan="1" rowspan="1" width="93px" class="whs9">
<p class="whs11">1.0</td>
<td colspan="1" rowspan="1" width="598px" class="whs10">
<p class="whs11">Initial version.</td></tr>
<script language='JavaScript'><!--
if ((navigator.appName == "Netscape") && (parseInt(navigator.appVersion) == 4)) document.write("</table></table><table>");
//--></script>
</table>
&nbsp;
<h2>Dialog Box Parameters &#8211;
General Tab</h2>
<table x-use-null-cells cellspacing="0" class="whs12">
<col class="whs13">
<col class="whs14">
<tr valign="top" class="whs15">
<td bgcolor="#DEE8F4" width="167px" class="whs16">
<p class=Table
style="font-weight: bold;">Parameter</td>
<td bgcolor="#DEE8F4" width="524px" class="whs17">
<p class=Table
style="font-weight: bold;">Description</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table
style="font-weight: normal;">Instance Name</td>
<td colspan="1" rowspan="1" width="524px" class="whs19">
<p class=Table
style="margin-left: 14px;">Specifies the name of the LatticeMico32
processor. Alphanumeric values and underscores are supported. The default
is LM32.</td></tr>
<tr valign="top" class="whs15">
<td colspan="2" rowspan="1" width="691px" class="whs20">
<p class=Table
style="font-weight: bold;">Settings</td>
</tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Use EBRs for Register File</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table>Uses embedded block RAMS for the register file.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Enable Divide</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table>Enables the divide and modulus instructions (<span style="font-family: Verdana, sans-serif;">divu,
modu</span>).</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Enable Sign Extend</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table>Enables the sign-extension instructions (<span style="font-family: Verdana, sans-serif;">sextb,
sexth</span><span style="font-family: Arial, sans-serif;">)</span>.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Location of Exception Handlers</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table>Specifies the default value for the vector table. This can
be changed by updating the EBA control register or status register.</p>
<p class=Table>This address must be aligned to a 256-byte boundary, since
the hardware ignores the least-significant byte. Unpredictable behavior
occurs when the exception base address and the exception vectors are not
aligned on a 256-byte boundary.</td></tr>
<tr valign="top" class="whs15">
<td colspan="2" rowspan="1" width="691px" class="whs20">
<p class=Table
style="font-weight: bold;">Multiplier Settings</td>
</tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Enable Multiplier</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table>Enables the multiply instructions (<span style="font-family: Verdana, sans-serif;">mul,
muli)</span>.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Enable Pipelined Multiplier (DSP Block if available)</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table>Enables the multiplier using the DSP block, if available.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Enable Multicycle (LUT-based, 32 cycles) Multiplier</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table>Enables the multiplier using LUTs.</td></tr>
<tr valign="top" class="whs15">
<td colspan="2" rowspan="1" width="691px" class="whs20">
<p class=Table
style="font-weight: bold;">Instruction Cache</td>
</tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Instruction Cache Enabled</td>
<td colspan="1" rowspan="1" width="524px" class="whs19">
<p class=Table
style="margin-left: 14px;">Determines whether an instruction cache
is implemented.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Number of Sets</td>
<td colspan="1" rowspan="1" width="524px" class="whs19">
<p class=Table
style="margin-left: 14px;">Specifies the number of sets in the instruction
cache. Supported values are 128, 256, 512, 1024.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Set Associativity</td>
<td colspan="1" rowspan="1" width="524px" class="whs19">
<p class=Table
style="margin-left: 14px;">Specifies the associativity of the instruction
cache. Supported values are 1, 2.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Bytes/Cache Line</td>
<td colspan="1" rowspan="1" width="524px" class="whs19">
<p class=Table
style="margin-left: 15px;">Specifies the number of bytes per instruction
cache line. Supported values are 4, 8, 16.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Memory Type</td>
<td colspan="1" rowspan="1" width="524px" class="whs19">
<p class=Table
style="margin-left: 15px;">Determines the FPGA resource to be used
to implement the instruction cache. The decision can be left to the synthesis
tool (Auto), or you can select from the following options:</p>
<ul type="disc" class="whs22">
<li class=kadov-p-CBullet><p class=Bullet>Auto &#8211;
Leaves the implementation of the instruction cache to the synthesis tool.</p></li>
<li class=kadov-p-CBullet><p class=Bullet>Distributed RAM &#8211;
Implements the instruction cache as distributed RAM.</p></li>
<li class=kadov-p-CBullet><p class=Bullet>Dual-Port EBR &#8211;
Implements the instruction cache as dual-port EBR (two read/write ports).</p></li>
<li class=kadov-p-CBullet><p class=Bullet>Pseudo Dual-Port EBR &#8211; Implements
the instruction cache as pseudo-dual-port EBR (one read port and one write
port). </p></li>
</ul></td></tr>
<tr valign="top" class="whs15">
<td colspan="2" rowspan="1" width="691px" class="whs20">
<p class=Table
style="font-weight: bold;">Debug Setting</td>
</tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Enable Debug Interface</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table>Includes the debugger stub in the CPU, which is required
for debugging.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table># of H/W Watchpoint Registers</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table
style="font-weight: normal;">Specifies the number of hardware watchpoint
registers to be used in the debugging process.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Enable Debugging Code in Flash or ROM</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table
style="font-weight: normal;">Enables you to set hardware breakpoints
in read-only memory.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table># of H/W Breakpoint Registers</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table>Specifies the number of hardware breakpoint registers to
be used in the debugging process.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Enable PC Trace</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table>Enables the Program Counter Trace feature, which enables
you to run the program trace during debug to find items in your C or C++
Code during debug, such as breakpoints and exceptions. Refer to <span
style="font-weight: bold;"><B>Help &gt; Help Contents &gt; C/C++ SPE</B></span>
and <span style="font-weight: bold;"><B>Debug &gt; Concepts &gt; Program
Counter Trace</B></span> for more information on Program Counter Trace.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Trace Depth</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table>Enables you to specify the depth of the Program Counter
Trace buffer. Refer to <span style="font-weight: bold;"><B>Help &gt; Help
Contents &gt; C/C++ SPE</B></span> and <span style="font-weight: bold;"><B>Debug
&gt; Concepts &gt; Program Counter Trace</B></span> for more information on
Program Counter Trace.</td></tr>
<tr valign="top" class="whs15">
<td colspan="2" rowspan="1" width="691px" class="whs20">
<p class=Table
style="font-weight: bold;">Shifter Settings</td>
</tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Enable Shifter</td>
<td colspan="1" rowspan="1" width="524px" class="whs19">
<p>Enables the multi-bit shift instructions (sr, sri, sru, srui, sl, sli).
</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Enable Piplined Barrel Shifter</td>
<td colspan="1" rowspan="1" width="524px" class="whs19">
<p>Enables the barrel shifter to be pipelined. The barrel shifter is implemented
to perform a shift operation in three cycles.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Enable Multicycle Barrel Shifter (up to 32 cycles)</td>
<td colspan="1" rowspan="1" width="524px" class="whs19">
<p>Enables multi-cycle shift operation for the barrel shifter. The barrel
shifter is implemented to shift one bit per cycle and take thirty-two
cycles to complete.</td></tr>
<tr valign="top" class="whs15">
<td colspan="2" rowspan="1" width="691px" class="whs20">
<p class=Table><span style="font-weight: bold;"><B>Data Cache</B></span></td>
</tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Data Cache Enabled</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table>Determines whether a data cache is implemented.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Number of Sets</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table>Specifies the number of sets in the data cache. Supported
values are 128, 256, 512, 1024.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Set Associativity</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table>Specifies the associativity of the data cache. Supported
values are 1, 2.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs18">
<p class=Table>Bytes/Cache Line</td>
<td colspan="1" rowspan="1" width="524px" class="whs21">
<p class=Table>Specifies the number of bytes per data cache line. Supported
values are 4, 8, 16.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs23">
<p class=Table>Memory Type</td>
<td colspan="1" rowspan="1" width="524px" class="whs24">
<p class=Table>Determines the FPGA resource to be used to implement the
data cache. The decision can be left to the synthesis tool (Auto), or
you can select from the following options:</p>
<ul>
<li class=kadov-p-CBullet><p class=Bullet>Auto &#8211;
Leaves the implementation of the data cache to the synthesis tool.</p></li>
<li class=kadov-p-CBullet><p class=Bullet>Distributed RAM &#8211;
Implements the data cache as distributed RAM.</p></li>
<li class=kadov-p-CBullet><p class=Bullet>Dual-Port EBR &#8211;
Implements the data cache as dual-port EBR (two read/write ports).</p></li>
</ul></td></tr>
</table>
<p>&nbsp;</p>
<h2>Dialog Box Parameters &#8211;
Inline Memory Tab</h2>
<table x-use-null-cells cellspacing="0" class="whs12">
<col class="whs13">
<col class="whs14">
<tr valign="top" class="whs15">
<td bgcolor="#DEE8F4" width="167px" class="whs25">
<p class=Table
style="font-weight: bold;">Parameter</td>
<td bgcolor="#DEE8F4" width="524px" class="whs26">
<p class=Table
style="font-weight: bold;">Description</td></tr>
<tr valign="top" class="whs15">
<td rowspan="1" colspan="2" width="691px" class="whs27">
<p class=Table
style="font-weight: bold;">Instruction Inline Memory</td>
</tr>
<tr valign="top" class="whs15">
<td width="167px" class="whs28">
<p class=Table>Enable</td>
<td width="524px" class="whs29">
<p class=Table>Enables the instruction inline memory</td></tr>
<tr valign="top" class="whs15">
<td width="167px" class="whs28">
<p class=Table>Instance Name</td>
<td width="524px" class="whs29">
<p class=Table>Specifics the name of the instruction inline memory. Alphanumeric
values and underscores are supported. The default is Instruction_IM.</td></tr>
<tr valign="top" class="whs15">
<td width="167px" class="whs28">
<p class=Table>Base Address</td>
<td width="524px" class="whs29">
<p class=Table>Specifies the base address for the instruction inline memory.
The default is 0x10000000.</td></tr>
<tr valign="top" class="whs15">
<td width="167px" class="whs28">
<p class=Table>Size of Memory in Bytes</td>
<td width="524px" class="whs29">
<p class=Table>Specifies the size of the instruction inline memory.</td></tr>
<tr valign="top" class="whs15">
<td rowspan="1" colspan="2" width="691px" class="whs27">
<p class=Table><span style="font-weight: bold;"><B>Memory File</B></span></td>
</tr>
<tr valign="top" class="whs15">
<td width="167px" class="whs28">
<p class=Table>Initialization File Name</td>
<td width="524px" class="whs29">
<p class=Table>Specifies the name of the memory initialization file for
instruction inline memory.</td></tr>
<tr valign="top" class="whs15">
<td width="167px" class="whs28">
<p class=Table>File Format</td>
<td width="524px" class="whs29">
<p class=Table>Specifies the format of the memory initialization file:
hex or binary.</td></tr>
<tr valign="top" class="whs15">
<td rowspan="1" colspan="2" width="691px" class="whs27">
<p class=Table
style="font-weight: bold;">Data Inline Memory</td>
</tr>
<tr valign="top" class="whs15">
<td width="167px" class="whs28">
<p class=Table>Enabled</td>
<td width="524px" class="whs29">
<p class=Table>Enables the data inline memory.</td></tr>
<tr valign="top" class="whs15">
<td width="167px" class="whs28">
<p class=Table>Instance Name</td>
<td width="524px" class="whs29">
<p class=Table>Specifies the name of the data inline memory. Alphanumeric
values and underscores are supported. The default is Data_IM.</td></tr>
<tr valign="top" class="whs15">
<td width="167px" class="whs28">
<p class=Table>Base Address</td>
<td width="524px" class="whs29">
<p class=Table>Specifies the base address for the data inline memory. The
default is 0x20000000.</td></tr>
<tr valign="top" class="whs15">
<td width="167px" class="whs28">
<p class=Table>Size of Memory in Bytes</td>
<td width="524px" class="whs29">
<p class=Table>Specifies the size of the data inline memory.</td></tr>
<tr valign="top" class="whs15">
<td colspan="2" rowspan="1" width="691px" class="whs27">
<p class=Table
style="font-weight: bold;">Memory File</td>
</tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs28">
<p class=Table>Initialization File Name</td>
<td colspan="1" rowspan="1" width="524px" class="whs29">
<p class=Table>Specifies the name of the memory initialization file for
data inline memory.</td></tr>
<tr valign="top" class="whs15">
<td colspan="1" rowspan="1" width="167px" class="whs30">
<p class=Table>File Format</td>
<td colspan="1" rowspan="1" width="524px" class="whs31">
<p class=Table>Specifies the format of the memory initialization file:
hex or binary.</td></tr>
</table>
<p>&nbsp;</p>
<p>For the revision history of the component RTL files, refer to the header
of each component Verilog source file. </p>
<p><span style="font-weight: bold;"><B>Note</B></span>: If the processor manual
fails to open, click <img src="qm_icon.jpg" x-maintain-ratio="TRUE" width="14px" height="16px" border="0" class="img_whs32"> on the Available Components toolbar,
and then click the note button.</p>
<script type="text/javascript" language="JavaScript">
<!--
if ((parseInt(navigator.appVersion) == 4) && (navigator.appName == 'Netscape'))
document.write("<div id='tooltip' class='WebHelpPopupMenu'></div>");
//-->
</script><script type="text/javascript" language="javascript1.2">
<!--
if (window.writeIntopicBar)
writeIntopicBar(0);
//-->
</script>
</body>
</html>
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : JTAGB.v
// Title : JTAGB Black Box
// Dependencies : None
// Version : 6.0.14
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
module JTAGB (
output JTCK,
output JRTI1,
output JRTI2,
output JTDI,
output JSHIFT,
output JUPDATE,
output JRSTN,
output JCE1,
output JCE2,
input JTDO1,
input JTDO2
) /*synthesis syn_black_box */;
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : er1.v
// Description:
// This module is where the ER1 register implemented. ER1 and ER2 registers
// can be registers implemented in Lattice FPGAs using normal FPGA's
// programmable logic resources. Once they are implemented, they can be
// accessed as if they are JTAG data registers through the FPGA JTAG port.
// In order to accessing these registers, JTAG instructions ER1(0x32) or
// ER2(0x38) needs to be written to the JTAG IR register for enabling the
// ER1/ER2 accessing logic. The ER1 or ER2 accessing logic can only be
// enabled one at a time. Once they are enabled, they will be disabled if
// another JTAG instruction is written into the JTAG instruction register.
// The registers allow dynamically accessing the FPGA internal information
// even when the device is running. Therefore, they are very useful for some
// of the IP cores. In order to let ER1/ER2 registers shared by multiple IP
// cores or other designs, there is a ER1/ER2 structure patterned by Lattice.
// The ER1/ER2 structure allows only one ER1 register but more than one ER2
// registers in an FPGA device. Please refer to the related document for
// this patterned ER1/ER2 structure.
// Dependencies : None
// Version : 6.0.14
// : Initial Version
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
module ER1 (input JTCK,
input JTDI,
output JTDO1,
output reg JTDO2,
input JSHIFT,
input JUPDATE,
input JRSTN,
input JCE1,
input [14:0] ER2_TDO,
output reg [14:0] IP_ENABLE,
input ISPTRACY_ER2_TDO,
output ISPTRACY_ENABLE,
output CONTROL_DATAN)/* synthesis syn_hier = hard */;
wire controlDataNBit;
wire ispTracyEnableBit;
wire [3:0] encodedIpEnableBits;
wire [9:0] er1TdiBit;
wire captureDrER1;
assign JTDO1 = er1TdiBit[0];
TYPEB BIT0 (.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(JCE1),
.TDI(er1TdiBit[1]),
.TDO(er1TdiBit[0]),
.DATA_IN(1'b0),
.CAPTURE_DR(captureDrER1));
TYPEB BIT1 (.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(JCE1),
.TDI(er1TdiBit[2]),
.TDO(er1TdiBit[1]),
.DATA_IN(1'b0),
.CAPTURE_DR(captureDrER1));
TYPEB BIT2 (.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(JCE1),
.TDI(er1TdiBit[3]),
.TDO(er1TdiBit[2]),
.DATA_IN(1'b1),
.CAPTURE_DR(captureDrER1));
TYPEA BIT3 (.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(JCE1),
.TDI(er1TdiBit[4]),
.TDO(er1TdiBit[3]),
.DATA_OUT(controlDataNBit),
.DATA_IN(controlDataNBit),
.CAPTURE_DR(captureDrER1),
.UPDATE_DR(JUPDATE));
assign CONTROL_DATAN = controlDataNBit;
TYPEA BIT4 (.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(JCE1),
.TDI(er1TdiBit[5]),
.TDO(er1TdiBit[4]),
.DATA_OUT(ispTracyEnableBit),
.DATA_IN(ispTracyEnableBit),
.CAPTURE_DR(captureDrER1),
.UPDATE_DR(JUPDATE)
);
assign ISPTRACY_ENABLE = ispTracyEnableBit;
TYPEA BIT5 (.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(JCE1),
.TDI(er1TdiBit[6]),
.TDO(er1TdiBit[5]),
.DATA_OUT(encodedIpEnableBits[0]),
.DATA_IN(encodedIpEnableBits[0]),
.CAPTURE_DR(captureDrER1),
.UPDATE_DR(JUPDATE));
TYPEA BIT6 (.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(JCE1),
.TDI(er1TdiBit[7]),
.TDO(er1TdiBit[6]),
.DATA_OUT(encodedIpEnableBits[1]),
.DATA_IN(encodedIpEnableBits[1]),
.CAPTURE_DR(captureDrER1),
.UPDATE_DR(JUPDATE));
TYPEA BIT7 (.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(JCE1),
.TDI(er1TdiBit[8]),
.TDO(er1TdiBit[7]),
.DATA_OUT(encodedIpEnableBits[2]),
.DATA_IN(encodedIpEnableBits[2]),
.CAPTURE_DR(captureDrER1),
.UPDATE_DR(JUPDATE));
TYPEA BIT8 (.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(JCE1),
.TDI(er1TdiBit[9]),
.TDO(er1TdiBit[8]),
.DATA_OUT(encodedIpEnableBits[3]),
.DATA_IN(encodedIpEnableBits[3]),
.CAPTURE_DR(captureDrER1),
.UPDATE_DR(JUPDATE)
);
assign er1TdiBit[9] = JTDI;
assign captureDrER1 = !JSHIFT & JCE1;
always @ (encodedIpEnableBits,ISPTRACY_ER2_TDO, ER2_TDO)
begin
case (encodedIpEnableBits)
4'h0: begin
IP_ENABLE <= 15'b000000000000000;
JTDO2 <= ISPTRACY_ER2_TDO;
end
4'h1: begin
IP_ENABLE <= 15'b000000000000001;
JTDO2 <= ER2_TDO[0];
end
4'h2: begin
IP_ENABLE <= 15'b000000000000010;
JTDO2 <= ER2_TDO[1];
end
4'h3: begin
IP_ENABLE <= 15'b000000000000100;
JTDO2 <= ER2_TDO[2];
end
4'h4: begin
IP_ENABLE <= 15'b000000000001000;
JTDO2 <= ER2_TDO[3];
end
4'h5: begin
IP_ENABLE <= 15'b000000000010000;
JTDO2 <= ER2_TDO[4];
end
4'h6: begin
IP_ENABLE <= 15'b000000000100000;
JTDO2 <= ER2_TDO[5];
end
4'h7: begin
IP_ENABLE <= 15'b000000001000000;
JTDO2 <= ER2_TDO[6];
end
4'h8: begin
IP_ENABLE <= 15'b000000010000000;
JTDO2 <= ER2_TDO[7];
end
4'h9: begin
IP_ENABLE <= 15'b000000100000000;
JTDO2 <= ER2_TDO[8];
end
4'hA: begin
IP_ENABLE <= 15'b000001000000000;
JTDO2 <= ER2_TDO[9];
end
4'hB: begin
IP_ENABLE <= 15'b000010000000000;
JTDO2 <= ER2_TDO[10];
end
4'hC: begin
IP_ENABLE <= 15'b000100000000000;
JTDO2 <= ER2_TDO[11];
end
4'hD: begin
IP_ENABLE <= 15'b001000000000000;
JTDO2 <= ER2_TDO[12];
end
4'hE: begin
IP_ENABLE <= 15'b010000000000000;
JTDO2 <= ER2_TDO[13];
end
4'hF: begin
IP_ENABLE <= 15'b100000000000000;
JTDO2 <= ER2_TDO[14];
end
endcase
end
endmodule
// ============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// ============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : jtag_cores.v
// Title : Instantiates all IP cores on JTAG chain.
// Dependencies : system_conf.v
// Version : 6.0.14
// : modified to use jtagconn for LM32,
// : all technologies 7/10/07
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// ============================================================================
`include "system_conf.v"
/////////////////////////////////////////////////////
// jtagconn16 Module Definition
/////////////////////////////////////////////////////
module jtagconn16 (er2_tdo, jtck, jtdi, jshift, jupdate, jrstn, jce2, ip_enable) ;
input er2_tdo ;
output jtck ;
output jtdi ;
output jshift ;
output jupdate ;
output jrstn ;
output jce2 ;
output ip_enable ;
endmodule
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
(* syn_hier="hard" *) module jtag_cores (
// ----- Inputs -------
reg_d,
reg_addr_d,
// ----- Outputs -------
reg_update,
reg_q,
reg_addr_q,
jtck,
jrstn
);
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input [7:0] reg_d;
input [2:0] reg_addr_d;
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
output reg_update;
wire reg_update;
output [7:0] reg_q;
wire [7:0] reg_q;
output [2:0] reg_addr_q;
wire [2:0] reg_addr_q;
output jtck;
wire jtck; /* synthesis syn_keep=1 */
output jrstn;
wire jrstn; /* synthesis syn_keep=1 */
/////////////////////////////////////////////////////
// Instantiations
/////////////////////////////////////////////////////
wire jtdi; /* synthesis syn_keep=1 */
wire er2_tdo2; /* synthesis syn_keep=1 */
wire jshift; /* synthesis syn_keep=1 */
wire jupdate; /* synthesis syn_keep=1 */
wire jce2; /* synthesis syn_keep=1 */
wire ip_enable; /* synthesis syn_keep=1 */
(* JTAG_IP="LM32", IP_ID="0", HUB_ID="0", syn_noprune=1 *) jtagconn16 jtagconn16_lm32_inst (
.er2_tdo (er2_tdo2),
.jtck (jtck),
.jtdi (jtdi),
.jshift (jshift),
.jupdate (jupdate),
.jrstn (jrstn),
.jce2 (jce2),
.ip_enable (ip_enable)
);
(* syn_noprune=1 *) jtag_lm32 jtag_lm32_inst (
.JTCK (jtck),
.JTDI (jtdi),
.JTDO2 (er2_tdo2),
.JSHIFT (jshift),
.JUPDATE (jupdate),
.JRSTN (jrstn),
.JCE2 (jce2),
.JTAGREG_ENABLE (ip_enable),
.CONTROL_DATAN (),
.REG_UPDATE (reg_update),
.REG_D (reg_d),
.REG_ADDR_D (reg_addr_d),
.REG_Q (reg_q),
.REG_ADDR_Q (reg_addr_q)
);
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : jtag_lm32.v
// Title : JTAG data register for LM32 CPU debug interface
// Version : 6.0.13
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module jtag_lm32 (
input JTCK,
input JTDI,
output JTDO2,
input JSHIFT,
input JUPDATE,
input JRSTN,
input JCE2,
input JTAGREG_ENABLE,
input CONTROL_DATAN,
output REG_UPDATE,
input [7:0] REG_D,
input [2:0] REG_ADDR_D,
output [7:0] REG_Q,
output [2:0] REG_ADDR_Q
);
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
wire [9:0] tdibus;
/////////////////////////////////////////////////////
// Instantiations
/////////////////////////////////////////////////////
TYPEA DATA_BIT0 (
.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(clk_enable),
.TDI(JTDI),
.TDO(tdibus[0]),
.DATA_OUT(REG_Q[0]),
.DATA_IN(REG_D[0]),
.CAPTURE_DR(captureDr),
.UPDATE_DR(JUPDATE)
);
TYPEA DATA_BIT1 (
.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(clk_enable),
.TDI(tdibus[0]),
.TDO(tdibus[1]),
.DATA_OUT(REG_Q[1]),
.DATA_IN(REG_D[1]),
.CAPTURE_DR(captureDr),
.UPDATE_DR(JUPDATE)
);
TYPEA DATA_BIT2 (
.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(clk_enable),
.TDI(tdibus[1]),
.TDO(tdibus[2]),
.DATA_OUT(REG_Q[2]),
.DATA_IN(REG_D[2]),
.CAPTURE_DR(captureDr),
.UPDATE_DR(JUPDATE)
);
TYPEA DATA_BIT3 (
.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(clk_enable),
.TDI(tdibus[2]),
.TDO(tdibus[3]),
.DATA_OUT(REG_Q[3]),
.DATA_IN(REG_D[3]),
.CAPTURE_DR(captureDr),
.UPDATE_DR(JUPDATE)
);
TYPEA DATA_BIT4 (
.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(clk_enable),
.TDI(tdibus[3]),
.TDO(tdibus[4]),
.DATA_OUT(REG_Q[4]),
.DATA_IN(REG_D[4]),
.CAPTURE_DR(captureDr),
.UPDATE_DR(JUPDATE)
);
TYPEA DATA_BIT5 (
.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(clk_enable),
.TDI(tdibus[4]),
.TDO(tdibus[5]),
.DATA_OUT(REG_Q[5]),
.DATA_IN(REG_D[5]),
.CAPTURE_DR(captureDr),
.UPDATE_DR(JUPDATE)
);
TYPEA DATA_BIT6 (
.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(clk_enable),
.TDI(tdibus[5]),
.TDO(tdibus[6]),
.DATA_OUT(REG_Q[6]),
.DATA_IN(REG_D[6]),
.CAPTURE_DR(captureDr),
.UPDATE_DR(JUPDATE)
);
TYPEA DATA_BIT7 (
.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(clk_enable),
.TDI(tdibus[6]),
.TDO(tdibus[7]),
.DATA_OUT(REG_Q[7]),
.DATA_IN(REG_D[7]),
.CAPTURE_DR(captureDr),
.UPDATE_DR(JUPDATE)
);
TYPEA ADDR_BIT0 (
.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(clk_enable),
.TDI(tdibus[7]),
.TDO(tdibus[8]),
.DATA_OUT(REG_ADDR_Q[0]),
.DATA_IN(REG_ADDR_D[0]),
.CAPTURE_DR(captureDr),
.UPDATE_DR(JUPDATE)
);
TYPEA ADDR_BIT1 (
.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(clk_enable),
.TDI(tdibus[8]),
.TDO(tdibus[9]),
.DATA_OUT(REG_ADDR_Q[1]),
.DATA_IN(REG_ADDR_D[1]),
.CAPTURE_DR(captureDr),
.UPDATE_DR(JUPDATE)
);
TYPEA ADDR_BIT2 (
.CLK(JTCK),
.RESET_N(JRSTN),
.CLKEN(clk_enable),
.TDI(tdibus[9]),
.TDO(JTDO2),
.DATA_OUT(REG_ADDR_Q[2]),
.DATA_IN(REG_ADDR_D[2]),
.CAPTURE_DR(captureDr),
.UPDATE_DR(JUPDATE)
);
/////////////////////////////////////////////////////
// Combinational logic
/////////////////////////////////////////////////////
assign clk_enable = JTAGREG_ENABLE & JCE2;
assign captureDr = !JSHIFT & JCE2;
// JCE2 is only active during shift
assign REG_UPDATE = JTAGREG_ENABLE & JUPDATE;
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// ============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_adder.v
// Title : Integer adder / subtractor with comparison flag generation
// Dependencies : lm32_include.v
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
`include "lm32_include.v"
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_adder (
// ----- Inputs -------
adder_op_x,
adder_op_x_n,
operand_0_x,
operand_1_x,
// ----- Outputs -------
adder_result_x,
adder_carry_n_x,
adder_overflow_x
);
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input adder_op_x; // Operating to perform, 0 for addition, 1 for subtraction
input adder_op_x_n; // Inverted version of adder_op_x
input [`LM32_WORD_RNG] operand_0_x; // Operand to add, or subtract from
input [`LM32_WORD_RNG] operand_1_x; // Opearnd to add, or subtract by
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
output [`LM32_WORD_RNG] adder_result_x; // Result of addition or subtraction
wire [`LM32_WORD_RNG] adder_result_x;
output adder_carry_n_x; // Inverted carry
wire adder_carry_n_x;
output adder_overflow_x; // Indicates if overflow occured, only valid for subtractions
reg adder_overflow_x;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
wire a_sign; // Sign (i.e. positive or negative) of operand 0
wire b_sign; // Sign of operand 1
wire result_sign; // Sign of result
/////////////////////////////////////////////////////
// Instantiations
/////////////////////////////////////////////////////
lm32_addsub addsub (
// ----- Inputs -----
.DataA (operand_0_x),
.DataB (operand_1_x),
.Cin (adder_op_x),
.Add_Sub (adder_op_x_n),
// ----- Ouputs -----
.Result (adder_result_x),
.Cout (adder_carry_n_x)
);
/////////////////////////////////////////////////////
// Combinational Logic
/////////////////////////////////////////////////////
// Extract signs of operands and result
assign a_sign = operand_0_x[`LM32_WORD_WIDTH-1];
assign b_sign = operand_1_x[`LM32_WORD_WIDTH-1];
assign result_sign = adder_result_x[`LM32_WORD_WIDTH-1];
// Determine whether an overflow occured when performing a subtraction
always @(*)
begin
// +ve - -ve = -ve -> overflow
// -ve - +ve = +ve -> overflow
if ( (!a_sign & b_sign & result_sign)
|| (a_sign & !b_sign & !result_sign)
)
adder_overflow_x = `TRUE;
else
adder_overflow_x = `FALSE;
end
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_addsub.v
// Title : PMI adder/subtractor.
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
`include "lm32_include.v"
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_addsub (
// ----- Inputs -------
DataA,
DataB,
Cin,
Add_Sub,
// ----- Outputs -------
Result,
Cout
);
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input [31:0] DataA;
input [31:0] DataB;
input Cin;
input Add_Sub;
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
output [31:0] Result;
wire [31:0] Result;
output Cout;
wire Cout;
/////////////////////////////////////////////////////
// Instantiations
/////////////////////////////////////////////////////
// Modified for Milkymist: removed non-portable instantiated block
wire [32:0] tmp_addResult = DataA + DataB + Cin;
wire [32:0] tmp_subResult = DataA - DataB - !Cin;
assign Result = (Add_Sub == 1) ? tmp_addResult[31:0] : tmp_subResult[31:0];
assign Cout = (Add_Sub == 1) ? tmp_addResult[32] : !tmp_subResult[32];
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_cpu.v
// Title : Top-level of CPU.
// Dependencies : lm32_include.v
//
// Version 3.4
// 1. Bug Fix: In a tight infinite loop (add, sw, bi) incoming interrupts were
// never serviced.
//
// Version 3.3
// 1. Feature: Support for memory that is tightly coupled to processor core, and
// has a single-cycle access latency (same as caches). Instruction port has
// access to a dedicated physically-mapped memory. Data port has access to
// a dedicated physically-mapped memory. In order to be able to manipulate
// values in both these memories via the debugger, these memories also
// interface with the data port of LM32.
// 2. Feature: Extended Configuration Register
// 3. Bug Fix: Removed port names that conflict with keywords reserved in System-
// Verilog.
//
// Version 3.2
// 1. Bug Fix: Single-stepping a load/store to invalid address causes debugger to
// hang. At the same time CPU fails to register data bus error exception. Bug
// is caused because (a) data bus error exception occurs after load/store has
// passed X stage and next sequential instruction (e.g., brk) is already in X
// stage, and (b) data bus error exception had lower priority than, say, brk
// exception.
// 2. Bug Fix: If a brk (or scall/eret/bret) sequentially follows a load/store to
// invalid location, CPU will fail to register data bus error exception. The
// solution is to stall scall/eret/bret/brk instructions in D pipeline stage
// until load/store has completed.
// 3. Feature: Enable precise identification of load/store that causes seg fault.
// 4. SYNC resets used for register file when implemented in EBRs.
//
// Version 3.1
// 1. Feature: LM32 Register File can now be mapped in to on-chip block RAM (EBR)
// instead of distributed memory by enabling the option in LM32 GUI.
// 2. Feature: LM32 also adds a static branch predictor to improve branch
// performance. All immediate-based forward-pointing branches are predicted
// not-taken. All immediate-based backward-pointing branches are predicted taken.
//
// Version 7.0SP2, 3.0
// No Change
//
// Version 6.1.17
// Initial Release
// =============================================================================
`include "lm32_include.v"
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_cpu (
// ----- Inputs -------
clk_i,
`ifdef CFG_EBR_NEGEDGE_REGISTER_FILE
clk_n_i,
`endif
rst_i,
// From external devices
`ifdef CFG_INTERRUPTS_ENABLED
interrupt,
`endif
// From user logic
`ifdef CFG_USER_ENABLED
user_result,
user_complete,
`endif
`ifdef CFG_JTAG_ENABLED
// From JTAG
jtag_clk,
jtag_update,
jtag_reg_q,
jtag_reg_addr_q,
`endif
`ifdef CFG_IWB_ENABLED
// Instruction Wishbone master
I_DAT_I,
I_ACK_I,
I_ERR_I,
I_RTY_I,
`endif
// Data Wishbone master
D_DAT_I,
D_ACK_I,
D_ERR_I,
D_RTY_I,
// ----- Outputs -------
`ifdef CFG_TRACE_ENABLED
trace_pc,
trace_pc_valid,
trace_exception,
trace_eid,
trace_eret,
`ifdef CFG_DEBUG_ENABLED
trace_bret,
`endif
`endif
`ifdef CFG_JTAG_ENABLED
jtag_reg_d,
jtag_reg_addr_d,
`endif
`ifdef CFG_USER_ENABLED
user_valid,
user_opcode,
user_operand_0,
user_operand_1,
`endif
`ifdef CFG_IWB_ENABLED
// Instruction Wishbone master
I_DAT_O,
I_ADR_O,
I_CYC_O,
I_SEL_O,
I_STB_O,
I_WE_O,
I_CTI_O,
I_LOCK_O,
I_BTE_O,
`endif
// Data Wishbone master
D_DAT_O,
D_ADR_O,
D_CYC_O,
D_SEL_O,
D_STB_O,
D_WE_O,
D_CTI_O,
D_LOCK_O,
D_BTE_O
);
/////////////////////////////////////////////////////
// Parameters
/////////////////////////////////////////////////////
parameter eba_reset = `CFG_EBA_RESET; // Reset value for EBA CSR
`ifdef CFG_DEBUG_ENABLED
parameter deba_reset = `CFG_DEBA_RESET; // Reset value for DEBA CSR
`endif
`ifdef CFG_ICACHE_ENABLED
parameter icache_associativity = `CFG_ICACHE_ASSOCIATIVITY; // Associativity of the cache (Number of ways)
parameter icache_sets = `CFG_ICACHE_SETS; // Number of sets
parameter icache_bytes_per_line = `CFG_ICACHE_BYTES_PER_LINE; // Number of bytes per cache line
parameter icache_base_address = `CFG_ICACHE_BASE_ADDRESS; // Base address of cachable memory
parameter icache_limit = `CFG_ICACHE_LIMIT; // Limit (highest address) of cachable memory
`else
parameter icache_associativity = 1;
parameter icache_sets = 512;
parameter icache_bytes_per_line = 16;
parameter icache_base_address = 0;
parameter icache_limit = 0;
`endif
`ifdef CFG_DCACHE_ENABLED
parameter dcache_associativity = `CFG_DCACHE_ASSOCIATIVITY; // Associativity of the cache (Number of ways)
parameter dcache_sets = `CFG_DCACHE_SETS; // Number of sets
parameter dcache_bytes_per_line = `CFG_DCACHE_BYTES_PER_LINE; // Number of bytes per cache line
parameter dcache_base_address = `CFG_DCACHE_BASE_ADDRESS; // Base address of cachable memory
parameter dcache_limit = `CFG_DCACHE_LIMIT; // Limit (highest address) of cachable memory
`else
parameter dcache_associativity = 1;
parameter dcache_sets = 512;
parameter dcache_bytes_per_line = 16;
parameter dcache_base_address = 0;
parameter dcache_limit = 0;
`endif
`ifdef CFG_DEBUG_ENABLED
parameter watchpoints = `CFG_WATCHPOINTS; // Number of h/w watchpoint CSRs
`else
parameter watchpoints = 0;
`endif
`ifdef CFG_ROM_DEBUG_ENABLED
parameter breakpoints = `CFG_BREAKPOINTS; // Number of h/w breakpoint CSRs
`else
parameter breakpoints = 0;
`endif
`ifdef CFG_INTERRUPTS_ENABLED
parameter interrupts = `CFG_INTERRUPTS; // Number of interrupts
`else
parameter interrupts = 0;
`endif
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input clk_i; // Clock
`ifdef CFG_EBR_NEGEDGE_REGISTER_FILE
input clk_n_i; // Inverted clock
`endif
input rst_i; // Reset
`ifdef CFG_INTERRUPTS_ENABLED
input [`LM32_INTERRUPT_RNG] interrupt; // Interrupt pins
`endif
`ifdef CFG_USER_ENABLED
input [`LM32_WORD_RNG] user_result; // User-defined instruction result
input user_complete; // User-defined instruction execution is complete
`endif
`ifdef CFG_JTAG_ENABLED
input jtag_clk; // JTAG clock
input jtag_update; // JTAG state machine is in data register update state
input [`LM32_BYTE_RNG] jtag_reg_q;
input [2:0] jtag_reg_addr_q;
`endif
`ifdef CFG_IWB_ENABLED
input [`LM32_WORD_RNG] I_DAT_I; // Instruction Wishbone interface read data
input I_ACK_I; // Instruction Wishbone interface acknowledgement
input I_ERR_I; // Instruction Wishbone interface error
input I_RTY_I; // Instruction Wishbone interface retry
`endif
input [`LM32_WORD_RNG] D_DAT_I; // Data Wishbone interface read data
input D_ACK_I; // Data Wishbone interface acknowledgement
input D_ERR_I; // Data Wishbone interface error
input D_RTY_I; // Data Wishbone interface retry
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
`ifdef CFG_TRACE_ENABLED
output [`LM32_PC_RNG] trace_pc; // PC to trace
reg [`LM32_PC_RNG] trace_pc;
output trace_pc_valid; // Indicates that a new trace PC is valid
reg trace_pc_valid;
output trace_exception; // Indicates an exception has occured
reg trace_exception;
output [`LM32_EID_RNG] trace_eid; // Indicates what type of exception has occured
reg [`LM32_EID_RNG] trace_eid;
output trace_eret; // Indicates an eret instruction has been executed
reg trace_eret;
`ifdef CFG_DEBUG_ENABLED
output trace_bret; // Indicates a bret instruction has been executed
reg trace_bret;
`endif
`endif
`ifdef CFG_JTAG_ENABLED
output [`LM32_BYTE_RNG] jtag_reg_d;
wire [`LM32_BYTE_RNG] jtag_reg_d;
output [2:0] jtag_reg_addr_d;
wire [2:0] jtag_reg_addr_d;
`endif
`ifdef CFG_USER_ENABLED
output user_valid; // Indicates if user_opcode is valid
wire user_valid;
output [`LM32_USER_OPCODE_RNG] user_opcode; // User-defined instruction opcode
reg [`LM32_USER_OPCODE_RNG] user_opcode;
output [`LM32_WORD_RNG] user_operand_0; // First operand for user-defined instruction
wire [`LM32_WORD_RNG] user_operand_0;
output [`LM32_WORD_RNG] user_operand_1; // Second operand for user-defined instruction
wire [`LM32_WORD_RNG] user_operand_1;
`endif
`ifdef CFG_IWB_ENABLED
output [`LM32_WORD_RNG] I_DAT_O; // Instruction Wishbone interface write data
wire [`LM32_WORD_RNG] I_DAT_O;
output [`LM32_WORD_RNG] I_ADR_O; // Instruction Wishbone interface address
wire [`LM32_WORD_RNG] I_ADR_O;
output I_CYC_O; // Instruction Wishbone interface cycle
wire I_CYC_O;
output [`LM32_BYTE_SELECT_RNG] I_SEL_O; // Instruction Wishbone interface byte select
wire [`LM32_BYTE_SELECT_RNG] I_SEL_O;
output I_STB_O; // Instruction Wishbone interface strobe
wire I_STB_O;
output I_WE_O; // Instruction Wishbone interface write enable
wire I_WE_O;
output [`LM32_CTYPE_RNG] I_CTI_O; // Instruction Wishbone interface cycle type
wire [`LM32_CTYPE_RNG] I_CTI_O;
output I_LOCK_O; // Instruction Wishbone interface lock bus
wire I_LOCK_O;
output [`LM32_BTYPE_RNG] I_BTE_O; // Instruction Wishbone interface burst type
wire [`LM32_BTYPE_RNG] I_BTE_O;
`endif
output [`LM32_WORD_RNG] D_DAT_O; // Data Wishbone interface write data
wire [`LM32_WORD_RNG] D_DAT_O;
output [`LM32_WORD_RNG] D_ADR_O; // Data Wishbone interface address
wire [`LM32_WORD_RNG] D_ADR_O;
output D_CYC_O; // Data Wishbone interface cycle
wire D_CYC_O;
output [`LM32_BYTE_SELECT_RNG] D_SEL_O; // Data Wishbone interface byte select
wire [`LM32_BYTE_SELECT_RNG] D_SEL_O;
output D_STB_O; // Data Wishbone interface strobe
wire D_STB_O;
output D_WE_O; // Data Wishbone interface write enable
wire D_WE_O;
output [`LM32_CTYPE_RNG] D_CTI_O; // Data Wishbone interface cycle type
wire [`LM32_CTYPE_RNG] D_CTI_O;
output D_LOCK_O; // Date Wishbone interface lock bus
wire D_LOCK_O;
output [`LM32_BTYPE_RNG] D_BTE_O; // Data Wishbone interface burst type
wire [`LM32_BTYPE_RNG] D_BTE_O;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
// Pipeline registers
`ifdef LM32_CACHE_ENABLED
reg valid_a; // Instruction in A stage is valid
`endif
reg valid_f; // Instruction in F stage is valid
reg valid_d; // Instruction in D stage is valid
reg valid_x; // Instruction in X stage is valid
reg valid_m; // Instruction in M stage is valid
reg valid_w; // Instruction in W stage is valid
wire q_x;
wire [`LM32_WORD_RNG] immediate_d; // Immediate operand
wire load_d; // Indicates a load instruction
reg load_x;
reg load_m;
wire load_q_x;
wire store_q_x;
wire store_d; // Indicates a store instruction
reg store_x;
reg store_m;
wire [`LM32_SIZE_RNG] size_d; // Size of load/store (byte, hword, word)
reg [`LM32_SIZE_RNG] size_x;
wire branch_d; // Indicates a branch instruction
wire branch_predict_d; // Indicates a branch is predicted
wire branch_predict_taken_d; // Indicates a branch is predicted taken
wire [`LM32_PC_RNG] branch_predict_address_d; // Address to which predicted branch jumps
wire [`LM32_PC_RNG] branch_target_d;
wire bi_unconditional;
wire bi_conditional;
reg branch_x;
reg branch_predict_x;
reg branch_predict_taken_x;
reg branch_m;
reg branch_predict_m;
reg branch_predict_taken_m;
wire branch_mispredict_taken_m; // Indicates a branch was mispredicted as taken
wire branch_flushX_m; // Indicates that instruction in X stage must be squashed
wire branch_reg_d; // Branch to register or immediate
wire [`LM32_PC_RNG] branch_offset_d; // Branch offset for immediate branches
reg [`LM32_PC_RNG] branch_target_x; // Address to branch to
reg [`LM32_PC_RNG] branch_target_m;
wire [`LM32_D_RESULT_SEL_0_RNG] d_result_sel_0_d; // Which result should be selected in D stage for operand 0
wire [`LM32_D_RESULT_SEL_1_RNG] d_result_sel_1_d; // Which result should be selected in D stage for operand 1
wire x_result_sel_csr_d; // Select X stage result from CSRs
reg x_result_sel_csr_x;
`ifdef LM32_MC_ARITHMETIC_ENABLED
wire x_result_sel_mc_arith_d; // Select X stage result from multi-cycle arithmetic unit
reg x_result_sel_mc_arith_x;
`endif
`ifdef LM32_NO_BARREL_SHIFT
wire x_result_sel_shift_d; // Select X stage result from shifter
reg x_result_sel_shift_x;
`endif
`ifdef CFG_SIGN_EXTEND_ENABLED
wire x_result_sel_sext_d; // Select X stage result from sign-extend logic
reg x_result_sel_sext_x;
`endif
wire x_result_sel_logic_d; // Select X stage result from logic op unit
reg x_result_sel_logic_x;
`ifdef CFG_USER_ENABLED
wire x_result_sel_user_d; // Select X stage result from user-defined logic
reg x_result_sel_user_x;
`endif
wire x_result_sel_add_d; // Select X stage result from adder
reg x_result_sel_add_x;
wire m_result_sel_compare_d; // Select M stage result from comparison logic
reg m_result_sel_compare_x;
reg m_result_sel_compare_m;
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
wire m_result_sel_shift_d; // Select M stage result from shifter
reg m_result_sel_shift_x;
reg m_result_sel_shift_m;
`endif
wire w_result_sel_load_d; // Select W stage result from load/store unit
reg w_result_sel_load_x;
reg w_result_sel_load_m;
reg w_result_sel_load_w;
`ifdef CFG_PL_MULTIPLY_ENABLED
wire w_result_sel_mul_d; // Select W stage result from multiplier
reg w_result_sel_mul_x;
reg w_result_sel_mul_m;
reg w_result_sel_mul_w;
`endif
wire x_bypass_enable_d; // Whether result is bypassable in X stage
reg x_bypass_enable_x;
wire m_bypass_enable_d; // Whether result is bypassable in M stage
reg m_bypass_enable_x;
reg m_bypass_enable_m;
wire sign_extend_d; // Whether to sign-extend or zero-extend
reg sign_extend_x;
wire write_enable_d; // Register file write enable
reg write_enable_x;
wire write_enable_q_x;
reg write_enable_m;
wire write_enable_q_m;
reg write_enable_w;
wire write_enable_q_w;
wire read_enable_0_d; // Register file read enable 0
wire [`LM32_REG_IDX_RNG] read_idx_0_d; // Register file read index 0
wire read_enable_1_d; // Register file read enable 1
wire [`LM32_REG_IDX_RNG] read_idx_1_d; // Register file read index 1
wire [`LM32_REG_IDX_RNG] write_idx_d; // Register file write index
reg [`LM32_REG_IDX_RNG] write_idx_x;
reg [`LM32_REG_IDX_RNG] write_idx_m;
reg [`LM32_REG_IDX_RNG] write_idx_w;
wire [`LM32_CSR_RNG] csr_d; // CSR read/write index
reg [`LM32_CSR_RNG] csr_x;
wire [`LM32_CONDITION_RNG] condition_d; // Branch condition
reg [`LM32_CONDITION_RNG] condition_x;
`ifdef CFG_DEBUG_ENABLED
wire break_d; // Indicates a break instruction
reg break_x;
`endif
wire scall_d; // Indicates a scall instruction
reg scall_x;
wire eret_d; // Indicates an eret instruction
reg eret_x;
wire eret_q_x;
reg eret_m;
`ifdef CFG_TRACE_ENABLED
reg eret_w;
`endif
`ifdef CFG_DEBUG_ENABLED
wire bret_d; // Indicates a bret instruction
reg bret_x;
wire bret_q_x;
reg bret_m;
`ifdef CFG_TRACE_ENABLED
reg bret_w;
`endif
`endif
wire csr_write_enable_d; // CSR write enable
reg csr_write_enable_x;
wire csr_write_enable_q_x;
`ifdef CFG_USER_ENABLED
wire [`LM32_USER_OPCODE_RNG] user_opcode_d; // User-defined instruction opcode
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
wire bus_error_d; // Indicates an bus error occured while fetching the instruction in this pipeline stage
reg bus_error_x;
reg data_bus_error_exception_m;
reg [`LM32_PC_RNG] memop_pc_w;
`endif
reg [`LM32_WORD_RNG] d_result_0; // Result of instruction in D stage (operand 0)
reg [`LM32_WORD_RNG] d_result_1; // Result of instruction in D stage (operand 1)
reg [`LM32_WORD_RNG] x_result; // Result of instruction in X stage
reg [`LM32_WORD_RNG] m_result; // Result of instruction in M stage
reg [`LM32_WORD_RNG] w_result; // Result of instruction in W stage
reg [`LM32_WORD_RNG] operand_0_x; // Operand 0 for X stage instruction
reg [`LM32_WORD_RNG] operand_1_x; // Operand 1 for X stage instruction
reg [`LM32_WORD_RNG] store_operand_x; // Data read from register to store
reg [`LM32_WORD_RNG] operand_m; // Operand for M stage instruction
reg [`LM32_WORD_RNG] operand_w; // Operand for W stage instruction
// To/from register file
`ifdef CFG_EBR_POSEDGE_REGISTER_FILE
reg [`LM32_WORD_RNG] reg_data_live_0;
reg [`LM32_WORD_RNG] reg_data_live_1;
reg use_buf; // Whether to use reg_data_live or reg_data_buf
reg [`LM32_WORD_RNG] reg_data_buf_0;
reg [`LM32_WORD_RNG] reg_data_buf_1;
`endif
`ifdef LM32_EBR_REGISTER_FILE
`else
reg [`LM32_WORD_RNG] registers[0:(1<<`LM32_REG_IDX_WIDTH)-1]; // Register file
`endif
wire [`LM32_WORD_RNG] reg_data_0; // Register file read port 0 data
wire [`LM32_WORD_RNG] reg_data_1; // Register file read port 1 data
reg [`LM32_WORD_RNG] bypass_data_0; // Register value 0 after bypassing
reg [`LM32_WORD_RNG] bypass_data_1; // Register value 1 after bypassing
wire reg_write_enable_q_w;
reg interlock; // Indicates pipeline should be stalled because of a read-after-write hazzard
wire stall_a; // Stall instruction in A pipeline stage
wire stall_f; // Stall instruction in F pipeline stage
wire stall_d; // Stall instruction in D pipeline stage
wire stall_x; // Stall instruction in X pipeline stage
wire stall_m; // Stall instruction in M pipeline stage
// To/from adder
wire adder_op_d; // Whether to add or subtract
reg adder_op_x;
reg adder_op_x_n; // Inverted version of adder_op_x
wire [`LM32_WORD_RNG] adder_result_x; // Result from adder
wire adder_overflow_x; // Whether a signed overflow occured
wire adder_carry_n_x; // Whether a carry was generated
// To/from logical operations unit
wire [`LM32_LOGIC_OP_RNG] logic_op_d; // Which operation to perform
reg [`LM32_LOGIC_OP_RNG] logic_op_x;
wire [`LM32_WORD_RNG] logic_result_x; // Result of logical operation
`ifdef CFG_SIGN_EXTEND_ENABLED
// From sign-extension unit
wire [`LM32_WORD_RNG] sextb_result_x; // Result of byte sign-extension
wire [`LM32_WORD_RNG] sexth_result_x; // Result of half-word sign-extenstion
wire [`LM32_WORD_RNG] sext_result_x; // Result of sign-extension specified by instruction
`endif
// To/from shifter
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
`ifdef CFG_ROTATE_ENABLED
wire rotate_d; // Whether we should rotate or shift
reg rotate_x;
`endif
wire direction_d; // Which direction to shift in
reg direction_x;
reg direction_m;
wire [`LM32_WORD_RNG] shifter_result_m; // Result of shifter
`endif
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
wire shift_left_d; // Indicates whether to perform a left shift or not
wire shift_left_q_d;
wire shift_right_d; // Indicates whether to perform a right shift or not
wire shift_right_q_d;
`endif
`ifdef LM32_NO_BARREL_SHIFT
wire [`LM32_WORD_RNG] shifter_result_x; // Result of single-bit right shifter
`endif
// To/from multiplier
`ifdef LM32_MULTIPLY_ENABLED
wire [`LM32_WORD_RNG] multiplier_result_w; // Result from multiplier
`endif
`ifdef CFG_MC_MULTIPLY_ENABLED
wire multiply_d; // Indicates whether to perform a multiply or not
wire multiply_q_d;
`endif
// To/from divider
`ifdef CFG_MC_DIVIDE_ENABLED
wire divide_d; // Indicates whether to perform a divider or not
wire divide_q_d;
wire modulus_d;
wire modulus_q_d;
wire divide_by_zero_x; // Indicates an attempt was made to divide by zero
`endif
// To from multi-cycle arithmetic unit
`ifdef LM32_MC_ARITHMETIC_ENABLED
wire mc_stall_request_x; // Multi-cycle arithmetic unit stall request
wire [`LM32_WORD_RNG] mc_result_x;
`endif
// From CSRs
`ifdef CFG_INTERRUPTS_ENABLED
wire [`LM32_WORD_RNG] interrupt_csr_read_data_x;// Data read from interrupt CSRs
`endif
wire [`LM32_WORD_RNG] cfg; // Configuration CSR
wire [`LM32_WORD_RNG] cfg2; // Extended Configuration CSR
`ifdef CFG_CYCLE_COUNTER_ENABLED
reg [`LM32_WORD_RNG] cc; // Cycle counter CSR
`endif
reg [`LM32_WORD_RNG] csr_read_data_x; // Data read from CSRs
// To/from instruction unit
wire [`LM32_PC_RNG] pc_f; // PC of instruction in F stage
wire [`LM32_PC_RNG] pc_d; // PC of instruction in D stage
wire [`LM32_PC_RNG] pc_x; // PC of instruction in X stage
wire [`LM32_PC_RNG] pc_m; // PC of instruction in M stage
wire [`LM32_PC_RNG] pc_w; // PC of instruction in W stage
`ifdef CFG_TRACE_ENABLED
reg [`LM32_PC_RNG] pc_c; // PC of last commited instruction
`endif
`ifdef CFG_EBR_POSEDGE_REGISTER_FILE
wire [`LM32_INSTRUCTION_RNG] instruction_f; // Instruction in F stage
`endif
//pragma attribute instruction_d preserve_signal true
//pragma attribute instruction_d preserve_driver true
wire [`LM32_INSTRUCTION_RNG] instruction_d; // Instruction in D stage
`ifdef CFG_ICACHE_ENABLED
wire iflush; // Flush instruction cache
wire icache_stall_request; // Stall pipeline because instruction cache is busy
wire icache_restart_request; // Restart instruction that caused an instruction cache miss
wire icache_refill_request; // Request to refill instruction cache
wire icache_refilling; // Indicates the instruction cache is being refilled
`endif
`ifdef CFG_IROM_ENABLED
wire [`LM32_WORD_RNG] irom_store_data_m; // Store data to instruction ROM
wire [`LM32_WORD_RNG] irom_address_xm; // Address to instruction ROM from load-store unit
wire [`LM32_WORD_RNG] irom_data_m; // Load data from instruction ROM
wire irom_we_xm; // Indicates data needs to be written to instruction ROM
wire irom_stall_request_x; // Indicates D stage needs to be stalled on a store to instruction ROM
`endif
// To/from load/store unit
`ifdef CFG_DCACHE_ENABLED
wire dflush_x; // Flush data cache
reg dflush_m;
wire dcache_stall_request; // Stall pipeline because data cache is busy
wire dcache_restart_request; // Restart instruction that caused a data cache miss
wire dcache_refill_request; // Request to refill data cache
wire dcache_refilling; // Indicates the data cache is being refilled
`endif
wire [`LM32_WORD_RNG] load_data_w; // Result of a load instruction
wire stall_wb_load; // Stall pipeline because of a load via the data Wishbone interface
// To/from JTAG interface
`ifdef CFG_JTAG_ENABLED
`ifdef CFG_JTAG_UART_ENABLED
wire [`LM32_WORD_RNG] jtx_csr_read_data; // Read data for JTX CSR
wire [`LM32_WORD_RNG] jrx_csr_read_data; // Read data for JRX CSR
`endif
`ifdef CFG_HW_DEBUG_ENABLED
wire jtag_csr_write_enable; // Debugger CSR write enable
wire [`LM32_WORD_RNG] jtag_csr_write_data; // Data to write to specified CSR
wire [`LM32_CSR_RNG] jtag_csr; // Which CSR to write
wire jtag_read_enable;
wire [`LM32_BYTE_RNG] jtag_read_data;
wire jtag_write_enable;
wire [`LM32_BYTE_RNG] jtag_write_data;
wire [`LM32_WORD_RNG] jtag_address;
wire jtag_access_complete;
`endif
`ifdef CFG_DEBUG_ENABLED
wire jtag_break; // Request from debugger to raise a breakpoint
`endif
`endif
// Hazzard detection
wire raw_x_0; // RAW hazzard between instruction in X stage and read port 0
wire raw_x_1; // RAW hazzard between instruction in X stage and read port 1
wire raw_m_0; // RAW hazzard between instruction in M stage and read port 0
wire raw_m_1; // RAW hazzard between instruction in M stage and read port 1
wire raw_w_0; // RAW hazzard between instruction in W stage and read port 0
wire raw_w_1; // RAW hazzard between instruction in W stage and read port 1
// Control flow
wire cmp_zero; // Result of comparison is zero
wire cmp_negative; // Result of comparison is negative
wire cmp_overflow; // Comparison produced an overflow
wire cmp_carry_n; // Comparison produced a carry, inverted
reg condition_met_x; // Condition of branch instruction is met
reg condition_met_m;
`ifdef CFG_FAST_UNCONDITIONAL_BRANCH
wire branch_taken_x; // Branch is taken in X stage
`endif
wire branch_taken_m; // Branch is taken in M stage
wire kill_f; // Kill instruction in F stage
wire kill_d; // Kill instruction in D stage
wire kill_x; // Kill instruction in X stage
wire kill_m; // Kill instruction in M stage
wire kill_w; // Kill instruction in W stage
reg [`LM32_PC_WIDTH+2-1:8] eba; // Exception Base Address (EBA) CSR
`ifdef CFG_DEBUG_ENABLED
reg [`LM32_PC_WIDTH+2-1:8] deba; // Debug Exception Base Address (DEBA) CSR
`endif
reg [`LM32_EID_RNG] eid_x; // Exception ID in X stage
`ifdef CFG_TRACE_ENABLED
reg [`LM32_EID_RNG] eid_m; // Exception ID in M stage
reg [`LM32_EID_RNG] eid_w; // Exception ID in W stage
`endif
`ifdef CFG_DEBUG_ENABLED
`ifdef LM32_SINGLE_STEP_ENABLED
wire dc_ss; // Is single-step enabled
`endif
wire dc_re; // Remap all exceptions
wire exception_x; // An exception occured in the X stage
reg exception_m; // An instruction that caused an exception is in the M stage
wire debug_exception_x; // Indicates if a debug exception has occured
reg debug_exception_m;
reg debug_exception_w;
wire debug_exception_q_w;
wire non_debug_exception_x; // Indicates if a non debug exception has occured
reg non_debug_exception_m;
reg non_debug_exception_w;
wire non_debug_exception_q_w;
`else
wire exception_x; // Indicates if a debug exception has occured
reg exception_m;
reg exception_w;
wire exception_q_w;
`endif
`ifdef CFG_DEBUG_ENABLED
`ifdef CFG_JTAG_ENABLED
wire reset_exception; // Indicates if a reset exception has occured
`endif
`endif
`ifdef CFG_INTERRUPTS_ENABLED
wire interrupt_exception; // Indicates if an interrupt exception has occured
`endif
`ifdef CFG_DEBUG_ENABLED
wire breakpoint_exception; // Indicates if a breakpoint exception has occured
wire watchpoint_exception; // Indicates if a watchpoint exception has occured
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
wire instruction_bus_error_exception; // Indicates if an instruction bus error exception has occured
wire data_bus_error_exception; // Indicates if a data bus error exception has occured
`endif
`ifdef CFG_MC_DIVIDE_ENABLED
wire divide_by_zero_exception; // Indicates if a divide by zero exception has occured
`endif
wire system_call_exception; // Indicates if a system call exception has occured
`ifdef CFG_BUS_ERRORS_ENABLED
reg data_bus_error_seen; // Indicates if a data bus error was seen
`endif
/////////////////////////////////////////////////////
// Functions
/////////////////////////////////////////////////////
`include "lm32_functions.v"
/////////////////////////////////////////////////////
// Instantiations
/////////////////////////////////////////////////////
// Instruction unit
lm32_instruction_unit #(
.associativity (icache_associativity),
.sets (icache_sets),
.bytes_per_line (icache_bytes_per_line),
.base_address (icache_base_address),
.limit (icache_limit)
) instruction_unit (
// ----- Inputs -------
.clk_i (clk_i),
.rst_i (rst_i),
// From pipeline
.stall_a (stall_a),
.stall_f (stall_f),
.stall_d (stall_d),
.stall_x (stall_x),
.stall_m (stall_m),
.valid_f (valid_f),
.valid_d (valid_d),
.kill_f (kill_f),
.branch_predict_taken_d (branch_predict_taken_d),
.branch_predict_address_d (branch_predict_address_d),
`ifdef CFG_FAST_UNCONDITIONAL_BRANCH
.branch_taken_x (branch_taken_x),
.branch_target_x (branch_target_x),
`endif
.exception_m (exception_m),
.branch_taken_m (branch_taken_m),
.branch_mispredict_taken_m (branch_mispredict_taken_m),
.branch_target_m (branch_target_m),
`ifdef CFG_ICACHE_ENABLED
.iflush (iflush),
`endif
`ifdef CFG_IROM_ENABLED
.irom_store_data_m (irom_store_data_m),
.irom_address_xm (irom_address_xm),
.irom_we_xm (irom_we_xm),
`endif
`ifdef CFG_DCACHE_ENABLED
.dcache_restart_request (dcache_restart_request),
.dcache_refill_request (dcache_refill_request),
.dcache_refilling (dcache_refilling),
`endif
`ifdef CFG_IWB_ENABLED
// From Wishbone
.i_dat_i (I_DAT_I),
.i_ack_i (I_ACK_I),
.i_err_i (I_ERR_I),
.i_rty_i (I_RTY_I),
`endif
`ifdef CFG_HW_DEBUG_ENABLED
.jtag_read_enable (jtag_read_enable),
.jtag_write_enable (jtag_write_enable),
.jtag_write_data (jtag_write_data),
.jtag_address (jtag_address),
`endif
// ----- Outputs -------
// To pipeline
.pc_f (pc_f),
.pc_d (pc_d),
.pc_x (pc_x),
.pc_m (pc_m),
.pc_w (pc_w),
`ifdef CFG_ICACHE_ENABLED
.icache_stall_request (icache_stall_request),
.icache_restart_request (icache_restart_request),
.icache_refill_request (icache_refill_request),
.icache_refilling (icache_refilling),
`endif
`ifdef CFG_IROM_ENABLED
.irom_data_m (irom_data_m),
`endif
`ifdef CFG_IWB_ENABLED
// To Wishbone
.i_dat_o (I_DAT_O),
.i_adr_o (I_ADR_O),
.i_cyc_o (I_CYC_O),
.i_sel_o (I_SEL_O),
.i_stb_o (I_STB_O),
.i_we_o (I_WE_O),
.i_cti_o (I_CTI_O),
.i_lock_o (I_LOCK_O),
.i_bte_o (I_BTE_O),
`endif
`ifdef CFG_HW_DEBUG_ENABLED
.jtag_read_data (jtag_read_data),
.jtag_access_complete (jtag_access_complete),
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
.bus_error_d (bus_error_d),
`endif
`ifdef CFG_EBR_POSEDGE_REGISTER_FILE
.instruction_f (instruction_f),
`endif
.instruction_d (instruction_d)
);
// Instruction decoder
lm32_decoder decoder (
// ----- Inputs -------
.instruction (instruction_d),
// ----- Outputs -------
.d_result_sel_0 (d_result_sel_0_d),
.d_result_sel_1 (d_result_sel_1_d),
.x_result_sel_csr (x_result_sel_csr_d),
`ifdef LM32_MC_ARITHMETIC_ENABLED
.x_result_sel_mc_arith (x_result_sel_mc_arith_d),
`endif
`ifdef LM32_NO_BARREL_SHIFT
.x_result_sel_shift (x_result_sel_shift_d),
`endif
`ifdef CFG_SIGN_EXTEND_ENABLED
.x_result_sel_sext (x_result_sel_sext_d),
`endif
.x_result_sel_logic (x_result_sel_logic_d),
`ifdef CFG_USER_ENABLED
.x_result_sel_user (x_result_sel_user_d),
`endif
.x_result_sel_add (x_result_sel_add_d),
.m_result_sel_compare (m_result_sel_compare_d),
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
.m_result_sel_shift (m_result_sel_shift_d),
`endif
.w_result_sel_load (w_result_sel_load_d),
`ifdef CFG_PL_MULTIPLY_ENABLED
.w_result_sel_mul (w_result_sel_mul_d),
`endif
.x_bypass_enable (x_bypass_enable_d),
.m_bypass_enable (m_bypass_enable_d),
.read_enable_0 (read_enable_0_d),
.read_idx_0 (read_idx_0_d),
.read_enable_1 (read_enable_1_d),
.read_idx_1 (read_idx_1_d),
.write_enable (write_enable_d),
.write_idx (write_idx_d),
.immediate (immediate_d),
.branch_offset (branch_offset_d),
.load (load_d),
.store (store_d),
.size (size_d),
.sign_extend (sign_extend_d),
.adder_op (adder_op_d),
.logic_op (logic_op_d),
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
.direction (direction_d),
`endif
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
.shift_left (shift_left_d),
.shift_right (shift_right_d),
`endif
`ifdef CFG_MC_MULTIPLY_ENABLED
.multiply (multiply_d),
`endif
`ifdef CFG_MC_DIVIDE_ENABLED
.divide (divide_d),
.modulus (modulus_d),
`endif
.branch (branch_d),
.bi_unconditional (bi_unconditional),
.bi_conditional (bi_conditional),
.branch_reg (branch_reg_d),
.condition (condition_d),
`ifdef CFG_DEBUG_ENABLED
.break_opcode (break_d),
`endif
.scall (scall_d),
.eret (eret_d),
`ifdef CFG_DEBUG_ENABLED
.bret (bret_d),
`endif
`ifdef CFG_USER_ENABLED
.user_opcode (user_opcode_d),
`endif
.csr_write_enable (csr_write_enable_d)
);
// Load/store unit
lm32_load_store_unit #(
.associativity (dcache_associativity),
.sets (dcache_sets),
.bytes_per_line (dcache_bytes_per_line),
.base_address (dcache_base_address),
.limit (dcache_limit)
) load_store_unit (
// ----- Inputs -------
.clk_i (clk_i),
.rst_i (rst_i),
// From pipeline
.stall_a (stall_a),
.stall_x (stall_x),
.stall_m (stall_m),
.kill_x (kill_x),
.kill_m (kill_m),
.exception_m (exception_m),
.store_operand_x (store_operand_x),
.load_store_address_x (adder_result_x),
.load_store_address_m (operand_m),
.load_store_address_w (operand_w[1:0]),
.load_x (load_x),
.store_x (store_x),
.load_q_x (load_q_x),
.store_q_x (store_q_x),
.load_q_m (load_q_m),
.store_q_m (store_q_m),
.sign_extend_x (sign_extend_x),
.size_x (size_x),
`ifdef CFG_DCACHE_ENABLED
.dflush (dflush_m),
`endif
`ifdef CFG_IROM_ENABLED
.irom_data_m (irom_data_m),
`endif
// From Wishbone
.d_dat_i (D_DAT_I),
.d_ack_i (D_ACK_I),
.d_err_i (D_ERR_I),
.d_rty_i (D_RTY_I),
// ----- Outputs -------
// To pipeline
`ifdef CFG_DCACHE_ENABLED
.dcache_refill_request (dcache_refill_request),
.dcache_restart_request (dcache_restart_request),
.dcache_stall_request (dcache_stall_request),
.dcache_refilling (dcache_refilling),
`endif
`ifdef CFG_IROM_ENABLED
.irom_store_data_m (irom_store_data_m),
.irom_address_xm (irom_address_xm),
.irom_we_xm (irom_we_xm),
.irom_stall_request_x (irom_stall_request_x),
`endif
.load_data_w (load_data_w),
.stall_wb_load (stall_wb_load),
// To Wishbone
.d_dat_o (D_DAT_O),
.d_adr_o (D_ADR_O),
.d_cyc_o (D_CYC_O),
.d_sel_o (D_SEL_O),
.d_stb_o (D_STB_O),
.d_we_o (D_WE_O),
.d_cti_o (D_CTI_O),
.d_lock_o (D_LOCK_O),
.d_bte_o (D_BTE_O)
);
// Adder
lm32_adder adder (
// ----- Inputs -------
.adder_op_x (adder_op_x),
.adder_op_x_n (adder_op_x_n),
.operand_0_x (operand_0_x),
.operand_1_x (operand_1_x),
// ----- Outputs -------
.adder_result_x (adder_result_x),
.adder_carry_n_x (adder_carry_n_x),
.adder_overflow_x (adder_overflow_x)
);
// Logic operations
lm32_logic_op logic_op (
// ----- Inputs -------
.logic_op_x (logic_op_x),
.operand_0_x (operand_0_x),
.operand_1_x (operand_1_x),
// ----- Outputs -------
.logic_result_x (logic_result_x)
);
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
// Pipelined barrel-shifter
lm32_shifter shifter (
// ----- Inputs -------
.clk_i (clk_i),
.rst_i (rst_i),
.stall_x (stall_x),
.direction_x (direction_x),
.sign_extend_x (sign_extend_x),
.operand_0_x (operand_0_x),
.operand_1_x (operand_1_x),
// ----- Outputs -------
.shifter_result_m (shifter_result_m)
);
`endif
`ifdef CFG_PL_MULTIPLY_ENABLED
// Pipeline fixed-point multiplier
lm32_multiplier multiplier (
// ----- Inputs -------
.clk_i (clk_i),
.rst_i (rst_i),
.stall_x (stall_x),
.stall_m (stall_m),
.operand_0 (d_result_0),
.operand_1 (d_result_1),
// ----- Outputs -------
.result (multiplier_result_w)
);
`endif
`ifdef LM32_MC_ARITHMETIC_ENABLED
// Multi-cycle arithmetic
lm32_mc_arithmetic mc_arithmetic (
// ----- Inputs -------
.clk_i (clk_i),
.rst_i (rst_i),
.stall_d (stall_d),
.kill_x (kill_x),
`ifdef CFG_MC_DIVIDE_ENABLED
.divide_d (divide_q_d),
.modulus_d (modulus_q_d),
`endif
`ifdef CFG_MC_MULTIPLY_ENABLED
.multiply_d (multiply_q_d),
`endif
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
.shift_left_d (shift_left_q_d),
.shift_right_d (shift_right_q_d),
.sign_extend_d (sign_extend_d),
`endif
.operand_0_d (d_result_0),
.operand_1_d (d_result_1),
// ----- Outputs -------
.result_x (mc_result_x),
`ifdef CFG_MC_DIVIDE_ENABLED
.divide_by_zero_x (divide_by_zero_x),
`endif
.stall_request_x (mc_stall_request_x)
);
`endif
`ifdef CFG_INTERRUPTS_ENABLED
// Interrupt unit
lm32_interrupt interrupt_unit (
// ----- Inputs -------
.clk_i (clk_i),
.rst_i (rst_i),
// From external devices
.interrupt (interrupt),
// From pipeline
.stall_x (stall_x),
`ifdef CFG_DEBUG_ENABLED
.non_debug_exception (non_debug_exception_q_w),
.debug_exception (debug_exception_q_w),
`else
.exception (exception_q_w),
`endif
.eret_q_x (eret_q_x),
`ifdef CFG_DEBUG_ENABLED
.bret_q_x (bret_q_x),
`endif
.csr (csr_x),
.csr_write_data (operand_1_x),
.csr_write_enable (csr_write_enable_q_x),
// ----- Outputs -------
.interrupt_exception (interrupt_exception),
// To pipeline
.csr_read_data (interrupt_csr_read_data_x)
);
`endif
`ifdef CFG_JTAG_ENABLED
// JTAG interface
lm32_jtag jtag (
// ----- Inputs -------
.clk_i (clk_i),
.rst_i (rst_i),
// From JTAG
.jtag_clk (jtag_clk),
.jtag_update (jtag_update),
.jtag_reg_q (jtag_reg_q),
.jtag_reg_addr_q (jtag_reg_addr_q),
// From pipeline
`ifdef CFG_JTAG_UART_ENABLED
.csr (csr_x),
.csr_write_data (operand_1_x),
.csr_write_enable (csr_write_enable_q_x),
.stall_x (stall_x),
`endif
`ifdef CFG_HW_DEBUG_ENABLED
.jtag_read_data (jtag_read_data),
.jtag_access_complete (jtag_access_complete),
`endif
`ifdef CFG_DEBUG_ENABLED
.exception_q_w (debug_exception_q_w || non_debug_exception_q_w),
`endif
// ----- Outputs -------
// To pipeline
`ifdef CFG_JTAG_UART_ENABLED
.jtx_csr_read_data (jtx_csr_read_data),
.jrx_csr_read_data (jrx_csr_read_data),
`endif
`ifdef CFG_HW_DEBUG_ENABLED
.jtag_csr_write_enable (jtag_csr_write_enable),
.jtag_csr_write_data (jtag_csr_write_data),
.jtag_csr (jtag_csr),
.jtag_read_enable (jtag_read_enable),
.jtag_write_enable (jtag_write_enable),
.jtag_write_data (jtag_write_data),
.jtag_address (jtag_address),
`endif
`ifdef CFG_DEBUG_ENABLED
.jtag_break (jtag_break),
.jtag_reset (reset_exception),
`endif
// To JTAG
.jtag_reg_d (jtag_reg_d),
.jtag_reg_addr_d (jtag_reg_addr_d)
);
`endif
`ifdef CFG_DEBUG_ENABLED
// Debug unit
lm32_debug #(
.breakpoints (breakpoints),
.watchpoints (watchpoints)
) hw_debug (
// ----- Inputs -------
.clk_i (clk_i),
.rst_i (rst_i),
.pc_x (pc_x),
.load_x (load_x),
.store_x (store_x),
.load_store_address_x (adder_result_x),
.csr_write_enable_x (csr_write_enable_q_x),
.csr_write_data (operand_1_x),
.csr_x (csr_x),
`ifdef CFG_HW_DEBUG_ENABLED
.jtag_csr_write_enable (jtag_csr_write_enable),
.jtag_csr_write_data (jtag_csr_write_data),
.jtag_csr (jtag_csr),
`endif
`ifdef LM32_SINGLE_STEP_ENABLED
.eret_q_x (eret_q_x),
.bret_q_x (bret_q_x),
.stall_x (stall_x),
.exception_x (exception_x),
.q_x (q_x),
`ifdef CFG_DCACHE_ENABLED
.dcache_refill_request (dcache_refill_request),
`endif
`endif
// ----- Outputs -------
`ifdef LM32_SINGLE_STEP_ENABLED
.dc_ss (dc_ss),
`endif
.dc_re (dc_re),
.bp_match (bp_match),
.wp_match (wp_match)
);
`endif
// Register file
`ifdef CFG_EBR_POSEDGE_REGISTER_FILE
/*----------------------------------------------------------------------
Register File is implemented using EBRs. There can be three accesses to
the register file in each cycle: two reads and one write. On-chip block
RAM has two read/write ports. To accomodate three accesses, two on-chip
block RAMs are used (each register file "write" is made to both block
RAMs).
One limitation of the on-chip block RAMs is that one cannot perform a
read and write to same location in a cycle (if this is done, then the
data read out is indeterminate).
----------------------------------------------------------------------*/
wire [31:0] regfile_data_0, regfile_data_1;
reg [31:0] w_result_d;
reg regfile_raw_0, regfile_raw_0_nxt;
reg regfile_raw_1, regfile_raw_1_nxt;
/*----------------------------------------------------------------------
Check if read and write is being performed to same register in current
cycle? This is done by comparing the read and write IDXs.
----------------------------------------------------------------------*/
always @(reg_write_enable_q_w or write_idx_w or instruction_f)
begin
if (reg_write_enable_q_w
&& (write_idx_w == instruction_f[25:21]))
regfile_raw_0_nxt = 1'b1;
else
regfile_raw_0_nxt = 1'b0;
if (reg_write_enable_q_w
&& (write_idx_w == instruction_f[20:16]))
regfile_raw_1_nxt = 1'b1;
else
regfile_raw_1_nxt = 1'b0;
end
/*----------------------------------------------------------------------
Select latched (delayed) write value or data from register file. If
read in previous cycle was performed to register written to in same
cycle, then latched (delayed) write value is selected.
----------------------------------------------------------------------*/
always @(regfile_raw_0 or w_result_d or regfile_data_0)
if (regfile_raw_0)
reg_data_live_0 = w_result_d;
else
reg_data_live_0 = regfile_data_0;
/*----------------------------------------------------------------------
Select latched (delayed) write value or data from register file. If
read in previous cycle was performed to register written to in same
cycle, then latched (delayed) write value is selected.
----------------------------------------------------------------------*/
always @(regfile_raw_1 or w_result_d or regfile_data_1)
if (regfile_raw_1)
reg_data_live_1 = w_result_d;
else
reg_data_live_1 = regfile_data_1;
/*----------------------------------------------------------------------
Latch value written to register file
----------------------------------------------------------------------*/
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
if (rst_i == `TRUE)
begin
regfile_raw_0 <= 1'b0;
regfile_raw_1 <= 1'b0;
w_result_d <= 32'b0;
end
else
begin
regfile_raw_0 <= regfile_raw_0_nxt;
regfile_raw_1 <= regfile_raw_1_nxt;
w_result_d <= w_result;
end
/*----------------------------------------------------------------------
Register file instantiation as Pseudo-Dual Port EBRs.
----------------------------------------------------------------------*/
pmi_ram_dp
#(
// ----- Parameters -----
.pmi_wr_addr_depth(1<<5),
.pmi_wr_addr_width(5),
.pmi_wr_data_width(32),
.pmi_rd_addr_depth(1<<5),
.pmi_rd_addr_width(5),
.pmi_rd_data_width(32),
.pmi_regmode("noreg"),
.pmi_gsr("enable"),
.pmi_resetmode("sync"),
.pmi_init_file("none"),
.pmi_init_file_format("binary"),
.pmi_family(`LATTICE_FAMILY),
.module_type("pmi_ram_dp")
)
reg_0
(
// ----- Inputs -----
.Data(w_result),
.WrAddress(write_idx_w),
.RdAddress(instruction_f[25:21]),
.WrClock(clk_i),
.RdClock(clk_i),
.WrClockEn(`TRUE),
.RdClockEn(`TRUE),
.WE(reg_write_enable_q_w),
.Reset(rst_i),
// ----- Outputs -----
.Q(regfile_data_0)
);
pmi_ram_dp
#(
// ----- Parameters -----
.pmi_wr_addr_depth(1<<5),
.pmi_wr_addr_width(5),
.pmi_wr_data_width(32),
.pmi_rd_addr_depth(1<<5),
.pmi_rd_addr_width(5),
.pmi_rd_data_width(32),
.pmi_regmode("noreg"),
.pmi_gsr("enable"),
.pmi_resetmode("sync"),
.pmi_init_file("none"),
.pmi_init_file_format("binary"),
.pmi_family(`LATTICE_FAMILY),
.module_type("pmi_ram_dp")
)
reg_1
(
// ----- Inputs -----
.Data(w_result),
.WrAddress(write_idx_w),
.RdAddress(instruction_f[20:16]),
.WrClock(clk_i),
.RdClock(clk_i),
.WrClockEn(`TRUE),
.RdClockEn(`TRUE),
.WE(reg_write_enable_q_w),
.Reset(rst_i),
// ----- Outputs -----
.Q(regfile_data_1)
);
`endif
`ifdef CFG_EBR_NEGEDGE_REGISTER_FILE
pmi_ram_dp
#(
// ----- Parameters -----
.pmi_wr_addr_depth(1<<5),
.pmi_wr_addr_width(5),
.pmi_wr_data_width(32),
.pmi_rd_addr_depth(1<<5),
.pmi_rd_addr_width(5),
.pmi_rd_data_width(32),
.pmi_regmode("noreg"),
.pmi_gsr("enable"),
.pmi_resetmode("sync"),
.pmi_init_file("none"),
.pmi_init_file_format("binary"),
.pmi_family(`LATTICE_FAMILY),
.module_type("pmi_ram_dp")
)
reg_0
(
// ----- Inputs -----
.Data(w_result),
.WrAddress(write_idx_w),
.RdAddress(read_idx_0_d),
.WrClock(clk_i),
.RdClock(clk_n_i),
.WrClockEn(`TRUE),
.RdClockEn(stall_f == `FALSE),
.WE(reg_write_enable_q_w),
.Reset(rst_i),
// ----- Outputs -----
.Q(reg_data_0)
);
pmi_ram_dp
#(
// ----- Parameters -----
.pmi_wr_addr_depth(1<<5),
.pmi_wr_addr_width(5),
.pmi_wr_data_width(32),
.pmi_rd_addr_depth(1<<5),
.pmi_rd_addr_width(5),
.pmi_rd_data_width(32),
.pmi_regmode("noreg"),
.pmi_gsr("enable"),
.pmi_resetmode("sync"),
.pmi_init_file("none"),
.pmi_init_file_format("binary"),
.pmi_family(`LATTICE_FAMILY),
.module_type("pmi_ram_dp")
)
reg_1
(
// ----- Inputs -----
.Data(w_result),
.WrAddress(write_idx_w),
.RdAddress(read_idx_1_d),
.WrClock(clk_i),
.RdClock(clk_n_i),
.WrClockEn(`TRUE),
.RdClockEn(stall_f == `FALSE),
.WE(reg_write_enable_q_w),
.Reset(rst_i),
// ----- Outputs -----
.Q(reg_data_1)
);
`endif
/////////////////////////////////////////////////////
// Combinational Logic
/////////////////////////////////////////////////////
`ifdef CFG_EBR_POSEDGE_REGISTER_FILE
// Select between buffered and live data from register file
assign reg_data_0 = use_buf ? reg_data_buf_0 : reg_data_live_0;
assign reg_data_1 = use_buf ? reg_data_buf_1 : reg_data_live_1;
`endif
`ifdef LM32_EBR_REGISTER_FILE
`else
// Register file read ports
assign reg_data_0 = registers[read_idx_0_d];
assign reg_data_1 = registers[read_idx_1_d];
`endif
// Detect read-after-write hazzards
assign raw_x_0 = (write_idx_x == read_idx_0_d) && (write_enable_q_x == `TRUE);
assign raw_m_0 = (write_idx_m == read_idx_0_d) && (write_enable_q_m == `TRUE);
assign raw_w_0 = (write_idx_w == read_idx_0_d) && (write_enable_q_w == `TRUE);
assign raw_x_1 = (write_idx_x == read_idx_1_d) && (write_enable_q_x == `TRUE);
assign raw_m_1 = (write_idx_m == read_idx_1_d) && (write_enable_q_m == `TRUE);
assign raw_w_1 = (write_idx_w == read_idx_1_d) && (write_enable_q_w == `TRUE);
// Interlock detection - Raise an interlock for RAW hazzards
always @(*)
begin
if ( ( (x_bypass_enable_x == `FALSE)
&& ( ((read_enable_0_d == `TRUE) && (raw_x_0 == `TRUE))
|| ((read_enable_1_d == `TRUE) && (raw_x_1 == `TRUE))
)
)
|| ( (m_bypass_enable_m == `FALSE)
&& ( ((read_enable_0_d == `TRUE) && (raw_m_0 == `TRUE))
|| ((read_enable_1_d == `TRUE) && (raw_m_1 == `TRUE))
)
)
)
interlock = `TRUE;
else
interlock = `FALSE;
end
// Bypass for reg port 0
always @(*)
begin
if (raw_x_0 == `TRUE)
bypass_data_0 = x_result;
else if (raw_m_0 == `TRUE)
bypass_data_0 = m_result;
else if (raw_w_0 == `TRUE)
bypass_data_0 = w_result;
else
bypass_data_0 = reg_data_0;
end
// Bypass for reg port 1
always @(*)
begin
if (raw_x_1 == `TRUE)
bypass_data_1 = x_result;
else if (raw_m_1 == `TRUE)
bypass_data_1 = m_result;
else if (raw_w_1 == `TRUE)
bypass_data_1 = w_result;
else
bypass_data_1 = reg_data_1;
end
/*----------------------------------------------------------------------
Branch prediction is performed in D stage of pipeline. Only PC-relative
branches are predicted: forward-pointing conditional branches are not-
taken, while backward-pointing conditional branches are taken.
Unconditional branches are always predicted taken!
----------------------------------------------------------------------*/
assign branch_predict_d = bi_unconditional | bi_conditional;
assign branch_predict_taken_d = bi_unconditional ? 1'b1 : (bi_conditional ? instruction_d[15] : 1'b0);
// Compute branch target address: Branch PC PLUS Offset
assign branch_target_d = pc_d + branch_offset_d;
// Compute fetch address. Address of instruction sequentially after the
// branch if branch is not taken. Target address of branch is branch is
// taken
assign branch_predict_address_d = branch_predict_taken_d ? branch_target_d : pc_f;
// D stage result selection
always @(*)
begin
d_result_0 = d_result_sel_0_d[0] ? {pc_f, 2'b00} : bypass_data_0;
case (d_result_sel_1_d)
`LM32_D_RESULT_SEL_1_ZERO: d_result_1 = {`LM32_WORD_WIDTH{1'b0}};
`LM32_D_RESULT_SEL_1_REG_1: d_result_1 = bypass_data_1;
`LM32_D_RESULT_SEL_1_IMMEDIATE: d_result_1 = immediate_d;
default: d_result_1 = {`LM32_WORD_WIDTH{1'bx}};
endcase
end
`ifdef CFG_USER_ENABLED
// Operands for user-defined instructions
assign user_operand_0 = operand_0_x;
assign user_operand_1 = operand_1_x;
`endif
`ifdef CFG_SIGN_EXTEND_ENABLED
// Sign-extension
assign sextb_result_x = {{24{operand_0_x[7]}}, operand_0_x[7:0]};
assign sexth_result_x = {{16{operand_0_x[15]}}, operand_0_x[15:0]};
assign sext_result_x = size_x == `LM32_SIZE_BYTE ? sextb_result_x : sexth_result_x;
`endif
`ifdef LM32_NO_BARREL_SHIFT
// Only single bit shift operations are supported when barrel-shifter isn't implemented
assign shifter_result_x = {operand_0_x[`LM32_WORD_WIDTH-1] & sign_extend_x, operand_0_x[`LM32_WORD_WIDTH-1:1]};
`endif
// Condition evaluation
assign cmp_zero = operand_0_x == operand_1_x;
assign cmp_negative = adder_result_x[`LM32_WORD_WIDTH-1];
assign cmp_overflow = adder_overflow_x;
assign cmp_carry_n = adder_carry_n_x;
always @(*)
begin
case (condition_x)
`LM32_CONDITION_U1: condition_met_x = `TRUE;
`LM32_CONDITION_U2: condition_met_x = `TRUE;
`LM32_CONDITION_E: condition_met_x = cmp_zero;
`LM32_CONDITION_NE: condition_met_x = !cmp_zero;
`LM32_CONDITION_G: condition_met_x = !cmp_zero && (cmp_negative == cmp_overflow);
`LM32_CONDITION_GU: condition_met_x = cmp_carry_n && !cmp_zero;
`LM32_CONDITION_GE: condition_met_x = cmp_negative == cmp_overflow;
`LM32_CONDITION_GEU: condition_met_x = cmp_carry_n;
default: condition_met_x = 1'bx;
endcase
end
// X stage result selection
always @(*)
begin
x_result = x_result_sel_add_x ? adder_result_x
: x_result_sel_csr_x ? csr_read_data_x
`ifdef CFG_SIGN_EXTEND_ENABLED
: x_result_sel_sext_x ? sext_result_x
`endif
`ifdef CFG_USER_ENABLED
: x_result_sel_user_x ? user_result
`endif
`ifdef LM32_NO_BARREL_SHIFT
: x_result_sel_shift_x ? shifter_result_x
`endif
`ifdef LM32_MC_ARITHMETIC_ENABLED
: x_result_sel_mc_arith_x ? mc_result_x
`endif
: logic_result_x;
end
// M stage result selection
always @(*)
begin
m_result = m_result_sel_compare_m ? {{`LM32_WORD_WIDTH-1{1'b0}}, condition_met_m}
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
: m_result_sel_shift_m ? shifter_result_m
`endif
: operand_m;
end
// W stage result selection
always @(*)
begin
w_result = w_result_sel_load_w ? load_data_w
`ifdef CFG_PL_MULTIPLY_ENABLED
: w_result_sel_mul_w ? multiplier_result_w
`endif
: operand_w;
end
`ifdef CFG_FAST_UNCONDITIONAL_BRANCH
// Indicate when a branch should be taken in X stage
assign branch_taken_x = (stall_x == `FALSE)
&& ( (branch_x == `TRUE)
&& ((condition_x == `LM32_CONDITION_U1) || (condition_x == `LM32_CONDITION_U2))
&& (valid_x == `TRUE)
&& (branch_predict_x == `FALSE)
);
`endif
// Indicate when a branch should be taken in M stage (exceptions are a type of branch)
assign branch_taken_m = (stall_m == `FALSE)
&& ( ( (branch_m == `TRUE)
&& (valid_m == `TRUE)
&& ( ( (condition_met_m == `TRUE)
&& (branch_predict_taken_m == `FALSE)
)
|| ( (condition_met_m == `FALSE)
&& (branch_predict_m == `TRUE)
&& (branch_predict_taken_m == `TRUE)
)
)
)
|| (exception_m == `TRUE)
);
// Indicate when a branch in M stage is mispredicted as being taken
assign branch_mispredict_taken_m = (condition_met_m == `FALSE)
&& (branch_predict_m == `TRUE)
&& (branch_predict_taken_m == `TRUE);
// Indicate when a branch in M stage will cause flush in X stage
assign branch_flushX_m = (stall_m == `FALSE)
&& ( ( (branch_m == `TRUE)
&& (valid_m == `TRUE)
&& ( (condition_met_m == `TRUE)
|| ( (condition_met_m == `FALSE)
&& (branch_predict_m == `TRUE)
&& (branch_predict_taken_m == `TRUE)
)
)
)
|| (exception_m == `TRUE)
);
// Generate signal that will kill instructions in each pipeline stage when necessary
assign kill_f = ( (valid_d == `TRUE)
&& (branch_predict_taken_d == `TRUE)
)
|| (branch_taken_m == `TRUE)
`ifdef CFG_FAST_UNCONDITIONAL_BRANCH
|| (branch_taken_x == `TRUE)
`endif
`ifdef CFG_ICACHE_ENABLED
|| (icache_refill_request == `TRUE)
`endif
`ifdef CFG_DCACHE_ENABLED
|| (dcache_refill_request == `TRUE)
`endif
;
assign kill_d = (branch_taken_m == `TRUE)
`ifdef CFG_FAST_UNCONDITIONAL_BRANCH
|| (branch_taken_x == `TRUE)
`endif
`ifdef CFG_ICACHE_ENABLED
|| (icache_refill_request == `TRUE)
`endif
`ifdef CFG_DCACHE_ENABLED
|| (dcache_refill_request == `TRUE)
`endif
;
assign kill_x = (branch_flushX_m == `TRUE)
`ifdef CFG_DCACHE_ENABLED
|| (dcache_refill_request == `TRUE)
`endif
;
assign kill_m = `FALSE
`ifdef CFG_DCACHE_ENABLED
|| (dcache_refill_request == `TRUE)
`endif
;
assign kill_w = `FALSE
`ifdef CFG_DCACHE_ENABLED
|| (dcache_refill_request == `TRUE)
`endif
;
// Exceptions
`ifdef CFG_DEBUG_ENABLED
assign breakpoint_exception = ( ( (break_x == `TRUE)
|| (bp_match == `TRUE)
)
&& (valid_x == `TRUE)
)
`ifdef CFG_JTAG_ENABLED
|| (jtag_break == `TRUE)
`endif
;
`endif
`ifdef CFG_DEBUG_ENABLED
assign watchpoint_exception = wp_match == `TRUE;
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
assign instruction_bus_error_exception = ( (bus_error_x == `TRUE)
&& (valid_x == `TRUE)
);
assign data_bus_error_exception = data_bus_error_seen == `TRUE;
`endif
`ifdef CFG_MC_DIVIDE_ENABLED
assign divide_by_zero_exception = divide_by_zero_x == `TRUE;
`endif
assign system_call_exception = ( (scall_x == `TRUE)
`ifdef CFG_BUS_ERRORS_ENABLED
&& (valid_x == `TRUE)
`endif
);
`ifdef CFG_DEBUG_ENABLED
assign debug_exception_x = (breakpoint_exception == `TRUE)
|| (watchpoint_exception == `TRUE)
;
assign non_debug_exception_x = (system_call_exception == `TRUE)
`ifdef CFG_JTAG_ENABLED
|| (reset_exception == `TRUE)
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
|| (instruction_bus_error_exception == `TRUE)
|| (data_bus_error_exception == `TRUE)
`endif
`ifdef CFG_MC_DIVIDE_ENABLED
|| (divide_by_zero_exception == `TRUE)
`endif
`ifdef CFG_INTERRUPTS_ENABLED
|| ( (interrupt_exception == `TRUE)
`ifdef LM32_SINGLE_STEP_ENABLED
&& (dc_ss == `FALSE)
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
&& (store_q_m == `FALSE)
&& (D_CYC_O == `FALSE)
`endif
)
`endif
;
assign exception_x = (debug_exception_x == `TRUE) || (non_debug_exception_x == `TRUE);
`else
assign exception_x = (system_call_exception == `TRUE)
`ifdef CFG_BUS_ERRORS_ENABLED
|| (instruction_bus_error_exception == `TRUE)
|| (data_bus_error_exception == `TRUE)
`endif
`ifdef CFG_MC_DIVIDE_ENABLED
|| (divide_by_zero_exception == `TRUE)
`endif
`ifdef CFG_INTERRUPTS_ENABLED
|| ( (interrupt_exception == `TRUE)
`ifdef LM32_SINGLE_STEP_ENABLED
&& (dc_ss == `FALSE)
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
&& (store_q_m == `FALSE)
&& (D_CYC_O == `FALSE)
`endif
)
`endif
;
`endif
// Exception ID
always @(*)
begin
`ifdef CFG_DEBUG_ENABLED
`ifdef CFG_JTAG_ENABLED
if (reset_exception == `TRUE)
eid_x = `LM32_EID_RESET;
else
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
if (data_bus_error_exception == `TRUE)
eid_x = `LM32_EID_DATA_BUS_ERROR;
else
`endif
if (breakpoint_exception == `TRUE)
eid_x = `LM32_EID_BREAKPOINT;
else
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
if (data_bus_error_exception == `TRUE)
eid_x = `LM32_EID_DATA_BUS_ERROR;
else
if (instruction_bus_error_exception == `TRUE)
eid_x = `LM32_EID_INST_BUS_ERROR;
else
`endif
`ifdef CFG_DEBUG_ENABLED
if (watchpoint_exception == `TRUE)
eid_x = `LM32_EID_WATCHPOINT;
else
`endif
`ifdef CFG_MC_DIVIDE_ENABLED
if (divide_by_zero_exception == `TRUE)
eid_x = `LM32_EID_DIVIDE_BY_ZERO;
else
`endif
`ifdef CFG_INTERRUPTS_ENABLED
if ( (interrupt_exception == `TRUE)
`ifdef LM32_SINGLE_STEP_ENABLED
&& (dc_ss == `FALSE)
`endif
)
eid_x = `LM32_EID_INTERRUPT;
else
`endif
eid_x = `LM32_EID_SCALL;
end
// Stall generation
assign stall_a = (stall_f == `TRUE);
assign stall_f = (stall_d == `TRUE);
assign stall_d = (stall_x == `TRUE)
|| ( (interlock == `TRUE)
&& (kill_d == `FALSE)
)
|| ( ( (eret_d == `TRUE)
|| (scall_d == `TRUE)
|| (bus_error_d == `TRUE)
)
&& ( (load_q_x == `TRUE)
|| (load_q_m == `TRUE)
|| (store_q_x == `TRUE)
|| (store_q_m == `TRUE)
|| (D_CYC_O == `TRUE)
)
&& (kill_d == `FALSE)
)
`ifdef CFG_DEBUG_ENABLED
|| ( ( (break_d == `TRUE)
|| (bret_d == `TRUE)
)
&& ( (load_q_x == `TRUE)
|| (store_q_x == `TRUE)
|| (load_q_m == `TRUE)
|| (store_q_m == `TRUE)
|| (D_CYC_O == `TRUE)
)
&& (kill_d == `FALSE)
)
`endif
|| ( (csr_write_enable_d == `TRUE)
&& (load_q_x == `TRUE)
)
;
assign stall_x = (stall_m == `TRUE)
`ifdef LM32_MC_ARITHMETIC_ENABLED
|| ( (mc_stall_request_x == `TRUE)
&& (kill_x == `FALSE)
)
`endif
`ifdef CFG_IROM_ENABLED
// Stall load/store instruction in D stage if there is an ongoing store
// operation to instruction ROM in M stage
|| ( (irom_stall_request_x == `TRUE)
&& ( (load_d == `TRUE)
|| (store_d == `TRUE)
)
)
`endif
;
assign stall_m = (stall_wb_load == `TRUE)
`ifdef CFG_SIZE_OVER_SPEED
|| (D_CYC_O == `TRUE)
`else
|| ( (D_CYC_O == `TRUE)
&& ( (store_m == `TRUE)
/*
Bug: Following loop does not allow interrupts to be services since
either D_CYC_O or store_m is always high during entire duration of
loop.
L1: addi r1, r1, 1
sw (r2,0), r1
bi L1
Introduce a single-cycle stall when a wishbone cycle is in progress
and a new store instruction is in Execute stage and a interrupt
exception has occured. This stall will ensure that D_CYC_O and
store_m will both be low for one cycle.
*/
|| ((store_x == `TRUE) && (interrupt_exception == `TRUE))
|| (load_m == `TRUE)
|| (load_x == `TRUE)
)
)
`endif
`ifdef CFG_DCACHE_ENABLED
|| (dcache_stall_request == `TRUE) // Need to stall in case a taken branch is in M stage and data cache is only being flush, so wont be restarted
`endif
`ifdef CFG_ICACHE_ENABLED
|| (icache_stall_request == `TRUE) // Pipeline needs to be stalled otherwise branches may be lost
|| ((I_CYC_O == `TRUE) && ((branch_m == `TRUE) || (exception_m == `TRUE)))
`else
`ifdef CFG_IWB_ENABLED
|| (I_CYC_O == `TRUE)
`endif
`endif
`ifdef CFG_USER_ENABLED
|| ( (user_valid == `TRUE) // Stall whole pipeline, rather than just X stage, where the instruction is, so we don't have to worry about exceptions (maybe)
&& (user_complete == `FALSE)
)
`endif
;
// Qualify state changing control signals
`ifdef LM32_MC_ARITHMETIC_ENABLED
assign q_d = (valid_d == `TRUE) && (kill_d == `FALSE);
`endif
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
assign shift_left_q_d = (shift_left_d == `TRUE) && (q_d == `TRUE);
assign shift_right_q_d = (shift_right_d == `TRUE) && (q_d == `TRUE);
`endif
`ifdef CFG_MC_MULTIPLY_ENABLED
assign multiply_q_d = (multiply_d == `TRUE) && (q_d == `TRUE);
`endif
`ifdef CFG_MC_DIVIDE_ENABLED
assign divide_q_d = (divide_d == `TRUE) && (q_d == `TRUE);
assign modulus_q_d = (modulus_d == `TRUE) && (q_d == `TRUE);
`endif
assign q_x = (valid_x == `TRUE) && (kill_x == `FALSE);
assign csr_write_enable_q_x = (csr_write_enable_x == `TRUE) && (q_x == `TRUE);
assign eret_q_x = (eret_x == `TRUE) && (q_x == `TRUE);
`ifdef CFG_DEBUG_ENABLED
assign bret_q_x = (bret_x == `TRUE) && (q_x == `TRUE);
`endif
assign load_q_x = (load_x == `TRUE)
&& (q_x == `TRUE)
`ifdef CFG_DEBUG_ENABLED
&& (bp_match == `FALSE)
`endif
;
assign store_q_x = (store_x == `TRUE)
&& (q_x == `TRUE)
`ifdef CFG_DEBUG_ENABLED
&& (bp_match == `FALSE)
`endif
;
`ifdef CFG_USER_ENABLED
assign user_valid = (x_result_sel_user_x == `TRUE) && (q_x == `TRUE);
`endif
assign q_m = (valid_m == `TRUE) && (kill_m == `FALSE) && (exception_m == `FALSE);
assign load_q_m = (load_m == `TRUE) && (q_m == `TRUE);
assign store_q_m = (store_m == `TRUE) && (q_m == `TRUE);
`ifdef CFG_DEBUG_ENABLED
assign debug_exception_q_w = ((debug_exception_w == `TRUE) && (valid_w == `TRUE));
assign non_debug_exception_q_w = ((non_debug_exception_w == `TRUE) && (valid_w == `TRUE));
`else
assign exception_q_w = ((exception_w == `TRUE) && (valid_w == `TRUE));
`endif
// Don't qualify register write enables with kill, as the signal is needed early, and it doesn't matter if the instruction is killed (except for the actual write - but that is handled separately)
assign write_enable_q_x = (write_enable_x == `TRUE) && (valid_x == `TRUE) && (branch_flushX_m == `FALSE);
assign write_enable_q_m = (write_enable_m == `TRUE) && (valid_m == `TRUE);
assign write_enable_q_w = (write_enable_w == `TRUE) && (valid_w == `TRUE);
// The enable that actually does write the registers needs to be qualified with kill
assign reg_write_enable_q_w = (write_enable_w == `TRUE) && (kill_w == `FALSE) && (valid_w == `TRUE);
// Configuration (CFG) CSR
assign cfg = {
`LM32_REVISION,
watchpoints[3:0],
breakpoints[3:0],
interrupts[5:0],
`ifdef CFG_JTAG_UART_ENABLED
`TRUE,
`else
`FALSE,
`endif
`ifdef CFG_ROM_DEBUG_ENABLED
`TRUE,
`else
`FALSE,
`endif
`ifdef CFG_HW_DEBUG_ENABLED
`TRUE,
`else
`FALSE,
`endif
`ifdef CFG_DEBUG_ENABLED
`TRUE,
`else
`FALSE,
`endif
`ifdef CFG_ICACHE_ENABLED
`TRUE,
`else
`FALSE,
`endif
`ifdef CFG_DCACHE_ENABLED
`TRUE,
`else
`FALSE,
`endif
`ifdef CFG_CYCLE_COUNTER_ENABLED
`TRUE,
`else
`FALSE,
`endif
`ifdef CFG_USER_ENABLED
`TRUE,
`else
`FALSE,
`endif
`ifdef CFG_SIGN_EXTEND_ENABLED
`TRUE,
`else
`FALSE,
`endif
`ifdef LM32_BARREL_SHIFT_ENABLED
`TRUE,
`else
`FALSE,
`endif
`ifdef CFG_MC_DIVIDE_ENABLED
`TRUE,
`else
`FALSE,
`endif
`ifdef LM32_MULTIPLY_ENABLED
`TRUE
`else
`FALSE
`endif
};
assign cfg2 = {
30'b0,
`ifdef CFG_IROM_ENABLED
`TRUE,
`else
`FALSE,
`endif
`ifdef CFG_DRAM_ENABLED
`TRUE
`else
`FALSE
`endif
};
// Cache flush
`ifdef CFG_ICACHE_ENABLED
assign iflush = (csr_write_enable_d == `TRUE)
&& (csr_d == `LM32_CSR_ICC)
&& (stall_d == `FALSE)
&& (kill_d == `FALSE)
&& (valid_d == `TRUE);
`endif
`ifdef CFG_DCACHE_ENABLED
assign dflush_x = (csr_write_enable_q_x == `TRUE)
&& (csr_x == `LM32_CSR_DCC);
`endif
// Extract CSR index
assign csr_d = read_idx_0_d[`LM32_CSR_RNG];
// CSR reads
always @(*)
begin
case (csr_x)
`ifdef CFG_INTERRUPTS_ENABLED
`LM32_CSR_IE,
`LM32_CSR_IM,
`LM32_CSR_IP: csr_read_data_x = interrupt_csr_read_data_x;
`endif
`ifdef CFG_CYCLE_COUNTER_ENABLED
`LM32_CSR_CC: csr_read_data_x = cc;
`endif
`LM32_CSR_CFG: csr_read_data_x = cfg;
`LM32_CSR_EBA: csr_read_data_x = {eba, 8'h00};
`ifdef CFG_DEBUG_ENABLED
`LM32_CSR_DEBA: csr_read_data_x = {deba, 8'h00};
`endif
`ifdef CFG_JTAG_UART_ENABLED
`LM32_CSR_JTX: csr_read_data_x = jtx_csr_read_data;
`LM32_CSR_JRX: csr_read_data_x = jrx_csr_read_data;
`endif
`LM32_CSR_CFG2: csr_read_data_x = cfg2;
default: csr_read_data_x = {`LM32_WORD_WIDTH{1'bx}};
endcase
end
/////////////////////////////////////////////////////
// Sequential Logic
/////////////////////////////////////////////////////
// Exception Base Address (EBA) CSR
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
eba <= eba_reset[`LM32_PC_WIDTH+2-1:8];
else
begin
if ((csr_write_enable_q_x == `TRUE) && (csr_x == `LM32_CSR_EBA) && (stall_x == `FALSE))
eba <= operand_1_x[`LM32_PC_WIDTH+2-1:8];
`ifdef CFG_HW_DEBUG_ENABLED
if ((jtag_csr_write_enable == `TRUE) && (jtag_csr == `LM32_CSR_EBA))
eba <= jtag_csr_write_data[`LM32_PC_WIDTH+2-1:8];
`endif
end
end
`ifdef CFG_DEBUG_ENABLED
// Debug Exception Base Address (DEBA) CSR
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
deba <= deba_reset[`LM32_PC_WIDTH+2-1:8];
else
begin
if ((csr_write_enable_q_x == `TRUE) && (csr_x == `LM32_CSR_DEBA) && (stall_x == `FALSE))
deba <= operand_1_x[`LM32_PC_WIDTH+2-1:8];
`ifdef CFG_HW_DEBUG_ENABLED
if ((jtag_csr_write_enable == `TRUE) && (jtag_csr == `LM32_CSR_DEBA))
deba <= jtag_csr_write_data[`LM32_PC_WIDTH+2-1:8];
`endif
end
end
`endif
// Cycle Counter (CC) CSR
`ifdef CFG_CYCLE_COUNTER_ENABLED
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
cc <= {`LM32_WORD_WIDTH{1'b0}};
else
cc <= cc + 1'b1;
end
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
// Watch for data bus errors
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
data_bus_error_seen <= `FALSE;
else
begin
// Set flag when bus error is detected
if ((D_ERR_I == `TRUE) && (D_CYC_O == `TRUE))
data_bus_error_seen <= `TRUE;
// Clear flag when exception is taken
if ((exception_m == `TRUE) && (kill_m == `FALSE))
data_bus_error_seen <= `FALSE;
end
end
`endif
// Valid bits to indicate whether an instruction in a partcular pipeline stage is valid or not
`ifdef CFG_ICACHE_ENABLED
`ifdef CFG_DCACHE_ENABLED
always @(*)
begin
if ( (icache_refill_request == `TRUE)
|| (dcache_refill_request == `TRUE)
)
valid_a = `FALSE;
else if ( (icache_restart_request == `TRUE)
|| (dcache_restart_request == `TRUE)
)
valid_a = `TRUE;
else
valid_a = !icache_refilling && !dcache_refilling;
end
`else
always @(*)
begin
if (icache_refill_request == `TRUE)
valid_a = `FALSE;
else if (icache_restart_request == `TRUE)
valid_a = `TRUE;
else
valid_a = !icache_refilling;
end
`endif
`else
`ifdef CFG_DCACHE_ENABLED
always @(*)
begin
if (dcache_refill_request == `TRUE)
valid_a = `FALSE;
else if (dcache_restart_request == `TRUE)
valid_a = `TRUE;
else
valid_a = !dcache_refilling;
end
`endif
`endif
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
valid_f <= `FALSE;
valid_d <= `FALSE;
valid_x <= `FALSE;
valid_m <= `FALSE;
valid_w <= `FALSE;
end
else
begin
if ((kill_f == `TRUE) || (stall_a == `FALSE))
`ifdef LM32_CACHE_ENABLED
valid_f <= valid_a;
`else
valid_f <= `TRUE;
`endif
else if (stall_f == `FALSE)
valid_f <= `FALSE;
if (kill_d == `TRUE)
valid_d <= `FALSE;
else if (stall_f == `FALSE)
valid_d <= valid_f & !kill_f;
else if (stall_d == `FALSE)
valid_d <= `FALSE;
if (stall_d == `FALSE)
valid_x <= valid_d & !kill_d;
else if (kill_x == `TRUE)
valid_x <= `FALSE;
else if (stall_x == `FALSE)
valid_x <= `FALSE;
if (kill_m == `TRUE)
valid_m <= `FALSE;
else if (stall_x == `FALSE)
valid_m <= valid_x & !kill_x;
else if (stall_m == `FALSE)
valid_m <= `FALSE;
if (stall_m == `FALSE)
valid_w <= valid_m & !kill_m;
else
valid_w <= `FALSE;
end
end
// Microcode pipeline registers
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
`ifdef CFG_USER_ENABLED
user_opcode <= {`LM32_USER_OPCODE_WIDTH{1'b0}};
`endif
operand_0_x <= {`LM32_WORD_WIDTH{1'b0}};
operand_1_x <= {`LM32_WORD_WIDTH{1'b0}};
store_operand_x <= {`LM32_WORD_WIDTH{1'b0}};
branch_target_x <= {`LM32_WORD_WIDTH{1'b0}};
x_result_sel_csr_x <= `FALSE;
`ifdef LM32_MC_ARITHMETIC_ENABLED
x_result_sel_mc_arith_x <= `FALSE;
`endif
`ifdef LM32_NO_BARREL_SHIFT
x_result_sel_shift_x <= `FALSE;
`endif
`ifdef CFG_SIGN_EXTEND_ENABLED
x_result_sel_sext_x <= `FALSE;
`endif
x_result_sel_logic_x <= `FALSE;
`ifdef CFG_USER_ENABLED
x_result_sel_user_x <= `FALSE;
`endif
x_result_sel_add_x <= `FALSE;
m_result_sel_compare_x <= `FALSE;
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
m_result_sel_shift_x <= `FALSE;
`endif
w_result_sel_load_x <= `FALSE;
`ifdef CFG_PL_MULTIPLY_ENABLED
w_result_sel_mul_x <= `FALSE;
`endif
x_bypass_enable_x <= `FALSE;
m_bypass_enable_x <= `FALSE;
write_enable_x <= `FALSE;
write_idx_x <= {`LM32_REG_IDX_WIDTH{1'b0}};
csr_x <= {`LM32_CSR_WIDTH{1'b0}};
load_x <= `FALSE;
store_x <= `FALSE;
size_x <= {`LM32_SIZE_WIDTH{1'b0}};
sign_extend_x <= `FALSE;
adder_op_x <= `FALSE;
adder_op_x_n <= `FALSE;
logic_op_x <= 4'h0;
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
direction_x <= `FALSE;
`endif
`ifdef CFG_ROTATE_ENABLED
rotate_x <= `FALSE;
`endif
branch_x <= `FALSE;
branch_predict_x <= `FALSE;
branch_predict_taken_x <= `FALSE;
condition_x <= `LM32_CONDITION_U1;
`ifdef CFG_DEBUG_ENABLED
break_x <= `FALSE;
`endif
scall_x <= `FALSE;
eret_x <= `FALSE;
`ifdef CFG_DEBUG_ENABLED
bret_x <= `FALSE;
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
bus_error_x <= `FALSE;
data_bus_error_exception_m <= `FALSE;
`endif
csr_write_enable_x <= `FALSE;
operand_m <= {`LM32_WORD_WIDTH{1'b0}};
branch_target_m <= {`LM32_WORD_WIDTH{1'b0}};
m_result_sel_compare_m <= `FALSE;
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
m_result_sel_shift_m <= `FALSE;
`endif
w_result_sel_load_m <= `FALSE;
`ifdef CFG_PL_MULTIPLY_ENABLED
w_result_sel_mul_m <= `FALSE;
`endif
m_bypass_enable_m <= `FALSE;
branch_m <= `FALSE;
branch_predict_m <= `FALSE;
branch_predict_taken_m <= `FALSE;
exception_m <= `FALSE;
load_m <= `FALSE;
store_m <= `FALSE;
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
direction_m <= `FALSE;
`endif
write_enable_m <= `FALSE;
write_idx_m <= {`LM32_REG_IDX_WIDTH{1'b0}};
condition_met_m <= `FALSE;
`ifdef CFG_DCACHE_ENABLED
dflush_m <= `FALSE;
`endif
`ifdef CFG_DEBUG_ENABLED
debug_exception_m <= `FALSE;
non_debug_exception_m <= `FALSE;
`endif
operand_w <= {`LM32_WORD_WIDTH{1'b0}};
w_result_sel_load_w <= `FALSE;
`ifdef CFG_PL_MULTIPLY_ENABLED
w_result_sel_mul_w <= `FALSE;
`endif
write_idx_w <= {`LM32_REG_IDX_WIDTH{1'b0}};
write_enable_w <= `FALSE;
`ifdef CFG_DEBUG_ENABLED
debug_exception_w <= `FALSE;
non_debug_exception_w <= `FALSE;
`else
exception_w <= `FALSE;
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
memop_pc_w <= {`LM32_PC_WIDTH{1'b0}};
`endif
end
else
begin
// D/X stage registers
if (stall_x == `FALSE)
begin
`ifdef CFG_USER_ENABLED
user_opcode <= user_opcode_d;
`endif
operand_0_x <= d_result_0;
operand_1_x <= d_result_1;
store_operand_x <= bypass_data_1;
branch_target_x <= branch_reg_d == `TRUE ? bypass_data_0[`LM32_PC_RNG] : branch_target_d;
x_result_sel_csr_x <= x_result_sel_csr_d;
`ifdef LM32_MC_ARITHMETIC_ENABLED
x_result_sel_mc_arith_x <= x_result_sel_mc_arith_d;
`endif
`ifdef LM32_NO_BARREL_SHIFT
x_result_sel_shift_x <= x_result_sel_shift_d;
`endif
`ifdef CFG_SIGN_EXTEND_ENABLED
x_result_sel_sext_x <= x_result_sel_sext_d;
`endif
x_result_sel_logic_x <= x_result_sel_logic_d;
`ifdef CFG_USER_ENABLED
x_result_sel_user_x <= x_result_sel_user_d;
`endif
x_result_sel_add_x <= x_result_sel_add_d;
m_result_sel_compare_x <= m_result_sel_compare_d;
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
m_result_sel_shift_x <= m_result_sel_shift_d;
`endif
w_result_sel_load_x <= w_result_sel_load_d;
`ifdef CFG_PL_MULTIPLY_ENABLED
w_result_sel_mul_x <= w_result_sel_mul_d;
`endif
x_bypass_enable_x <= x_bypass_enable_d;
m_bypass_enable_x <= m_bypass_enable_d;
load_x <= load_d;
store_x <= store_d;
branch_x <= branch_d;
branch_predict_x <= branch_predict_d;
branch_predict_taken_x <= branch_predict_taken_d;
write_idx_x <= write_idx_d;
csr_x <= csr_d;
size_x <= size_d;
sign_extend_x <= sign_extend_d;
adder_op_x <= adder_op_d;
adder_op_x_n <= ~adder_op_d;
logic_op_x <= logic_op_d;
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
direction_x <= direction_d;
`endif
`ifdef CFG_ROTATE_ENABLED
rotate_x <= rotate_d;
`endif
condition_x <= condition_d;
csr_write_enable_x <= csr_write_enable_d;
`ifdef CFG_DEBUG_ENABLED
break_x <= break_d;
`endif
scall_x <= scall_d;
`ifdef CFG_BUS_ERRORS_ENABLED
bus_error_x <= bus_error_d;
`endif
eret_x <= eret_d;
`ifdef CFG_DEBUG_ENABLED
bret_x <= bret_d;
`endif
write_enable_x <= write_enable_d;
end
// X/M stage registers
if (stall_m == `FALSE)
begin
operand_m <= x_result;
m_result_sel_compare_m <= m_result_sel_compare_x;
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
m_result_sel_shift_m <= m_result_sel_shift_x;
`endif
if (exception_x == `TRUE)
begin
w_result_sel_load_m <= `FALSE;
`ifdef CFG_PL_MULTIPLY_ENABLED
w_result_sel_mul_m <= `FALSE;
`endif
end
else
begin
w_result_sel_load_m <= w_result_sel_load_x;
`ifdef CFG_PL_MULTIPLY_ENABLED
w_result_sel_mul_m <= w_result_sel_mul_x;
`endif
end
m_bypass_enable_m <= m_bypass_enable_x;
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
direction_m <= direction_x;
`endif
load_m <= load_x;
store_m <= store_x;
`ifdef CFG_FAST_UNCONDITIONAL_BRANCH
branch_m <= branch_x && !branch_taken_x;
`else
branch_m <= branch_x;
branch_predict_m <= branch_predict_x;
branch_predict_taken_m <= branch_predict_taken_x;
`endif
`ifdef CFG_DEBUG_ENABLED
// Data bus errors are generated by the wishbone and are
// made known to the processor only in next cycle (as a
// non-debug exception). A break instruction can be seen
// in same cycle (causing a debug exception). Handle non
// -debug exception first!
if (non_debug_exception_x == `TRUE)
write_idx_m <= `LM32_EA_REG;
else if (debug_exception_x == `TRUE)
write_idx_m <= `LM32_BA_REG;
else
write_idx_m <= write_idx_x;
`else
if (exception_x == `TRUE)
write_idx_m <= `LM32_EA_REG;
else
write_idx_m <= write_idx_x;
`endif
condition_met_m <= condition_met_x;
`ifdef CFG_DEBUG_ENABLED
if (exception_x == `TRUE)
if ((dc_re == `TRUE)
|| ((debug_exception_x == `TRUE)
&& (non_debug_exception_x == `FALSE)))
branch_target_m <= {deba, eid_x, {3{1'b0}}};
else
branch_target_m <= {eba, eid_x, {3{1'b0}}};
else
branch_target_m <= branch_target_x;
`else
branch_target_m <= exception_x == `TRUE ? {eba, eid_x, {3{1'b0}}} : branch_target_x;
`endif
`ifdef CFG_TRACE_ENABLED
eid_m <= eid_x;
`endif
`ifdef CFG_DCACHE_ENABLED
dflush_m <= dflush_x;
`endif
eret_m <= eret_q_x;
`ifdef CFG_DEBUG_ENABLED
bret_m <= bret_q_x;
`endif
write_enable_m <= exception_x == `TRUE ? `TRUE : write_enable_x;
`ifdef CFG_DEBUG_ENABLED
debug_exception_m <= debug_exception_x;
non_debug_exception_m <= non_debug_exception_x;
`endif
end
// State changing regs
if (stall_m == `FALSE)
begin
if ((exception_x == `TRUE) && (q_x == `TRUE) && (stall_x == `FALSE))
exception_m <= `TRUE;
else
exception_m <= `FALSE;
`ifdef CFG_BUS_ERRORS_ENABLED
data_bus_error_exception_m <= (data_bus_error_exception == `TRUE)
`ifdef CFG_DEBUG_ENABLED
&& (reset_exception == `FALSE)
`endif
;
`endif
end
// M/W stage registers
`ifdef CFG_BUS_ERRORS_ENABLED
operand_w <= exception_m == `TRUE ? (data_bus_error_exception_m ? {memop_pc_w, 2'b00} : {pc_m, 2'b00}) : m_result;
`else
operand_w <= exception_m == `TRUE ? {pc_m, 2'b00} : m_result;
`endif
w_result_sel_load_w <= w_result_sel_load_m;
`ifdef CFG_PL_MULTIPLY_ENABLED
w_result_sel_mul_w <= w_result_sel_mul_m;
`endif
write_idx_w <= write_idx_m;
`ifdef CFG_TRACE_ENABLED
eid_w <= eid_m;
eret_w <= eret_m;
`ifdef CFG_DEBUG_ENABLED
bret_w <= bret_m;
`endif
`endif
write_enable_w <= write_enable_m;
`ifdef CFG_DEBUG_ENABLED
debug_exception_w <= debug_exception_m;
non_debug_exception_w <= non_debug_exception_m;
`else
exception_w <= exception_m;
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
if ( (stall_m == `FALSE)
&& ( (load_q_m == `TRUE)
|| (store_q_m == `TRUE)
)
)
memop_pc_w <= pc_m;
`endif
end
end
`ifdef CFG_EBR_POSEDGE_REGISTER_FILE
// Buffer data read from register file, in case a stall occurs, and watch for
// any writes to the modified registers
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
use_buf <= `FALSE;
reg_data_buf_0 <= {`LM32_WORD_WIDTH{1'b0}};
reg_data_buf_1 <= {`LM32_WORD_WIDTH{1'b0}};
end
else
begin
if (stall_d == `FALSE)
use_buf <= `FALSE;
else if (use_buf == `FALSE)
begin
reg_data_buf_0 <= reg_data_live_0;
reg_data_buf_1 <= reg_data_live_1;
use_buf <= `TRUE;
end
if (reg_write_enable_q_w == `TRUE)
begin
if (write_idx_w == read_idx_0_d)
reg_data_buf_0 <= w_result;
if (write_idx_w == read_idx_1_d)
reg_data_buf_1 <= w_result;
end
end
end
`endif
`ifdef LM32_EBR_REGISTER_FILE
`else
// Register file write port
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE) begin
registers[0] <= {`LM32_WORD_WIDTH{1'b0}};
registers[1] <= {`LM32_WORD_WIDTH{1'b0}};
registers[2] <= {`LM32_WORD_WIDTH{1'b0}};
registers[3] <= {`LM32_WORD_WIDTH{1'b0}};
registers[4] <= {`LM32_WORD_WIDTH{1'b0}};
registers[5] <= {`LM32_WORD_WIDTH{1'b0}};
registers[6] <= {`LM32_WORD_WIDTH{1'b0}};
registers[7] <= {`LM32_WORD_WIDTH{1'b0}};
registers[8] <= {`LM32_WORD_WIDTH{1'b0}};
registers[9] <= {`LM32_WORD_WIDTH{1'b0}};
registers[10] <= {`LM32_WORD_WIDTH{1'b0}};
registers[11] <= {`LM32_WORD_WIDTH{1'b0}};
registers[12] <= {`LM32_WORD_WIDTH{1'b0}};
registers[13] <= {`LM32_WORD_WIDTH{1'b0}};
registers[14] <= {`LM32_WORD_WIDTH{1'b0}};
registers[15] <= {`LM32_WORD_WIDTH{1'b0}};
registers[16] <= {`LM32_WORD_WIDTH{1'b0}};
registers[17] <= {`LM32_WORD_WIDTH{1'b0}};
registers[18] <= {`LM32_WORD_WIDTH{1'b0}};
registers[19] <= {`LM32_WORD_WIDTH{1'b0}};
registers[20] <= {`LM32_WORD_WIDTH{1'b0}};
registers[21] <= {`LM32_WORD_WIDTH{1'b0}};
registers[22] <= {`LM32_WORD_WIDTH{1'b0}};
registers[23] <= {`LM32_WORD_WIDTH{1'b0}};
registers[24] <= {`LM32_WORD_WIDTH{1'b0}};
registers[25] <= {`LM32_WORD_WIDTH{1'b0}};
registers[26] <= {`LM32_WORD_WIDTH{1'b0}};
registers[27] <= {`LM32_WORD_WIDTH{1'b0}};
registers[28] <= {`LM32_WORD_WIDTH{1'b0}};
registers[29] <= {`LM32_WORD_WIDTH{1'b0}};
registers[30] <= {`LM32_WORD_WIDTH{1'b0}};
registers[31] <= {`LM32_WORD_WIDTH{1'b0}};
end
else begin
if (reg_write_enable_q_w == `TRUE)
registers[write_idx_w] <= w_result;
end
end
`endif
`ifdef CFG_TRACE_ENABLED
// PC tracing logic
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
trace_pc_valid <= `FALSE;
trace_pc <= {`LM32_PC_WIDTH{1'b0}};
trace_exception <= `FALSE;
trace_eid <= `LM32_EID_RESET;
trace_eret <= `FALSE;
`ifdef CFG_DEBUG_ENABLED
trace_bret <= `FALSE;
`endif
pc_c <= `CFG_EBA_RESET/4;
end
else
begin
trace_pc_valid <= `FALSE;
// Has an exception occured
`ifdef CFG_DEBUG_ENABLED
if ((debug_exception_q_w == `TRUE) || (non_debug_exception_q_w == `TRUE))
`else
if (exception_q_w == `TRUE)
`endif
begin
trace_exception <= `TRUE;
trace_pc_valid <= `TRUE;
trace_pc <= pc_w;
trace_eid <= eid_w;
end
else
trace_exception <= `FALSE;
if ((valid_w == `TRUE) && (!kill_w))
begin
// An instruction is commiting. Determine if it is non-sequential
if (pc_c + 1'b1 != pc_w)
begin
// Non-sequential instruction
trace_pc_valid <= `TRUE;
trace_pc <= pc_w;
end
// Record PC so we can determine if next instruction is sequential or not
pc_c <= pc_w;
// Indicate if it was an eret/bret instruction
trace_eret <= eret_w;
`ifdef CFG_DEBUG_ENABLED
trace_bret <= bret_w;
`endif
end
else
begin
trace_eret <= `FALSE;
`ifdef CFG_DEBUG_ENABLED
trace_bret <= `FALSE;
`endif
end
end
end
`endif
/////////////////////////////////////////////////////
// Behavioural Logic
/////////////////////////////////////////////////////
// synthesis translate_off
// Reset register 0. Only needed for simulation.
initial
begin
`ifdef LM32_EBR_REGISTER_FILE
reg_0.mem[0] = {`LM32_WORD_WIDTH{1'b0}};
reg_1.mem[0] = {`LM32_WORD_WIDTH{1'b0}};
`else
registers[0] = {`LM32_WORD_WIDTH{1'b0}};
`endif
end
// synthesis translate_on
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_dcache.v
// Title : Data cache
// Dependencies : lm32_include.v
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : Support for user-selected resource usage when implementing
// : cache memory. Additional parameters must be defined when
// : invoking lm32_ram.v
// =============================================================================
`include "lm32_include.v"
`ifdef CFG_DCACHE_ENABLED
`define LM32_DC_ADDR_OFFSET_RNG addr_offset_msb:addr_offset_lsb
`define LM32_DC_ADDR_SET_RNG addr_set_msb:addr_set_lsb
`define LM32_DC_ADDR_TAG_RNG addr_tag_msb:addr_tag_lsb
`define LM32_DC_ADDR_IDX_RNG addr_set_msb:addr_offset_lsb
`define LM32_DC_TMEM_ADDR_WIDTH addr_set_width
`define LM32_DC_TMEM_ADDR_RNG (`LM32_DC_TMEM_ADDR_WIDTH-1):0
`define LM32_DC_DMEM_ADDR_WIDTH (addr_offset_width+addr_set_width)
`define LM32_DC_DMEM_ADDR_RNG (`LM32_DC_DMEM_ADDR_WIDTH-1):0
`define LM32_DC_TAGS_WIDTH (addr_tag_width+1)
`define LM32_DC_TAGS_RNG (`LM32_DC_TAGS_WIDTH-1):0
`define LM32_DC_TAGS_TAG_RNG (`LM32_DC_TAGS_WIDTH-1):1
`define LM32_DC_TAGS_VALID_RNG 0
`define LM32_DC_STATE_RNG 2:0
`define LM32_DC_STATE_FLUSH 3'b001
`define LM32_DC_STATE_CHECK 3'b010
`define LM32_DC_STATE_REFILL 3'b100
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_dcache (
// ----- Inputs -----
clk_i,
rst_i,
stall_a,
stall_x,
stall_m,
address_x,
address_m,
load_q_m,
store_q_m,
store_data,
store_byte_select,
refill_ready,
refill_data,
dflush,
// ----- Outputs -----
stall_request,
restart_request,
refill_request,
refill_address,
refilling,
load_data
);
/////////////////////////////////////////////////////
// Parameters
/////////////////////////////////////////////////////
parameter associativity = 1; // Associativity of the cache (Number of ways)
parameter sets = 512; // Number of sets
parameter bytes_per_line = 16; // Number of bytes per cache line
parameter base_address = 0; // Base address of cachable memory
parameter limit = 0; // Limit (highest address) of cachable memory
localparam addr_offset_width = clogb2(bytes_per_line)-1-2;
localparam addr_set_width = clogb2(sets)-1;
localparam addr_offset_lsb = 2;
localparam addr_offset_msb = (addr_offset_lsb+addr_offset_width-1);
localparam addr_set_lsb = (addr_offset_msb+1);
localparam addr_set_msb = (addr_set_lsb+addr_set_width-1);
localparam addr_tag_lsb = (addr_set_msb+1);
localparam addr_tag_msb = clogb2(`CFG_DCACHE_LIMIT-`CFG_DCACHE_BASE_ADDRESS)-1;
localparam addr_tag_width = (addr_tag_msb-addr_tag_lsb+1);
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input clk_i; // Clock
input rst_i; // Reset
input stall_a; // Stall A stage
input stall_x; // Stall X stage
input stall_m; // Stall M stage
input [`LM32_WORD_RNG] address_x; // X stage load/store address
input [`LM32_WORD_RNG] address_m; // M stage load/store address
input load_q_m; // Load instruction in M stage
input store_q_m; // Store instruction in M stage
input [`LM32_WORD_RNG] store_data; // Data to store
input [`LM32_BYTE_SELECT_RNG] store_byte_select; // Which bytes in store data should be modified
input refill_ready; // Indicates next word of refill data is ready
input [`LM32_WORD_RNG] refill_data; // Refill data
input dflush; // Indicates cache should be flushed
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
output stall_request; // Request pipeline be stalled because cache is busy
wire stall_request;
output restart_request; // Request to restart instruction that caused the cache miss
reg restart_request;
output refill_request; // Request a refill
reg refill_request;
output [`LM32_WORD_RNG] refill_address; // Address to refill from
reg [`LM32_WORD_RNG] refill_address;
output refilling; // Indicates if the cache is currently refilling
reg refilling;
output [`LM32_WORD_RNG] load_data; // Data read from cache
wire [`LM32_WORD_RNG] load_data;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
wire read_port_enable; // Cache memory read port clock enable
wire write_port_enable; // Cache memory write port clock enable
wire [0:associativity-1] way_tmem_we; // Tag memory write enable
wire [0:associativity-1] way_dmem_we; // Data memory write enable
wire [`LM32_WORD_RNG] way_data[0:associativity-1]; // Data read from data memory
wire [`LM32_DC_TAGS_TAG_RNG] way_tag[0:associativity-1];// Tag read from tag memory
wire [0:associativity-1] way_valid; // Indicates which ways are valid
wire [0:associativity-1] way_match; // Indicates which ways matched
wire miss; // Indicates no ways matched
wire [`LM32_DC_TMEM_ADDR_RNG] tmem_read_address; // Tag memory read address
wire [`LM32_DC_TMEM_ADDR_RNG] tmem_write_address; // Tag memory write address
wire [`LM32_DC_DMEM_ADDR_RNG] dmem_read_address; // Data memory read address
wire [`LM32_DC_DMEM_ADDR_RNG] dmem_write_address; // Data memory write address
wire [`LM32_DC_TAGS_RNG] tmem_write_data; // Tag memory write data
reg [`LM32_WORD_RNG] dmem_write_data; // Data memory write data
reg [`LM32_DC_STATE_RNG] state; // Current state of FSM
wire flushing; // Indicates if cache is currently flushing
wire check; // Indicates if cache is currently checking for hits/misses
wire refill; // Indicates if cache is currently refilling
wire valid_store; // Indicates if there is a valid store instruction
reg [associativity-1:0] refill_way_select; // Which way should be refilled
reg [`LM32_DC_ADDR_OFFSET_RNG] refill_offset; // Which word in cache line should be refilled
wire last_refill; // Indicates when on last cycle of cache refill
reg [`LM32_DC_TMEM_ADDR_RNG] flush_set; // Which set is currently being flushed
genvar i, j;
/////////////////////////////////////////////////////
// Functions
/////////////////////////////////////////////////////
`include "lm32_functions.v"
/////////////////////////////////////////////////////
// Instantiations
/////////////////////////////////////////////////////
generate
for (i = 0; i < associativity; i = i + 1)
begin : memories
// Way data
if (`LM32_DC_DMEM_ADDR_WIDTH < 11)
begin : data_memories
lm32_ram
#(
// ----- Parameters -------
.data_width (32),
.address_width (`LM32_DC_DMEM_ADDR_WIDTH)
// Modified for Milkymist: removed non-portable RAM parameters
) way_0_data_ram
(
// ----- Inputs -------
.read_clk (clk_i),
.write_clk (clk_i),
.reset (rst_i),
.read_address (dmem_read_address),
.enable_read (read_port_enable),
.write_address (dmem_write_address),
.enable_write (write_port_enable),
.write_enable (way_dmem_we[i]),
.write_data (dmem_write_data),
// ----- Outputs -------
.read_data (way_data[i])
);
end
else
begin
for (j = 0; j < 4; j = j + 1)
begin : byte_memories
lm32_ram
#(
// ----- Parameters -------
.data_width (8),
.address_width (`LM32_DC_DMEM_ADDR_WIDTH)
// Modified for Milkymist: removed non-portable RAM parameters
) way_0_data_ram
(
// ----- Inputs -------
.read_clk (clk_i),
.write_clk (clk_i),
.reset (rst_i),
.read_address (dmem_read_address),
.enable_read (read_port_enable),
.write_address (dmem_write_address),
.enable_write (write_port_enable),
.write_enable (way_dmem_we[i] & (store_byte_select[j] | refill)),
.write_data (dmem_write_data[(j+1)*8-1:j*8]),
// ----- Outputs -------
.read_data (way_data[i][(j+1)*8-1:j*8])
);
end
end
// Way tags
lm32_ram
#(
// ----- Parameters -------
.data_width (`LM32_DC_TAGS_WIDTH),
.address_width (`LM32_DC_TMEM_ADDR_WIDTH)
// Modified for Milkymist: removed non-portable RAM parameters
) way_0_tag_ram
(
// ----- Inputs -------
.read_clk (clk_i),
.write_clk (clk_i),
.reset (rst_i),
.read_address (tmem_read_address),
.enable_read (read_port_enable),
.write_address (tmem_write_address),
.enable_write (`TRUE),
.write_enable (way_tmem_we[i]),
.write_data (tmem_write_data),
// ----- Outputs -------
.read_data ({way_tag[i], way_valid[i]})
);
end
endgenerate
/////////////////////////////////////////////////////
// Combinational logic
/////////////////////////////////////////////////////
// Compute which ways in the cache match the address being read
generate
for (i = 0; i < associativity; i = i + 1)
begin : match
assign way_match[i] = ({way_tag[i], way_valid[i]} == {address_m[`LM32_DC_ADDR_TAG_RNG], `TRUE});
end
endgenerate
// Select data from way that matched the address being read
generate
if (associativity == 1)
begin : data_1
assign load_data = way_data[0];
end
else if (associativity == 2)
begin : data_2
assign load_data = way_match[0] ? way_data[0] : way_data[1];
end
endgenerate
generate
if (`LM32_DC_DMEM_ADDR_WIDTH < 11)
begin
// Select data to write to data memories
always @(*)
begin
if (refill == `TRUE)
dmem_write_data = refill_data;
else
begin
dmem_write_data[`LM32_BYTE_0_RNG] = store_byte_select[0] ? store_data[`LM32_BYTE_0_RNG] : load_data[`LM32_BYTE_0_RNG];
dmem_write_data[`LM32_BYTE_1_RNG] = store_byte_select[1] ? store_data[`LM32_BYTE_1_RNG] : load_data[`LM32_BYTE_1_RNG];
dmem_write_data[`LM32_BYTE_2_RNG] = store_byte_select[2] ? store_data[`LM32_BYTE_2_RNG] : load_data[`LM32_BYTE_2_RNG];
dmem_write_data[`LM32_BYTE_3_RNG] = store_byte_select[3] ? store_data[`LM32_BYTE_3_RNG] : load_data[`LM32_BYTE_3_RNG];
end
end
end
else
begin
// Select data to write to data memories - FIXME: Should use different write ports on dual port RAMs, but they don't work
always @(*)
begin
if (refill == `TRUE)
dmem_write_data = refill_data;
else
dmem_write_data = store_data;
end
end
endgenerate
// Compute address to use to index into the data memories
generate
if (bytes_per_line > 4)
assign dmem_write_address = (refill == `TRUE)
? {refill_address[`LM32_DC_ADDR_SET_RNG], refill_offset}
: address_m[`LM32_DC_ADDR_IDX_RNG];
else
assign dmem_write_address = (refill == `TRUE)
? refill_address[`LM32_DC_ADDR_SET_RNG]
: address_m[`LM32_DC_ADDR_IDX_RNG];
endgenerate
assign dmem_read_address = address_x[`LM32_DC_ADDR_IDX_RNG];
// Compute address to use to index into the tag memories
assign tmem_write_address = (flushing == `TRUE)
? flush_set
: refill_address[`LM32_DC_ADDR_SET_RNG];
assign tmem_read_address = address_x[`LM32_DC_ADDR_SET_RNG];
// Compute signal to indicate when we are on the last refill accesses
generate
if (bytes_per_line > 4)
assign last_refill = refill_offset == {addr_offset_width{1'b1}};
else
assign last_refill = `TRUE;
endgenerate
// Compute data and tag memory access enable
assign read_port_enable = (stall_x == `FALSE);
assign write_port_enable = (refill_ready == `TRUE) || !stall_m;
// Determine when we have a valid store
assign valid_store = (store_q_m == `TRUE) && (check == `TRUE);
// Compute data and tag memory write enables
generate
if (associativity == 1)
begin : we_1
assign way_dmem_we[0] = (refill_ready == `TRUE) || ((valid_store == `TRUE) && (way_match[0] == `TRUE));
assign way_tmem_we[0] = (refill_ready == `TRUE) || (flushing == `TRUE);
end
else
begin : we_2
assign way_dmem_we[0] = ((refill_ready == `TRUE) && (refill_way_select[0] == `TRUE)) || ((valid_store == `TRUE) && (way_match[0] == `TRUE));
assign way_dmem_we[1] = ((refill_ready == `TRUE) && (refill_way_select[1] == `TRUE)) || ((valid_store == `TRUE) && (way_match[1] == `TRUE));
assign way_tmem_we[0] = ((refill_ready == `TRUE) && (refill_way_select[0] == `TRUE)) || (flushing == `TRUE);
assign way_tmem_we[1] = ((refill_ready == `TRUE) && (refill_way_select[1] == `TRUE)) || (flushing == `TRUE);
end
endgenerate
// On the last refill cycle set the valid bit, for all other writes it should be cleared
assign tmem_write_data[`LM32_DC_TAGS_VALID_RNG] = ((last_refill == `TRUE) || (valid_store == `TRUE)) && (flushing == `FALSE);
assign tmem_write_data[`LM32_DC_TAGS_TAG_RNG] = refill_address[`LM32_DC_ADDR_TAG_RNG];
// Signals that indicate which state we are in
assign flushing = state[0];
assign check = state[1];
assign refill = state[2];
assign miss = (~(|way_match)) && (load_q_m == `TRUE) && (stall_m == `FALSE);
assign stall_request = (check == `FALSE);
/////////////////////////////////////////////////////
// Sequential logic
/////////////////////////////////////////////////////
// Record way selected for replacement on a cache miss
generate
if (associativity >= 2)
begin : way_select
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
refill_way_select <= {{associativity-1{1'b0}}, 1'b1};
else
begin
if (refill_request == `TRUE)
refill_way_select <= {refill_way_select[0], refill_way_select[1]};
end
end
end
endgenerate
// Record whether we are currently refilling
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
refilling <= `FALSE;
else
refilling <= refill;
end
// Instruction cache control FSM
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
state <= `LM32_DC_STATE_FLUSH;
flush_set <= {`LM32_DC_TMEM_ADDR_WIDTH{1'b1}};
refill_request <= `FALSE;
refill_address <= {`LM32_WORD_WIDTH{1'bx}};
restart_request <= `FALSE;
end
else
begin
case (state)
// Flush the cache
`LM32_DC_STATE_FLUSH:
begin
if (flush_set == {`LM32_DC_TMEM_ADDR_WIDTH{1'b0}})
state <= `LM32_DC_STATE_CHECK;
flush_set <= flush_set - 1'b1;
end
// Check for cache misses
`LM32_DC_STATE_CHECK:
begin
if (stall_a == `FALSE)
restart_request <= `FALSE;
if (miss == `TRUE)
begin
refill_request <= `TRUE;
refill_address <= address_m;
state <= `LM32_DC_STATE_REFILL;
end
else if (dflush == `TRUE)
state <= `LM32_DC_STATE_FLUSH;
end
// Refill a cache line
`LM32_DC_STATE_REFILL:
begin
refill_request <= `FALSE;
if (refill_ready == `TRUE)
begin
if (last_refill == `TRUE)
begin
restart_request <= `TRUE;
state <= `LM32_DC_STATE_CHECK;
end
end
end
endcase
end
end
generate
if (bytes_per_line > 4)
begin
// Refill offset
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
refill_offset <= {addr_offset_width{1'b0}};
else
begin
case (state)
// Check for cache misses
`LM32_DC_STATE_CHECK:
begin
if (miss == `TRUE)
refill_offset <= {addr_offset_width{1'b0}};
end
// Refill a cache line
`LM32_DC_STATE_REFILL:
begin
if (refill_ready == `TRUE)
refill_offset <= refill_offset + 1'b1;
end
endcase
end
end
end
endgenerate
endmodule
`endif
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_debug.v
// Title : Hardware debug registers and associated logic.
// Dependencies : lm32_include.v
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// Version : 3.2
// : Fixed simulation bug which flares up when number of
// : watchpoints is zero.
// =============================================================================
`include "lm32_include.v"
`ifdef CFG_DEBUG_ENABLED
// States for single-step FSM
`define LM32_DEBUG_SS_STATE_RNG 2:0
`define LM32_DEBUG_SS_STATE_IDLE 3'b000
`define LM32_DEBUG_SS_STATE_WAIT_FOR_RET 3'b001
`define LM32_DEBUG_SS_STATE_EXECUTE_ONE_INSN 3'b010
`define LM32_DEBUG_SS_STATE_RAISE_BREAKPOINT 3'b011
`define LM32_DEBUG_SS_STATE_RESTART 3'b100
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_debug (
// ----- Inputs -------
clk_i,
rst_i,
pc_x,
load_x,
store_x,
load_store_address_x,
csr_write_enable_x,
csr_write_data,
csr_x,
`ifdef CFG_HW_DEBUG_ENABLED
jtag_csr_write_enable,
jtag_csr_write_data,
jtag_csr,
`endif
`ifdef LM32_SINGLE_STEP_ENABLED
eret_q_x,
bret_q_x,
stall_x,
exception_x,
q_x,
`ifdef CFG_DCACHE_ENABLED
dcache_refill_request,
`endif
`endif
// ----- Outputs -------
`ifdef LM32_SINGLE_STEP_ENABLED
dc_ss,
`endif
dc_re,
bp_match,
wp_match
);
/////////////////////////////////////////////////////
// Parameters
/////////////////////////////////////////////////////
parameter breakpoints = 0; // Number of breakpoint CSRs
parameter watchpoints = 0; // Number of watchpoint CSRs
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input clk_i; // Clock
input rst_i; // Reset
input [`LM32_PC_RNG] pc_x; // X stage PC
input load_x; // Load instruction in X stage
input store_x; // Store instruction in X stage
input [`LM32_WORD_RNG] load_store_address_x; // Load or store effective address
input csr_write_enable_x; // wcsr instruction in X stage
input [`LM32_WORD_RNG] csr_write_data; // Data to write to CSR
input [`LM32_CSR_RNG] csr_x; // Which CSR to write
`ifdef CFG_HW_DEBUG_ENABLED
input jtag_csr_write_enable; // JTAG interface CSR write enable
input [`LM32_WORD_RNG] jtag_csr_write_data; // Data to write to CSR
input [`LM32_CSR_RNG] jtag_csr; // Which CSR to write
`endif
`ifdef LM32_SINGLE_STEP_ENABLED
input eret_q_x; // eret instruction in X stage
input bret_q_x; // bret instruction in X stage
input stall_x; // Instruction in X stage is stalled
input exception_x; // An exception has occured in X stage
input q_x; // Indicates the instruction in the X stage is qualified
`ifdef CFG_DCACHE_ENABLED
input dcache_refill_request; // Indicates data cache wants to be refilled
`endif
`endif
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
`ifdef LM32_SINGLE_STEP_ENABLED
output dc_ss; // Single-step enable
reg dc_ss;
`endif
output dc_re; // Remap exceptions
reg dc_re;
output bp_match; // Indicates a breakpoint has matched
wire bp_match;
output wp_match; // Indicates a watchpoint has matched
wire wp_match;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
genvar i; // Loop index for generate statements
// Debug CSRs
reg [`LM32_PC_RNG] bp_a[0:breakpoints-1]; // Instruction breakpoint address
reg bp_e[0:breakpoints-1]; // Instruction breakpoint enable
wire [0:breakpoints-1]bp_match_n; // Indicates if a h/w instruction breakpoint matched
reg [`LM32_WPC_C_RNG] wpc_c[0:watchpoints-1]; // Watchpoint enable
reg [`LM32_WORD_RNG] wp[0:watchpoints-1]; // Watchpoint address
wire [0:watchpoints]wp_match_n; // Indicates if a h/w data watchpoint matched
wire debug_csr_write_enable; // Debug CSR write enable (from either a wcsr instruction of external debugger)
wire [`LM32_WORD_RNG] debug_csr_write_data; // Data to write to debug CSR
wire [`LM32_CSR_RNG] debug_csr; // Debug CSR to write to
`ifdef LM32_SINGLE_STEP_ENABLED
// FIXME: Declaring this as a reg causes ModelSim 6.1.15b to crash, so use integer for now
//reg [`LM32_DEBUG_SS_STATE_RNG] state; // State of single-step FSM
integer state; // State of single-step FSM
`endif
/////////////////////////////////////////////////////
// Functions
/////////////////////////////////////////////////////
`include "lm32_functions.v"
/////////////////////////////////////////////////////
// Combinational Logic
/////////////////////////////////////////////////////
// Check for breakpoints
generate
for (i = 0; i < breakpoints; i = i + 1)
begin : bp_comb
assign bp_match_n[i] = ((bp_a[i] == pc_x) && (bp_e[i] == `TRUE));
end
endgenerate
generate
`ifdef LM32_SINGLE_STEP_ENABLED
if (breakpoints > 0)
assign bp_match = (|bp_match_n) || (state == `LM32_DEBUG_SS_STATE_RAISE_BREAKPOINT);
else
assign bp_match = state == `LM32_DEBUG_SS_STATE_RAISE_BREAKPOINT;
`else
if (breakpoints > 0)
assign bp_match = |bp_match_n;
else
assign bp_match = `FALSE;
`endif
endgenerate
// Check for watchpoints
generate
for (i = 0; i < watchpoints; i = i + 1)
begin : wp_comb
assign wp_match_n[i] = (wp[i] == load_store_address_x) && ((load_x & wpc_c[i][0]) | (store_x & wpc_c[i][1]));
end
endgenerate
generate
if (watchpoints > 0)
assign wp_match = |wp_match_n;
else
assign wp_match = `FALSE;
endgenerate
`ifdef CFG_HW_DEBUG_ENABLED
// Multiplex between wcsr instruction writes and debugger writes to the debug CSRs
assign debug_csr_write_enable = (csr_write_enable_x == `TRUE) || (jtag_csr_write_enable == `TRUE);
assign debug_csr_write_data = jtag_csr_write_enable == `TRUE ? jtag_csr_write_data : csr_write_data;
assign debug_csr = jtag_csr_write_enable == `TRUE ? jtag_csr : csr_x;
`else
assign debug_csr_write_enable = csr_write_enable_x;
assign debug_csr_write_data = csr_write_data;
assign debug_csr = csr_x;
`endif
/////////////////////////////////////////////////////
// Sequential Logic
/////////////////////////////////////////////////////
// Breakpoint address and enable CSRs
generate
for (i = 0; i < breakpoints; i = i + 1)
begin : bp_seq
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
bp_a[i] <= {`LM32_PC_WIDTH{1'bx}};
bp_e[i] <= `FALSE;
end
else
begin
if ((debug_csr_write_enable == `TRUE) && (debug_csr == `LM32_CSR_BP0 + i))
begin
bp_a[i] <= debug_csr_write_data[`LM32_PC_RNG];
bp_e[i] <= debug_csr_write_data[0];
end
end
end
end
endgenerate
// Watchpoint address and control flags CSRs
generate
for (i = 0; i < watchpoints; i = i + 1)
begin : wp_seq
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
wp[i] <= {`LM32_WORD_WIDTH{1'bx}};
wpc_c[i] <= `LM32_WPC_C_DISABLED;
end
else
begin
if (debug_csr_write_enable == `TRUE)
begin
if (debug_csr == `LM32_CSR_DC)
wpc_c[i] <= debug_csr_write_data[3+i*2:2+i*2];
if (debug_csr == `LM32_CSR_WP0 + i)
wp[i] <= debug_csr_write_data;
end
end
end
end
endgenerate
// Remap exceptions control bit
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
dc_re <= `FALSE;
else
begin
if ((debug_csr_write_enable == `TRUE) && (debug_csr == `LM32_CSR_DC))
dc_re <= debug_csr_write_data[1];
end
end
`ifdef LM32_SINGLE_STEP_ENABLED
// Single-step control flag
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
state <= `LM32_DEBUG_SS_STATE_IDLE;
dc_ss <= `FALSE;
end
else
begin
if ((debug_csr_write_enable == `TRUE) && (debug_csr == `LM32_CSR_DC))
begin
dc_ss <= debug_csr_write_data[0];
if (debug_csr_write_data[0] == `FALSE)
state <= `LM32_DEBUG_SS_STATE_IDLE;
else
state <= `LM32_DEBUG_SS_STATE_WAIT_FOR_RET;
end
case (state)
`LM32_DEBUG_SS_STATE_WAIT_FOR_RET:
begin
// Wait for eret or bret instruction to be executed
if ( ( (eret_q_x == `TRUE)
|| (bret_q_x == `TRUE)
)
&& (stall_x == `FALSE)
)
state <= `LM32_DEBUG_SS_STATE_EXECUTE_ONE_INSN;
end
`LM32_DEBUG_SS_STATE_EXECUTE_ONE_INSN:
begin
// Wait for an instruction to be executed
if ((q_x == `TRUE) && (stall_x == `FALSE))
state <= `LM32_DEBUG_SS_STATE_RAISE_BREAKPOINT;
end
`LM32_DEBUG_SS_STATE_RAISE_BREAKPOINT:
begin
// Wait for exception to be raised
`ifdef CFG_DCACHE_ENABLED
if (dcache_refill_request == `TRUE)
state <= `LM32_DEBUG_SS_STATE_EXECUTE_ONE_INSN;
else
`endif
if ((exception_x == `TRUE) && (q_x == `TRUE) && (stall_x == `FALSE))
begin
dc_ss <= `FALSE;
state <= `LM32_DEBUG_SS_STATE_RESTART;
end
end
`LM32_DEBUG_SS_STATE_RESTART:
begin
// Watch to see if stepped instruction is restarted due to a cache miss
`ifdef CFG_DCACHE_ENABLED
if (dcache_refill_request == `TRUE)
state <= `LM32_DEBUG_SS_STATE_EXECUTE_ONE_INSN;
else
`endif
state <= `LM32_DEBUG_SS_STATE_IDLE;
end
endcase
end
end
`endif
endmodule
`endif
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_decoder.v
// Title : Instruction decoder
// Dependencies : lm32_include.v
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : Support for static branch prediction. Information about
// : branch type is generated and passed on to the predictor.
// Version : 3.2
// : No change
// Version : 3.3
// : Renamed port names that conflict with keywords reserved
// : in System-Verilog.
// =============================================================================
`include "lm32_include.v"
// Index of opcode field in an instruction
`define LM32_OPCODE_RNG 31:26
`define LM32_OP_RNG 30:26
// Opcodes - Some are only listed as 5 bits as their MSB is a don't care
`define LM32_OPCODE_ADD 5'b01101
`define LM32_OPCODE_AND 5'b01000
`define LM32_OPCODE_ANDHI 6'b011000
`define LM32_OPCODE_B 6'b110000
`define LM32_OPCODE_BI 6'b111000
`define LM32_OPCODE_BE 6'b010001
`define LM32_OPCODE_BG 6'b010010
`define LM32_OPCODE_BGE 6'b010011
`define LM32_OPCODE_BGEU 6'b010100
`define LM32_OPCODE_BGU 6'b010101
`define LM32_OPCODE_BNE 6'b010111
`define LM32_OPCODE_CALL 6'b110110
`define LM32_OPCODE_CALLI 6'b111110
`define LM32_OPCODE_CMPE 5'b11001
`define LM32_OPCODE_CMPG 5'b11010
`define LM32_OPCODE_CMPGE 5'b11011
`define LM32_OPCODE_CMPGEU 5'b11100
`define LM32_OPCODE_CMPGU 5'b11101
`define LM32_OPCODE_CMPNE 5'b11111
`define LM32_OPCODE_DIVU 6'b100011
`define LM32_OPCODE_LB 6'b000100
`define LM32_OPCODE_LBU 6'b010000
`define LM32_OPCODE_LH 6'b000111
`define LM32_OPCODE_LHU 6'b001011
`define LM32_OPCODE_LW 6'b001010
`define LM32_OPCODE_MODU 6'b110001
`define LM32_OPCODE_MUL 5'b00010
`define LM32_OPCODE_NOR 5'b00001
`define LM32_OPCODE_OR 5'b01110
`define LM32_OPCODE_ORHI 6'b011110
`define LM32_OPCODE_RAISE 6'b101011
`define LM32_OPCODE_RCSR 6'b100100
`define LM32_OPCODE_SB 6'b001100
`define LM32_OPCODE_SEXTB 6'b101100
`define LM32_OPCODE_SEXTH 6'b110111
`define LM32_OPCODE_SH 6'b000011
`define LM32_OPCODE_SL 5'b01111
`define LM32_OPCODE_SR 5'b00101
`define LM32_OPCODE_SRU 5'b00000
`define LM32_OPCODE_SUB 6'b110010
`define LM32_OPCODE_SW 6'b010110
`define LM32_OPCODE_USER 6'b110011
`define LM32_OPCODE_WCSR 6'b110100
`define LM32_OPCODE_XNOR 5'b01001
`define LM32_OPCODE_XOR 5'b00110
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_decoder (
// ----- Inputs -------
instruction,
// ----- Outputs -------
d_result_sel_0,
d_result_sel_1,
x_result_sel_csr,
`ifdef LM32_MC_ARITHMETIC_ENABLED
x_result_sel_mc_arith,
`endif
`ifdef LM32_NO_BARREL_SHIFT
x_result_sel_shift,
`endif
`ifdef CFG_SIGN_EXTEND_ENABLED
x_result_sel_sext,
`endif
x_result_sel_logic,
`ifdef CFG_USER_ENABLED
x_result_sel_user,
`endif
x_result_sel_add,
m_result_sel_compare,
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
m_result_sel_shift,
`endif
w_result_sel_load,
`ifdef CFG_PL_MULTIPLY_ENABLED
w_result_sel_mul,
`endif
x_bypass_enable,
m_bypass_enable,
read_enable_0,
read_idx_0,
read_enable_1,
read_idx_1,
write_enable,
write_idx,
immediate,
branch_offset,
load,
store,
size,
sign_extend,
adder_op,
logic_op,
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
direction,
`endif
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
shift_left,
shift_right,
`endif
`ifdef CFG_MC_MULTIPLY_ENABLED
multiply,
`endif
`ifdef CFG_MC_DIVIDE_ENABLED
divide,
modulus,
`endif
branch,
branch_reg,
condition,
bi_conditional,
bi_unconditional,
`ifdef CFG_DEBUG_ENABLED
break_opcode,
`endif
scall,
eret,
`ifdef CFG_DEBUG_ENABLED
bret,
`endif
`ifdef CFG_USER_ENABLED
user_opcode,
`endif
csr_write_enable
);
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input [`LM32_INSTRUCTION_RNG] instruction; // Instruction to decode
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
output [`LM32_D_RESULT_SEL_0_RNG] d_result_sel_0;
reg [`LM32_D_RESULT_SEL_0_RNG] d_result_sel_0;
output [`LM32_D_RESULT_SEL_1_RNG] d_result_sel_1;
reg [`LM32_D_RESULT_SEL_1_RNG] d_result_sel_1;
output x_result_sel_csr;
reg x_result_sel_csr;
`ifdef LM32_MC_ARITHMETIC_ENABLED
output x_result_sel_mc_arith;
reg x_result_sel_mc_arith;
`endif
`ifdef LM32_NO_BARREL_SHIFT
output x_result_sel_shift;
reg x_result_sel_shift;
`endif
`ifdef CFG_SIGN_EXTEND_ENABLED
output x_result_sel_sext;
reg x_result_sel_sext;
`endif
output x_result_sel_logic;
reg x_result_sel_logic;
`ifdef CFG_USER_ENABLED
output x_result_sel_user;
reg x_result_sel_user;
`endif
output x_result_sel_add;
reg x_result_sel_add;
output m_result_sel_compare;
reg m_result_sel_compare;
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
output m_result_sel_shift;
reg m_result_sel_shift;
`endif
output w_result_sel_load;
reg w_result_sel_load;
`ifdef CFG_PL_MULTIPLY_ENABLED
output w_result_sel_mul;
reg w_result_sel_mul;
`endif
output x_bypass_enable;
wire x_bypass_enable;
output m_bypass_enable;
wire m_bypass_enable;
output read_enable_0;
wire read_enable_0;
output [`LM32_REG_IDX_RNG] read_idx_0;
wire [`LM32_REG_IDX_RNG] read_idx_0;
output read_enable_1;
wire read_enable_1;
output [`LM32_REG_IDX_RNG] read_idx_1;
wire [`LM32_REG_IDX_RNG] read_idx_1;
output write_enable;
wire write_enable;
output [`LM32_REG_IDX_RNG] write_idx;
wire [`LM32_REG_IDX_RNG] write_idx;
output [`LM32_WORD_RNG] immediate;
wire [`LM32_WORD_RNG] immediate;
output [`LM32_PC_RNG] branch_offset;
wire [`LM32_PC_RNG] branch_offset;
output load;
wire load;
output store;
wire store;
output [`LM32_SIZE_RNG] size;
wire [`LM32_SIZE_RNG] size;
output sign_extend;
wire sign_extend;
output adder_op;
wire adder_op;
output [`LM32_LOGIC_OP_RNG] logic_op;
wire [`LM32_LOGIC_OP_RNG] logic_op;
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
output direction;
wire direction;
`endif
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
output shift_left;
wire shift_left;
output shift_right;
wire shift_right;
`endif
`ifdef CFG_MC_MULTIPLY_ENABLED
output multiply;
wire multiply;
`endif
`ifdef CFG_MC_DIVIDE_ENABLED
output divide;
wire divide;
output modulus;
wire modulus;
`endif
output branch;
wire branch;
output branch_reg;
wire branch_reg;
output [`LM32_CONDITION_RNG] condition;
wire [`LM32_CONDITION_RNG] condition;
output bi_conditional;
wire bi_conditional;
output bi_unconditional;
wire bi_unconditional;
`ifdef CFG_DEBUG_ENABLED
output break_opcode;
wire break_opcode;
`endif
output scall;
wire scall;
output eret;
wire eret;
`ifdef CFG_DEBUG_ENABLED
output bret;
wire bret;
`endif
`ifdef CFG_USER_ENABLED
output [`LM32_USER_OPCODE_RNG] user_opcode;
wire [`LM32_USER_OPCODE_RNG] user_opcode;
`endif
output csr_write_enable;
wire csr_write_enable;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
wire [`LM32_WORD_RNG] extended_immediate; // Zero or sign extended immediate
wire [`LM32_WORD_RNG] high_immediate; // Immediate as high 16 bits
wire [`LM32_WORD_RNG] call_immediate; // Call immediate
wire [`LM32_WORD_RNG] branch_immediate; // Conditional branch immediate
wire sign_extend_immediate; // Whether the immediate should be sign extended (`TRUE) or zero extended (`FALSE)
wire select_high_immediate; // Whether to select the high immediate
wire select_call_immediate; // Whether to select the call immediate
/////////////////////////////////////////////////////
// Functions
/////////////////////////////////////////////////////
`include "lm32_functions.v"
/////////////////////////////////////////////////////
// Combinational logic
/////////////////////////////////////////////////////
// Determine opcode
assign op_add = instruction[`LM32_OP_RNG] == `LM32_OPCODE_ADD;
assign op_and = instruction[`LM32_OP_RNG] == `LM32_OPCODE_AND;
assign op_andhi = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_ANDHI;
assign op_b = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_B;
assign op_bi = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_BI;
assign op_be = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_BE;
assign op_bg = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_BG;
assign op_bge = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_BGE;
assign op_bgeu = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_BGEU;
assign op_bgu = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_BGU;
assign op_bne = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_BNE;
assign op_call = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_CALL;
assign op_calli = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_CALLI;
assign op_cmpe = instruction[`LM32_OP_RNG] == `LM32_OPCODE_CMPE;
assign op_cmpg = instruction[`LM32_OP_RNG] == `LM32_OPCODE_CMPG;
assign op_cmpge = instruction[`LM32_OP_RNG] == `LM32_OPCODE_CMPGE;
assign op_cmpgeu = instruction[`LM32_OP_RNG] == `LM32_OPCODE_CMPGEU;
assign op_cmpgu = instruction[`LM32_OP_RNG] == `LM32_OPCODE_CMPGU;
assign op_cmpne = instruction[`LM32_OP_RNG] == `LM32_OPCODE_CMPNE;
`ifdef CFG_MC_DIVIDE_ENABLED
assign op_divu = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_DIVU;
`endif
assign op_lb = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_LB;
assign op_lbu = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_LBU;
assign op_lh = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_LH;
assign op_lhu = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_LHU;
assign op_lw = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_LW;
`ifdef CFG_MC_DIVIDE_ENABLED
assign op_modu = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_MODU;
`endif
`ifdef LM32_MULTIPLY_ENABLED
assign op_mul = instruction[`LM32_OP_RNG] == `LM32_OPCODE_MUL;
`endif
assign op_nor = instruction[`LM32_OP_RNG] == `LM32_OPCODE_NOR;
assign op_or = instruction[`LM32_OP_RNG] == `LM32_OPCODE_OR;
assign op_orhi = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_ORHI;
assign op_raise = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_RAISE;
assign op_rcsr = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_RCSR;
assign op_sb = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_SB;
`ifdef CFG_SIGN_EXTEND_ENABLED
assign op_sextb = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_SEXTB;
assign op_sexth = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_SEXTH;
`endif
assign op_sh = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_SH;
`ifdef LM32_BARREL_SHIFT_ENABLED
assign op_sl = instruction[`LM32_OP_RNG] == `LM32_OPCODE_SL;
`endif
assign op_sr = instruction[`LM32_OP_RNG] == `LM32_OPCODE_SR;
assign op_sru = instruction[`LM32_OP_RNG] == `LM32_OPCODE_SRU;
assign op_sub = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_SUB;
assign op_sw = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_SW;
assign op_user = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_USER;
assign op_wcsr = instruction[`LM32_OPCODE_RNG] == `LM32_OPCODE_WCSR;
assign op_xnor = instruction[`LM32_OP_RNG] == `LM32_OPCODE_XNOR;
assign op_xor = instruction[`LM32_OP_RNG] == `LM32_OPCODE_XOR;
// Group opcodes by function
assign arith = op_add | op_sub;
assign logical = op_and | op_andhi | op_nor | op_or | op_orhi | op_xor | op_xnor;
assign cmp = op_cmpe | op_cmpg | op_cmpge | op_cmpgeu | op_cmpgu | op_cmpne;
assign bi_conditional = op_be | op_bg | op_bge | op_bgeu | op_bgu | op_bne;
assign bi_unconditional = op_bi;
assign bra = op_b | bi_unconditional | bi_conditional;
assign call = op_call | op_calli;
`ifdef LM32_BARREL_SHIFT_ENABLED
assign shift = op_sl | op_sr | op_sru;
`endif
`ifdef LM32_NO_BARREL_SHIFT
assign shift = op_sr | op_sru;
`endif
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
assign shift_left = op_sl;
assign shift_right = op_sr | op_sru;
`endif
`ifdef CFG_SIGN_EXTEND_ENABLED
assign sext = op_sextb | op_sexth;
`endif
`ifdef LM32_MULTIPLY_ENABLED
assign multiply = op_mul;
`endif
`ifdef CFG_MC_DIVIDE_ENABLED
assign divide = op_divu;
assign modulus = op_modu;
`endif
assign load = op_lb | op_lbu | op_lh | op_lhu | op_lw;
assign store = op_sb | op_sh | op_sw;
// Select pipeline multiplexor controls
always @(*)
begin
// D stage
if (call)
d_result_sel_0 = `LM32_D_RESULT_SEL_0_NEXT_PC;
else
d_result_sel_0 = `LM32_D_RESULT_SEL_0_REG_0;
if (call)
d_result_sel_1 = `LM32_D_RESULT_SEL_1_ZERO;
else if ((instruction[31] == 1'b0) && !bra)
d_result_sel_1 = `LM32_D_RESULT_SEL_1_IMMEDIATE;
else
d_result_sel_1 = `LM32_D_RESULT_SEL_1_REG_1;
// X stage
x_result_sel_csr = `FALSE;
`ifdef LM32_MC_ARITHMETIC_ENABLED
x_result_sel_mc_arith = `FALSE;
`endif
`ifdef LM32_NO_BARREL_SHIFT
x_result_sel_shift = `FALSE;
`endif
`ifdef CFG_SIGN_EXTEND_ENABLED
x_result_sel_sext = `FALSE;
`endif
x_result_sel_logic = `FALSE;
`ifdef CFG_USER_ENABLED
x_result_sel_user = `FALSE;
`endif
x_result_sel_add = `FALSE;
if (op_rcsr)
x_result_sel_csr = `TRUE;
`ifdef LM32_MC_ARITHMETIC_ENABLED
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
else if (shift_left | shift_right)
x_result_sel_mc_arith = `TRUE;
`endif
`ifdef CFG_MC_DIVIDE_ENABLED
else if (divide | modulus)
x_result_sel_mc_arith = `TRUE;
`endif
`ifdef CFG_MC_MULTIPLY_ENABLED
else if (multiply)
x_result_sel_mc_arith = `TRUE;
`endif
`endif
`ifdef LM32_NO_BARREL_SHIFT
else if (shift)
x_result_sel_shift = `TRUE;
`endif
`ifdef CFG_SIGN_EXTEND_ENABLED
else if (sext)
x_result_sel_sext = `TRUE;
`endif
else if (logical)
x_result_sel_logic = `TRUE;
`ifdef CFG_USER_ENABLED
else if (op_user)
x_result_sel_user = `TRUE;
`endif
else
x_result_sel_add = `TRUE;
// M stage
m_result_sel_compare = cmp;
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
m_result_sel_shift = shift;
`endif
// W stage
w_result_sel_load = load;
`ifdef CFG_PL_MULTIPLY_ENABLED
w_result_sel_mul = op_mul;
`endif
end
// Set if result is valid at end of X stage
assign x_bypass_enable = arith
| logical
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
| shift_left
| shift_right
`endif
`ifdef CFG_MC_MULTIPLY_ENABLED
| multiply
`endif
`ifdef CFG_MC_DIVIDE_ENABLED
| divide
| modulus
`endif
`ifdef LM32_NO_BARREL_SHIFT
| shift
`endif
`ifdef CFG_SIGN_EXTEND_ENABLED
| sext
`endif
`ifdef CFG_USER_ENABLED
| op_user
`endif
| op_rcsr
;
// Set if result is valid at end of M stage
assign m_bypass_enable = x_bypass_enable
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
| shift
`endif
| cmp
;
// Register file read port 0
assign read_enable_0 = ~(op_bi | op_calli);
assign read_idx_0 = instruction[25:21];
// Register file read port 1
assign read_enable_1 = ~(op_bi | op_calli | load);
assign read_idx_1 = instruction[20:16];
// Register file write port
assign write_enable = ~(bra | op_raise | store | op_wcsr);
assign write_idx = call
? 5'd29
: instruction[31] == 1'b0
? instruction[20:16]
: instruction[15:11];
// Size of load/stores
assign size = instruction[27:26];
// Whether to sign or zero extend
assign sign_extend = instruction[28];
// Set adder_op to 1 to perform a subtraction
assign adder_op = op_sub | op_cmpe | op_cmpg | op_cmpge | op_cmpgeu | op_cmpgu | op_cmpne | bra;
// Logic operation (and, or, etc)
assign logic_op = instruction[29:26];
`ifdef CFG_PL_BARREL_SHIFT_ENABLED
// Shift direction
assign direction = instruction[29];
`endif
// Control flow microcodes
assign branch = bra | call;
assign branch_reg = op_call | op_b;
assign condition = instruction[28:26];
`ifdef CFG_DEBUG_ENABLED
assign break_opcode = op_raise & ~instruction[2];
`endif
assign scall = op_raise & instruction[2];
assign eret = op_b & (instruction[25:21] == 5'd30);
`ifdef CFG_DEBUG_ENABLED
assign bret = op_b & (instruction[25:21] == 5'd31);
`endif
`ifdef CFG_USER_ENABLED
// Extract user opcode
assign user_opcode = instruction[10:0];
`endif
// CSR read/write
assign csr_write_enable = op_wcsr;
// Extract immediate from instruction
assign sign_extend_immediate = ~(op_and | op_cmpgeu | op_cmpgu | op_nor | op_or | op_xnor | op_xor);
assign select_high_immediate = op_andhi | op_orhi;
assign select_call_immediate = instruction[31];
assign high_immediate = {instruction[15:0], 16'h0000};
assign extended_immediate = {{16{sign_extend_immediate & instruction[15]}}, instruction[15:0]};
assign call_immediate = {{6{instruction[25]}}, instruction[25:0]};
assign branch_immediate = {{16{instruction[15]}}, instruction[15:0]};
assign immediate = select_high_immediate == `TRUE
? high_immediate
: extended_immediate;
assign branch_offset = select_call_immediate == `TRUE
? call_immediate
: branch_immediate;
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_functions.v
// Title : Common functions
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.5
// : Added function to generate log-of-two that rounds-up to
// : power-of-two
// =============================================================================
function integer clogb2;
input [31:0] value;
begin
for (clogb2 = 0; value > 0; clogb2 = clogb2 + 1)
value = value >> 1;
end
endfunction
function integer clogb2_v1;
input [31:0] value;
reg [31:0] i;
reg [31:0] temp;
begin
temp = 0;
i = 0;
for (i = 0; temp < value; i = i + 1)
temp = 1<<i;
clogb2_v1 = i-1;
end
endfunction
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_icache.v
// Title : Instruction cache
// Dependencies : lm32_include.v
//
// Version 3.5
// 1. Bug Fix: Instruction cache flushes issued from Instruction Inline Memory
// cause segmentation fault due to incorrect fetches.
//
// Version 3.1
// 1. Feature: Support for user-selected resource usage when implementing
// cache memory. Additional parameters must be defined when invoking module
// lm32_ram. Instruction cache miss mechanism is dependent on branch
// prediction being performed in D stage of pipeline.
//
// Version 7.0SP2, 3.0
// No change
// =============================================================================
`include "lm32_include.v"
`ifdef CFG_ICACHE_ENABLED
`define LM32_IC_ADDR_OFFSET_RNG addr_offset_msb:addr_offset_lsb
`define LM32_IC_ADDR_SET_RNG addr_set_msb:addr_set_lsb
`define LM32_IC_ADDR_TAG_RNG addr_tag_msb:addr_tag_lsb
`define LM32_IC_ADDR_IDX_RNG addr_set_msb:addr_offset_lsb
`define LM32_IC_TMEM_ADDR_WIDTH addr_set_width
`define LM32_IC_TMEM_ADDR_RNG (`LM32_IC_TMEM_ADDR_WIDTH-1):0
`define LM32_IC_DMEM_ADDR_WIDTH (addr_offset_width+addr_set_width)
`define LM32_IC_DMEM_ADDR_RNG (`LM32_IC_DMEM_ADDR_WIDTH-1):0
`define LM32_IC_TAGS_WIDTH (addr_tag_width+1)
`define LM32_IC_TAGS_RNG (`LM32_IC_TAGS_WIDTH-1):0
`define LM32_IC_TAGS_TAG_RNG (`LM32_IC_TAGS_WIDTH-1):1
`define LM32_IC_TAGS_VALID_RNG 0
`define LM32_IC_STATE_RNG 3:0
`define LM32_IC_STATE_FLUSH_INIT 4'b0001
`define LM32_IC_STATE_FLUSH 4'b0010
`define LM32_IC_STATE_CHECK 4'b0100
`define LM32_IC_STATE_REFILL 4'b1000
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_icache (
// ----- Inputs -----
clk_i,
rst_i,
stall_a,
stall_f,
address_a,
address_f,
read_enable_f,
refill_ready,
refill_data,
iflush,
`ifdef CFG_IROM_ENABLED
select_f,
`endif
valid_d,
branch_predict_taken_d,
// ----- Outputs -----
stall_request,
restart_request,
refill_request,
refill_address,
refilling,
inst
);
/////////////////////////////////////////////////////
// Parameters
/////////////////////////////////////////////////////
parameter associativity = 1; // Associativity of the cache (Number of ways)
parameter sets = 512; // Number of sets
parameter bytes_per_line = 16; // Number of bytes per cache line
parameter base_address = 0; // Base address of cachable memory
parameter limit = 0; // Limit (highest address) of cachable memory
localparam addr_offset_width = clogb2(bytes_per_line)-1-2;
localparam addr_set_width = clogb2(sets)-1;
localparam addr_offset_lsb = 2;
localparam addr_offset_msb = (addr_offset_lsb+addr_offset_width-1);
localparam addr_set_lsb = (addr_offset_msb+1);
localparam addr_set_msb = (addr_set_lsb+addr_set_width-1);
localparam addr_tag_lsb = (addr_set_msb+1);
localparam addr_tag_msb = clogb2(`CFG_ICACHE_LIMIT-`CFG_ICACHE_BASE_ADDRESS)-1;
localparam addr_tag_width = (addr_tag_msb-addr_tag_lsb+1);
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input clk_i; // Clock
input rst_i; // Reset
input stall_a; // Stall instruction in A stage
input stall_f; // Stall instruction in F stage
input valid_d; // Valid instruction in D stage
input branch_predict_taken_d; // Instruction in D stage is a branch and is predicted taken
input [`LM32_PC_RNG] address_a; // Address of instruction in A stage
input [`LM32_PC_RNG] address_f; // Address of instruction in F stage
input read_enable_f; // Indicates if cache access is valid
input refill_ready; // Next word of refill data is ready
input [`LM32_INSTRUCTION_RNG] refill_data; // Data to refill the cache with
input iflush; // Flush the cache
`ifdef CFG_IROM_ENABLED
input select_f; // Instruction in F stage is mapped through instruction cache
`endif
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
output stall_request; // Request to stall the pipeline
wire stall_request;
output restart_request; // Request to restart instruction that caused the cache miss
reg restart_request;
output refill_request; // Request to refill a cache line
wire refill_request;
output [`LM32_PC_RNG] refill_address; // Base address of cache refill
reg [`LM32_PC_RNG] refill_address;
output refilling; // Indicates the instruction cache is currently refilling
reg refilling;
output [`LM32_INSTRUCTION_RNG] inst; // Instruction read from cache
wire [`LM32_INSTRUCTION_RNG] inst;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
wire enable;
wire [0:associativity-1] way_mem_we;
wire [`LM32_INSTRUCTION_RNG] way_data[0:associativity-1];
wire [`LM32_IC_TAGS_TAG_RNG] way_tag[0:associativity-1];
wire [0:associativity-1] way_valid;
wire [0:associativity-1] way_match;
wire miss;
wire [`LM32_IC_TMEM_ADDR_RNG] tmem_read_address;
wire [`LM32_IC_TMEM_ADDR_RNG] tmem_write_address;
wire [`LM32_IC_DMEM_ADDR_RNG] dmem_read_address;
wire [`LM32_IC_DMEM_ADDR_RNG] dmem_write_address;
wire [`LM32_IC_TAGS_RNG] tmem_write_data;
reg [`LM32_IC_STATE_RNG] state;
wire flushing;
wire check;
wire refill;
reg [associativity-1:0] refill_way_select;
reg [`LM32_IC_ADDR_OFFSET_RNG] refill_offset;
wire last_refill;
reg [`LM32_IC_TMEM_ADDR_RNG] flush_set;
genvar i;
/////////////////////////////////////////////////////
// Functions
/////////////////////////////////////////////////////
`include "lm32_functions.v"
/////////////////////////////////////////////////////
// Instantiations
/////////////////////////////////////////////////////
generate
for (i = 0; i < associativity; i = i + 1)
begin : memories
lm32_ram
#(
// ----- Parameters -------
.data_width (32),
.address_width (`LM32_IC_DMEM_ADDR_WIDTH)
// Modified for Milkymist: removed non-portable RAM parameters
)
way_0_data_ram
(
// ----- Inputs -------
.read_clk (clk_i),
.write_clk (clk_i),
.reset (rst_i),
.read_address (dmem_read_address),
.enable_read (enable),
.write_address (dmem_write_address),
.enable_write (`TRUE),
.write_enable (way_mem_we[i]),
.write_data (refill_data),
// ----- Outputs -------
.read_data (way_data[i])
);
lm32_ram
#(
// ----- Parameters -------
.data_width (`LM32_IC_TAGS_WIDTH),
.address_width (`LM32_IC_TMEM_ADDR_WIDTH)
// Modified for Milkymist: removed non-portable RAM parameters
)
way_0_tag_ram
(
// ----- Inputs -------
.read_clk (clk_i),
.write_clk (clk_i),
.reset (rst_i),
.read_address (tmem_read_address),
.enable_read (enable),
.write_address (tmem_write_address),
.enable_write (`TRUE),
.write_enable (way_mem_we[i] | flushing),
.write_data (tmem_write_data),
// ----- Outputs -------
.read_data ({way_tag[i], way_valid[i]})
);
end
endgenerate
/////////////////////////////////////////////////////
// Combinational logic
/////////////////////////////////////////////////////
// Compute which ways in the cache match the address address being read
generate
for (i = 0; i < associativity; i = i + 1)
begin : match
assign way_match[i] = ({way_tag[i], way_valid[i]} == {address_f[`LM32_IC_ADDR_TAG_RNG], `TRUE});
end
endgenerate
// Select data from way that matched the address being read
generate
if (associativity == 1)
begin : inst_1
assign inst = way_match[0] ? way_data[0] : 32'b0;
end
else if (associativity == 2)
begin : inst_2
assign inst = way_match[0] ? way_data[0] : (way_match[1] ? way_data[1] : 32'b0);
end
endgenerate
// Compute address to use to index into the data memories
generate
if (bytes_per_line > 4)
assign dmem_write_address = {refill_address[`LM32_IC_ADDR_SET_RNG], refill_offset};
else
assign dmem_write_address = refill_address[`LM32_IC_ADDR_SET_RNG];
endgenerate
assign dmem_read_address = address_a[`LM32_IC_ADDR_IDX_RNG];
// Compute address to use to index into the tag memories
assign tmem_read_address = address_a[`LM32_IC_ADDR_SET_RNG];
assign tmem_write_address = flushing
? flush_set
: refill_address[`LM32_IC_ADDR_SET_RNG];
// Compute signal to indicate when we are on the last refill accesses
generate
if (bytes_per_line > 4)
assign last_refill = refill_offset == {addr_offset_width{1'b1}};
else
assign last_refill = `TRUE;
endgenerate
// Compute data and tag memory access enable
assign enable = (stall_a == `FALSE);
// Compute data and tag memory write enables
generate
if (associativity == 1)
begin : we_1
assign way_mem_we[0] = (refill_ready == `TRUE);
end
else
begin : we_2
assign way_mem_we[0] = (refill_ready == `TRUE) && (refill_way_select[0] == `TRUE);
assign way_mem_we[1] = (refill_ready == `TRUE) && (refill_way_select[1] == `TRUE);
end
endgenerate
// On the last refill cycle set the valid bit, for all other writes it should be cleared
assign tmem_write_data[`LM32_IC_TAGS_VALID_RNG] = last_refill & !flushing;
assign tmem_write_data[`LM32_IC_TAGS_TAG_RNG] = refill_address[`LM32_IC_ADDR_TAG_RNG];
// Signals that indicate which state we are in
assign flushing = |state[1:0];
assign check = state[2];
assign refill = state[3];
assign miss = (~(|way_match)) && (read_enable_f == `TRUE) && (stall_f == `FALSE) && !(valid_d && branch_predict_taken_d);
assign stall_request = (check == `FALSE);
assign refill_request = (refill == `TRUE);
/////////////////////////////////////////////////////
// Sequential logic
/////////////////////////////////////////////////////
// Record way selected for replacement on a cache miss
generate
if (associativity >= 2)
begin : way_select
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
refill_way_select <= {{associativity-1{1'b0}}, 1'b1};
else
begin
if (miss == `TRUE)
refill_way_select <= {refill_way_select[0], refill_way_select[1]};
end
end
end
endgenerate
// Record whether we are refilling
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
refilling <= `FALSE;
else
refilling <= refill;
end
// Instruction cache control FSM
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
state <= `LM32_IC_STATE_FLUSH_INIT;
flush_set <= {`LM32_IC_TMEM_ADDR_WIDTH{1'b1}};
refill_address <= {`LM32_PC_WIDTH{1'bx}};
restart_request <= `FALSE;
end
else
begin
case (state)
// Flush the cache for the first time after reset
`LM32_IC_STATE_FLUSH_INIT:
begin
if (flush_set == {`LM32_IC_TMEM_ADDR_WIDTH{1'b0}})
state <= `LM32_IC_STATE_CHECK;
flush_set <= flush_set - 1'b1;
end
// Flush the cache in response to an write to the ICC CSR
`LM32_IC_STATE_FLUSH:
begin
if (flush_set == {`LM32_IC_TMEM_ADDR_WIDTH{1'b0}})
`ifdef CFG_IROM_ENABLED
if (select_f)
state <= `LM32_IC_STATE_REFILL;
else
`endif
state <= `LM32_IC_STATE_CHECK;
flush_set <= flush_set - 1'b1;
end
// Check for cache misses
`LM32_IC_STATE_CHECK:
begin
if (stall_a == `FALSE)
restart_request <= `FALSE;
if (iflush == `TRUE)
begin
refill_address <= address_f;
state <= `LM32_IC_STATE_FLUSH;
end
else if (miss == `TRUE)
begin
refill_address <= address_f;
state <= `LM32_IC_STATE_REFILL;
end
end
// Refill a cache line
`LM32_IC_STATE_REFILL:
begin
if (refill_ready == `TRUE)
begin
if (last_refill == `TRUE)
begin
restart_request <= `TRUE;
state <= `LM32_IC_STATE_CHECK;
end
end
end
endcase
end
end
generate
if (bytes_per_line > 4)
begin
// Refill offset
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
refill_offset <= {addr_offset_width{1'b0}};
else
begin
case (state)
// Check for cache misses
`LM32_IC_STATE_CHECK:
begin
if (iflush == `TRUE)
refill_offset <= {addr_offset_width{1'b0}};
else if (miss == `TRUE)
refill_offset <= {addr_offset_width{1'b0}};
end
// Refill a cache line
`LM32_IC_STATE_REFILL:
begin
if (refill_ready == `TRUE)
refill_offset <= refill_offset + 1'b1;
end
endcase
end
end
end
endgenerate
endmodule
`endif
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_instruction_unit.v
// Title : Instruction unit
// Dependencies : lm32_include.v
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : Support for static branch prediction is added. Fetching of
// : instructions can also be altered by branches predicted in D
// : stage of pipeline, and mispredicted branches in the X and M
// : stages of the pipeline.
// Version : 3.2
// : EBRs use SYNC resets instead of ASYNC resets.
// Version : 3.3
// : Support for a non-cacheable Instruction Memory that has a
// : single-cycle access latency. This memory can be accessed by
// : data port of LM32 (so that debugger has access to it).
// Version : 3.4
// : No change
// Version : 3.5
// : Bug fix: Inline memory is correctly generated if it is not a
// : power-of-two.
// : Bug fix: Fixed a bug that caused LM32 (configured without
// : instruction cache) to lock up in to an infinite loop due to a
// : instruction bus error when EBA was set to instruction inline
// : memory.
// =============================================================================
`include "lm32_include.v"
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_instruction_unit (
// ----- Inputs -------
clk_i,
rst_i,
// From pipeline
stall_a,
stall_f,
stall_d,
stall_x,
stall_m,
valid_f,
valid_d,
kill_f,
branch_predict_taken_d,
branch_predict_address_d,
`ifdef CFG_FAST_UNCONDITIONAL_BRANCH
branch_taken_x,
branch_target_x,
`endif
exception_m,
branch_taken_m,
branch_mispredict_taken_m,
branch_target_m,
`ifdef CFG_ICACHE_ENABLED
iflush,
`endif
`ifdef CFG_DCACHE_ENABLED
dcache_restart_request,
dcache_refill_request,
dcache_refilling,
`endif
`ifdef CFG_IROM_ENABLED
irom_store_data_m,
irom_address_xm,
irom_we_xm,
`endif
`ifdef CFG_IWB_ENABLED
// From Wishbone
i_dat_i,
i_ack_i,
i_err_i,
i_rty_i,
`endif
`ifdef CFG_HW_DEBUG_ENABLED
jtag_read_enable,
jtag_write_enable,
jtag_write_data,
jtag_address,
`endif
// ----- Outputs -------
// To pipeline
pc_f,
pc_d,
pc_x,
pc_m,
pc_w,
`ifdef CFG_ICACHE_ENABLED
icache_stall_request,
icache_restart_request,
icache_refill_request,
icache_refilling,
`endif
`ifdef CFG_IROM_ENABLED
irom_data_m,
`endif
`ifdef CFG_IWB_ENABLED
// To Wishbone
i_dat_o,
i_adr_o,
i_cyc_o,
i_sel_o,
i_stb_o,
i_we_o,
i_cti_o,
i_lock_o,
i_bte_o,
`endif
`ifdef CFG_HW_DEBUG_ENABLED
jtag_read_data,
jtag_access_complete,
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
bus_error_d,
`endif
`ifdef CFG_EBR_POSEDGE_REGISTER_FILE
instruction_f,
`endif
instruction_d
);
/////////////////////////////////////////////////////
// Parameters
/////////////////////////////////////////////////////
parameter associativity = 1; // Associativity of the cache (Number of ways)
parameter sets = 512; // Number of sets
parameter bytes_per_line = 16; // Number of bytes per cache line
parameter base_address = 0; // Base address of cachable memory
parameter limit = 0; // Limit (highest address) of cachable memory
// For bytes_per_line == 4, we set 1 so part-select range isn't reversed, even though not really used
localparam addr_offset_width = bytes_per_line == 4 ? 1 : clogb2(bytes_per_line)-1-2;
localparam addr_offset_lsb = 2;
localparam addr_offset_msb = (addr_offset_lsb+addr_offset_width-1);
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input clk_i; // Clock
input rst_i; // Reset
input stall_a; // Stall A stage instruction
input stall_f; // Stall F stage instruction
input stall_d; // Stall D stage instruction
input stall_x; // Stall X stage instruction
input stall_m; // Stall M stage instruction
input valid_f; // Instruction in F stage is valid
input valid_d; // Instruction in D stage is valid
input kill_f; // Kill instruction in F stage
input branch_predict_taken_d; // Branch is predicted taken in D stage
input [`LM32_PC_RNG] branch_predict_address_d; // Branch target address
`ifdef CFG_FAST_UNCONDITIONAL_BRANCH
input branch_taken_x; // Branch instruction in X stage is taken
input [`LM32_PC_RNG] branch_target_x; // Target PC of X stage branch instruction
`endif
input exception_m;
input branch_taken_m; // Branch instruction in M stage is taken
input branch_mispredict_taken_m; // Branch instruction in M stage is mispredicted as taken
input [`LM32_PC_RNG] branch_target_m; // Target PC of M stage branch instruction
`ifdef CFG_ICACHE_ENABLED
input iflush; // Flush instruction cache
`endif
`ifdef CFG_DCACHE_ENABLED
input dcache_restart_request; // Restart instruction that caused a data cache miss
input dcache_refill_request; // Request to refill data cache
input dcache_refilling;
`endif
`ifdef CFG_IROM_ENABLED
input [`LM32_WORD_RNG] irom_store_data_m; // Data from load-store unit
input [`LM32_WORD_RNG] irom_address_xm; // Address from load-store unit
input irom_we_xm; // Indicates if memory operation is load or store
`endif
`ifdef CFG_IWB_ENABLED
input [`LM32_WORD_RNG] i_dat_i; // Instruction Wishbone interface read data
input i_ack_i; // Instruction Wishbone interface acknowledgement
input i_err_i; // Instruction Wishbone interface error
input i_rty_i; // Instruction Wishbone interface retry
`endif
`ifdef CFG_HW_DEBUG_ENABLED
input jtag_read_enable; // JTAG read memory request
input jtag_write_enable; // JTAG write memory request
input [`LM32_BYTE_RNG] jtag_write_data; // JTAG wrirte data
input [`LM32_WORD_RNG] jtag_address; // JTAG read/write address
`endif
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
output [`LM32_PC_RNG] pc_f; // F stage PC
reg [`LM32_PC_RNG] pc_f;
output [`LM32_PC_RNG] pc_d; // D stage PC
reg [`LM32_PC_RNG] pc_d;
output [`LM32_PC_RNG] pc_x; // X stage PC
reg [`LM32_PC_RNG] pc_x;
output [`LM32_PC_RNG] pc_m; // M stage PC
reg [`LM32_PC_RNG] pc_m;
output [`LM32_PC_RNG] pc_w; // W stage PC
reg [`LM32_PC_RNG] pc_w;
`ifdef CFG_ICACHE_ENABLED
output icache_stall_request; // Instruction cache stall request
wire icache_stall_request;
output icache_restart_request; // Request to restart instruction that cached instruction cache miss
wire icache_restart_request;
output icache_refill_request; // Instruction cache refill request
wire icache_refill_request;
output icache_refilling; // Indicates the icache is refilling
wire icache_refilling;
`endif
`ifdef CFG_IROM_ENABLED
output [`LM32_WORD_RNG] irom_data_m; // Data to load-store unit on load
wire [`LM32_WORD_RNG] irom_data_m;
`endif
`ifdef CFG_IWB_ENABLED
output [`LM32_WORD_RNG] i_dat_o; // Instruction Wishbone interface write data
`ifdef CFG_HW_DEBUG_ENABLED
reg [`LM32_WORD_RNG] i_dat_o;
`else
wire [`LM32_WORD_RNG] i_dat_o;
`endif
output [`LM32_WORD_RNG] i_adr_o; // Instruction Wishbone interface address
reg [`LM32_WORD_RNG] i_adr_o;
output i_cyc_o; // Instruction Wishbone interface cycle
reg i_cyc_o;
output [`LM32_BYTE_SELECT_RNG] i_sel_o; // Instruction Wishbone interface byte select
`ifdef CFG_HW_DEBUG_ENABLED
reg [`LM32_BYTE_SELECT_RNG] i_sel_o;
`else
wire [`LM32_BYTE_SELECT_RNG] i_sel_o;
`endif
output i_stb_o; // Instruction Wishbone interface strobe
reg i_stb_o;
output i_we_o; // Instruction Wishbone interface write enable
`ifdef CFG_HW_DEBUG_ENABLED
reg i_we_o;
`else
wire i_we_o;
`endif
output [`LM32_CTYPE_RNG] i_cti_o; // Instruction Wishbone interface cycle type
reg [`LM32_CTYPE_RNG] i_cti_o;
output i_lock_o; // Instruction Wishbone interface lock bus
reg i_lock_o;
output [`LM32_BTYPE_RNG] i_bte_o; // Instruction Wishbone interface burst type
wire [`LM32_BTYPE_RNG] i_bte_o;
`endif
`ifdef CFG_HW_DEBUG_ENABLED
output [`LM32_BYTE_RNG] jtag_read_data; // Data read for JTAG interface
reg [`LM32_BYTE_RNG] jtag_read_data;
output jtag_access_complete; // Requested memory access by JTAG interface is complete
wire jtag_access_complete;
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
output bus_error_d; // Indicates a bus error occured while fetching the instruction
reg bus_error_d;
`endif
`ifdef CFG_EBR_POSEDGE_REGISTER_FILE
output [`LM32_INSTRUCTION_RNG] instruction_f; // F stage instruction (only to have register indices extracted from)
wire [`LM32_INSTRUCTION_RNG] instruction_f;
`endif
output [`LM32_INSTRUCTION_RNG] instruction_d; // D stage instruction to be decoded
reg [`LM32_INSTRUCTION_RNG] instruction_d;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
reg [`LM32_PC_RNG] pc_a; // A stage PC
`ifdef LM32_CACHE_ENABLED
reg [`LM32_PC_RNG] restart_address; // Address to restart from after a cache miss
`endif
`ifdef CFG_ICACHE_ENABLED
wire icache_read_enable_f; // Indicates if instruction cache miss is valid
wire [`LM32_PC_RNG] icache_refill_address; // Address that caused cache miss
reg icache_refill_ready; // Indicates when next word of refill data is ready to be written to cache
reg [`LM32_INSTRUCTION_RNG] icache_refill_data; // Next word of refill data, fetched from Wishbone
wire [`LM32_INSTRUCTION_RNG] icache_data_f; // Instruction fetched from instruction cache
wire [`LM32_CTYPE_RNG] first_cycle_type; // First Wishbone cycle type
wire [`LM32_CTYPE_RNG] next_cycle_type; // Next Wishbone cycle type
wire last_word; // Indicates if this is the last word in the cache line
wire [`LM32_PC_RNG] first_address; // First cache refill address
`else
`ifdef CFG_IWB_ENABLED
reg [`LM32_INSTRUCTION_RNG] wb_data_f; // Instruction fetched from Wishbone
`endif
`endif
`ifdef CFG_IROM_ENABLED
wire irom_select_a; // Indicates if A stage PC maps to a ROM address
reg irom_select_f; // Indicates if F stage PC maps to a ROM address
wire [`LM32_INSTRUCTION_RNG] irom_data_f; // Instruction fetched from ROM
`endif
`ifdef CFG_EBR_POSEDGE_REGISTER_FILE
`else
wire [`LM32_INSTRUCTION_RNG] instruction_f; // F stage instruction
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
reg bus_error_f; // Indicates if a bus error occured while fetching the instruction in the F stage
`endif
`ifdef CFG_HW_DEBUG_ENABLED
reg jtag_access; // Indicates if a JTAG WB access is in progress
`endif
/////////////////////////////////////////////////////
// Functions
/////////////////////////////////////////////////////
`include "lm32_functions.v"
/////////////////////////////////////////////////////
// Instantiations
/////////////////////////////////////////////////////
// Instruction ROM
`ifdef CFG_IROM_ENABLED
pmi_ram_dp_true
#(
// ----- Parameters -------
.pmi_family (`LATTICE_FAMILY),
//.pmi_addr_depth_a (1 << (clogb2(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)-1)),
//.pmi_addr_width_a ((clogb2(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)-1)),
//.pmi_data_width_a (`LM32_WORD_WIDTH),
//.pmi_addr_depth_b (1 << (clogb2(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)-1)),
//.pmi_addr_width_b ((clogb2(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)-1)),
//.pmi_data_width_b (`LM32_WORD_WIDTH),
.pmi_addr_depth_a (`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1),
.pmi_addr_width_a (clogb2_v1(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)),
.pmi_data_width_a (`LM32_WORD_WIDTH),
.pmi_addr_depth_b (`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1),
.pmi_addr_width_b (clogb2_v1(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)),
.pmi_data_width_b (`LM32_WORD_WIDTH),
.pmi_regmode_a ("noreg"),
.pmi_regmode_b ("noreg"),
.pmi_gsr ("enable"),
.pmi_resetmode ("sync"),
.pmi_init_file (`CFG_IROM_INIT_FILE),
.pmi_init_file_format (`CFG_IROM_INIT_FILE_FORMAT),
.module_type ("pmi_ram_dp_true")
)
ram (
// ----- Inputs -------
.ClockA (clk_i),
.ClockB (clk_i),
.ResetA (rst_i),
.ResetB (rst_i),
.DataInA ({32{1'b0}}),
.DataInB (irom_store_data_m),
.AddressA (pc_a[(clogb2(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)-1)+2-1:2]),
.AddressB (irom_address_xm[(clogb2(`CFG_IROM_LIMIT/4-`CFG_IROM_BASE_ADDRESS/4+1)-1)+2-1:2]),
.ClockEnA (!stall_a),
.ClockEnB (!stall_x || !stall_m),
.WrA (`FALSE),
.WrB (irom_we_xm),
// ----- Outputs -------
.QA (irom_data_f),
.QB (irom_data_m)
);
`endif
`ifdef CFG_ICACHE_ENABLED
// Instruction cache
lm32_icache #(
.associativity (associativity),
.sets (sets),
.bytes_per_line (bytes_per_line),
.base_address (base_address),
.limit (limit)
) icache (
// ----- Inputs -----
.clk_i (clk_i),
.rst_i (rst_i),
.stall_a (stall_a),
.stall_f (stall_f),
.branch_predict_taken_d (branch_predict_taken_d),
.valid_d (valid_d),
.address_a (pc_a),
.address_f (pc_f),
.read_enable_f (icache_read_enable_f),
.refill_ready (icache_refill_ready),
.refill_data (icache_refill_data),
.iflush (iflush),
// ----- Outputs -----
.stall_request (icache_stall_request),
.restart_request (icache_restart_request),
.refill_request (icache_refill_request),
.refill_address (icache_refill_address),
.refilling (icache_refilling),
.inst (icache_data_f)
);
`endif
/////////////////////////////////////////////////////
// Combinational Logic
/////////////////////////////////////////////////////
`ifdef CFG_ICACHE_ENABLED
// Generate signal that indicates when instruction cache misses are valid
assign icache_read_enable_f = (valid_f == `TRUE)
&& (kill_f == `FALSE)
`ifdef CFG_DCACHE_ENABLED
&& (dcache_restart_request == `FALSE)
`endif
`ifdef CFG_IROM_ENABLED
&& (irom_select_f == `FALSE)
`endif
;
`endif
// Compute address of next instruction to fetch
always @(*)
begin
// The request from the latest pipeline stage must take priority
`ifdef CFG_DCACHE_ENABLED
if (dcache_restart_request == `TRUE)
pc_a = restart_address;
else
`endif
if (branch_taken_m == `TRUE)
if ((branch_mispredict_taken_m == `TRUE) && (exception_m == `FALSE))
pc_a = pc_x;
else
pc_a = branch_target_m;
`ifdef CFG_FAST_UNCONDITIONAL_BRANCH
else if (branch_taken_x == `TRUE)
pc_a = branch_target_x;
`endif
else
if ( (valid_d == `TRUE) && (branch_predict_taken_d == `TRUE) )
pc_a = branch_predict_address_d;
else
`ifdef CFG_ICACHE_ENABLED
if (icache_restart_request == `TRUE)
pc_a = restart_address;
else
`endif
pc_a = pc_f + 1'b1;
end
// Select where instruction should be fetched from
`ifdef CFG_IROM_ENABLED
assign irom_select_a = ({pc_a, 2'b00} >= `CFG_IROM_BASE_ADDRESS) && ({pc_a, 2'b00} <= `CFG_IROM_LIMIT);
`endif
// Select instruction from selected source
`ifdef CFG_ICACHE_ENABLED
`ifdef CFG_IROM_ENABLED
assign instruction_f = irom_select_f == `TRUE ? irom_data_f : icache_data_f;
`else
assign instruction_f = icache_data_f;
`endif
`else
`ifdef CFG_IROM_ENABLED
`ifdef CFG_IWB_ENABLED
assign instruction_f = irom_select_f == `TRUE ? irom_data_f : wb_data_f;
`else
assign instruction_f = irom_data_f;
`endif
`else
assign instruction_f = wb_data_f;
`endif
`endif
// Unused/constant Wishbone signals
`ifdef CFG_IWB_ENABLED
`ifdef CFG_HW_DEBUG_ENABLED
`else
assign i_dat_o = 32'd0;
assign i_we_o = `FALSE;
assign i_sel_o = 4'b1111;
`endif
assign i_bte_o = `LM32_BTYPE_LINEAR;
`endif
`ifdef CFG_ICACHE_ENABLED
// Determine parameters for next cache refill Wishbone access
generate
case (bytes_per_line)
4:
begin
assign first_cycle_type = `LM32_CTYPE_END;
assign next_cycle_type = `LM32_CTYPE_END;
assign last_word = `TRUE;
assign first_address = icache_refill_address;
end
8:
begin
assign first_cycle_type = `LM32_CTYPE_INCREMENTING;
assign next_cycle_type = `LM32_CTYPE_END;
assign last_word = i_adr_o[addr_offset_msb:addr_offset_lsb] == 1'b1;
assign first_address = {icache_refill_address[`LM32_PC_WIDTH+2-1:addr_offset_msb+1], {addr_offset_width{1'b0}}};
end
16:
begin
assign first_cycle_type = `LM32_CTYPE_INCREMENTING;
assign next_cycle_type = i_adr_o[addr_offset_msb] == 1'b1 ? `LM32_CTYPE_END : `LM32_CTYPE_INCREMENTING;
assign last_word = i_adr_o[addr_offset_msb:addr_offset_lsb] == 2'b11;
assign first_address = {icache_refill_address[`LM32_PC_WIDTH+2-1:addr_offset_msb+1], {addr_offset_width{1'b0}}};
end
endcase
endgenerate
`endif
/////////////////////////////////////////////////////
// Sequential Logic
/////////////////////////////////////////////////////
// PC
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
pc_f <= (`CFG_EBA_RESET-4)/4;
pc_d <= {`LM32_PC_WIDTH{1'b0}};
pc_x <= {`LM32_PC_WIDTH{1'b0}};
pc_m <= {`LM32_PC_WIDTH{1'b0}};
pc_w <= {`LM32_PC_WIDTH{1'b0}};
end
else
begin
if (stall_f == `FALSE)
pc_f <= pc_a;
if (stall_d == `FALSE)
pc_d <= pc_f;
if (stall_x == `FALSE)
pc_x <= pc_d;
if (stall_m == `FALSE)
pc_m <= pc_x;
pc_w <= pc_m;
end
end
`ifdef LM32_CACHE_ENABLED
// Address to restart from after a cache miss has been handled
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
restart_address <= {`LM32_PC_WIDTH{1'b0}};
else
begin
`ifdef CFG_DCACHE_ENABLED
`ifdef CFG_ICACHE_ENABLED
// D-cache restart address must take priority, otherwise instructions will be lost
if (dcache_refill_request == `TRUE)
restart_address <= pc_w;
else if ((icache_refill_request == `TRUE) && (!dcache_refilling) && (!dcache_restart_request))
restart_address <= icache_refill_address;
`else
if (dcache_refill_request == `TRUE)
restart_address <= pc_w;
`endif
`else
`ifdef CFG_ICACHE_ENABLED
if (icache_refill_request == `TRUE)
restart_address <= icache_refill_address;
`endif
`endif
end
end
`endif
// Record where instruction was fetched from
`ifdef CFG_IROM_ENABLED
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
irom_select_f <= `FALSE;
else
begin
if (stall_f == `FALSE)
irom_select_f <= irom_select_a;
end
end
`endif
`ifdef CFG_HW_DEBUG_ENABLED
assign jtag_access_complete = (i_cyc_o == `TRUE) && ((i_ack_i == `TRUE) || (i_err_i == `TRUE)) && (jtag_access == `TRUE);
always @(*)
begin
case (jtag_address[1:0])
2'b00: jtag_read_data = i_dat_i[`LM32_BYTE_3_RNG];
2'b01: jtag_read_data = i_dat_i[`LM32_BYTE_2_RNG];
2'b10: jtag_read_data = i_dat_i[`LM32_BYTE_1_RNG];
2'b11: jtag_read_data = i_dat_i[`LM32_BYTE_0_RNG];
endcase
end
`endif
`ifdef CFG_IWB_ENABLED
// Instruction Wishbone interface
`ifdef CFG_ICACHE_ENABLED
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
i_cyc_o <= `FALSE;
i_stb_o <= `FALSE;
i_adr_o <= {`LM32_WORD_WIDTH{1'b0}};
i_cti_o <= `LM32_CTYPE_END;
i_lock_o <= `FALSE;
icache_refill_data <= {`LM32_INSTRUCTION_WIDTH{1'b0}};
icache_refill_ready <= `FALSE;
`ifdef CFG_BUS_ERRORS_ENABLED
bus_error_f <= `FALSE;
`endif
`ifdef CFG_HW_DEBUG_ENABLED
i_we_o <= `FALSE;
i_sel_o <= 4'b1111;
jtag_access <= `FALSE;
`endif
end
else
begin
icache_refill_ready <= `FALSE;
// Is a cycle in progress?
if (i_cyc_o == `TRUE)
begin
// Has cycle completed?
if ((i_ack_i == `TRUE) || (i_err_i == `TRUE))
begin
`ifdef CFG_HW_DEBUG_ENABLED
if (jtag_access == `TRUE)
begin
i_cyc_o <= `FALSE;
i_stb_o <= `FALSE;
i_we_o <= `FALSE;
jtag_access <= `FALSE;
end
else
`endif
begin
if (last_word == `TRUE)
begin
// Cache line fill complete
i_cyc_o <= `FALSE;
i_stb_o <= `FALSE;
i_lock_o <= `FALSE;
end
// Fetch next word in cache line
i_adr_o[addr_offset_msb:addr_offset_lsb] <= i_adr_o[addr_offset_msb:addr_offset_lsb] + 1'b1;
i_cti_o <= next_cycle_type;
// Write fetched data into instruction cache
icache_refill_ready <= `TRUE;
icache_refill_data <= i_dat_i;
end
end
`ifdef CFG_BUS_ERRORS_ENABLED
if (i_err_i == `TRUE)
begin
bus_error_f <= `TRUE;
$display ("Instruction bus error. Address: %x", i_adr_o);
end
`endif
end
else
begin
if ((icache_refill_request == `TRUE) && (icache_refill_ready == `FALSE))
begin
// Read first word of cache line
`ifdef CFG_HW_DEBUG_ENABLED
i_sel_o <= 4'b1111;
`endif
i_adr_o <= {first_address, 2'b00};
i_cyc_o <= `TRUE;
i_stb_o <= `TRUE;
i_cti_o <= first_cycle_type;
//i_lock_o <= `TRUE;
`ifdef CFG_BUS_ERRORS_ENABLED
bus_error_f <= `FALSE;
`endif
end
`ifdef CFG_HW_DEBUG_ENABLED
else
begin
if ((jtag_read_enable == `TRUE) || (jtag_write_enable == `TRUE))
begin
case (jtag_address[1:0])
2'b00: i_sel_o <= 4'b1000;
2'b01: i_sel_o <= 4'b0100;
2'b10: i_sel_o <= 4'b0010;
2'b11: i_sel_o <= 4'b0001;
endcase
i_adr_o <= jtag_address;
i_dat_o <= {4{jtag_write_data}};
i_cyc_o <= `TRUE;
i_stb_o <= `TRUE;
i_we_o <= jtag_write_enable;
i_cti_o <= `LM32_CTYPE_END;
jtag_access <= `TRUE;
end
end
`endif
`ifdef CFG_BUS_ERRORS_ENABLED
// Clear bus error when exception taken, otherwise they would be
// continually generated if exception handler is cached
`ifdef CFG_FAST_UNCONDITIONAL_BRANCH
if (branch_taken_x == `TRUE)
bus_error_f <= `FALSE;
`endif
if (branch_taken_m == `TRUE)
bus_error_f <= `FALSE;
`endif
end
end
end
`else
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
i_cyc_o <= `FALSE;
i_stb_o <= `FALSE;
i_adr_o <= {`LM32_WORD_WIDTH{1'b0}};
i_cti_o <= `LM32_CTYPE_END;
i_lock_o <= `FALSE;
wb_data_f <= {`LM32_INSTRUCTION_WIDTH{1'b0}};
`ifdef CFG_BUS_ERRORS_ENABLED
bus_error_f <= `FALSE;
`endif
end
else
begin
// Is a cycle in progress?
if (i_cyc_o == `TRUE)
begin
// Has cycle completed?
if((i_ack_i == `TRUE) || (i_err_i == `TRUE))
begin
// Cycle complete
i_cyc_o <= `FALSE;
i_stb_o <= `FALSE;
// Register fetched instruction
wb_data_f <= i_dat_i;
end
`ifdef CFG_BUS_ERRORS_ENABLED
if (i_err_i == `TRUE)
begin
bus_error_f <= `TRUE;
$display ("Instruction bus error. Address: %x", i_adr_o);
end
`endif
end
else
begin
// Wait for an instruction fetch from an external address
if ( (stall_a == `FALSE)
`ifdef CFG_IROM_ENABLED
&& (irom_select_a == `FALSE)
`endif
)
begin
// Fetch instruction
`ifdef CFG_HW_DEBUG_ENABLED
i_sel_o <= 4'b1111;
`endif
i_adr_o <= {pc_a, 2'b00};
i_cyc_o <= `TRUE;
i_stb_o <= `TRUE;
`ifdef CFG_BUS_ERRORS_ENABLED
bus_error_f <= `FALSE;
`endif
end
else
begin
if ( (stall_a == `FALSE)
`ifdef CFG_IROM_ENABLED
&& (irom_select_a == `TRUE)
`endif
)
begin
`ifdef CFG_BUS_ERRORS_ENABLED
bus_error_f <= `FALSE;
`endif
end
end
end
end
end
`endif
`endif
// Instruction register
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
instruction_d <= {`LM32_INSTRUCTION_WIDTH{1'b0}};
`ifdef CFG_BUS_ERRORS_ENABLED
bus_error_d <= `FALSE;
`endif
end
else
begin
if (stall_d == `FALSE)
begin
instruction_d <= instruction_f;
`ifdef CFG_BUS_ERRORS_ENABLED
bus_error_d <= bus_error_f;
`endif
end
end
end
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_interrupt.v
// Title : Interrupt logic
// Dependencies : lm32_include.v
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
`include "lm32_include.v"
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_interrupt (
// ----- Inputs -------
clk_i,
rst_i,
// From external devices
interrupt,
// From pipeline
stall_x,
`ifdef CFG_DEBUG_ENABLED
non_debug_exception,
debug_exception,
`else
exception,
`endif
eret_q_x,
`ifdef CFG_DEBUG_ENABLED
bret_q_x,
`endif
csr,
csr_write_data,
csr_write_enable,
// ----- Outputs -------
interrupt_exception,
// To pipeline
csr_read_data
);
/////////////////////////////////////////////////////
// Parameters
/////////////////////////////////////////////////////
parameter interrupts = `CFG_INTERRUPTS; // Number of interrupts
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input clk_i; // Clock
input rst_i; // Reset
input [interrupts-1:0] interrupt; // Interrupt pins, active-low
input stall_x; // Stall X pipeline stage
`ifdef CFG_DEBUG_ENABLED
input non_debug_exception; // Non-debug related exception has been raised
input debug_exception; // Debug-related exception has been raised
`else
input exception; // Exception has been raised
`endif
input eret_q_x; // Return from exception
`ifdef CFG_DEBUG_ENABLED
input bret_q_x; // Return from breakpoint
`endif
input [`LM32_CSR_RNG] csr; // CSR read/write index
input [`LM32_WORD_RNG] csr_write_data; // Data to write to specified CSR
input csr_write_enable; // CSR write enable
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
output interrupt_exception; // Request to raide an interrupt exception
wire interrupt_exception;
output [`LM32_WORD_RNG] csr_read_data; // Data read from CSR
reg [`LM32_WORD_RNG] csr_read_data;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
wire [interrupts-1:0] asserted; // Which interrupts are currently being asserted
//pragma attribute asserted preserve_signal true
wire [interrupts-1:0] interrupt_n_exception;
// Interrupt CSRs
reg ie; // Interrupt enable
reg eie; // Exception interrupt enable
`ifdef CFG_DEBUG_ENABLED
reg bie; // Breakpoint interrupt enable
`endif
reg [interrupts-1:0] ip; // Interrupt pending
reg [interrupts-1:0] im; // Interrupt mask
/////////////////////////////////////////////////////
// Combinational Logic
/////////////////////////////////////////////////////
// Determine which interrupts have occured and are unmasked
assign interrupt_n_exception = ip & im;
// Determine if any unmasked interrupts have occured
assign interrupt_exception = (|interrupt_n_exception) & ie;
// Determine which interrupts are currently being asserted (active-low) or are already pending
assign asserted = ip | interrupt;
assign ie_csr_read_data = {{`LM32_WORD_WIDTH-3{1'b0}},
`ifdef CFG_DEBUG_ENABLED
bie,
`else
1'b0,
`endif
eie,
ie
};
assign ip_csr_read_data = ip;
assign im_csr_read_data = im;
generate
if (interrupts > 1)
begin
// CSR read
always @(*)
begin
case (csr)
`LM32_CSR_IE: csr_read_data = {{`LM32_WORD_WIDTH-3{1'b0}},
`ifdef CFG_DEBUG_ENABLED
bie,
`else
1'b0,
`endif
eie,
ie
};
`LM32_CSR_IP: csr_read_data = ip;
`LM32_CSR_IM: csr_read_data = im;
default: csr_read_data = {`LM32_WORD_WIDTH{1'bx}};
endcase
end
end
else
begin
// CSR read
always @(*)
begin
case (csr)
`LM32_CSR_IE: csr_read_data = {{`LM32_WORD_WIDTH-3{1'b0}},
`ifdef CFG_DEBUG_ENABLED
bie,
`else
1'b0,
`endif
eie,
ie
};
`LM32_CSR_IP: csr_read_data = ip;
default: csr_read_data = {`LM32_WORD_WIDTH{1'bx}};
endcase
end
end
endgenerate
/////////////////////////////////////////////////////
// Sequential Logic
/////////////////////////////////////////////////////
generate
if (interrupts > 1)
begin
// IE, IM, IP - Interrupt Enable, Interrupt Mask and Interrupt Pending CSRs
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
ie <= `FALSE;
eie <= `FALSE;
`ifdef CFG_DEBUG_ENABLED
bie <= `FALSE;
`endif
im <= {interrupts{1'b0}};
ip <= {interrupts{1'b0}};
end
else
begin
// Set IP bit when interrupt line is asserted
ip <= asserted;
`ifdef CFG_DEBUG_ENABLED
if (non_debug_exception == `TRUE)
begin
// Save and then clear interrupt enable
eie <= ie;
ie <= `FALSE;
end
else if (debug_exception == `TRUE)
begin
// Save and then clear interrupt enable
bie <= ie;
ie <= `FALSE;
end
`else
if (exception == `TRUE)
begin
// Save and then clear interrupt enable
eie <= ie;
ie <= `FALSE;
end
`endif
else if (stall_x == `FALSE)
begin
if (eret_q_x == `TRUE)
// Restore interrupt enable
ie <= eie;
`ifdef CFG_DEBUG_ENABLED
else if (bret_q_x == `TRUE)
// Restore interrupt enable
ie <= bie;
`endif
else if (csr_write_enable == `TRUE)
begin
// Handle wcsr write
if (csr == `LM32_CSR_IE)
begin
ie <= csr_write_data[0];
eie <= csr_write_data[1];
`ifdef CFG_DEBUG_ENABLED
bie <= csr_write_data[2];
`endif
end
if (csr == `LM32_CSR_IM)
im <= csr_write_data[interrupts-1:0];
if (csr == `LM32_CSR_IP)
ip <= asserted & ~csr_write_data[interrupts-1:0];
end
end
end
end
end
else
begin
// IE, IM, IP - Interrupt Enable, Interrupt Mask and Interrupt Pending CSRs
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
ie <= `FALSE;
eie <= `FALSE;
`ifdef CFG_DEBUG_ENABLED
bie <= `FALSE;
`endif
ip <= {interrupts{1'b0}};
end
else
begin
// Set IP bit when interrupt line is asserted
ip <= asserted;
`ifdef CFG_DEBUG_ENABLED
if (non_debug_exception == `TRUE)
begin
// Save and then clear interrupt enable
eie <= ie;
ie <= `FALSE;
end
else if (debug_exception == `TRUE)
begin
// Save and then clear interrupt enable
bie <= ie;
ie <= `FALSE;
end
`else
if (exception == `TRUE)
begin
// Save and then clear interrupt enable
eie <= ie;
ie <= `FALSE;
end
`endif
else if (stall_x == `FALSE)
begin
if (eret_q_x == `TRUE)
// Restore interrupt enable
ie <= eie;
`ifdef CFG_DEBUG_ENABLED
else if (bret_q_x == `TRUE)
// Restore interrupt enable
ie <= bie;
`endif
else if (csr_write_enable == `TRUE)
begin
// Handle wcsr write
if (csr == `LM32_CSR_IE)
begin
ie <= csr_write_data[0];
eie <= csr_write_data[1];
`ifdef CFG_DEBUG_ENABLED
bie <= csr_write_data[2];
`endif
end
if (csr == `LM32_CSR_IP)
ip <= asserted & ~csr_write_data[interrupts-1:0];
end
end
end
end
end
endgenerate
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_jtag.v
// Title : JTAG interface
// Dependencies : lm32_include.v
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
`include "lm32_include.v"
`ifdef CFG_JTAG_ENABLED
`define LM32_DP 3'b000
`define LM32_TX 3'b001
`define LM32_RX 3'b010
// LM32 Debug Protocol commands IDs
`define LM32_DP_RNG 3:0
`define LM32_DP_READ_MEMORY 4'b0001
`define LM32_DP_WRITE_MEMORY 4'b0010
`define LM32_DP_READ_SEQUENTIAL 4'b0011
`define LM32_DP_WRITE_SEQUENTIAL 4'b0100
`define LM32_DP_WRITE_CSR 4'b0101
`define LM32_DP_BREAK 4'b0110
`define LM32_DP_RESET 4'b0111
// States for FSM
`define LM32_JTAG_STATE_RNG 3:0
`define LM32_JTAG_STATE_READ_COMMAND 4'h0
`define LM32_JTAG_STATE_READ_BYTE_0 4'h1
`define LM32_JTAG_STATE_READ_BYTE_1 4'h2
`define LM32_JTAG_STATE_READ_BYTE_2 4'h3
`define LM32_JTAG_STATE_READ_BYTE_3 4'h4
`define LM32_JTAG_STATE_READ_BYTE_4 4'h5
`define LM32_JTAG_STATE_PROCESS_COMMAND 4'h6
`define LM32_JTAG_STATE_WAIT_FOR_MEMORY 4'h7
`define LM32_JTAG_STATE_WAIT_FOR_CSR 4'h8
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_jtag (
// ----- Inputs -------
clk_i,
rst_i,
jtag_clk,
jtag_update,
jtag_reg_q,
jtag_reg_addr_q,
`ifdef CFG_JTAG_UART_ENABLED
csr,
csr_write_enable,
csr_write_data,
stall_x,
`endif
`ifdef CFG_HW_DEBUG_ENABLED
jtag_read_data,
jtag_access_complete,
`endif
`ifdef CFG_DEBUG_ENABLED
exception_q_w,
`endif
// ----- Outputs -------
`ifdef CFG_JTAG_UART_ENABLED
jtx_csr_read_data,
jrx_csr_read_data,
`endif
`ifdef CFG_HW_DEBUG_ENABLED
jtag_csr_write_enable,
jtag_csr_write_data,
jtag_csr,
jtag_read_enable,
jtag_write_enable,
jtag_write_data,
jtag_address,
`endif
`ifdef CFG_DEBUG_ENABLED
jtag_break,
jtag_reset,
`endif
jtag_reg_d,
jtag_reg_addr_d
);
parameter lat_family = `LATTICE_FAMILY;
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input clk_i; // Clock
input rst_i; // Reset
input jtag_clk; // JTAG clock
input jtag_update; // JTAG data register has been updated
input [`LM32_BYTE_RNG] jtag_reg_q; // JTAG data register
input [2:0] jtag_reg_addr_q; // JTAG data register
`ifdef CFG_JTAG_UART_ENABLED
input [`LM32_CSR_RNG] csr; // CSR to write
input csr_write_enable; // CSR write enable
input [`LM32_WORD_RNG] csr_write_data; // Data to write to specified CSR
input stall_x; // Stall instruction in X stage
`endif
`ifdef CFG_HW_DEBUG_ENABLED
input [`LM32_BYTE_RNG] jtag_read_data; // Data read from requested address
input jtag_access_complete; // Memory access if complete
`endif
`ifdef CFG_DEBUG_ENABLED
input exception_q_w; // Indicates an exception has occured in W stage
`endif
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
`ifdef CFG_JTAG_UART_ENABLED
output [`LM32_WORD_RNG] jtx_csr_read_data; // Value of JTX CSR for rcsr instructions
wire [`LM32_WORD_RNG] jtx_csr_read_data;
output [`LM32_WORD_RNG] jrx_csr_read_data; // Value of JRX CSR for rcsr instructions
wire [`LM32_WORD_RNG] jrx_csr_read_data;
`endif
`ifdef CFG_HW_DEBUG_ENABLED
output jtag_csr_write_enable; // CSR write enable
reg jtag_csr_write_enable;
output [`LM32_WORD_RNG] jtag_csr_write_data; // Data to write to specified CSR
wire [`LM32_WORD_RNG] jtag_csr_write_data;
output [`LM32_CSR_RNG] jtag_csr; // CSR to write
wire [`LM32_CSR_RNG] jtag_csr;
output jtag_read_enable; // Memory read enable
reg jtag_read_enable;
output jtag_write_enable; // Memory write enable
reg jtag_write_enable;
output [`LM32_BYTE_RNG] jtag_write_data; // Data to write to specified address
wire [`LM32_BYTE_RNG] jtag_write_data;
output [`LM32_WORD_RNG] jtag_address; // Memory read/write address
wire [`LM32_WORD_RNG] jtag_address;
`endif
`ifdef CFG_DEBUG_ENABLED
output jtag_break; // Request to raise a breakpoint exception
reg jtag_break;
output jtag_reset; // Request to raise a reset exception
reg jtag_reset;
`endif
output [`LM32_BYTE_RNG] jtag_reg_d;
reg [`LM32_BYTE_RNG] jtag_reg_d;
output [2:0] jtag_reg_addr_d;
wire [2:0] jtag_reg_addr_d;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
reg rx_toggle; // Clock-domain crossing registers
reg rx_toggle_r; // Registered version of rx_toggle
reg rx_toggle_r_r; // Registered version of rx_toggle_r
reg rx_toggle_r_r_r; // Registered version of rx_toggle_r_r
reg [`LM32_BYTE_RNG] rx_byte;
reg [2:0] rx_addr;
`ifdef CFG_JTAG_UART_ENABLED
reg [`LM32_BYTE_RNG] uart_tx_byte; // UART TX data
reg uart_tx_valid; // TX data is valid
reg [`LM32_BYTE_RNG] uart_rx_byte; // UART RX data
reg uart_rx_valid; // RX data is valid
`endif
reg [`LM32_DP_RNG] command; // The last received command
`ifdef CFG_HW_DEBUG_ENABLED
reg [`LM32_BYTE_RNG] jtag_byte_0; // Registers to hold command paramaters
reg [`LM32_BYTE_RNG] jtag_byte_1;
reg [`LM32_BYTE_RNG] jtag_byte_2;
reg [`LM32_BYTE_RNG] jtag_byte_3;
reg [`LM32_BYTE_RNG] jtag_byte_4;
reg processing; // Indicates if we're still processing a memory read/write
`endif
reg [`LM32_JTAG_STATE_RNG] state; // Current state of FSM
/////////////////////////////////////////////////////
// Combinational Logic
/////////////////////////////////////////////////////
`ifdef CFG_HW_DEBUG_ENABLED
assign jtag_csr_write_data = {jtag_byte_0, jtag_byte_1, jtag_byte_2, jtag_byte_3};
assign jtag_csr = jtag_byte_4[`LM32_CSR_RNG];
assign jtag_address = {jtag_byte_0, jtag_byte_1, jtag_byte_2, jtag_byte_3};
assign jtag_write_data = jtag_byte_4;
`endif
// Generate status flags for reading via the JTAG interface
`ifdef CFG_JTAG_UART_ENABLED
assign jtag_reg_addr_d[1:0] = {uart_rx_valid, uart_tx_valid};
`else
assign jtag_reg_addr_d[1:0] = 2'b00;
`endif
`ifdef CFG_HW_DEBUG_ENABLED
assign jtag_reg_addr_d[2] = processing;
`else
assign jtag_reg_addr_d[2] = 1'b0;
`endif
`ifdef CFG_JTAG_UART_ENABLED
assign jtx_csr_read_data = {{`LM32_WORD_WIDTH-9{1'b0}}, uart_tx_valid, 8'h00};
assign jrx_csr_read_data = {{`LM32_WORD_WIDTH-9{1'b0}}, uart_rx_valid, uart_rx_byte};
`endif
/////////////////////////////////////////////////////
// Sequential Logic
/////////////////////////////////////////////////////
// Toggle a flag when a JTAG write occurs
always @(negedge jtag_update `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
rx_toggle <= 1'b0;
else
rx_toggle <= ~rx_toggle;
end
always @(*)
begin
rx_byte = jtag_reg_q;
rx_addr = jtag_reg_addr_q;
end
// Clock domain crossing from JTAG clock domain to CPU clock domain
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
rx_toggle_r <= 1'b0;
rx_toggle_r_r <= 1'b0;
rx_toggle_r_r_r <= 1'b0;
end
else
begin
rx_toggle_r <= rx_toggle;
rx_toggle_r_r <= rx_toggle_r;
rx_toggle_r_r_r <= rx_toggle_r_r;
end
end
// LM32 debug protocol state machine
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
state <= `LM32_JTAG_STATE_READ_COMMAND;
command <= 4'b0000;
jtag_reg_d <= 8'h00;
`ifdef CFG_HW_DEBUG_ENABLED
processing <= `FALSE;
jtag_csr_write_enable <= `FALSE;
jtag_read_enable <= `FALSE;
jtag_write_enable <= `FALSE;
`endif
`ifdef CFG_DEBUG_ENABLED
jtag_break <= `FALSE;
jtag_reset <= `FALSE;
`endif
`ifdef CFG_JTAG_UART_ENABLED
uart_tx_byte <= 8'h00;
uart_tx_valid <= `FALSE;
uart_rx_byte <= 8'h00;
uart_rx_valid <= `FALSE;
`endif
end
else
begin
`ifdef CFG_JTAG_UART_ENABLED
if ((csr_write_enable == `TRUE) && (stall_x == `FALSE))
begin
case (csr)
`LM32_CSR_JTX:
begin
// Set flag indicating data is available
uart_tx_byte <= csr_write_data[`LM32_BYTE_0_RNG];
uart_tx_valid <= `TRUE;
end
`LM32_CSR_JRX:
begin
// Clear flag indidicating data has been received
uart_rx_valid <= `FALSE;
end
endcase
end
`endif
`ifdef CFG_DEBUG_ENABLED
// When an exception has occured, clear the requests
if (exception_q_w == `TRUE)
begin
jtag_break <= `FALSE;
jtag_reset <= `FALSE;
end
`endif
case (state)
`LM32_JTAG_STATE_READ_COMMAND:
begin
// Wait for rx register to toggle which indicates new data is available
if (rx_toggle_r_r != rx_toggle_r_r_r)
begin
command <= rx_byte[7:4];
case (rx_addr)
`ifdef CFG_DEBUG_ENABLED
`LM32_DP:
begin
case (rx_byte[7:4])
`ifdef CFG_HW_DEBUG_ENABLED
`LM32_DP_READ_MEMORY:
state <= `LM32_JTAG_STATE_READ_BYTE_0;
`LM32_DP_READ_SEQUENTIAL:
begin
{jtag_byte_2, jtag_byte_3} <= {jtag_byte_2, jtag_byte_3} + 1'b1;
state <= `LM32_JTAG_STATE_PROCESS_COMMAND;
end
`LM32_DP_WRITE_MEMORY:
state <= `LM32_JTAG_STATE_READ_BYTE_0;
`LM32_DP_WRITE_SEQUENTIAL:
begin
{jtag_byte_2, jtag_byte_3} <= {jtag_byte_2, jtag_byte_3} + 1'b1;
state <= 5;
end
`LM32_DP_WRITE_CSR:
state <= `LM32_JTAG_STATE_READ_BYTE_0;
`endif
`LM32_DP_BREAK:
begin
`ifdef CFG_JTAG_UART_ENABLED
uart_rx_valid <= `FALSE;
uart_tx_valid <= `FALSE;
`endif
jtag_break <= `TRUE;
end
`LM32_DP_RESET:
begin
`ifdef CFG_JTAG_UART_ENABLED
uart_rx_valid <= `FALSE;
uart_tx_valid <= `FALSE;
`endif
jtag_reset <= `TRUE;
end
endcase
end
`endif
`ifdef CFG_JTAG_UART_ENABLED
`LM32_TX:
begin
uart_rx_byte <= rx_byte;
uart_rx_valid <= `TRUE;
end
`LM32_RX:
begin
jtag_reg_d <= uart_tx_byte;
uart_tx_valid <= `FALSE;
end
`endif
default:
;
endcase
end
end
`ifdef CFG_HW_DEBUG_ENABLED
`LM32_JTAG_STATE_READ_BYTE_0:
begin
if (rx_toggle_r_r != rx_toggle_r_r_r)
begin
jtag_byte_0 <= rx_byte;
state <= `LM32_JTAG_STATE_READ_BYTE_1;
end
end
`LM32_JTAG_STATE_READ_BYTE_1:
begin
if (rx_toggle_r_r != rx_toggle_r_r_r)
begin
jtag_byte_1 <= rx_byte;
state <= `LM32_JTAG_STATE_READ_BYTE_2;
end
end
`LM32_JTAG_STATE_READ_BYTE_2:
begin
if (rx_toggle_r_r != rx_toggle_r_r_r)
begin
jtag_byte_2 <= rx_byte;
state <= `LM32_JTAG_STATE_READ_BYTE_3;
end
end
`LM32_JTAG_STATE_READ_BYTE_3:
begin
if (rx_toggle_r_r != rx_toggle_r_r_r)
begin
jtag_byte_3 <= rx_byte;
if (command == `LM32_DP_READ_MEMORY)
state <= `LM32_JTAG_STATE_PROCESS_COMMAND;
else
state <= `LM32_JTAG_STATE_READ_BYTE_4;
end
end
`LM32_JTAG_STATE_READ_BYTE_4:
begin
if (rx_toggle_r_r != rx_toggle_r_r_r)
begin
jtag_byte_4 <= rx_byte;
state <= `LM32_JTAG_STATE_PROCESS_COMMAND;
end
end
`LM32_JTAG_STATE_PROCESS_COMMAND:
begin
case (command)
`LM32_DP_READ_MEMORY,
`LM32_DP_READ_SEQUENTIAL:
begin
jtag_read_enable <= `TRUE;
processing <= `TRUE;
state <= `LM32_JTAG_STATE_WAIT_FOR_MEMORY;
end
`LM32_DP_WRITE_MEMORY,
`LM32_DP_WRITE_SEQUENTIAL:
begin
jtag_write_enable <= `TRUE;
processing <= `TRUE;
state <= `LM32_JTAG_STATE_WAIT_FOR_MEMORY;
end
`LM32_DP_WRITE_CSR:
begin
jtag_csr_write_enable <= `TRUE;
processing <= `TRUE;
state <= `LM32_JTAG_STATE_WAIT_FOR_CSR;
end
endcase
end
`LM32_JTAG_STATE_WAIT_FOR_MEMORY:
begin
if (jtag_access_complete == `TRUE)
begin
jtag_read_enable <= `FALSE;
jtag_reg_d <= jtag_read_data;
jtag_write_enable <= `FALSE;
processing <= `FALSE;
state <= `LM32_JTAG_STATE_READ_COMMAND;
end
end
`LM32_JTAG_STATE_WAIT_FOR_CSR:
begin
jtag_csr_write_enable <= `FALSE;
processing <= `FALSE;
state <= `LM32_JTAG_STATE_READ_COMMAND;
end
`endif
endcase
end
end
endmodule
`endif
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_load_store_unit.v
// Title : Load and store unit
// Dependencies : lm32_include.v
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : Instead of disallowing an instruction cache miss on a data cache
// : miss, both can now occur at the same time. If both occur at same
// : time, then restart address is the address of instruction that
// : caused data cache miss.
// Version : 3.2
// : EBRs use SYNC resets instead of ASYNC resets.
// Version : 3.3
// : Support for new non-cacheable Data Memory that is accessible by
// : the data port and has a one cycle access latency.
// Version : 3.4
// : No change
// Version : 3.5
// : Bug fix: Inline memory is correctly generated if it is not a
// : power-of-two
// =============================================================================
`include "lm32_include.v"
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_load_store_unit (
// ----- Inputs -------
clk_i,
rst_i,
// From pipeline
stall_a,
stall_x,
stall_m,
kill_x,
kill_m,
exception_m,
store_operand_x,
load_store_address_x,
load_store_address_m,
load_store_address_w,
load_x,
store_x,
load_q_x,
store_q_x,
load_q_m,
store_q_m,
sign_extend_x,
size_x,
`ifdef CFG_DCACHE_ENABLED
dflush,
`endif
`ifdef CFG_IROM_ENABLED
irom_data_m,
`endif
// From Wishbone
d_dat_i,
d_ack_i,
d_err_i,
d_rty_i,
// ----- Outputs -------
// To pipeline
`ifdef CFG_DCACHE_ENABLED
dcache_refill_request,
dcache_restart_request,
dcache_stall_request,
dcache_refilling,
`endif
`ifdef CFG_IROM_ENABLED
irom_store_data_m,
irom_address_xm,
irom_we_xm,
irom_stall_request_x,
`endif
load_data_w,
stall_wb_load,
// To Wishbone
d_dat_o,
d_adr_o,
d_cyc_o,
d_sel_o,
d_stb_o,
d_we_o,
d_cti_o,
d_lock_o,
d_bte_o
);
/////////////////////////////////////////////////////
// Parameters
/////////////////////////////////////////////////////
parameter associativity = 1; // Associativity of the cache (Number of ways)
parameter sets = 512; // Number of sets
parameter bytes_per_line = 16; // Number of bytes per cache line
parameter base_address = 0; // Base address of cachable memory
parameter limit = 0; // Limit (highest address) of cachable memory
// For bytes_per_line == 4, we set 1 so part-select range isn't reversed, even though not really used
localparam addr_offset_width = bytes_per_line == 4 ? 1 : clogb2(bytes_per_line)-1-2;
localparam addr_offset_lsb = 2;
localparam addr_offset_msb = (addr_offset_lsb+addr_offset_width-1);
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input clk_i; // Clock
input rst_i; // Reset
input stall_a; // A stage stall
input stall_x; // X stage stall
input stall_m; // M stage stall
input kill_x; // Kill instruction in X stage
input kill_m; // Kill instruction in M stage
input exception_m; // An exception occured in the M stage
input [`LM32_WORD_RNG] store_operand_x; // Data read from register to store
input [`LM32_WORD_RNG] load_store_address_x; // X stage load/store address
input [`LM32_WORD_RNG] load_store_address_m; // M stage load/store address
input [1:0] load_store_address_w; // W stage load/store address (only least two significant bits are needed)
input load_x; // Load instruction in X stage
input store_x; // Store instruction in X stage
input load_q_x; // Load instruction in X stage
input store_q_x; // Store instruction in X stage
input load_q_m; // Load instruction in M stage
input store_q_m; // Store instruction in M stage
input sign_extend_x; // Whether load instruction in X stage should sign extend or zero extend
input [`LM32_SIZE_RNG] size_x; // Size of load or store (byte, hword, word)
`ifdef CFG_DCACHE_ENABLED
input dflush; // Flush the data cache
`endif
`ifdef CFG_IROM_ENABLED
input [`LM32_WORD_RNG] irom_data_m; // Data from Instruction-ROM
`endif
input [`LM32_WORD_RNG] d_dat_i; // Data Wishbone interface read data
input d_ack_i; // Data Wishbone interface acknowledgement
input d_err_i; // Data Wishbone interface error
input d_rty_i; // Data Wishbone interface retry
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
`ifdef CFG_DCACHE_ENABLED
output dcache_refill_request; // Request to refill data cache
wire dcache_refill_request;
output dcache_restart_request; // Request to restart the instruction that caused a data cache miss
wire dcache_restart_request;
output dcache_stall_request; // Data cache stall request
wire dcache_stall_request;
output dcache_refilling;
wire dcache_refilling;
`endif
`ifdef CFG_IROM_ENABLED
output irom_store_data_m; // Store data to Instruction ROM
wire [`LM32_WORD_RNG] irom_store_data_m;
output [`LM32_WORD_RNG] irom_address_xm; // Load/store address to Instruction ROM
wire [`LM32_WORD_RNG] irom_address_xm;
output irom_we_xm; // Write-enable of 2nd port of Instruction ROM
wire irom_we_xm;
output irom_stall_request_x; // Stall instruction in D stage
wire irom_stall_request_x;
`endif
output [`LM32_WORD_RNG] load_data_w; // Result of a load instruction
reg [`LM32_WORD_RNG] load_data_w;
output stall_wb_load; // Request to stall pipeline due to a load from the Wishbone interface
reg stall_wb_load;
output [`LM32_WORD_RNG] d_dat_o; // Data Wishbone interface write data
reg [`LM32_WORD_RNG] d_dat_o;
output [`LM32_WORD_RNG] d_adr_o; // Data Wishbone interface address
reg [`LM32_WORD_RNG] d_adr_o;
output d_cyc_o; // Data Wishbone interface cycle
reg d_cyc_o;
output [`LM32_BYTE_SELECT_RNG] d_sel_o; // Data Wishbone interface byte select
reg [`LM32_BYTE_SELECT_RNG] d_sel_o;
output d_stb_o; // Data Wishbone interface strobe
reg d_stb_o;
output d_we_o; // Data Wishbone interface write enable
reg d_we_o;
output [`LM32_CTYPE_RNG] d_cti_o; // Data Wishbone interface cycle type
reg [`LM32_CTYPE_RNG] d_cti_o;
output d_lock_o; // Date Wishbone interface lock bus
reg d_lock_o;
output [`LM32_BTYPE_RNG] d_bte_o; // Data Wishbone interface burst type
wire [`LM32_BTYPE_RNG] d_bte_o;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
// Microcode pipeline registers - See inputs for description
reg [`LM32_SIZE_RNG] size_m;
reg [`LM32_SIZE_RNG] size_w;
reg sign_extend_m;
reg sign_extend_w;
reg [`LM32_WORD_RNG] store_data_x;
reg [`LM32_WORD_RNG] store_data_m;
reg [`LM32_BYTE_SELECT_RNG] byte_enable_x;
reg [`LM32_BYTE_SELECT_RNG] byte_enable_m;
wire [`LM32_WORD_RNG] data_m;
reg [`LM32_WORD_RNG] data_w;
`ifdef CFG_DCACHE_ENABLED
wire dcache_select_x; // Select data cache to load from / store to
reg dcache_select_m;
wire [`LM32_WORD_RNG] dcache_data_m; // Data read from cache
wire [`LM32_WORD_RNG] dcache_refill_address; // Address to refill data cache from
reg dcache_refill_ready; // Indicates the next word of refill data is ready
wire [`LM32_CTYPE_RNG] first_cycle_type; // First Wishbone cycle type
wire [`LM32_CTYPE_RNG] next_cycle_type; // Next Wishbone cycle type
wire last_word; // Indicates if this is the last word in the cache line
wire [`LM32_WORD_RNG] first_address; // First cache refill address
`endif
`ifdef CFG_DRAM_ENABLED
wire dram_select_x; // Select data RAM to load from / store to
reg dram_select_m;
reg dram_bypass_en; // RAW in data RAM; read latched (bypass) value rather than value from memory
reg [`LM32_WORD_RNG] dram_bypass_data; // Latched value of store'd data to data RAM
wire [`LM32_WORD_RNG] dram_data_out; // Data read from data RAM
wire [`LM32_WORD_RNG] dram_data_m; // Data read from data RAM: bypass value or value from memory
wire [`LM32_WORD_RNG] dram_store_data_m; // Data to write to RAM
`endif
wire wb_select_x; // Select Wishbone to load from / store to
`ifdef CFG_IROM_ENABLED
wire irom_select_x; // Select instruction ROM to load from / store to
reg irom_select_m;
`endif
reg wb_select_m;
reg [`LM32_WORD_RNG] wb_data_m; // Data read from Wishbone
reg wb_load_complete; // Indicates when a Wishbone load is complete
/////////////////////////////////////////////////////
// Functions
/////////////////////////////////////////////////////
`include "lm32_functions.v"
/////////////////////////////////////////////////////
// Instantiations
/////////////////////////////////////////////////////
`ifdef CFG_DRAM_ENABLED
// Data RAM
pmi_ram_dp_true
#(
// ----- Parameters -------
.pmi_family (`LATTICE_FAMILY),
//.pmi_addr_depth_a (1 << (clogb2(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)-1)),
//.pmi_addr_width_a ((clogb2(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)-1)),
//.pmi_data_width_a (`LM32_WORD_WIDTH),
//.pmi_addr_depth_b (1 << (clogb2(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)-1)),
//.pmi_addr_width_b ((clogb2(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)-1)),
//.pmi_data_width_b (`LM32_WORD_WIDTH),
.pmi_addr_depth_a (`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1),
.pmi_addr_width_a (clogb2_v1(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)),
.pmi_data_width_a (`LM32_WORD_WIDTH),
.pmi_addr_depth_b (`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1),
.pmi_addr_width_b (clogb2_v1(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)),
.pmi_data_width_b (`LM32_WORD_WIDTH),
.pmi_regmode_a ("noreg"),
.pmi_regmode_b ("noreg"),
.pmi_gsr ("enable"),
.pmi_resetmode ("sync"),
.pmi_init_file (`CFG_DRAM_INIT_FILE),
.pmi_init_file_format (`CFG_DRAM_INIT_FILE_FORMAT),
.module_type ("pmi_ram_dp_true")
)
ram (
// ----- Inputs -------
.ClockA (clk_i),
.ClockB (clk_i),
.ResetA (rst_i),
.ResetB (rst_i),
.DataInA ({32{1'b0}}),
.DataInB (dram_store_data_m),
.AddressA (load_store_address_x[(clogb2(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)-1)+2-1:2]),
.AddressB (load_store_address_m[(clogb2(`CFG_DRAM_LIMIT/4-`CFG_DRAM_BASE_ADDRESS/4+1)-1)+2-1:2]),
// .ClockEnA (!stall_x & (load_x | store_x)),
.ClockEnA (!stall_x),
.ClockEnB (!stall_m),
.WrA (`FALSE),
.WrB (store_q_m & dram_select_m),
// ----- Outputs -------
.QA (dram_data_out),
.QB ()
);
/*----------------------------------------------------------------------
EBRs cannot perform reads from location 'written to' on the same clock
edge. Therefore bypass logic is required to latch the store'd value
and use it for the load (instead of value from memory).
----------------------------------------------------------------------*/
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
if (rst_i == `TRUE)
begin
dram_bypass_en <= `FALSE;
dram_bypass_data <= 0;
end
else
begin
if (stall_x == `FALSE)
dram_bypass_data <= dram_store_data_m;
if ( (stall_m == `FALSE)
&& (stall_x == `FALSE)
&& (store_q_m == `TRUE)
&& ( (load_x == `TRUE)
|| (store_x == `TRUE)
)
&& (load_store_address_x[(`LM32_WORD_WIDTH-1):2] == load_store_address_m[(`LM32_WORD_WIDTH-1):2])
)
dram_bypass_en <= `TRUE;
else
if ( (dram_bypass_en == `TRUE)
&& (stall_x == `FALSE)
)
dram_bypass_en <= `FALSE;
end
assign dram_data_m = dram_bypass_en ? dram_bypass_data : dram_data_out;
`endif
`ifdef CFG_DCACHE_ENABLED
// Data cache
lm32_dcache #(
.associativity (associativity),
.sets (sets),
.bytes_per_line (bytes_per_line),
.base_address (base_address),
.limit (limit)
) dcache (
// ----- Inputs -----
.clk_i (clk_i),
.rst_i (rst_i),
.stall_a (stall_a),
.stall_x (stall_x),
.stall_m (stall_m),
.address_x (load_store_address_x),
.address_m (load_store_address_m),
.load_q_m (load_q_m & dcache_select_m),
.store_q_m (store_q_m & dcache_select_m),
.store_data (store_data_m),
.store_byte_select (byte_enable_m & {4{dcache_select_m}}),
.refill_ready (dcache_refill_ready),
.refill_data (wb_data_m),
.dflush (dflush),
// ----- Outputs -----
.stall_request (dcache_stall_request),
.restart_request (dcache_restart_request),
.refill_request (dcache_refill_request),
.refill_address (dcache_refill_address),
.refilling (dcache_refilling),
.load_data (dcache_data_m)
);
`endif
/////////////////////////////////////////////////////
// Combinational Logic
/////////////////////////////////////////////////////
// Select where data should be loaded from / stored to
`ifdef CFG_DRAM_ENABLED
assign dram_select_x = (load_store_address_x >= `CFG_DRAM_BASE_ADDRESS)
&& (load_store_address_x <= `CFG_DRAM_LIMIT);
`endif
`ifdef CFG_IROM_ENABLED
assign irom_select_x = (load_store_address_x >= `CFG_IROM_BASE_ADDRESS)
&& (load_store_address_x <= `CFG_IROM_LIMIT);
`endif
`ifdef CFG_DCACHE_ENABLED
assign dcache_select_x = (load_store_address_x >= `CFG_DCACHE_BASE_ADDRESS)
&& (load_store_address_x <= `CFG_DCACHE_LIMIT)
`ifdef CFG_DRAM_ENABLED
&& (dram_select_x == `FALSE)
`endif
`ifdef CFG_IROM_ENABLED
&& (irom_select_x == `FALSE)
`endif
;
`endif
assign wb_select_x = `TRUE
`ifdef CFG_DCACHE_ENABLED
&& !dcache_select_x
`endif
`ifdef CFG_DRAM_ENABLED
&& !dram_select_x
`endif
`ifdef CFG_IROM_ENABLED
&& !irom_select_x
`endif
;
// Make sure data to store is in correct byte lane
always @(*)
begin
case (size_x)
`LM32_SIZE_BYTE: store_data_x = {4{store_operand_x[7:0]}};
`LM32_SIZE_HWORD: store_data_x = {2{store_operand_x[15:0]}};
`LM32_SIZE_WORD: store_data_x = store_operand_x;
default: store_data_x = {`LM32_WORD_WIDTH{1'bx}};
endcase
end
// Generate byte enable accoring to size of load or store and address being accessed
always @(*)
begin
casez ({size_x, load_store_address_x[1:0]})
{`LM32_SIZE_BYTE, 2'b11}: byte_enable_x = 4'b0001;
{`LM32_SIZE_BYTE, 2'b10}: byte_enable_x = 4'b0010;
{`LM32_SIZE_BYTE, 2'b01}: byte_enable_x = 4'b0100;
{`LM32_SIZE_BYTE, 2'b00}: byte_enable_x = 4'b1000;
{`LM32_SIZE_HWORD, 2'b1?}: byte_enable_x = 4'b0011;
{`LM32_SIZE_HWORD, 2'b0?}: byte_enable_x = 4'b1100;
{`LM32_SIZE_WORD, 2'b??}: byte_enable_x = 4'b1111;
default: byte_enable_x = 4'bxxxx;
endcase
end
`ifdef CFG_DRAM_ENABLED
// Only replace selected bytes
assign dram_store_data_m[`LM32_BYTE_0_RNG] = byte_enable_m[0] ? store_data_m[`LM32_BYTE_0_RNG] : dram_data_m[`LM32_BYTE_0_RNG];
assign dram_store_data_m[`LM32_BYTE_1_RNG] = byte_enable_m[1] ? store_data_m[`LM32_BYTE_1_RNG] : dram_data_m[`LM32_BYTE_1_RNG];
assign dram_store_data_m[`LM32_BYTE_2_RNG] = byte_enable_m[2] ? store_data_m[`LM32_BYTE_2_RNG] : dram_data_m[`LM32_BYTE_2_RNG];
assign dram_store_data_m[`LM32_BYTE_3_RNG] = byte_enable_m[3] ? store_data_m[`LM32_BYTE_3_RNG] : dram_data_m[`LM32_BYTE_3_RNG];
`endif
`ifdef CFG_IROM_ENABLED
// Only replace selected bytes
assign irom_store_data_m[`LM32_BYTE_0_RNG] = byte_enable_m[0] ? store_data_m[`LM32_BYTE_0_RNG] : irom_data_m[`LM32_BYTE_0_RNG];
assign irom_store_data_m[`LM32_BYTE_1_RNG] = byte_enable_m[1] ? store_data_m[`LM32_BYTE_1_RNG] : irom_data_m[`LM32_BYTE_1_RNG];
assign irom_store_data_m[`LM32_BYTE_2_RNG] = byte_enable_m[2] ? store_data_m[`LM32_BYTE_2_RNG] : irom_data_m[`LM32_BYTE_2_RNG];
assign irom_store_data_m[`LM32_BYTE_3_RNG] = byte_enable_m[3] ? store_data_m[`LM32_BYTE_3_RNG] : irom_data_m[`LM32_BYTE_3_RNG];
`endif
`ifdef CFG_IROM_ENABLED
// Instead of implementing a byte-addressable instruction ROM (for store byte instruction),
// a load-and-store architecture is used wherein a 32-bit value is loaded, the requisite
// byte is replaced, and the whole 32-bit value is written back
assign irom_address_xm = ((irom_select_m == `TRUE) && (store_q_m == `TRUE))
? load_store_address_m
: load_store_address_x;
// All store instructions perform a write operation in the M stage
assign irom_we_xm = (irom_select_m == `TRUE)
&& (store_q_m == `TRUE);
// A single port in instruction ROM is available to load-store unit for doing loads/stores.
// Since every store requires a load (in X stage) and then a store (in M stage), we cannot
// allow load (or store) instructions sequentially after the store instructions to proceed
// until the store instruction has vacated M stage (i.e., completed the store operation)
assign irom_stall_request_x = (irom_select_x == `TRUE)
&& (store_q_x == `TRUE);
`endif
`ifdef CFG_DCACHE_ENABLED
`ifdef CFG_DRAM_ENABLED
`ifdef CFG_IROM_ENABLED
// WB + DC + DRAM + IROM
assign data_m = wb_select_m == `TRUE
? wb_data_m
: dram_select_m == `TRUE
? dram_data_m
: irom_select_m == `TRUE
? irom_data_m
: dcache_data_m;
`else
// WB + DC + DRAM
assign data_m = wb_select_m == `TRUE
? wb_data_m
: dram_select_m == `TRUE
? dram_data_m
: dcache_data_m;
`endif
`else
`ifdef CFG_IROM_ENABLED
// WB + DC + IROM
assign data_m = wb_select_m == `TRUE
? wb_data_m
: irom_select_m == `TRUE
? irom_data_m
: dcache_data_m;
`else
// WB + DC
assign data_m = wb_select_m == `TRUE
? wb_data_m
: dcache_data_m;
`endif
`endif
`else
`ifdef CFG_DRAM_ENABLED
`ifdef CFG_IROM_ENABLED
// WB + DRAM + IROM
assign data_m = wb_select_m == `TRUE
? wb_data_m
: dram_select_m == `TRUE
? dram_data_m
: irom_data_m;
`else
// WB + DRAM
assign data_m = wb_select_m == `TRUE
? wb_data_m
: dram_data_m;
`endif
`else
`ifdef CFG_IROM_ENABLED
// WB + IROM
assign data_m = wb_select_m == `TRUE
? wb_data_m
: irom_data_m;
`else
// WB
assign data_m = wb_data_m;
`endif
`endif
`endif
// Sub-word selection and sign/zero-extension for loads
always @(*)
begin
casez ({size_w, load_store_address_w[1:0]})
{`LM32_SIZE_BYTE, 2'b11}: load_data_w = {{24{sign_extend_w & data_w[7]}}, data_w[7:0]};
{`LM32_SIZE_BYTE, 2'b10}: load_data_w = {{24{sign_extend_w & data_w[15]}}, data_w[15:8]};
{`LM32_SIZE_BYTE, 2'b01}: load_data_w = {{24{sign_extend_w & data_w[23]}}, data_w[23:16]};
{`LM32_SIZE_BYTE, 2'b00}: load_data_w = {{24{sign_extend_w & data_w[31]}}, data_w[31:24]};
{`LM32_SIZE_HWORD, 2'b1?}: load_data_w = {{16{sign_extend_w & data_w[15]}}, data_w[15:0]};
{`LM32_SIZE_HWORD, 2'b0?}: load_data_w = {{16{sign_extend_w & data_w[31]}}, data_w[31:16]};
{`LM32_SIZE_WORD, 2'b??}: load_data_w = data_w;
default: load_data_w = {`LM32_WORD_WIDTH{1'bx}};
endcase
end
// Unused/constant Wishbone signals
assign d_bte_o = `LM32_BTYPE_LINEAR;
`ifdef CFG_DCACHE_ENABLED
// Generate signal to indicate last word in cache line
generate
case (bytes_per_line)
4:
begin
assign first_cycle_type = `LM32_CTYPE_END;
assign next_cycle_type = `LM32_CTYPE_END;
assign last_word = `TRUE;
assign first_address = {dcache_refill_address[`LM32_WORD_WIDTH-1:2], 2'b00};
end
8:
begin
assign first_cycle_type = `LM32_CTYPE_INCREMENTING;
assign next_cycle_type = `LM32_CTYPE_END;
assign last_word = (&d_adr_o[addr_offset_msb:addr_offset_lsb]) == 1'b1;
assign first_address = {dcache_refill_address[`LM32_WORD_WIDTH-1:addr_offset_msb+1], {addr_offset_width{1'b0}}, 2'b00};
end
16:
begin
assign first_cycle_type = `LM32_CTYPE_INCREMENTING;
assign next_cycle_type = d_adr_o[addr_offset_msb] == 1'b1 ? `LM32_CTYPE_END : `LM32_CTYPE_INCREMENTING;
assign last_word = (&d_adr_o[addr_offset_msb:addr_offset_lsb]) == 1'b1;
assign first_address = {dcache_refill_address[`LM32_WORD_WIDTH-1:addr_offset_msb+1], {addr_offset_width{1'b0}}, 2'b00};
end
endcase
endgenerate
`endif
/////////////////////////////////////////////////////
// Sequential Logic
/////////////////////////////////////////////////////
// Data Wishbone interface
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
d_cyc_o <= `FALSE;
d_stb_o <= `FALSE;
d_dat_o <= {`LM32_WORD_WIDTH{1'b0}};
d_adr_o <= {`LM32_WORD_WIDTH{1'b0}};
d_sel_o <= {`LM32_BYTE_SELECT_WIDTH{`FALSE}};
d_we_o <= `FALSE;
d_cti_o <= `LM32_CTYPE_END;
d_lock_o <= `FALSE;
wb_data_m <= {`LM32_WORD_WIDTH{1'b0}};
wb_load_complete <= `FALSE;
stall_wb_load <= `FALSE;
`ifdef CFG_DCACHE_ENABLED
dcache_refill_ready <= `FALSE;
`endif
end
else
begin
`ifdef CFG_DCACHE_ENABLED
// Refill ready should only be asserted for a single cycle
dcache_refill_ready <= `FALSE;
`endif
// Is a Wishbone cycle already in progress?
if (d_cyc_o == `TRUE)
begin
// Is the cycle complete?
if ((d_ack_i == `TRUE) || (d_err_i == `TRUE))
begin
`ifdef CFG_DCACHE_ENABLED
if ((dcache_refilling == `TRUE) && (!last_word))
begin
// Fetch next word of cache line
d_adr_o[addr_offset_msb:addr_offset_lsb] <= d_adr_o[addr_offset_msb:addr_offset_lsb] + 1'b1;
end
else
`endif
begin
// Refill/access complete
d_cyc_o <= `FALSE;
d_stb_o <= `FALSE;
d_lock_o <= `FALSE;
end
`ifdef CFG_DCACHE_ENABLED
d_cti_o <= next_cycle_type;
// If we are performing a refill, indicate to cache next word of data is ready
dcache_refill_ready <= dcache_refilling;
`endif
// Register data read from Wishbone interface
wb_data_m <= d_dat_i;
// Don't set when stores complete - otherwise we'll deadlock if load in m stage
wb_load_complete <= !d_we_o;
end
// synthesis translate_off
if (d_err_i == `TRUE)
$display ("Data bus error. Address: %x", d_adr_o);
// synthesis translate_on
end
else
begin
`ifdef CFG_DCACHE_ENABLED
if (dcache_refill_request == `TRUE)
begin
// Start cache refill
d_adr_o <= first_address;
d_cyc_o <= `TRUE;
d_sel_o <= {`LM32_WORD_WIDTH/8{`TRUE}};
d_stb_o <= `TRUE;
d_we_o <= `FALSE;
d_cti_o <= first_cycle_type;
//d_lock_o <= `TRUE;
end
else
`endif
if ( (store_q_m == `TRUE)
&& (stall_m == `FALSE)
`ifdef CFG_DRAM_ENABLED
&& (dram_select_m == `FALSE)
`endif
`ifdef CFG_IROM_ENABLED
&& (irom_select_m == `FALSE)
`endif
)
begin
// Data cache is write through, so all stores go to memory
d_dat_o <= store_data_m;
d_adr_o <= load_store_address_m;
d_cyc_o <= `TRUE;
d_sel_o <= byte_enable_m;
d_stb_o <= `TRUE;
d_we_o <= `TRUE;
d_cti_o <= `LM32_CTYPE_END;
end
else if ( (load_q_m == `TRUE)
&& (wb_select_m == `TRUE)
&& (wb_load_complete == `FALSE)
// stall_m will be TRUE, because stall_wb_load will be TRUE
)
begin
// Read requested address
stall_wb_load <= `FALSE;
d_adr_o <= load_store_address_m;
d_cyc_o <= `TRUE;
d_sel_o <= byte_enable_m;
d_stb_o <= `TRUE;
d_we_o <= `FALSE;
d_cti_o <= `LM32_CTYPE_END;
end
end
// Clear load/store complete flag when instruction leaves M stage
if (stall_m == `FALSE)
wb_load_complete <= `FALSE;
// When a Wishbone load first enters the M stage, we need to stall it
if ((load_q_x == `TRUE) && (wb_select_x == `TRUE) && (stall_x == `FALSE))
stall_wb_load <= `TRUE;
// Clear stall request if load instruction is killed
if ((kill_m == `TRUE) || (exception_m == `TRUE))
stall_wb_load <= `FALSE;
end
end
// Pipeline registers
// X/M stage pipeline registers
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
sign_extend_m <= `FALSE;
size_m <= 2'b00;
byte_enable_m <= `FALSE;
store_data_m <= {`LM32_WORD_WIDTH{1'b0}};
`ifdef CFG_DCACHE_ENABLED
dcache_select_m <= `FALSE;
`endif
`ifdef CFG_DRAM_ENABLED
dram_select_m <= `FALSE;
`endif
`ifdef CFG_IROM_ENABLED
irom_select_m <= `FALSE;
`endif
wb_select_m <= `FALSE;
end
else
begin
if (stall_m == `FALSE)
begin
sign_extend_m <= sign_extend_x;
size_m <= size_x;
byte_enable_m <= byte_enable_x;
store_data_m <= store_data_x;
`ifdef CFG_DCACHE_ENABLED
dcache_select_m <= dcache_select_x;
`endif
`ifdef CFG_DRAM_ENABLED
dram_select_m <= dram_select_x;
`endif
`ifdef CFG_IROM_ENABLED
irom_select_m <= irom_select_x;
`endif
wb_select_m <= wb_select_x;
end
end
end
// M/W stage pipeline registers
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
size_w <= 2'b00;
data_w <= {`LM32_WORD_WIDTH{1'b0}};
sign_extend_w <= `FALSE;
end
else
begin
size_w <= size_m;
data_w <= data_m;
sign_extend_w <= sign_extend_m;
end
end
/////////////////////////////////////////////////////
// Behavioural Logic
/////////////////////////////////////////////////////
// synthesis translate_off
// Check for non-aligned loads or stores
always @(posedge clk_i)
begin
if (((load_q_m == `TRUE) || (store_q_m == `TRUE)) && (stall_m == `FALSE))
begin
if ((size_m === `LM32_SIZE_HWORD) && (load_store_address_m[0] !== 1'b0))
$display ("Warning: Non-aligned halfword access. Address: 0x%0x Time: %0t.", load_store_address_m, $time);
if ((size_m === `LM32_SIZE_WORD) && (load_store_address_m[1:0] !== 2'b00))
$display ("Warning: Non-aligned word access. Address: 0x%0x Time: %0t.", load_store_address_m, $time);
end
end
// synthesis translate_on
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_logic_op.v
// Title : Logic operations (and / or / not etc)
// Dependencies : lm32_include.v
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
`include "lm32_include.v"
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_logic_op (
// ----- Inputs -------
logic_op_x,
operand_0_x,
operand_1_x,
// ----- Outputs -------
logic_result_x
);
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input [`LM32_LOGIC_OP_RNG] logic_op_x;
input [`LM32_WORD_RNG] operand_0_x;
input [`LM32_WORD_RNG] operand_1_x;
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
output [`LM32_WORD_RNG] logic_result_x;
reg [`LM32_WORD_RNG] logic_result_x;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
integer logic_idx;
/////////////////////////////////////////////////////
// Combinational Logic
/////////////////////////////////////////////////////
always @(*)
begin
for(logic_idx = 0; logic_idx < `LM32_WORD_WIDTH; logic_idx = logic_idx + 1)
logic_result_x[logic_idx] = logic_op_x[{operand_1_x[logic_idx], operand_0_x[logic_idx]}];
end
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm_mc_arithmetic.v
// Title : Multi-cycle arithmetic unit.
// Dependencies : lm32_include.v
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
`include "lm32_include.v"
`define LM32_MC_STATE_RNG 2:0
`define LM32_MC_STATE_IDLE 3'b000
`define LM32_MC_STATE_MULTIPLY 3'b001
`define LM32_MC_STATE_MODULUS 3'b010
`define LM32_MC_STATE_DIVIDE 3'b011
`define LM32_MC_STATE_SHIFT_LEFT 3'b100
`define LM32_MC_STATE_SHIFT_RIGHT 3'b101
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_mc_arithmetic (
// ----- Inputs -----
clk_i,
rst_i,
stall_d,
kill_x,
`ifdef CFG_MC_DIVIDE_ENABLED
divide_d,
modulus_d,
`endif
`ifdef CFG_MC_MULTIPLY_ENABLED
multiply_d,
`endif
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
shift_left_d,
shift_right_d,
sign_extend_d,
`endif
operand_0_d,
operand_1_d,
// ----- Ouputs -----
result_x,
`ifdef CFG_MC_DIVIDE_ENABLED
divide_by_zero_x,
`endif
stall_request_x
);
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input clk_i; // Clock
input rst_i; // Reset
input stall_d; // Stall instruction in D stage
input kill_x; // Kill instruction in X stage
`ifdef CFG_MC_DIVIDE_ENABLED
input divide_d; // Perform divide
input modulus_d; // Perform modulus
`endif
`ifdef CFG_MC_MULTIPLY_ENABLED
input multiply_d; // Perform multiply
`endif
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
input shift_left_d; // Perform left shift
input shift_right_d; // Perform right shift
input sign_extend_d; // Whether to sign-extend (arithmetic) or zero-extend (logical)
`endif
input [`LM32_WORD_RNG] operand_0_d;
input [`LM32_WORD_RNG] operand_1_d;
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
output [`LM32_WORD_RNG] result_x; // Result of operation
reg [`LM32_WORD_RNG] result_x;
`ifdef CFG_MC_DIVIDE_ENABLED
output divide_by_zero_x; // A divide by zero was attempted
reg divide_by_zero_x;
`endif
output stall_request_x; // Request to stall pipeline from X stage back
wire stall_request_x;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
reg [`LM32_WORD_RNG] p; // Temporary registers
reg [`LM32_WORD_RNG] a;
reg [`LM32_WORD_RNG] b;
`ifdef CFG_MC_DIVIDE_ENABLED
wire [32:0] t;
`endif
reg [`LM32_MC_STATE_RNG] state; // Current state of FSM
reg [5:0] cycles; // Number of cycles remaining in the operation
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
reg sign_extend_x; // Whether to sign extend of zero extend right shifts
wire fill_value; // Value to fill with for right barrel-shifts
`endif
/////////////////////////////////////////////////////
// Combinational logic
/////////////////////////////////////////////////////
// Stall pipeline while any operation is being performed
assign stall_request_x = state != `LM32_MC_STATE_IDLE;
`ifdef CFG_MC_DIVIDE_ENABLED
// Subtraction
assign t = {p[`LM32_WORD_WIDTH-2:0], a[`LM32_WORD_WIDTH-1]} - b;
`endif
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
// Determine fill value for right shift - Sign bit for arithmetic shift, or zero for logical shift
assign fill_value = (sign_extend_x == `TRUE) & b[`LM32_WORD_WIDTH-1];
`endif
/////////////////////////////////////////////////////
// Sequential logic
/////////////////////////////////////////////////////
// Perform right shift
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
cycles <= {6{1'b0}};
p <= {`LM32_WORD_WIDTH{1'b0}};
a <= {`LM32_WORD_WIDTH{1'b0}};
b <= {`LM32_WORD_WIDTH{1'b0}};
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
sign_extend_x <= 1'b0;
`endif
`ifdef CFG_MC_DIVIDE_ENABLED
divide_by_zero_x <= `FALSE;
`endif
result_x <= {`LM32_WORD_WIDTH{1'b0}};
state <= `LM32_MC_STATE_IDLE;
end
else
begin
`ifdef CFG_MC_DIVIDE_ENABLED
divide_by_zero_x <= `FALSE;
`endif
case (state)
`LM32_MC_STATE_IDLE:
begin
if (stall_d == `FALSE)
begin
cycles <= `LM32_WORD_WIDTH;
p <= 32'b0;
a <= operand_0_d;
b <= operand_1_d;
`ifdef CFG_MC_DIVIDE_ENABLED
if (divide_d == `TRUE)
state <= `LM32_MC_STATE_DIVIDE;
if (modulus_d == `TRUE)
state <= `LM32_MC_STATE_MODULUS;
`endif
`ifdef CFG_MC_MULTIPLY_ENABLED
if (multiply_d == `TRUE)
state <= `LM32_MC_STATE_MULTIPLY;
`endif
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
if (shift_left_d == `TRUE)
begin
state <= `LM32_MC_STATE_SHIFT_LEFT;
sign_extend_x <= sign_extend_d;
cycles <= operand_1_d[4:0];
a <= operand_0_d;
b <= operand_0_d;
end
if (shift_right_d == `TRUE)
begin
state <= `LM32_MC_STATE_SHIFT_RIGHT;
sign_extend_x <= sign_extend_d;
cycles <= operand_1_d[4:0];
a <= operand_0_d;
b <= operand_0_d;
end
`endif
end
end
`ifdef CFG_MC_DIVIDE_ENABLED
`LM32_MC_STATE_DIVIDE:
begin
if (t[32] == 1'b0)
begin
p <= t[31:0];
a <= {a[`LM32_WORD_WIDTH-2:0], 1'b1};
end
else
begin
p <= {p[`LM32_WORD_WIDTH-2:0], a[`LM32_WORD_WIDTH-1]};
a <= {a[`LM32_WORD_WIDTH-2:0], 1'b0};
end
result_x <= a;
if ((cycles == `LM32_WORD_WIDTH'd0) || (kill_x == `TRUE))
begin
// Check for divide by zero
divide_by_zero_x <= b == {`LM32_WORD_WIDTH{1'b0}};
state <= `LM32_MC_STATE_IDLE;
end
cycles <= cycles - 1'b1;
end
`LM32_MC_STATE_MODULUS:
begin
if (t[32] == 1'b0)
begin
p <= t[31:0];
a <= {a[`LM32_WORD_WIDTH-2:0], 1'b1};
end
else
begin
p <= {p[`LM32_WORD_WIDTH-2:0], a[`LM32_WORD_WIDTH-1]};
a <= {a[`LM32_WORD_WIDTH-2:0], 1'b0};
end
result_x <= p;
if ((cycles == `LM32_WORD_WIDTH'd0) || (kill_x == `TRUE))
begin
// Check for divide by zero
divide_by_zero_x <= b == {`LM32_WORD_WIDTH{1'b0}};
state <= `LM32_MC_STATE_IDLE;
end
cycles <= cycles - 1'b1;
end
`endif
`ifdef CFG_MC_MULTIPLY_ENABLED
`LM32_MC_STATE_MULTIPLY:
begin
if (b[0] == 1'b1)
p <= p + a;
b <= {1'b0, b[`LM32_WORD_WIDTH-1:1]};
a <= {a[`LM32_WORD_WIDTH-2:0], 1'b0};
result_x <= p;
if ((cycles == `LM32_WORD_WIDTH'd0) || (kill_x == `TRUE))
state <= `LM32_MC_STATE_IDLE;
cycles <= cycles - 1'b1;
end
`endif
`ifdef CFG_MC_BARREL_SHIFT_ENABLED
`LM32_MC_STATE_SHIFT_LEFT:
begin
a <= {a[`LM32_WORD_WIDTH-2:0], 1'b0};
result_x <= a;
if ((cycles == `LM32_WORD_WIDTH'd0) || (kill_x == `TRUE))
state <= `LM32_MC_STATE_IDLE;
cycles <= cycles - 1'b1;
end
`LM32_MC_STATE_SHIFT_RIGHT:
begin
b <= {fill_value, b[`LM32_WORD_WIDTH-1:1]};
result_x <= b;
if ((cycles == `LM32_WORD_WIDTH'd0) || (kill_x == `TRUE))
state <= `LM32_MC_STATE_IDLE;
cycles <= cycles - 1'b1;
end
`endif
endcase
end
end
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_monitor.v
// Title : Debug monitor memory Wishbone interface
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.3
// : Removed port mismatch in instantiation of module
// : lm32_monitor_ram.
// =============================================================================
`include "system_conf.v"
`include "lm32_include.v"
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_monitor (
// ----- Inputs -------
clk_i,
rst_i,
MON_ADR_I,
MON_CYC_I,
MON_DAT_I,
MON_SEL_I,
MON_STB_I,
MON_WE_I,
MON_LOCK_I,
MON_CTI_I,
MON_BTE_I,
// ----- Outputs -------
MON_ACK_O,
MON_RTY_O,
MON_DAT_O,
MON_ERR_O
);
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input clk_i; // Wishbone clock
input rst_i; // Wishbone reset
input [`LM32_WORD_RNG] MON_ADR_I; // Wishbone address
input MON_STB_I; // Wishbone strobe
input MON_CYC_I; // Wishbone cycle
input [`LM32_WORD_RNG] MON_DAT_I; // Wishbone write data
input [`LM32_BYTE_SELECT_RNG] MON_SEL_I; // Wishbone byte select
input MON_WE_I; // Wishbone write enable
input MON_LOCK_I; // Wishbone locked transfer
input [`LM32_CTYPE_RNG] MON_CTI_I; // Wishbone cycle type
input [`LM32_BTYPE_RNG] MON_BTE_I; // Wishbone burst type
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
output MON_ACK_O; // Wishbone acknowlege
reg MON_ACK_O;
output [`LM32_WORD_RNG] MON_DAT_O; // Wishbone data output
reg [`LM32_WORD_RNG] MON_DAT_O;
output MON_RTY_O; // Wishbone retry
wire MON_RTY_O;
output MON_ERR_O; // Wishbone error
wire MON_ERR_O;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
reg [1:0] state; // Current state of FSM
wire [`LM32_WORD_RNG] data, dataB; // Data read from RAM
reg write_enable; // RAM write enable
reg [`LM32_WORD_RNG] write_data; // RAM write data
/////////////////////////////////////////////////////
// Instantiations
/////////////////////////////////////////////////////
lm32_monitor_ram ram (
// ----- Inputs -------
.ClockA (clk_i),
.ClockB (clk_i),
.ResetA (rst_i),
.ResetB (rst_i),
.ClockEnA (`TRUE),
.ClockEnB (`FALSE),
.AddressA (MON_ADR_I[10:2]),
.AddressB (9'b0),
.DataInA (write_data),
.DataInB (32'b0),
.WrA (write_enable),
.WrB (`FALSE),
// ----- Outputs -------
.QA (data),
.QB (dataB)
);
/////////////////////////////////////////////////////
// Combinational Logic
/////////////////////////////////////////////////////
assign MON_RTY_O = `FALSE;
assign MON_ERR_O = `FALSE;
/////////////////////////////////////////////////////
// Sequential Logic
/////////////////////////////////////////////////////
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
write_enable <= `FALSE;
MON_ACK_O <= `FALSE;
MON_DAT_O <= {`LM32_WORD_WIDTH{1'bx}};
state <= 2'b00;
end
else
begin
case (state)
2'b00:
begin
// Wait for a Wishbone access
if ((MON_STB_I == `TRUE) && (MON_CYC_I == `TRUE))
state <= 2'b01;
end
2'b01:
begin
// Output read data to Wishbone
MON_ACK_O <= `TRUE;
MON_DAT_O <= data;
// Sub-word writes are performed using read-modify-write
// as the Lattice EBRs don't support byte enables
if (MON_WE_I == `TRUE)
write_enable <= `TRUE;
write_data[7:0] <= MON_SEL_I[0] ? MON_DAT_I[7:0] : data[7:0];
write_data[15:8] <= MON_SEL_I[1] ? MON_DAT_I[15:8] : data[15:8];
write_data[23:16] <= MON_SEL_I[2] ? MON_DAT_I[23:16] : data[23:16];
write_data[31:24] <= MON_SEL_I[3] ? MON_DAT_I[31:24] : data[31:24];
state <= 2'b10;
end
2'b10:
begin
// Wishbone access occurs in this cycle
write_enable <= `FALSE;
MON_ACK_O <= `FALSE;
MON_DAT_O <= {`LM32_WORD_WIDTH{1'bx}};
state <= 2'b00;
end
endcase
end
end
endmodule
This source diff could not be displayed because it is too large. You can view the blob instead.
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_multiplier.v
// Title : Pipelined multiplier.
// Dependencies : lm32_include.v
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
`include "lm32_include.v"
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_multiplier (
// ----- Inputs -----
clk_i,
rst_i,
stall_x,
stall_m,
operand_0,
operand_1,
// ----- Ouputs -----
result
);
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input clk_i; // Clock
input rst_i; // Reset
input stall_x; // Stall instruction in X stage
input stall_m; // Stall instruction in M stage
input [`LM32_WORD_RNG] operand_0; // Muliplicand
input [`LM32_WORD_RNG] operand_1; // Multiplier
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
output [`LM32_WORD_RNG] result; // Product of multiplication
reg [`LM32_WORD_RNG] result;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
reg [`LM32_WORD_RNG] muliplicand;
reg [`LM32_WORD_RNG] multiplier;
reg [`LM32_WORD_RNG] product;
/////////////////////////////////////////////////////
// Sequential logic
/////////////////////////////////////////////////////
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
muliplicand <= {`LM32_WORD_WIDTH{1'b0}};
multiplier <= {`LM32_WORD_WIDTH{1'b0}};
product <= {`LM32_WORD_WIDTH{1'b0}};
result <= {`LM32_WORD_WIDTH{1'b0}};
end
else
begin
if (stall_x == `FALSE)
begin
muliplicand <= operand_0;
multiplier <= operand_1;
end
if (stall_m == `FALSE)
product <= muliplicand * multiplier;
result <= product;
end
end
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_ram.v
// Title : Pseudo dual-port RAM.
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : Options added to select EBRs (True-DP, Psuedo-DP, DQ, or
// : Distributed RAM).
// Version : 3.2
// : EBRs use SYNC resets instead of ASYNC resets.
// Version : 3.5
// : Added read-after-write hazard resolution when using true
// : dual-port EBRs
// =============================================================================
`include "lm32_include.v"
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_ram
(
// ----- Inputs -------
read_clk,
write_clk,
reset,
enable_read,
read_address,
enable_write,
write_address,
write_data,
write_enable,
// ----- Outputs -------
read_data
);
/*----------------------------------------------------------------------
Parameters
----------------------------------------------------------------------*/
parameter data_width = 1; // Width of the data ports
parameter address_width = 1; // Width of the address ports
/*----------------------------------------------------------------------
Inputs
----------------------------------------------------------------------*/
input read_clk; // Read clock
input write_clk; // Write clock
input reset; // Reset
input enable_read; // Access enable
input [address_width-1:0] read_address; // Read/write address
input enable_write; // Access enable
input [address_width-1:0] write_address;// Read/write address
input [data_width-1:0] write_data; // Data to write to specified address
input write_enable; // Write enable
/*----------------------------------------------------------------------
Outputs
----------------------------------------------------------------------*/
output [data_width-1:0] read_data; // Data read from specified addess
wire [data_width-1:0] read_data;
/*----------------------------------------------------------------------
Internal nets and registers
----------------------------------------------------------------------*/
reg [data_width-1:0] mem[0:(1<<address_width)-1]; // The RAM
reg [address_width-1:0] ra; // Registered read address
/*----------------------------------------------------------------------
Combinational Logic
----------------------------------------------------------------------*/
// Read port
assign read_data = mem[ra];
/*----------------------------------------------------------------------
Sequential Logic
----------------------------------------------------------------------*/
// Write port
always @(posedge write_clk)
if ((write_enable == `TRUE) && (enable_write == `TRUE))
mem[write_address] <= write_data;
// Register read address for use on next cycle
always @(posedge read_clk)
if (enable_read)
ra <= read_address;
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_shifter.v
// Title : Barrel shifter
// Dependencies : lm32_include.v
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
`include "lm32_include.v"
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_shifter (
// ----- Inputs -------
clk_i,
rst_i,
stall_x,
direction_x,
sign_extend_x,
operand_0_x,
operand_1_x,
// ----- Outputs -------
shifter_result_m
);
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input clk_i; // Clock
input rst_i; // Reset
input stall_x; // Stall instruction in X stage
input direction_x; // Direction to shift
input sign_extend_x; // Whether shift is arithmetic (1'b1) or logical (1'b0)
input [`LM32_WORD_RNG] operand_0_x; // Operand to shift
input [`LM32_WORD_RNG] operand_1_x; // Operand that specifies how many bits to shift by
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
output [`LM32_WORD_RNG] shifter_result_m; // Result of shift
wire [`LM32_WORD_RNG] shifter_result_m;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
reg direction_m;
reg [`LM32_WORD_RNG] left_shift_result;
reg [`LM32_WORD_RNG] right_shift_result;
reg [`LM32_WORD_RNG] left_shift_operand;
wire [`LM32_WORD_RNG] right_shift_operand;
wire fill_value;
wire [`LM32_WORD_RNG] right_shift_in;
integer shift_idx_0;
integer shift_idx_1;
/////////////////////////////////////////////////////
// Combinational Logic
/////////////////////////////////////////////////////
// Select operands - To perform a left shift, we reverse the bits and perform a right shift
always @(*)
begin
for (shift_idx_0 = 0; shift_idx_0 < `LM32_WORD_WIDTH; shift_idx_0 = shift_idx_0 + 1)
left_shift_operand[`LM32_WORD_WIDTH-1-shift_idx_0] = operand_0_x[shift_idx_0];
end
assign right_shift_operand = direction_x == `LM32_SHIFT_OP_LEFT ? left_shift_operand : operand_0_x;
// Determine fill value for right shift - Sign bit for arithmetic shift, or zero for logical shift
assign fill_value = (sign_extend_x == `TRUE) && (direction_x == `LM32_SHIFT_OP_RIGHT)
? operand_0_x[`LM32_WORD_WIDTH-1]
: 1'b0;
// Determine bits to shift in for right shift or rotate
assign right_shift_in = {`LM32_WORD_WIDTH{fill_value}};
// Reverse bits to get left shift result
always @(*)
begin
for (shift_idx_1 = 0; shift_idx_1 < `LM32_WORD_WIDTH; shift_idx_1 = shift_idx_1 + 1)
left_shift_result[`LM32_WORD_WIDTH-1-shift_idx_1] = right_shift_result[shift_idx_1];
end
// Select result
assign shifter_result_m = direction_m == `LM32_SHIFT_OP_LEFT ? left_shift_result : right_shift_result;
/////////////////////////////////////////////////////
// Sequential Logic
/////////////////////////////////////////////////////
// Perform right shift
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE)
begin
right_shift_result <= {`LM32_WORD_WIDTH{1'b0}};
direction_m <= `FALSE;
end
else
begin
if (stall_x == `FALSE)
begin
right_shift_result <= {right_shift_in, right_shift_operand} >> operand_1_x[`LM32_SHIFT_RNG];
direction_m <= direction_x;
end
end
end
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_top.v
// Title : Top-level of CPU.
// Dependencies : lm32_include.v
// Version : 6.1.17
// : removed SPI - 04/12/07
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
`include "lm32_include.v"
/////////////////////////////////////////////////////
// Module interface
/////////////////////////////////////////////////////
module lm32_top (
// ----- Inputs -------
clk_i,
rst_i,
// From external devices
`ifdef CFG_INTERRUPTS_ENABLED
interrupt,
`endif
// From user logic
`ifdef CFG_USER_ENABLED
user_result,
user_complete,
`endif
`ifdef CFG_IWB_ENABLED
// Instruction Wishbone master
I_DAT_I,
I_ACK_I,
I_ERR_I,
I_RTY_I,
`endif
// Data Wishbone master
D_DAT_I,
D_ACK_I,
D_ERR_I,
D_RTY_I,
// Debug Slave port WishboneInterface
DEBUG_ADR_I,
DEBUG_DAT_I,
DEBUG_SEL_I,
DEBUG_WE_I,
DEBUG_CTI_I,
DEBUG_BTE_I,
DEBUG_LOCK_I,
DEBUG_CYC_I,
DEBUG_STB_I,
// ----- Outputs -------
`ifdef CFG_USER_ENABLED
user_valid,
user_opcode,
user_operand_0,
user_operand_1,
`endif
`ifdef CFG_IWB_ENABLED
// Instruction Wishbone master
I_DAT_O,
I_ADR_O,
I_CYC_O,
I_SEL_O,
I_STB_O,
I_WE_O,
I_CTI_O,
I_LOCK_O,
I_BTE_O,
`endif
// Data Wishbone master
D_DAT_O,
D_ADR_O,
D_CYC_O,
D_SEL_O,
D_STB_O,
D_WE_O,
D_CTI_O,
D_LOCK_O,
D_BTE_O,
// Debug Slave port WishboneInterface
DEBUG_ACK_O,
DEBUG_ERR_O,
DEBUG_RTY_O,
DEBUG_DAT_O
);
/////////////////////////////////////////////////////
// Inputs
/////////////////////////////////////////////////////
input clk_i; // Clock
input rst_i; // Reset
`ifdef CFG_INTERRUPTS_ENABLED
input [`LM32_INTERRUPT_RNG] interrupt; // Interrupt pins
`endif
`ifdef CFG_USER_ENABLED
input [`LM32_WORD_RNG] user_result; // User-defined instruction result
input user_complete; // Indicates the user-defined instruction result is valid
`endif
`ifdef CFG_IWB_ENABLED
input [`LM32_WORD_RNG] I_DAT_I; // Instruction Wishbone interface read data
input I_ACK_I; // Instruction Wishbone interface acknowledgement
input I_ERR_I; // Instruction Wishbone interface error
input I_RTY_I; // Instruction Wishbone interface retry
`endif
input [`LM32_WORD_RNG] D_DAT_I; // Data Wishbone interface read data
input D_ACK_I; // Data Wishbone interface acknowledgement
input D_ERR_I; // Data Wishbone interface error
input D_RTY_I; // Data Wishbone interface retry
input [`LM32_WORD_RNG] DEBUG_ADR_I; // Debug monitor Wishbone interface address
input [`LM32_WORD_RNG] DEBUG_DAT_I; // Debug monitor Wishbone interface write data
input [`LM32_BYTE_SELECT_RNG] DEBUG_SEL_I; // Debug monitor Wishbone interface byte select
input DEBUG_WE_I; // Debug monitor Wishbone interface write enable
input [`LM32_CTYPE_RNG] DEBUG_CTI_I; // Debug monitor Wishbone interface cycle type
input [`LM32_BTYPE_RNG] DEBUG_BTE_I; // Debug monitor Wishbone interface burst type
input DEBUG_LOCK_I; // Debug monitor Wishbone interface locked transfer
input DEBUG_CYC_I; // Debug monitor Wishbone interface cycle
input DEBUG_STB_I; // Debug monitor Wishbone interface strobe
/////////////////////////////////////////////////////
// Outputs
/////////////////////////////////////////////////////
`ifdef CFG_USER_ENABLED
output user_valid; // Indicates that user_opcode and user_operand_* are valid
wire user_valid;
output [`LM32_USER_OPCODE_RNG] user_opcode; // User-defined instruction opcode
reg [`LM32_USER_OPCODE_RNG] user_opcode;
output [`LM32_WORD_RNG] user_operand_0; // First operand for user-defined instruction
wire [`LM32_WORD_RNG] user_operand_0;
output [`LM32_WORD_RNG] user_operand_1; // Second operand for user-defined instruction
wire [`LM32_WORD_RNG] user_operand_1;
`endif
`ifdef CFG_IWB_ENABLED
output [`LM32_WORD_RNG] I_DAT_O; // Instruction Wishbone interface write data
wire [`LM32_WORD_RNG] I_DAT_O;
output [`LM32_WORD_RNG] I_ADR_O; // Instruction Wishbone interface address
wire [`LM32_WORD_RNG] I_ADR_O;
output I_CYC_O; // Instruction Wishbone interface cycle
wire I_CYC_O;
output [`LM32_BYTE_SELECT_RNG] I_SEL_O; // Instruction Wishbone interface byte select
wire [`LM32_BYTE_SELECT_RNG] I_SEL_O;
output I_STB_O; // Instruction Wishbone interface strobe
wire I_STB_O;
output I_WE_O; // Instruction Wishbone interface write enable
wire I_WE_O;
output [`LM32_CTYPE_RNG] I_CTI_O; // Instruction Wishbone interface cycle type
wire [`LM32_CTYPE_RNG] I_CTI_O;
output I_LOCK_O; // Instruction Wishbone interface lock bus
wire I_LOCK_O;
output [`LM32_BTYPE_RNG] I_BTE_O; // Instruction Wishbone interface burst type
wire [`LM32_BTYPE_RNG] I_BTE_O;
`endif
output [`LM32_WORD_RNG] D_DAT_O; // Data Wishbone interface write data
wire [`LM32_WORD_RNG] D_DAT_O;
output [`LM32_WORD_RNG] D_ADR_O; // Data Wishbone interface address
wire [`LM32_WORD_RNG] D_ADR_O;
output D_CYC_O; // Data Wishbone interface cycle
wire D_CYC_O;
output [`LM32_BYTE_SELECT_RNG] D_SEL_O; // Data Wishbone interface byte select
wire [`LM32_BYTE_SELECT_RNG] D_SEL_O;
output D_STB_O; // Data Wishbone interface strobe
wire D_STB_O;
output D_WE_O; // Data Wishbone interface write enable
wire D_WE_O;
output [`LM32_CTYPE_RNG] D_CTI_O; // Data Wishbone interface cycle type
wire [`LM32_CTYPE_RNG] D_CTI_O;
output D_LOCK_O; // Date Wishbone interface lock bus
wire D_LOCK_O;
output [`LM32_BTYPE_RNG] D_BTE_O; // Data Wishbone interface burst type
wire [`LM32_BTYPE_RNG] D_BTE_O;
output DEBUG_ACK_O; // Debug monitor Wishbone ack
wire DEBUG_ACK_O;
output DEBUG_ERR_O; // Debug monitor Wishbone error
wire DEBUG_ERR_O;
output DEBUG_RTY_O; // Debug monitor Wishbone retry
wire DEBUG_RTY_O;
output [`LM32_WORD_RNG] DEBUG_DAT_O; // Debug monitor Wishbone read data
wire [`LM32_WORD_RNG] DEBUG_DAT_O;
/////////////////////////////////////////////////////
// Internal nets and registers
/////////////////////////////////////////////////////
`ifdef CFG_JTAG_ENABLED
// Signals between JTAG interface and CPU
wire [`LM32_BYTE_RNG] jtag_reg_d;
wire [`LM32_BYTE_RNG] jtag_reg_q;
wire jtag_update;
wire [2:0] jtag_reg_addr_d;
wire [2:0] jtag_reg_addr_q;
wire jtck;
wire jrstn;
`endif
`ifdef CFG_TRACE_ENABLED
// PC trace signals
wire [`LM32_PC_RNG] trace_pc; // PC to trace (address of next non-sequential instruction)
wire trace_pc_valid; // Indicates that a new trace PC is valid
wire trace_exception; // Indicates an exception has occured
wire [`LM32_EID_RNG] trace_eid; // Indicates what type of exception has occured
wire trace_eret; // Indicates an eret instruction has been executed
`ifdef CFG_DEBUG_ENABLED
wire trace_bret; // Indicates a bret instruction has been executed
`endif
`endif
/////////////////////////////////////////////////////
// Functions
/////////////////////////////////////////////////////
`include "lm32_functions.v"
/////////////////////////////////////////////////////
// Instantiations
/////////////////////////////////////////////////////
// LM32 CPU
lm32_cpu cpu (
// ----- Inputs -------
.clk_i (clk_i),
`ifdef CFG_EBR_NEGEDGE_REGISTER_FILE
.clk_n_i (clk_n),
`endif
.rst_i (rst_i),
// From external devices
`ifdef CFG_INTERRUPTS_ENABLED
.interrupt (interrupt),
`endif
// From user logic
`ifdef CFG_USER_ENABLED
.user_result (user_result),
.user_complete (user_complete),
`endif
`ifdef CFG_JTAG_ENABLED
// From JTAG
.jtag_clk (jtck),
.jtag_update (jtag_update),
.jtag_reg_q (jtag_reg_q),
.jtag_reg_addr_q (jtag_reg_addr_q),
`endif
`ifdef CFG_IWB_ENABLED
// Instruction Wishbone master
.I_DAT_I (I_DAT_I),
.I_ACK_I (I_ACK_I),
.I_ERR_I (I_ERR_I),
.I_RTY_I (I_RTY_I),
`endif
// Data Wishbone master
.D_DAT_I (D_DAT_I),
.D_ACK_I (D_ACK_I),
.D_ERR_I (D_ERR_I),
.D_RTY_I (D_RTY_I),
// ----- Outputs -------
`ifdef CFG_TRACE_ENABLED
.trace_pc (trace_pc),
.trace_pc_valid (trace_pc_valid),
.trace_exception (trace_exception),
.trace_eid (trace_eid),
.trace_eret (trace_eret),
`ifdef CFG_DEBUG_ENABLED
.trace_bret (trace_bret),
`endif
`endif
`ifdef CFG_JTAG_ENABLED
.jtag_reg_d (jtag_reg_d),
.jtag_reg_addr_d (jtag_reg_addr_d),
`endif
`ifdef CFG_USER_ENABLED
.user_valid (user_valid),
.user_opcode (user_opcode),
.user_operand_0 (user_operand_0),
.user_operand_1 (user_operand_1),
`endif
`ifdef CFG_IWB_ENABLED
// Instruction Wishbone master
.I_DAT_O (I_DAT_O),
.I_ADR_O (I_ADR_O),
.I_CYC_O (I_CYC_O),
.I_SEL_O (I_SEL_O),
.I_STB_O (I_STB_O),
.I_WE_O (I_WE_O),
.I_CTI_O (I_CTI_O),
.I_LOCK_O (I_LOCK_O),
.I_BTE_O (I_BTE_O),
`endif
// Data Wishbone master
.D_DAT_O (D_DAT_O),
.D_ADR_O (D_ADR_O),
.D_CYC_O (D_CYC_O),
.D_SEL_O (D_SEL_O),
.D_STB_O (D_STB_O),
.D_WE_O (D_WE_O),
.D_CTI_O (D_CTI_O),
.D_LOCK_O (D_LOCK_O),
.D_BTE_O (D_BTE_O)
);
wire TRACE_ACK_O;
wire [`LM32_WORD_RNG] TRACE_DAT_O;
`ifdef CFG_TRACE_ENABLED
lm32_trace trace_module (.clk_i (clk_i),
.rst_i (rst_i),
.stb_i (DEBUG_STB_I & DEBUG_ADR_I[13]),
.we_i (DEBUG_WE_I),
.sel_i (DEBUG_SEL_I),
.dat_i (DEBUG_DAT_I),
.adr_i (DEBUG_ADR_I),
.trace_pc (trace_pc),
.trace_eid (trace_eid),
.trace_eret (trace_eret),
.trace_bret (trace_bret),
.trace_pc_valid (trace_pc_valid),
.trace_exception (trace_exception),
.ack_o (TRACE_ACK_O),
.dat_o (TRACE_DAT_O));
`else
assign TRACE_ACK_O = 0;
assign TRACE_DAT_O = 0;
`endif
`ifdef DEBUG_ROM
wire ROM_ACK_O;
wire [`LM32_WORD_RNG] ROM_DAT_O;
assign DEBUG_ACK_O = DEBUG_ADR_I[13] ? TRACE_ACK_O : ROM_ACK_O;
assign DEBUG_DAT_O = DEBUG_ADR_I[13] ? TRACE_DAT_O : ROM_DAT_O;
// ROM monitor
lm32_monitor debug_rom (
// ----- Inputs -------
.clk_i (clk_i),
.rst_i (rst_i),
.MON_ADR_I (DEBUG_ADR_I),
.MON_STB_I (DEBUG_STB_I & ~DEBUG_ADR_I[13]),
.MON_CYC_I (DEBUG_CYC_I & ~DEBUG_ADR_I[13]),
.MON_WE_I (DEBUG_WE_I),
.MON_SEL_I (DEBUG_SEL_I),
.MON_DAT_I (DEBUG_DAT_I),
.MON_CTI_I (DEBUG_CTI_I),
.MON_BTE_I (DEBUG_BTE_I),
.MON_LOCK_I (DEBUG_LOCK_I),
// ----- Outputs ------
.MON_RTY_O (DEBUG_RTY_O),
.MON_ERR_O (DEBUG_ERR_O),
.MON_ACK_O (ROM_ACK_O),
.MON_DAT_O (ROM_DAT_O)
);
`endif
`ifdef CFG_JTAG_ENABLED
// JTAG cores
jtag_cores jtag_cores (
// ----- Inputs -----
`ifdef INCLUDE_LM32
.reg_d (jtag_reg_d),
.reg_addr_d (jtag_reg_addr_d),
`endif
// ----- Outputs -----
`ifdef INCLUDE_LM32
.reg_update (jtag_update),
.reg_q (jtag_reg_q),
.reg_addr_q (jtag_reg_addr_q),
`endif
.jtck (jtck),
.jrstn (jrstn)
);
`endif
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : lm32_trace.v
// Title : PC Trace and associated logic.
// Dependencies : lm32_include.v, lm32_functions.v
// Version : 6.1.17
// : Initial Release
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
`include "lm32_include.v"
`include "system_conf.v"
`ifdef CFG_TRACE_ENABLED
module lm32_trace(
// ----- Inputs -------
clk_i,
rst_i,
stb_i,
we_i,
sel_i,
dat_i,
adr_i,
trace_pc,
trace_eid,
trace_eret,
trace_bret,
trace_pc_valid,
trace_exception,
// -- outputs
ack_o,
dat_o);
input clk_i;
input rst_i;
input stb_i;
input we_i;
input [3:0] sel_i;
input [`LM32_WORD_RNG] dat_i;
input [`LM32_WORD_RNG] adr_i;
input [`LM32_PC_RNG] trace_pc;
input [`LM32_EID_RNG] trace_eid;
input trace_eret;
input trace_bret;
input trace_pc_valid;
input trace_exception;
// -- outputs
output ack_o;
output [`LM32_WORD_RNG] dat_o;
reg ovrflw;
function integer clogb2;
input [31:0] value;
begin
for (clogb2 = 0; value > 0; clogb2 = clogb2 + 1)
value = value >> 1;
end
endfunction
// instantiate the trace memory
parameter mem_data_width = `LM32_PC_WIDTH;
parameter mem_addr_width = clogb2(`CFG_TRACE_DEPTH-1);
wire [`LM32_PC_RNG] trace_dat_o;
wire [mem_addr_width-1:0] trace_raddr;
wire [mem_addr_width-1:0] trace_waddr;
reg trace_we;
wire trace_be, trace_last;
wire rw_creg = adr_i[12];
lm32_ram #(.data_width (mem_data_width),
.address_width (mem_addr_width))
trace_mem (.read_clk (clk_i),
.write_clk (clk_i),
.reset (rst_i),
.read_address (adr_i[mem_addr_width+1:2]),
.write_address (trace_waddr),
.enable_read (`TRUE),
.enable_write ((trace_we | trace_be) & trace_pc_valid & !trace_last),
.write_enable (`TRUE),
.write_data (trace_pc),
.read_data (trace_dat_o));
// trigger type & stop type
// trig_type [0] = start capture when bret
// trig_type [1] = start capture when eret
// trig_type [2] = start capture when PC within a range
// trig_type [3] = start when an exception happens (other than breakpoint)
// trig_type [4] = start when a breakpoint exception happens
reg [4:0] trig_type; // at address 0
reg [4:0] stop_type; // at address 16
reg [`LM32_WORD_RNG] trace_len; // at address 4
reg [`LM32_WORD_RNG] pc_low; // at address 8
reg [`LM32_WORD_RNG] pc_high; // at address 12
reg trace_start,trace_stop;
reg ack_o;
reg mem_valid;
reg [`LM32_WORD_RNG] reg_dat_o;
reg started;
reg capturing;
assign dat_o = (rw_creg ? reg_dat_o : trace_dat_o);
initial begin
trig_type <= 0;
stop_type <= 0;
trace_len <= 0;
pc_low <= 0;
pc_high <= 0;
trace_start <= 0;
trace_stop <= 0;
ack_o <= 0;
reg_dat_o <= 0;
mem_valid <= 0;
started <= 0;
capturing <= 0;
end
// the host side control
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE) begin
trig_type <= 0;
trace_stop <= 0;
trace_start <= 0;
pc_low <= 0;
pc_high <= 0;
ack_o <= 0;
end else begin
if (stb_i == `TRUE && ack_o == `FALSE) begin
if (rw_creg) begin // control register access
ack_o <= `TRUE;
if (we_i == `TRUE) begin
case ({adr_i[11:2],2'b0})
// write to trig type
12'd0:
begin
if (sel_i[0]) begin
trig_type[4:0] <= dat_i[4:0];
end
if (sel_i[3]) begin
trace_start <= dat_i[31];
trace_stop <= dat_i[30];
end
end
12'd8:
begin
if (sel_i[3]) pc_low[31:24] <= dat_i[31:24];
if (sel_i[2]) pc_low[23:16] <= dat_i[23:16];
if (sel_i[1]) pc_low[15:8] <= dat_i[15:8];
if (sel_i[0]) pc_low[7:0] <= dat_i[7:0];
end
12'd12:
begin
if (sel_i[3]) pc_high[31:24] <= dat_i[31:24];
if (sel_i[2]) pc_high[23:16] <= dat_i[23:16];
if (sel_i[1]) pc_high[15:8] <= dat_i[15:8];
if (sel_i[0]) pc_high[7:0] <= dat_i[7:0];
end
12'd16:
begin
if (sel_i[0])begin
stop_type[4:0] <= dat_i[4:0];
end
end
endcase
end else begin // read control registers
case ({adr_i[11:2],2'b0})
// read the trig type
12'd0:
reg_dat_o <= {22'b1,capturing,mem_valid,ovrflw,trace_we,started,trig_type};
12'd4:
reg_dat_o <= trace_len;
12'd8:
reg_dat_o <= pc_low;
12'd12:
reg_dat_o <= pc_high;
default:
reg_dat_o <= {27'b0,stop_type};
endcase
end // else: !if(we_i == `TRUE)
end else // read / write memory
if (we_i == `FALSE) begin
ack_o <= `TRUE;
end else
ack_o <= `FALSE;
// not allowed to write to trace memory
end else begin // if (stb_i == `TRUE)
trace_start <= `FALSE;
trace_stop <= `FALSE;
ack_o <= `FALSE;
end // else: !if(stb_i == `TRUE)
end // else: !if(rst_i == `TRUE)
end
wire [`LM32_WORD_RNG] trace_pc_tmp = {trace_pc,2'b0};
// trace state machine
reg [2:0] tstate;
wire pc_in_range = {trace_pc,2'b0} >= pc_low &&
{trace_pc,2'b0} <= pc_high;
assign trace_waddr = trace_len[mem_addr_width-1:0];
wire trace_begin = ((trig_type[0] & trace_bret) ||
(trig_type[1] & trace_eret) ||
(trig_type[2] & pc_in_range & trace_pc_valid) ||
(trig_type[3] & trace_exception & (trace_eid != `LM32_EID_BREAKPOINT)) ||
(trig_type[4] & trace_exception & (trace_eid == `LM32_EID_BREAKPOINT))
);
wire trace_end = (trace_stop ||
(stop_type[0] & trace_bret) ||
(stop_type[1] & trace_eret) ||
(stop_type[2] & !pc_in_range & trace_pc_valid) ||
(stop_type[3] & trace_exception & (trace_eid != `LM32_EID_BREAKPOINT)) ||
(stop_type[4] & trace_exception & (trace_eid == `LM32_EID_BREAKPOINT))
);
assign trace_be = (trace_begin & (tstate == 3'd1));
assign trace_last = (trace_stop & (tstate == 3'd2));
always @(posedge clk_i `CFG_RESET_SENSITIVITY)
begin
if (rst_i == `TRUE) begin
tstate <= 0;
trace_we <= 0;
trace_len <= 0;
ovrflw <= `FALSE;
mem_valid <= 0;
started <= 0;
capturing <= 0;
end else begin
case (tstate)
3'd0:
// start capture
if (trace_start) begin
tstate <= 3'd1;
mem_valid <= 0;
started <= 1;
end
3'd1:
begin
// wait for trigger
if (trace_begin) begin
capturing <= 1;
tstate <= 3'd2;
trace_we <= `TRUE;
trace_len <= 0;
ovrflw <= `FALSE;
end
end // case: 3'd1
3'd2:
begin
if (trace_pc_valid) begin
if (trace_len[mem_addr_width])
trace_len <= 0;
else
trace_len <= trace_len + 1;
end
if (!ovrflw) ovrflw <= trace_len[mem_addr_width];
// wait for stop condition
if (trace_end) begin
tstate <= 3'd0;
trace_we <= 0;
mem_valid <= 1;
started <= 0;
capturing <= 0;
end
end // case: 3'd2
endcase
end // else: !if(rst_i == `TRUE)
end
endmodule
`endif
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : SPIPROG.v
// This module contains the ER2 regsiters of SPI Serial FLASH programmer IP
// core. There are only three ER2 registers, one control register and two
// data registers, in this IP core. The control register is a 8-bit wide
// register for selecting which data register will be accessed when the
// Control/Data# bit in ER1 register is low. Data register 0 is a readonly
// ID register. It is composed of three register fields -- an 8-bit
// "implementer", a 16-bit "IP_functionality", and a 12-bit "revision".
// Data register 1 is a variable length register for sending commands to or
// receiving readback data from the SPI Serial FLASH device.
// Dependencies : None
// Version : 6.1.17
// 1. Reduced the the ID register (DR0) length from 36 bits to 8 bits.
// 2. Same as TYPEA and TYPEB modules, use falling edge clock
// for all TCK Flip-Flops.
// 3. Added 7 delay Flip-Flops so that the DR1 readback data from
// SPI Serial FLASH is in the byte boundary.
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
//---------------------------------------------------------------------------
//
//Name : SPIPROG.v
//
//Description:
//
// This module contains the ER2 regsiters of SPI Serial FLASH programmer IP
// core. There are only three ER2 registers, one control register and two
// data registers, in this IP core. The control register is a 8-bit wide
// register for selecting which data register will be accessed when the
// Control/Data# bit in ER1 register is low. Data register 0 is a readonly
// ID register. It is composed of three register fields -- an 8-bit
// "implementer", a 16-bit "IP_functionality", and a 12-bit "revision".
// Data register 1 is a variable length register for sending commands to or
// receiving readback data from the SPI Serial FLASH device.
//
//$Log: spiprog.vhd,v $
//Revision 1.2 2004-09-09 11:43:26-07 jhsin
//1. Reduced the the ID register (DR0) length from 36 bits to 8 bits.
//2. Same as TYPEA and TYPEB modules, use falling edge clock
// for all TCK Flip-Flops.
//
//Revision 1.1 2004-08-12 13:22:05-07 jhsin
//Added 7 delay Flip-Flops so that the DR1 readback data from SPI Serial FLASH is in the byte boundary.
//
//Revision 1.0 2004-08-03 18:35:56-07 jhsin
//Initial revision
//
//
module SPIPROG (input JTCK ,
input JTDI ,
output JTDO2 ,
input JSHIFT ,
input JUPDATE ,
input JRSTN ,
input JCE2 ,
input SPIPROG_ENABLE ,
input CONTROL_DATAN ,
output SPI_C ,
output SPI_D ,
output SPI_SN ,
input SPI_Q);
wire er2Cr_enable ;
wire er2Dr0_enable;
wire er2Dr1_enable;
wire tdo_er2Cr ;
wire tdo_er2Dr0;
wire tdo_er2Dr1;
wire [7:0] encodedDrSelBits ;
wire [8:0] er2CrTdiBit ;
wire [8:0] er2Dr0TdiBit ;
wire captureDrER2;
reg spi_s ;
reg [6:0] spi_q_dly;
wire [7:0] ip_functionality_id;
genvar i;
// ------ Control Register 0 ------
assign er2Cr_enable = JCE2 & SPIPROG_ENABLE & CONTROL_DATAN;
assign tdo_er2Cr = er2CrTdiBit[0];
// CR_BIT0_BIT7
generate
for(i=0; i<=7; i=i+1)
begin:CR_BIT0_BIT7
TYPEA BIT_N (.CLK (JTCK),
.RESET_N (JRSTN),
.CLKEN (er2Cr_enable),
.TDI (er2CrTdiBit[i + 1]),
.TDO (er2CrTdiBit[i]),
.DATA_OUT (encodedDrSelBits[i]),
.DATA_IN (encodedDrSelBits[i]),
.CAPTURE_DR (captureDrER2),
.UPDATE_DR (JUPDATE));
end
endgenerate // CR_BIT0_BIT7
assign er2CrTdiBit[8] = JTDI;
// ------ Data Register 0 ------
assign er2Dr0_enable = (JCE2 & SPIPROG_ENABLE & ~CONTROL_DATAN & (encodedDrSelBits == 8'b00000000)) ? 1'b1 : 1'b0;
assign tdo_er2Dr0 = er2Dr0TdiBit[0];
assign ip_functionality_id = 8'b00000001; //-- SPI Serial FLASH Programmer (0x01)
// DR0_BIT0_BIT7
generate
for(i=0; i<=7; i=i+1)
begin:DR0_BIT0_BIT7
TYPEB BIT_N (.CLK (JTCK),
.RESET_N (JRSTN),
.CLKEN (er2Dr0_enable),
.TDI (er2Dr0TdiBit[i + 1]),
.TDO (er2Dr0TdiBit[i]),
.DATA_IN (ip_functionality_id[i]),
.CAPTURE_DR (captureDrER2));
end
endgenerate // DR0_BIT0_BIT7
assign er2Dr0TdiBit[8] = JTDI;
// ------ Data Register 1 ------
assign er2Dr1_enable = (JCE2 & JSHIFT & SPIPROG_ENABLE & ~CONTROL_DATAN & (encodedDrSelBits == 8'b00000001)) ? 1'b1 : 1'b0;
assign SPI_C = ~ (JTCK & er2Dr1_enable & spi_s);
assign SPI_D = JTDI & er2Dr1_enable;
// SPI_S_Proc
always @(negedge JTCK or negedge JRSTN)
begin
if (~JRSTN)
spi_s <= 1'b0;
else
if (JUPDATE)
spi_s <= 1'b0;
else
spi_s <= er2Dr1_enable;
end
assign SPI_SN = ~spi_s;
// SPI_Q_Proc
always @(negedge JTCK or negedge JRSTN)
begin
if (~JRSTN)
spi_q_dly <= 'b0;
else
if (er2Dr1_enable)
spi_q_dly <= {spi_q_dly[5:0],SPI_Q};
end
assign tdo_er2Dr1 = spi_q_dly[6];
// ------ JTDO2 MUX ------
assign JTDO2 = CONTROL_DATAN ? tdo_er2Cr :
(encodedDrSelBits == 8'b00000000) ? tdo_er2Dr0 :
(encodedDrSelBits == 8'b00000001) ? tdo_er2Dr1 : 1'b0;
assign captureDrER2 = ~JSHIFT & JCE2;
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : TYPEA.v
// Description:
// This is one of the two types of cells that are used to create ER1/ER2
// register bits.
// Dependencies : None
// Version : 6.1.17
// The SHIFT_DR_CAPTURE_DR and ENABLE_ER1/2 signals of the
// dedicate logic JTAG_PORT didn't act as what their names implied.
// The SHIFT_DR_CAPTURE_DR actually acts as SHIFT_DR.
// The ENABLE_ER1/2 actually acts as SHIFT_DR_CAPTURE_DR.
// These had caused a lot of headaches for a long time and now they are
// fixed by:
// (1) Use SHIFT_DR_CAPTURE_DR and ENABLE_ER1/2 to create
// CAPTURE_DR for all typeA, typeB bits in the ER1, ER2 registers.
// (2) Use ENABLE_ER1 or the enESR, enCSR, enBAR (these 3 signals
// have the same waveform of ENABLE_ER2) directly to be the CLKEN
// of all typeA, typeB bits in the ER1, ER2 registers.
// (3) Modify typea.vhd to use only UPDATE_DR signal for the clock enable
// of the holding flip-flop.
// These changes caused ispTracy.vhd and cge.dat changes and the new
// CGE.exe version will be 1.3.5.
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
module TYPEA(
input CLK,
input RESET_N,
input CLKEN,
input TDI,
output TDO,
output reg DATA_OUT,
input DATA_IN,
input CAPTURE_DR,
input UPDATE_DR
);
reg tdoInt;
always @ (negedge CLK or negedge RESET_N)
begin
if (RESET_N == 1'b0)
tdoInt <= 1'b0;
else if (CLK == 1'b0)
if (CLKEN == 1'b1)
if (CAPTURE_DR == 1'b0)
tdoInt <= TDI;
else
tdoInt <= DATA_IN;
end
assign TDO = tdoInt;
always @ (negedge CLK or negedge RESET_N)
begin
if (RESET_N == 1'b0)
DATA_OUT <= 1'b0;
else if (CLK == 1'b0)
if (UPDATE_DR == 1'b1)
DATA_OUT <= tdoInt;
end
endmodule
// =============================================================================
// COPYRIGHT NOTICE
// Copyright 2006 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court 408-826-6000 (other locations)
// Hillsboro, OR 97124 web : http://www.latticesemi.com/
// U.S.A email: techsupport@latticesemi.com
// =============================================================================/
// FILE DETAILS
// Project : LatticeMico32
// File : TYPEB.v
// Description:
// This is one of the two types of cells that are used to create ER1/ER2
// register bits.
// Dependencies : None
// Version : 6.1.17
// Modified typeb module to remove redundant DATA_OUT port.
// Version : 7.0SP2, 3.0
// : No Change
// Version : 3.1
// : No Change
// =============================================================================
module TYPEB
(
input CLK,
input RESET_N,
input CLKEN,
input TDI,
output TDO,
input DATA_IN,
input CAPTURE_DR
);
reg tdoInt;
always @ (negedge CLK or negedge RESET_N)
begin
if (RESET_N== 1'b0)
tdoInt <= 1'b0;
else if (CLK == 1'b0)
if (CLKEN==1'b1)
if (CAPTURE_DR==1'b0)
tdoInt <= TDI;
else
tdoInt <= DATA_IN;
end
assign TDO = tdoInt;
endmodule
TEX=sysctl.tex
DVI=$(TEX:.tex=.dvi)
PS=$(TEX:.tex=.ps)
PDF=$(TEX:.tex=.pdf)
AUX=$(TEX:.tex=.aux)
LOG=$(TEX:.tex=.log)
all: $(PDF)
%.dvi: %.tex
latex $<
%.ps: %.dvi
dvips $<
%.pdf: %.ps
ps2pdf $<
clean:
rm -f $(DVI) $(PS) $(PDF) $(AUX) $(LOG)
.PHONY: clean
\documentclass[a4paper,11pt]{article}
\usepackage{fullpage}
\usepackage[latin1]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[normalem]{ulem}
\usepackage[english]{babel}
\usepackage{listings,babel}
\lstset{breaklines=true,basicstyle=\ttfamily}
\usepackage{graphicx}
\usepackage{moreverb}
\usepackage{url}
\usepackage{tabularx}
\title{System controller}
\author{S\'ebastien Bourdeauducq}
\date{January 2010}
\begin{document}
\setlength{\parindent}{0pt}
\setlength{\parskip}{5pt}
\maketitle{}
\section{Overview}
The system controller includes basic functionality that is found on most SoC designs :
\begin{itemize}
\item a \textbf{GPIO controller}, which can be used for software-driven low-speed communication with peripherals and for simple user interaction like controlling LEDs and detecting keypresses.
\item two \textbf{timers} with a precision of one clock cycle.
\item a 32-bit \textbf{system identification} value.
\end{itemize}
\section{GPIO controller}
The GPIO controller can support a maximum of 32 inputs and 32 outputs. Bidirectional signals are not supported. The \verb!ninputs! and \verb!noutputs! control the actual number of input and outputs.
It is possible to generate an interrupt when an input changes. The interrupt will be generated on both rising and falling edges of the input.
\begin{tabularx}{\textwidth}{|l|l|l|X|}
\hline
\bf{Offset} & \bf{Read/Write} & \bf{Default} & \bf{Description} \\
\hline
0x00 & R & N/A & Inputs. \\
\hline
0x04 & RW & 0 & Outputs. \\
\hline
0x08 & RW & 0 & Interrupt enable. Lists the input pins whose level changes (bit set in the 0x08 register) generate an interrupt. \\
\hline
\end{tabularx}\\
\section{Dual timer}
The system controller provides two independent timers. Timer 0 uses registers 0x10, 0x14 and 0x18, while timer 1 uses registers 0x20, 0x24 and 0x28.
\subsection{Timer control register, offset 0x10/0x20}
\begin{tabularx}{\textwidth}{|l|l|l|X|}
\hline
\bf Bits & \bf Access & \bf Default & \bf Description \\
\hline
0 & RW & 0 & (Enable bit). If this bit is set, the counter register counts upwards until it reaches the value stored in the compare register. \\
\hline
1 & RW & 0 & If this bit is set, the counter will automatically restart from 1 when the compare value is reached, otherwise the counter will be disabled. \\
\hline
31 -- 2 & --- & 0 & Reserved. \\
\hline
\end{tabularx}
\subsection{Compare register, offset 0x14/0x24}
This register holds the value to which the counter is compared to, in order to stop/restart the timer and generate an interrupt.
\subsection{Counter register, offset 0x18/0x28}
This register holds the current value of the timer counter. It can be read or written at any time.
Writing it does not clear the trigger bit (bit 0 of the timer control register). The trigger bit should always be manually reset.
\section{System identification}
The system controller provides a 32-bit value defined at synthesis time that can be used to identify bitstreams or boards. The value is set by the \verb!systemid! Verilog parameter and read using the register 0x2c.
Writing any value to this register sends a hard system reset by asserting the \verb!hard_reset! output.
\section*{Copyright notice}
Copyright \copyright 2007-2010 S\'ebastien Bourdeauducq. \\
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the LICENSE.FDL file at the root of the Milkymist source distribution.
\end{document}
/*
* Milkymist VJ SoC
* Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
module sysctl #(
parameter csr_addr = 4'h0,
parameter ninputs = 16,
parameter noutputs = 16,
parameter systemid = 32'habadface
) (
input sys_clk,
input sys_rst,
/* Interrupts */
output reg gpio_irq,
output reg timer0_irq,
output reg timer1_irq,
/* CSR bus interface */
input [13:0] csr_a,
input csr_we,
input [31:0] csr_di,
output reg [31:0] csr_do,
/* GPIO */
input [ninputs-1:0] gpio_inputs,
output reg [noutputs-1:0] gpio_outputs,
output reg hard_reset
);
/*
* GPIO
*/
/* Synchronize the input */
reg [ninputs-1:0] gpio_in0;
reg [ninputs-1:0] gpio_in;
always @(posedge sys_clk) begin
gpio_in0 <= gpio_inputs;
gpio_in <= gpio_in0;
end
/* Detect level changes and generate IRQs */
reg [ninputs-1:0] gpio_inbefore;
always @(posedge sys_clk) gpio_inbefore <= gpio_in;
wire [ninputs-1:0] gpio_diff = gpio_inbefore ^ gpio_in;
reg [ninputs-1:0] gpio_irqen;
always @(posedge sys_clk) begin
if(sys_rst)
gpio_irq <= 1'b0;
else
gpio_irq <= |(gpio_diff & gpio_irqen);
end
/*
* Dual timer
*/
reg en0, en1;
reg ar0, ar1;
reg [31:0] counter0, counter1;
reg [31:0] compare0, compare1;
wire match0 = (counter0 == compare0);
wire match1 = (counter1 == compare1);
/*
* Logic and CSR interface
*/
wire csr_selected = csr_a[13:10] == csr_addr;
always @(posedge sys_clk) begin
if(sys_rst) begin
csr_do <= 32'd0;
timer0_irq <= 1'b0;
timer1_irq <= 1'b0;
gpio_outputs <= {noutputs{1'b0}};
gpio_irqen <= {ninputs{1'b0}};
en0 <= 1'b0;
en1 <= 1'b0;
ar0 <= 1'b0;
ar1 <= 1'b0;
counter0 <= 32'd0;
counter1 <= 32'd0;
compare0 <= 32'hFFFFFFFF;
compare1 <= 32'hFFFFFFFF;
hard_reset <= 1'b0;
end else begin
timer0_irq <= 1'b0;
timer1_irq <= 1'b0;
/* Handle timer 0 */
if( en0 & ~match0) counter0 <= counter0 + 32'd1;
if( en0 & match0) timer0_irq <= 1'b1;
if( ar0 & match0) counter0 <= 32'd1;
if(~ar0 & match0) en0 <= 1'b0;
/* Handle timer 1 */
if( en1 & ~match1) counter1 <= counter1 + 32'd1;
if( en1 & match1) timer1_irq <= 1'b1;
if( ar1 & match1) counter1 <= 32'd1;
if(~ar1 & match1) en1 <= 1'b0;
csr_do <= 32'd0;
if(csr_selected) begin
/* CSR Writes */
if(csr_we) begin
case(csr_a[3:0])
/* GPIO registers */
// 0000 is GPIO IN and is read-only
4'b0001: gpio_outputs <= csr_di[noutputs-1:0];
4'b0010: gpio_irqen <= csr_di[ninputs-1:0];
/* Timer 0 registers */
4'b0100: begin
en0 <= csr_di[0];
ar0 <= csr_di[1];
end
4'b0101: compare0 <= csr_di;
4'b0110: counter0 <= csr_di;
/* Timer 1 registers */
4'b1000: begin
en1 <= csr_di[0];
ar1 <= csr_di[1];
end
4'b1001: compare1 <= csr_di;
4'b1010: counter1 <= csr_di;
4'b1111: hard_reset <= 1'b1;
endcase
end
/* CSR Reads */
case(csr_a[3:0])
/* GPIO registers */
4'b0000: csr_do <= gpio_in;
4'b0001: csr_do <= gpio_outputs;
4'b0010: csr_do <= gpio_irqen;
/* Timer 0 registers */
4'b0100: csr_do <= {ar0, en0};
4'b0101: csr_do <= compare0;
4'b0110: csr_do <= counter0;
/* Timer 1 registers */
4'b1000: csr_do <= {ar1, en1};
4'b1001: csr_do <= compare1;
4'b1010: csr_do <= counter1;
4'b1111: csr_do <= systemid;
endcase
end
end
end
endmodule
TEX=uart.tex
DVI=$(TEX:.tex=.dvi)
PS=$(TEX:.tex=.ps)
PDF=$(TEX:.tex=.pdf)
AUX=$(TEX:.tex=.aux)
LOG=$(TEX:.tex=.log)
all: $(PDF)
%.dvi: %.tex
latex $<
%.ps: %.dvi
dvips $<
%.pdf: %.ps
ps2pdf $<
clean:
rm -f $(DVI) $(PS) $(PDF) $(AUX) $(LOG)
.PHONY: clean
\documentclass[a4paper,11pt]{article}
\usepackage{fullpage}
\usepackage[latin1]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[normalem]{ulem}
\usepackage[english]{babel}
\usepackage{listings,babel}
\lstset{breaklines=true,basicstyle=\ttfamily}
\usepackage{graphicx}
\usepackage{moreverb}
\usepackage{amsmath}
\usepackage{url}
\usepackage{tabularx}
\title{Simple UART}
\author{S\'ebastien Bourdeauducq}
\date{December 2009}
\begin{document}
\setlength{\parindent}{0pt}
\setlength{\parskip}{5pt}
\maketitle{}
\section{Specifications}
The UART is based on a very simple design from Das Labor. Its purpose is basically to provide a debug console.
The UART operates with 8 bits per character, no parity, and 1 stop bit. The default baudrate is configured during synthesis and can be modified at runtime using the divisor register.
The divisor is computed as follows :
\begin{equation*}
\text{divisor} = \frac{\text{Clock frequency (Hz)}}{16 \cdot \text{Bitrate (bps)}}
\end{equation*}
\section{Registers}
\begin{tabularx}{\textwidth}{|l|l|l|X|}
\hline
\bf{Offset} & \bf{Read/Write} & \bf{Default} & \bf{Description} \\
\hline
0x0 & RW & 0x00 & Data register. Received bytes and bytes to transmit are read/written from/to this register. \\
\hline
0x4 & RW & for default bitrate & Divisor register (for bitrate selection). \\
\hline
\end{tabularx}\\
\section{Interrupts}
The core has two active-high edge-sensitive interrupts outputs.
The ``RX'' interrupt is sent whenever a new character is received. The CPU should then read the data register immediately. If a new character is sent before the CPU has had time to read it, the first character will be lost.
The ``TX'' interrupt is sent as soon as the UART finished transmitting a character. When the CPU has written to the data register, it must wait for the interrupt before writing again.
\section{Using the core}
Connect the CSR signals and the interrupts to the system bus and the interrupt controller. The \verb!uart_txd! and \verb!uart_rxd! signals should go to the FPGA pads. You must also provide the desired default baudrate and the system clock frequency in Hz using the parameters.
\section*{Copyright notice}
Copyright \copyright 2007-2009 S\'ebastien Bourdeauducq. \\
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the LICENSE.FDL file at the root of the Milkymist source distribution.
\end{document}
/*
* Milkymist VJ SoC
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
module uart #(
parameter csr_addr = 4'h0,
parameter clk_freq = 100000000,
parameter baud = 115200
) (
input sys_clk,
input sys_rst,
input [13:0] csr_a,
input csr_we,
input [31:0] csr_di,
output reg [31:0] csr_do,
output rx_irq,
output tx_irq,
input uart_rxd,
output uart_txd
);
reg [15:0] divisor;
wire [7:0] rx_data;
wire [7:0] tx_data;
wire tx_wr;
uart_transceiver transceiver(
.sys_clk(sys_clk),
.sys_rst(sys_rst),
.uart_rxd(uart_rxd),
.uart_txd(uart_txd),
.divisor(divisor),
.rx_data(rx_data),
.rx_done(rx_irq),
.tx_data(tx_data),
.tx_wr(tx_wr),
.tx_done(tx_irq)
);
/* CSR interface */
wire csr_selected = csr_a[13:10] == csr_addr;
assign tx_data = csr_di[7:0];
assign tx_wr = csr_selected & csr_we & (csr_a[0] == 1'b0);
parameter default_divisor = clk_freq/baud/16;
always @(posedge sys_clk) begin
if(sys_rst) begin
divisor <= default_divisor;
csr_do <= 32'd0;
end else begin
csr_do <= 32'd0;
if(csr_selected) begin
case(csr_a[0])
1'b0: csr_do <= rx_data;
1'b1: csr_do <= divisor;
endcase
if(csr_we) begin
if(csr_a[0] == 1'b1)
divisor <= csr_di[15:0];
end
end
end
end
endmodule
/*
* Milkymist VJ SoC
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
* Copyright (C) 2007 Das Labor
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
module uart_transceiver(
input sys_rst,
input sys_clk,
input uart_rxd,
output reg uart_txd,
input [15:0] divisor,
output reg [7:0] rx_data,
output reg rx_done,
input [7:0] tx_data,
input tx_wr,
output reg tx_done
);
//-----------------------------------------------------------------
// enable16 generator
//-----------------------------------------------------------------
reg [15:0] enable16_counter;
wire enable16;
assign enable16 = (enable16_counter == 16'd0);
always @(posedge sys_clk) begin
if(sys_rst)
enable16_counter <= divisor - 16'b1;
else begin
enable16_counter <= enable16_counter - 16'd1;
if(enable16)
enable16_counter <= divisor - 16'b1;
end
end
//-----------------------------------------------------------------
// Synchronize uart_rxd
//-----------------------------------------------------------------
reg uart_rxd1;
reg uart_rxd2;
always @(posedge sys_clk) begin
uart_rxd1 <= uart_rxd;
uart_rxd2 <= uart_rxd1;
end
//-----------------------------------------------------------------
// UART RX Logic
//-----------------------------------------------------------------
reg rx_busy;
reg [3:0] rx_count16;
reg [3:0] rx_bitcount;
reg [7:0] rxd_reg;
always @(posedge sys_clk) begin
if(sys_rst) begin
rx_done <= 1'b0;
rx_busy <= 1'b0;
rx_count16 <= 4'd0;
rx_bitcount <= 4'd0;
end else begin
rx_done <= 1'b0;
if(enable16) begin
if(~rx_busy) begin // look for start bit
if(~uart_rxd2) begin // start bit found
rx_busy <= 1'b1;
rx_count16 <= 4'd7;
rx_bitcount <= 4'd0;
end
end else begin
rx_count16 <= rx_count16 + 4'd1;
if(rx_count16 == 4'd0) begin // sample
rx_bitcount <= rx_bitcount + 4'd1;
if(rx_bitcount == 4'd0) begin // verify startbit
if(uart_rxd2)
rx_busy <= 1'b0;
end else if(rx_bitcount == 4'd9) begin
rx_busy <= 1'b0;
if(uart_rxd2) begin // stop bit ok
rx_data <= rxd_reg;
rx_done <= 1'b1;
end // ignore RX error
end else
rxd_reg <= {uart_rxd2, rxd_reg[7:1]};
end
end
end
end
end
//-----------------------------------------------------------------
// UART TX Logic
//-----------------------------------------------------------------
reg tx_busy;
reg [3:0] tx_bitcount;
reg [3:0] tx_count16;
reg [7:0] txd_reg;
always @(posedge sys_clk) begin
if(sys_rst) begin
tx_done <= 1'b0;
tx_busy <= 1'b0;
uart_txd <= 1'b1;
end else begin
tx_done <= 1'b0;
if(tx_wr) begin
txd_reg <= tx_data;
tx_bitcount <= 4'd0;
tx_count16 <= 4'd1;
tx_busy <= 1'b1;
uart_txd <= 1'b0;
`ifdef SIMULATION
$display("UART: %c", tx_data);
`endif
end else if(enable16 && tx_busy) begin
tx_count16 <= tx_count16 + 4'd1;
if(tx_count16 == 4'd0) begin
tx_bitcount <= tx_bitcount + 4'd1;
if(tx_bitcount == 4'd8) begin
uart_txd <= 1'b1;
end else if(tx_bitcount == 4'd9) begin
uart_txd <= 1'b1;
tx_busy <= 1'b0;
tx_done <= 1'b1;
end else begin
uart_txd <= txd_reg[0];
txd_reg <= {1'b0, txd_reg[7:1]};
end
end
end
end
end
endmodule
MMDIR=../..
include $(MMDIR)/software/include.mak
OBJECTS=crt0.o main.o boot.o
SEGMENTS=-j .text -j .data -j .rodata
all: bios.bin
%.bin: %.elf
$(OBJCOPY) $(SEGMENTS) -O binary $< $@
chmod -x $@
$(MMDIR)/tools/crc32 $@ write
bios.elf: linker.ld $(OBJECTS)
$(LD) $(LDFLAGS) -T linker.ld -N -o $@ $(OBJECTS) -L$(MMDIR)/software/libbase -lbase
chmod -x $@
.PHONY: clean depend
depend:
makedepend -Y -- $(CFLAGS) -- *.c
clean:
rm -f *.o bios.elf bios.bin .*~ *~ Makefile.bak
# DO NOT DELETE
boot.o: ../../software/include/stdio.h ../../software/include/stdlib.h
boot.o: ../../software/include/console.h ../../software/include/uart.h
boot.o: ../../software/include/system.h ../../software/include/board.h
boot.o: ../../software/include/crc.h ../../tools/sfl.h boot.h
main.o: ../../software/include/stdio.h ../../software/include/stdlib.h
main.o: ../../software/include/console.h ../../software/include/string.h
main.o: ../../software/include/uart.h ../../software/include/crc.h
main.o: ../../software/include/system.h ../../software/include/board.h
main.o: ../../software/include/version.h ../../software/include/hw/sysctl.h
main.o: ../../software/include/hw/common.h ../../software/include/hw/gpio.h
main.o: ../../software/include/hw/uart.h boot.h
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <console.h>
#include <uart.h>
#include <system.h>
#include <board.h>
#include <crc.h>
#include <sfl.h>
#include "boot.h"
extern const struct board_desc *brd_desc;
/*
* HACK: by defining this function as not inlinable, GCC will automatically
* put the values we want into the good registers because it has to respect
* the LM32 calling conventions.
*/
static void __attribute__((noinline)) __attribute__((noreturn)) boot(unsigned int r1, unsigned int r2, unsigned int r3, unsigned int addr)
{
asm volatile( /* Invalidate instruction cache */
"wcsr ICC, r0\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"call r4\n"
);
}
/* Note that we do not use the hw timer so that this function works
* even if the system controller has been disabled at synthesis.
*/
static int check_ack()
{
int timeout;
int recognized;
static const char str[SFL_MAGIC_LEN] = SFL_MAGIC_ACK;
timeout = 4500000;
recognized = 0;
while(timeout > 0) {
if(readchar_nonblock()) {
char c;
c = readchar();
if(c == str[recognized]) {
recognized++;
if(recognized == SFL_MAGIC_LEN)
return 1;
} else {
if(c == str[0])
recognized = 1;
else
recognized = 0;
}
}
timeout--;
}
return 0;
}
#define MAX_FAILED 5
void serialboot()
{
struct sfl_frame frame;
int failed;
unsigned int cmdline_adr, initrdstart_adr, initrdend_adr;
printf("I: Attempting serial firmware loading\n");
putsnonl(SFL_MAGIC_REQ);
if(!check_ack()) {
printf("E: Timeout\n");
return;
}
failed = 0;
cmdline_adr = initrdstart_adr = initrdend_adr = 0;
while(1) {
int i;
int actualcrc;
int goodcrc;
/* Grab one frame */
frame.length = readchar();
frame.crc[0] = readchar();
frame.crc[1] = readchar();
frame.cmd = readchar();
for(i=0;i<frame.length;i++)
frame.payload[i] = readchar();
/* Check CRC */
actualcrc = ((int)frame.crc[0] << 8)|(int)frame.crc[1];
goodcrc = crc16(&frame.cmd, frame.length+1);
if(actualcrc != goodcrc) {
failed++;
if(failed == MAX_FAILED) {
printf("E: Too many consecutive errors, aborting");
return;
}
writechar(SFL_ACK_CRCERROR);
continue;
}
/* CRC OK */
switch(frame.cmd) {
case SFL_CMD_ABORT:
failed = 0;
writechar(SFL_ACK_SUCCESS);
return;
case SFL_CMD_LOAD: {
char *writepointer;
failed = 0;
writepointer = (char *)(
((unsigned int)frame.payload[0] << 24)
|((unsigned int)frame.payload[1] << 16)
|((unsigned int)frame.payload[2] << 8)
|((unsigned int)frame.payload[3] << 0));
for(i=4;i<frame.length;i++)
*(writepointer++) = frame.payload[i];
writechar(SFL_ACK_SUCCESS);
break;
}
case SFL_CMD_JUMP: {
unsigned int addr;
failed = 0;
addr = ((unsigned int)frame.payload[0] << 24)
|((unsigned int)frame.payload[1] << 16)
|((unsigned int)frame.payload[2] << 8)
|((unsigned int)frame.payload[3] << 0);
writechar(SFL_ACK_SUCCESS);
boot(cmdline_adr, initrdstart_adr, initrdend_adr, addr);
break;
}
case SFL_CMD_CMDLINE:
failed = 0;
cmdline_adr = ((unsigned int)frame.payload[0] << 24)
|((unsigned int)frame.payload[1] << 16)
|((unsigned int)frame.payload[2] << 8)
|((unsigned int)frame.payload[3] << 0);
writechar(SFL_ACK_SUCCESS);
break;
case SFL_CMD_INITRDSTART:
failed = 0;
initrdstart_adr = ((unsigned int)frame.payload[0] << 24)
|((unsigned int)frame.payload[1] << 16)
|((unsigned int)frame.payload[2] << 8)
|((unsigned int)frame.payload[3] << 0);
writechar(SFL_ACK_SUCCESS);
break;
case SFL_CMD_INITRDEND:
failed = 0;
initrdend_adr = ((unsigned int)frame.payload[0] << 24)
|((unsigned int)frame.payload[1] << 16)
|((unsigned int)frame.payload[2] << 8)
|((unsigned int)frame.payload[3] << 0);
writechar(SFL_ACK_SUCCESS);
break;
default:
failed++;
if(failed == MAX_FAILED) {
printf("E: Too many consecutive errors, aborting");
return;
}
writechar(SFL_ACK_UNKNOWN);
break;
}
}
}
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __BOOT_H
#define __BOOT_H
void cardboot(int alt);
void serialboot();
#endif /* __BOOT_H */
/*
* LatticeMico32 C startup code.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* Exception handlers - Must be 32 bytes long. */
.section .text, "ax", @progbits
.global _start
_start:
_reset_handler:
xor r0, r0, r0
wcsr IE, r0
mvhi r1, hi(_reset_handler)
ori r1, r1, lo(_reset_handler)
wcsr EBA, r1
xor r2, r2, r2
calli _crt0
nop
_breakpoint_handler:
nop
nop
nop
nop
nop
nop
nop
nop
_instruction_bus_error_handler:
nop; nop; nop; nop
nop; nop; nop; nop
_watchpoint_hander:
nop; nop; nop; nop
nop; nop; nop; nop
_data_bus_error_handler:
nop; nop; nop; nop
nop; nop; nop; nop
_divide_by_zero_handler:
nop; nop; nop; nop
nop; nop; nop; nop
_interrupt_handler:
nop; nop; nop; nop
nop; nop; nop; nop
_system_call_handler:
nop; nop; nop; nop
nop; nop; nop; nop
_crt0:
/* Setup stack and global pointer */
mvhi sp, hi(_fstack)
ori sp, sp, lo(_fstack)
mvhi gp, hi(_gp)
ori gp, gp, lo(_gp)
/* Clear BSS */
mvhi r1, hi(_fbss)
ori r1, r1, lo(_fbss)
mvhi r3, hi(_ebss)
ori r3, r3, lo(_ebss)
.clearBSS:
be r1, r3, .callMain
sw (r1+0), r0
addi r1, r1, 4
bi .clearBSS
.callMain:
mv r1, r2
mvi r2, 0
mvi r3, 0
calli main
OUTPUT_FORMAT("elf32-lm32")
ENTRY(_start)
__DYNAMIC = 0;
MEMORY {
bram : ORIGIN = 0x00000000, LENGTH = 0x80000
sram : ORIGIN = 0x40000000, LENGTH = 0x80000
}
SECTIONS
{
.text :
{
_ftext = .;
*(.text .stub .text.* .gnu.linkonce.t.*)
_etext = .;
} > bram
.rodata :
{
. = ALIGN(4);
_frodata = .;
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.rodata1)
_erodata = .;
} > bram
.data :
{
. = ALIGN(4);
_fdata = .;
*(.data .data.* .gnu.linkonce.d.*)
*(.data1)
_gp = ALIGN(16);
*(.sdata .sdata.* .gnu.linkonce.s.*)
_edata = .;
} > bram
.bss :
{
. = ALIGN(4);
_fbss = .;
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
_ebss = .;
_end = .;
} > sram
}
PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram) - 4);
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <console.h>
#include <string.h>
#include <uart.h>
#include <crc.h>
#include <system.h>
#include <board.h>
#include <version.h>
#include <hw/sysctl.h>
#include <hw/gpio.h>
#include <hw/uart.h>
#include "boot.h"
const struct board_desc *brd_desc;
/* General address space functions */
#define NUMBER_OF_BYTES_ON_A_LINE 16
static void dump_bytes(unsigned int *ptr, int count, unsigned addr)
{
char *data = (char *)ptr;
int line_bytes = 0, i = 0;
putsnonl("Memory dump:");
while(count > 0){
line_bytes =
(count > NUMBER_OF_BYTES_ON_A_LINE)?
NUMBER_OF_BYTES_ON_A_LINE : count;
printf("\n0x%08x ", addr);
for(i=0;i<line_bytes;i++)
printf("%02x ", *(unsigned char *)(data+i));
for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
printf(" ");
printf(" ");
for(i=0;i<line_bytes;i++) {
if((*(data+i) < 0x20) || (*(data+i) > 0x7e))
printf(".");
else
printf("%c", *(data+i));
}
for(;i<NUMBER_OF_BYTES_ON_A_LINE;i++)
printf(" ");
data += (char)line_bytes;
count -= line_bytes;
addr += line_bytes;
}
printf("\n");
}
static void mr(char *startaddr, char *len)
{
char *c;
unsigned int *addr;
unsigned int length;
if(*startaddr == 0) {
printf("mr <address> [length]\n");
return;
}
addr = (unsigned *)strtoul(startaddr, &c, 0);
if(*c != 0) {
printf("incorrect address\n");
return;
}
if(*len == 0) {
length = 1;
} else {
length = strtoul(len, &c, 0);
if(*c != 0) {
printf("incorrect length\n");
return;
}
}
dump_bytes(addr, length, (unsigned)addr);
}
static void mw(char *addr, char *value, char *count)
{
char *c;
unsigned int *addr2;
unsigned int value2;
unsigned int count2;
unsigned int i;
if((*addr == 0) || (*value == 0)) {
printf("mw <address> <value> [count]\n");
return;
}
addr2 = (unsigned int *)strtoul(addr, &c, 0);
if(*c != 0) {
printf("incorrect address\n");
return;
}
value2 = strtoul(value, &c, 0);
if(*c != 0) {
printf("incorrect value\n");
return;
}
if(*count == 0) {
count2 = 1;
} else {
count2 = strtoul(count, &c, 0);
if(*c != 0) {
printf("incorrect count\n");
return;
}
}
for (i=0;i<count2;i++) *addr2++ = value2;
}
static void mc(char *dstaddr, char *srcaddr, char *count)
{
char *c;
unsigned int *dstaddr2;
unsigned int *srcaddr2;
unsigned int count2;
unsigned int i;
if((*dstaddr == 0) || (*srcaddr == 0)) {
printf("mc <dst> <src> [count]\n");
return;
}
dstaddr2 = (unsigned int *)strtoul(dstaddr, &c, 0);
if(*c != 0) {
printf("incorrect destination address\n");
return;
}
srcaddr2 = (unsigned int *)strtoul(srcaddr, &c, 0);
if(*c != 0) {
printf("incorrect source address\n");
return;
}
if(*count == 0) {
count2 = 1;
} else {
count2 = strtoul(count, &c, 0);
if(*c != 0) {
printf("incorrect count\n");
return;
}
}
for (i=0;i<count2;i++) *dstaddr2++ = *srcaddr2++;
}
static void crc(char *startaddr, char *len)
{
char *c;
char *addr;
unsigned int length;
if((*startaddr == 0)||(*len == 0)) {
printf("crc <address> <length>\n");
return;
}
addr = (char *)strtoul(startaddr, &c, 0);
if(*c != 0) {
printf("incorrect address\n");
return;
}
length = strtoul(len, &c, 0);
if(*c != 0) {
printf("incorrect length\n");
return;
}
printf("CRC32: %08x\n", crc32((unsigned char *)addr, length));
}
/* Init + command line */
static void help()
{
puts("This is the Milkymist BIOS debug shell.");
puts("Available commands:");
puts("mr - read address space");
puts("mw - write address space");
puts("mc - copy address space");
puts("crc - compute CRC32 of a part of the address space");
puts("serialboot - attempt SFL boot");
puts("reboot - system reset");
}
static char *get_token(char **str)
{
char *c, *d;
c = (char *)strchr(*str, ' ');
if(c == NULL) {
d = *str;
*str = *str+strlen(*str);
return d;
}
*c = 0;
d = *str;
*str = c+1;
return d;
}
static void do_command(char *c)
{
char *token;
token = get_token(&c);
if(strcmp(token, "mr") == 0) mr(get_token(&c), get_token(&c));
else if(strcmp(token, "mw") == 0) mw(get_token(&c), get_token(&c), get_token(&c));
else if(strcmp(token, "mc") == 0) mc(get_token(&c), get_token(&c), get_token(&c));
else if(strcmp(token, "crc") == 0) crc(get_token(&c), get_token(&c));
else if(strcmp(token, "serialboot") == 0) serialboot();
else if(strcmp(token, "reboot") == 0) reboot();
else if(strcmp(token, "help") == 0) help();
else if(strcmp(token, "") != 0)
printf("Command not found\n");
}
static int test_user_abort()
{
unsigned int i;
char c;
puts("I: Press Q to abort boot");
for(i=0;i<4000000;i++) {
if(readchar_nonblock()) {
c = readchar();
if(c == 'Q') {
puts("I: Aborted boot on user request");
return 0;
}
}
}
return 1;
}
extern unsigned int _edata;
static void crcbios()
{
unsigned int length;
unsigned int expected_crc;
unsigned int actual_crc;
/*
* _edata is located right after the end of the flat
* binary image. The CRC tool writes the 32-bit CRC here.
* We also use the address of _edata to know the length
* of our code.
*/
expected_crc = _edata;
length = (unsigned int)&_edata;
actual_crc = crc32((unsigned char *)0, length);
if(expected_crc == actual_crc)
printf("I: BIOS CRC passed (%08x)\n", actual_crc);
else {
printf("W: BIOS CRC failed (expected %08x, got %08x)\n", expected_crc, actual_crc);
printf("W: The system will continue, but expect problems.\n");
}
}
static void display_board()
{
if(brd_desc == NULL) {
printf("E: Running on unknown board (ID=0x%08x), startup aborted.\n", CSR_SYSTEM_ID);
while(1);
}
printf("I: Running on %s\n", brd_desc->name);
}
static const char banner[] =
"\nMILKYMIST(tm) v"VERSION" BIOS\thttp://www.milkymist.org\n"
"(c) 2007, 2008, 2009, 2011 Sebastien Bourdeauducq\n\n"
"This program is free software: you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n"
"the Free Software Foundation, version 3 of the License.\n\n";
static void boot_sequence()
{
if(test_user_abort()) {
serialboot(1);
printf("E: No boot medium found\n");
}
}
int main(int i, char **c)
{
char buffer[64];
brd_desc = get_board_desc();
/* Display a banner as soon as possible to show that the system is alive */
putsnonl(banner);
crcbios();
display_board();
boot_sequence();
while(1) {
putsnonl("\e[1mBIOS>\e[0m ");
readstr(buffer, 64);
do_command(buffer);
}
return 0;
}
# Mico32 toolchain
#
AS=lm32-rtems4.11-as
CC=lm32-rtems4.11-gcc
LD=lm32-rtems4.11-ld
OBJCOPY=lm32-rtems4.11-objcopy
AR=lm32-rtems4.11-ar
RANLIB=lm32-rtems4.11-ranlib
# Toolchain options
#
INCLUDES=-I$(MMDIR)/software/include -I$(MMDIR)/tools
ASFLAGS=$(INCLUDES)
CFLAGS=-O9 -Wall -fomit-frame-pointer -fno-builtin -fsigned-char -fsingle-precision-constant $(INCLUDES)
LDFLAGS=-nostdlib -nodefaultlibs
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
* Copyright (C) Linux kernel developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ASSERT_H
#define __ASSERT_H
#define assert(x)
#endif /* __ASSERT_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009, 2011 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __BOARD_H
#define __BOARD_H
#define BOARD_NAME_LEN 32
struct board_desc {
unsigned int id;
char name[BOARD_NAME_LEN];
unsigned int clk_frequency;
};
const struct board_desc *get_board_desc_id(unsigned int id);
const struct board_desc *get_board_desc();
#endif /* __BOARD_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CONSOLE_H
#define __CONSOLE_H
int puts(const char *s);
void putsnonl(const char *s);
void readstr(char *s, int size);
#endif /* __CONSOLE_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CRC_H
#define __CRC_H
unsigned short crc16(const unsigned char *buffer, int len);
unsigned int crc32(const unsigned char *buffer, unsigned int len);
#endif
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CTYPE_H
#define __CTYPE_H
static inline int isdigit(char c)
{
return (c >= '0') && (c <= '9');
}
static inline int isxdigit(char c)
{
return isdigit(c) || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'));
}
static inline int isupper(char c)
{
return (c >= 'A') && (c <= 'Z');
}
static inline int islower(char c)
{
return (c >= 'a') && (c <= 'z');
}
static inline unsigned char tolower(unsigned char c)
{
if (isupper(c))
c -= 'A'-'a';
return c;
}
static inline unsigned char toupper(unsigned char c)
{
if (islower(c))
c -= 'a'-'A';
return c;
}
static inline char isspace(unsigned char c)
{
if(c == ' '
|| c == '\f'
|| c == '\n'
|| c == '\r'
|| c == '\t'
|| c == '\v')
return 1;
return 0;
}
#endif /* __CTYPE_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ENDIAN_H
#define __ENDIAN_H
#define __LITTLE_ENDIAN 0
#define __BIG_ENDIAN 1
#define __BYTE_ORDER __BIG_ENDIAN
static inline unsigned int le32toh(unsigned int val)
{
return (val & 0xff) << 24 |
(val & 0xff00) << 8 |
(val & 0xff0000) >> 8 |
(val & 0xff000000) >> 24;
}
static inline unsigned short le16toh(unsigned short val)
{
return (val & 0xff) << 8 |
(val & 0xff00) >> 8;
}
#endif /* __ENDIAN_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __HW_COMMON_H
#define __HW_COMMON_H
#ifdef __ASSEMBLER__
#define MMPTR(x) x
#else
#define MMPTR(x) (*((volatile unsigned int *)(x)))
#endif
#endif
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __HW_GPIO_H
#define __HW_GPIO_H
/* Inputs */
#define GPIO_PBN (0x00000001)
#define GPIO_PBW (0x00000002)
#define GPIO_PBS (0x00000004)
#define GPIO_PBE (0x00000008)
#define GPIO_PBC (0x00000010)
#define GPIO_DIP1 (0x00000020)
#define GPIO_DIP2 (0x00000040)
#define GPIO_DIP3 (0x00000080)
#define GPIO_DIP4 (0x00000100)
#define GPIO_DIP5 (0x00000200)
#define GPIO_DIP6 (0x00000400)
#define GPIO_DIP7 (0x00000800)
#define GPIO_DIP8 (0x00001000)
/* Outputs */
#define GPIO_LED2 (0x00000001)
#define GPIO_LED3 (0x00000002)
#define GPIO_LEDN (0x00000004)
#define GPIO_LEDW (0x00000008)
#define GPIO_LEDS (0x00000010)
#define GPIO_LEDE (0x00000020)
#define GPIO_LEDC (0x00000040)
#define GPIO_HDLCDE (0x00000080)
#define GPIO_HDLCDRS (0x00000100)
#define GPIO_HDLCDRW (0x00000200)
#define GPIO_HDLCDD_SHIFT (10)
#define GPIO_HDLCDD4 (0x00000400)
#define GPIO_HDLCDD5 (0x00000800)
#define GPIO_HDLCDD6 (0x00001000)
#define GPIO_HDLCDD7 (0x00002000)
#endif /* __HW_GPIO_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009, 2011 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __INTERRUPTS_H
#define __INTERRUPTS_H
#define IRQ_GPIO (0x00000001)
#define IRQ_TIMER0 (0x00000002)
#define IRQ_TIMER1 (0x00000004)
#define IRQ_UARTRX (0x00000008)
#define IRQ_UARTTX (0x00000010)
#endif /* __INTERRUPTS_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __HW_SYSCTL_H
#define __HW_SYSCTL_H
#include <hw/common.h>
#define CSR_GPIO_IN MMPTR(0x80001000)
#define CSR_GPIO_OUT MMPTR(0x80001004)
#define CSR_GPIO_INTEN MMPTR(0x80001008)
#define CSR_TIMER0_CONTROL MMPTR(0x80001010)
#define CSR_TIMER0_COMPARE MMPTR(0x80001014)
#define CSR_TIMER0_COUNTER MMPTR(0x80001018)
#define CSR_TIMER1_CONTROL MMPTR(0x80001020)
#define CSR_TIMER1_COMPARE MMPTR(0x80001024)
#define CSR_TIMER1_COUNTER MMPTR(0x80001028)
#define TIMER_ENABLE (0x01)
#define TIMER_AUTORESTART (0x02)
#define CSR_SYSTEM_ID MMPTR(0x8000103c)
#endif /* __HW_SYSCTL_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __HW_UART_H
#define __HW_UART_H
#include <hw/common.h>
#define CSR_UART_RXTX MMPTR(0x80000000)
#define CSR_UART_DIVISOR MMPTR(0x80000004)
#endif /* __HW_UART_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __IRQ_H
#define __IRQ_H
void irq_enable(unsigned int en);
unsigned int irq_isenabled(); /* < can we get interrupted? returns 0 within ISRs */
void irq_setmask(unsigned int mask);
unsigned int irq_getmask();
unsigned int irq_pending();
void irq_ack(unsigned int mask);
#endif /* __IRQ_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
* Copyright (C) Linux kernel developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LIMITS_H
#define __LIMITS_H
#define INT_MIN ((((unsigned long)-1) >> 1) + 1)
#define INT_MAX (((unsigned long)-1) >> 1)
#endif /* __LIMITS_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
* Copyright (C) Linux kernel developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __STDARG_H
#define __STDARG_H
#include <stdlib.h>
#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4))
#define va_start(v,l) __builtin_va_start((v),l)
#else
#define va_start(v,l) __builtin_stdarg_start((v),l)
#endif
#define va_arg(ap, type) \
__builtin_va_arg((ap), type)
#define va_end(ap) \
__builtin_va_end(ap)
#define va_list \
__builtin_va_list
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
int vsprintf(char *buf, const char *fmt, va_list args);
#endif /* __STDARG_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __STDIO_H
#define __STDIO_H
#include <stdlib.h>
int snprintf(char *buf, size_t size, const char *fmt, ...);
int scnprintf(char *buf, size_t size, const char *fmt, ...);
int sprintf(char *buf, const char *fmt, ...);
int printf(const char *fmt, ...);
#endif /* __STDIO_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
* Copyright (C) Linux kernel developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __STDLIB_H
#define __STDLIB_H
#define PRINTF_ZEROPAD 1 /* pad with zero */
#define PRINTF_SIGN 2 /* unsigned/signed long */
#define PRINTF_PLUS 4 /* show plus */
#define PRINTF_SPACE 8 /* space if plus */
#define PRINTF_LEFT 16 /* left justified */
#define PRINTF_SPECIAL 32 /* 0x */
#define PRINTF_LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
typedef int size_t;
typedef int ptrdiff_t;
#define NULL ((void *)0)
#define likely(x) x
#define unlikely(x) x
#define abs(x) ((x) > 0 ? (x) : -(x))
unsigned long strtoul(const char *nptr, char **endptr, int base);
int skip_atoi(const char **s);
static inline int atoi(const char *nptr) {
return strtoul(nptr, NULL, 0);
}
static inline long atol(const char *nptr) {
return (long)atoi(nptr);
}
char *number(char *buf, char *end, unsigned long num, int base, int size, int precision, int type);
long strtol(const char *nptr, char **endptr, int base);
float atof(const char *s);
unsigned int rand();
void *malloc(size_t size);
void free(void *p);
#endif /* __STDLIB_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
* Copyright (C) Linux kernel developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __STRING_H
#define __STRING_H
#include <stdlib.h>
char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
char *strnchr(const char *s, size_t count, int c);
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t count);
int strcmp(const char *cs, const char *ct);
int strncmp(const char *cs, const char *ct, size_t count);
size_t strlen(const char *s);
size_t strnlen(const char *s, size_t count);
int memcmp(const void *cs, const void *ct, size_t count);
void *memset(void *s, int c, size_t count);
void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t count);
#endif /* __STRING_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SYSTEM_H
#define __SYSTEM_H
__attribute__((noreturn)) void reboot();
#endif /* __SYSTEM_H */
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __UART_H
#define __UART_H
void uart_async_init();
void uart_async_isr_rx();
void uart_async_isr_tx();
void uart_force_sync(int f);
void writechar(char c);
char readchar();
int readchar_nonblock();
#endif
#ifndef __VERSION_H
#define __VERSION_H
#define VERSION "0.2-tdc"
#endif /* __VERSION_H */
MMDIR=../..
include $(MMDIR)/software/include.mak
OBJECTS=_ashlsi3.o _divsi3.o _modsi3.o _udivmodsi4.o _umodsi3.o _ashrsi3.o _lshrsi3.o _mulsi3.o _udivsi3.o
OBJECTS+=libc.o crc16.o crc32.o console.o system.o board.o irq.o vsnprintf-nofloat.o uart.o
all: libbase.a
libbase.a: $(OBJECTS)
$(AR) clr libbase.a $(OBJECTS)
$(RANLIB) libbase.a
.PHONY: clean depend
depend:
makedepend -Y -- $(CFLAGS) -- *.c
clean:
rm -f *.o libbase.a .*~ *~ Makefile.bak
# DO NOT DELETE
board.o: ../../software/include/hw/sysctl.h
board.o: ../../software/include/hw/common.h ../../software/include/stdlib.h
board.o: ../../software/include/board.h
console.o: ../../software/include/uart.h ../../software/include/console.h
console.o: ../../software/include/stdio.h ../../software/include/stdlib.h
console.o: ../../software/include/stdarg.h
crc16.o: ../../software/include/crc.h
crc32.o: ../../software/include/crc.h
_divsi3.o: libgcc_lm32.h
libc.o: ../../software/include/ctype.h ../../software/include/stdio.h
libc.o: ../../software/include/stdlib.h ../../software/include/stdarg.h
libc.o: ../../software/include/string.h ../../software/include/limits.h
_modsi3.o: libgcc_lm32.h
_mulsi3.o: libgcc_lm32.h
system.o: ../../software/include/irq.h ../../software/include/uart.h
system.o: ../../software/include/hw/sysctl.h
system.o: ../../software/include/hw/common.h ../../software/include/system.h
uart-async.o: ../../software/include/uart.h ../../software/include/irq.h
uart-async.o: ../../software/include/hw/uart.h
uart-async.o: ../../software/include/hw/common.h
uart-async.o: ../../software/include/hw/interrupts.h
uart.o: ../../software/include/uart.h ../../software/include/irq.h
uart.o: ../../software/include/hw/uart.h ../../software/include/hw/common.h
uart.o: ../../software/include/hw/interrupts.h
_udivmodsi4.o: libgcc_lm32.h
_udivsi3.o: libgcc_lm32.h
_umodsi3.o: libgcc_lm32.h
vsnprintf-nofloat.o: ../../software/include/stdlib.h
vsnprintf-nofloat.o: ../../software/include/stdio.h
vsnprintf-nofloat.o: ../../software/include/stdarg.h
vsnprintf-nofloat.o: ../../software/include/string.h
vsnprintf-nofloat.o: ../../software/include/ctype.h
# _ashlsi3.S for Lattice Mico32
# Contributed by Jon Beniston <jon@beniston.com> and Richard Henderson.
#
# Copyright (C) 2009 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3, or (at your option) any
# later version.
#
# This file is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# Under Section 7 of GPL version 3, you are granted additional
# permissions described in the GCC Runtime Library Exception, version
# 3.1, as published by the Free Software Foundation.
#
# You should have received a copy of the GNU General Public License and
# a copy of the GCC Runtime Library Exception along with this program;
# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
# <http://www.gnu.org/licenses/>.
#
/* Arithmetic left shift. */
.text
.global __ashlsi3
.type __ashlsi3,@function
.align 4
__ashlsi3:
/* Only use 5 LSBs, as that's all the h/w shifter uses. */
andi r2, r2, 0x1f
/* Get address of offset into unrolled shift loop to jump to. */
#ifdef __PIC__
lw r3, (gp+got(__ashlsi3_0))
#else
mvhi r3, hi(__ashlsi3_0)
ori r3, r3, lo(__ashlsi3_0)
#endif
add r2, r2, r2
add r2, r2, r2
sub r3, r3, r2
b r3
__ashlsi3_31:
add r1, r1, r1
__ashlsi3_30:
add r1, r1, r1
__ashlsi3_29:
add r1, r1, r1
__ashlsi3_28:
add r1, r1, r1
__ashlsi3_27:
add r1, r1, r1
__ashlsi3_26:
add r1, r1, r1
__ashlsi3_25:
add r1, r1, r1
__ashlsi3_24:
add r1, r1, r1
__ashlsi3_23:
add r1, r1, r1
__ashlsi3_22:
add r1, r1, r1
__ashlsi3_21:
add r1, r1, r1
__ashlsi3_20:
add r1, r1, r1
__ashlsi3_19:
add r1, r1, r1
__ashlsi3_18:
add r1, r1, r1
__ashlsi3_17:
add r1, r1, r1
__ashlsi3_16:
add r1, r1, r1
__ashlsi3_15:
add r1, r1, r1
__ashlsi3_14:
add r1, r1, r1
__ashlsi3_13:
add r1, r1, r1
__ashlsi3_12:
add r1, r1, r1
__ashlsi3_11:
add r1, r1, r1
__ashlsi3_10:
add r1, r1, r1
__ashlsi3_9:
add r1, r1, r1
__ashlsi3_8:
add r1, r1, r1
__ashlsi3_7:
add r1, r1, r1
__ashlsi3_6:
add r1, r1, r1
__ashlsi3_5:
add r1, r1, r1
__ashlsi3_4:
add r1, r1, r1
__ashlsi3_3:
add r1, r1, r1
__ashlsi3_2:
add r1, r1, r1
__ashlsi3_1:
add r1, r1, r1
__ashlsi3_0:
ret
\ No newline at end of file
# _ashrsi3.S for Lattice Mico32
# Contributed by Jon Beniston <jon@beniston.com> and Richard Henderson.
#
# Copyright (C) 2009 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3, or (at your option) any
# later version.
#
# This file is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# Under Section 7 of GPL version 3, you are granted additional
# permissions described in the GCC Runtime Library Exception, version
# 3.1, as published by the Free Software Foundation.
#
# You should have received a copy of the GNU General Public License and
# a copy of the GCC Runtime Library Exception along with this program;
# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
# <http://www.gnu.org/licenses/>.
#
/* Arithmetic right shift. */
.global __ashrsi3
.type __ashrsi3,@function
__ashrsi3:
/* Only use 5 LSBs, as that's all the h/w shifter uses. */
andi r2, r2, 0x1f
/* Get address of offset into unrolled shift loop to jump to. */
#ifdef __PIC__
lw r3, (gp+got(__ashrsi3_0))
#else
mvhi r3, hi(__ashrsi3_0)
ori r3, r3, lo(__ashrsi3_0)
#endif
add r2, r2, r2
add r2, r2, r2
sub r3, r3, r2
b r3
__ashrsi3_31:
sri r1, r1, 1
__ashrsi3_30:
sri r1, r1, 1
__ashrsi3_29:
sri r1, r1, 1
__ashrsi3_28:
sri r1, r1, 1
__ashrsi3_27:
sri r1, r1, 1
__ashrsi3_26:
sri r1, r1, 1
__ashrsi3_25:
sri r1, r1, 1
__ashrsi3_24:
sri r1, r1, 1
__ashrsi3_23:
sri r1, r1, 1
__ashrsi3_22:
sri r1, r1, 1
__ashrsi3_21:
sri r1, r1, 1
__ashrsi3_20:
sri r1, r1, 1
__ashrsi3_19:
sri r1, r1, 1
__ashrsi3_18:
sri r1, r1, 1
__ashrsi3_17:
sri r1, r1, 1
__ashrsi3_16:
sri r1, r1, 1
__ashrsi3_15:
sri r1, r1, 1
__ashrsi3_14:
sri r1, r1, 1
__ashrsi3_13:
sri r1, r1, 1
__ashrsi3_12:
sri r1, r1, 1
__ashrsi3_11:
sri r1, r1, 1
__ashrsi3_10:
sri r1, r1, 1
__ashrsi3_9:
sri r1, r1, 1
__ashrsi3_8:
sri r1, r1, 1
__ashrsi3_7:
sri r1, r1, 1
__ashrsi3_6:
sri r1, r1, 1
__ashrsi3_5:
sri r1, r1, 1
__ashrsi3_4:
sri r1, r1, 1
__ashrsi3_3:
sri r1, r1, 1
__ashrsi3_2:
sri r1, r1, 1
__ashrsi3_1:
sri r1, r1, 1
__ashrsi3_0:
ret
\ No newline at end of file
/* _divsi3 for Lattice Mico32.
Contributed by Jon Beniston <jon@beniston.com>
Copyright (C) 2009 Free Software Foundation, Inc.
This file is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#include "libgcc_lm32.h"
/* Signed integer division. */
static const UQItype __divsi3_table[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 4, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 5, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 6, 3, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 7, 3, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 8, 4, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
0, 9, 4, 3, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
0, 10, 5, 3, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
0, 11, 5, 3, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
0, 12, 6, 4, 3, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0,
0, 13, 6, 4, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 14, 7, 4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0,
0, 15, 7, 5, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
};
SItype
__divsi3 (SItype a, SItype b)
{
int neg = 0;
SItype res;
int cfg;
if (b == 0)
{
/* Raise divide by zero exception. */
int eba, sr;
/* Save interrupt enable. */
__asm__ __volatile__ ("rcsr %0, IE":"=r" (sr));
sr = (sr & 1) << 1;
__asm__ __volatile__ ("wcsr IE, %0"::"r" (sr));
/* Branch to exception handler. */
__asm__ __volatile__ ("rcsr %0, EBA":"=r" (eba));
eba += 32 * 5;
__asm__ __volatile__ ("mv ea, ra");
__asm__ __volatile__ ("b %0"::"r" (eba));
__builtin_unreachable ();
}
if (((USItype) (a | b)) < 16)
res = __divsi3_table[(a << 4) + b];
else
{
if (a < 0)
{
a = -a;
neg = !neg;
}
if (b < 0)
{
b = -b;
neg = !neg;
}
__asm__ ("rcsr %0, CFG":"=r" (cfg));
if (cfg & 2)
__asm__ ("divu %0, %1, %2": "=r" (res):"r" (a), "r" (b));
else
res = __udivmodsi4 (a, b, 0);
if (neg)
res = -res;
}
return res;
}
# _lshrsi3.S for Lattice Mico32
# Contributed by Jon Beniston <jon@beniston.com> and Richard Henderson.
#
# Copyright (C) 2009 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3, or (at your option) any
# later version.
#
# This file is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# Under Section 7 of GPL version 3, you are granted additional
# permissions described in the GCC Runtime Library Exception, version
# 3.1, as published by the Free Software Foundation.
#
# You should have received a copy of the GNU General Public License and
# a copy of the GCC Runtime Library Exception along with this program;
# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
# <http://www.gnu.org/licenses/>.
#
/* Logical right shift. */
.global __lshrsi3
.type __lshrsi3,@function
__lshrsi3:
/* Only use 5 LSBs, as that's all the h/w shifter uses. */
andi r2, r2, 0x1f
/* Get address of offset into unrolled shift loop to jump to. */
#ifdef __PIC__
lw r3, (gp+got(__lshrsi3_0))
#else
mvhi r3, hi(__lshrsi3_0)
ori r3, r3, lo(__lshrsi3_0)
#endif
add r2, r2, r2
add r2, r2, r2
sub r3, r3, r2
b r3
__lshrsi3_31:
srui r1, r1, 1
__lshrsi3_30:
srui r1, r1, 1
__lshrsi3_29:
srui r1, r1, 1
__lshrsi3_28:
srui r1, r1, 1
__lshrsi3_27:
srui r1, r1, 1
__lshrsi3_26:
srui r1, r1, 1
__lshrsi3_25:
srui r1, r1, 1
__lshrsi3_24:
srui r1, r1, 1
__lshrsi3_23:
srui r1, r1, 1
__lshrsi3_22:
srui r1, r1, 1
__lshrsi3_21:
srui r1, r1, 1
__lshrsi3_20:
srui r1, r1, 1
__lshrsi3_19:
srui r1, r1, 1
__lshrsi3_18:
srui r1, r1, 1
__lshrsi3_17:
srui r1, r1, 1
__lshrsi3_16:
srui r1, r1, 1
__lshrsi3_15:
srui r1, r1, 1
__lshrsi3_14:
srui r1, r1, 1
__lshrsi3_13:
srui r1, r1, 1
__lshrsi3_12:
srui r1, r1, 1
__lshrsi3_11:
srui r1, r1, 1
__lshrsi3_10:
srui r1, r1, 1
__lshrsi3_9:
srui r1, r1, 1
__lshrsi3_8:
srui r1, r1, 1
__lshrsi3_7:
srui r1, r1, 1
__lshrsi3_6:
srui r1, r1, 1
__lshrsi3_5:
srui r1, r1, 1
__lshrsi3_4:
srui r1, r1, 1
__lshrsi3_3:
srui r1, r1, 1
__lshrsi3_2:
srui r1, r1, 1
__lshrsi3_1:
srui r1, r1, 1
__lshrsi3_0:
ret
/* _modsi3 for Lattice Mico32.
Contributed by Jon Beniston <jon@beniston.com>
Copyright (C) 2009 Free Software Foundation, Inc.
This file is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#include "libgcc_lm32.h"
/* Signed integer modulus. */
SItype
__modsi3 (SItype a, SItype b)
{
int neg = 0;
SItype res;
int cfg;
if (b == 0)
{
/* Raise divide by zero exception. */
int eba, sr;
/* Save interrupt enable. */
__asm__ __volatile__ ("rcsr %0, IE":"=r" (sr));
sr = (sr & 1) << 1;
__asm__ __volatile__ ("wcsr IE, %0"::"r" (sr));
/* Branch to exception handler. */
__asm__ __volatile__ ("rcsr %0, EBA":"=r" (eba));
eba += 32 * 5;
__asm__ __volatile__ ("mv ea, ra");
__asm__ __volatile__ ("b %0"::"r" (eba));
__builtin_unreachable ();
}
if (a < 0)
{
a = -a;
neg = 1;
}
if (b < 0)
b = -b;
__asm__ ("rcsr %0, CFG":"=r" (cfg));
if (cfg & 2)
__asm__ ("modu %0, %1, %2": "=r" (res):"r" (a), "r" (b));
else
res = __udivmodsi4 (a, b, 1);
if (neg)
res = -res;
return res;
}
/* _mulsi3 for Lattice Mico32.
Contributed by Jon Beniston <jon@beniston.com>
Copyright (C) 2009 Free Software Foundation, Inc.
This file is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#include "libgcc_lm32.h"
/* Integer multiplication. */
USItype
__mulsi3 (USItype a, USItype b)
{
USItype result;
result = 0;
if (a == 0)
return 0;
while (b != 0)
{
if (b & 1)
result += a;
a <<= 1;
b >>= 1;
}
return result;
}
/* _udivmodsi4 for Lattice Mico32.
Contributed by Jon Beniston <jon@beniston.com>
Copyright (C) 2009 Free Software Foundation, Inc.
This file is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#include "libgcc_lm32.h"
/* Unsigned integer division/modulus. */
USItype
__udivmodsi4 (USItype num, USItype den, int modwanted)
{
USItype bit = 1;
USItype res = 0;
while (den < num && bit && !(den & (1L << 31)))
{
den <<= 1;
bit <<= 1;
}
while (bit)
{
if (num >= den)
{
num -= den;
res |= bit;
}
bit >>= 1;
den >>= 1;
}
if (modwanted)
return num;
return res;
}
/* _udivsi3 for Lattice Mico32.
Contributed by Jon Beniston <jon@beniston.com>
Copyright (C) 2009 Free Software Foundation, Inc.
This file is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#include "libgcc_lm32.h"
/* Unsigned integer division. */
USItype
__udivsi3 (USItype a, USItype b)
{
if (b == 0)
{
/* Raise divide by zero exception. */
int eba, sr;
/* Save interrupt enable. */
__asm__ __volatile__ ("rcsr %0, IE":"=r" (sr));
sr = (sr & 1) << 1;
__asm__ __volatile__ ("wcsr IE, %0"::"r" (sr));
/* Branch to exception handler. */
__asm__ __volatile__ ("rcsr %0, EBA":"=r" (eba));
eba += 32 * 5;
__asm__ __volatile__ ("mv ea, ra");
__asm__ __volatile__ ("b %0"::"r" (eba));
__builtin_unreachable ();
}
return __udivmodsi4 (a, b, 0);
}
/* _umodsi3 for Lattice Mico32.
Contributed by Jon Beniston <jon@beniston.com>
Copyright (C) 2009 Free Software Foundation, Inc.
This file is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#include "libgcc_lm32.h"
/* Unsigned modulus. */
USItype
__umodsi3 (USItype a, USItype b)
{
if (b == 0)
{
/* Raise divide by zero exception. */
int eba, sr;
/* Save interrupt enable. */
__asm__ __volatile__ ("rcsr %0, IE":"=r" (sr));
sr = (sr & 1) << 1;
__asm__ __volatile__ ("wcsr IE, %0"::"r" (sr));
/* Branch to exception handler. */
__asm__ __volatile__ ("rcsr %0, EBA":"=r" (eba));
eba += 32 * 5;
__asm__ __volatile__ ("mv ea, ra");
__asm__ __volatile__ ("b %0"::"r" (eba));
__builtin_unreachable ();
}
return __udivmodsi4 (a, b, 1);
}
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
* Copyright (C) 2011 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <hw/sysctl.h>
#include <stdlib.h>
#include <board.h>
static const struct board_desc boards[1] = {
{
.id = 0x53504543, /* SPEC */
.name = "SPEC",
.clk_frequency = 125000000,
},
};
const struct board_desc *get_board_desc_id(unsigned int id)
{
unsigned int i;
for(i=0;i<sizeof(boards)/sizeof(boards[0]);i++)
if(boards[i].id == id)
return &boards[i];
return NULL;
}
const struct board_desc *get_board_desc()
{
return get_board_desc_id(CSR_SYSTEM_ID);
}
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <uart.h>
#include <console.h>
#include <stdio.h>
#include <stdarg.h>
int puts(const char *s)
{
while(*s) {
writechar(*s);
s++;
}
writechar('\n');
return 1;
}
void putsnonl(const char *s)
{
while(*s) {
writechar(*s);
s++;
}
}
void readstr(char *s, int size)
{
char c;
int ptr;
ptr = 0;
while(1) {
c = readchar();
switch(c) {
case 0x7f:
case 0x08:
if(ptr > 0) {
ptr--;
putsnonl("\x08 \x08");
}
break;
case '\r':
case '\n':
s[ptr] = 0x00;
putsnonl("\n");
return;
default:
writechar(c);
s[ptr] = c;
ptr++;
break;
}
}
}
int printf(const char *fmt, ...)
{
va_list args;
int len;
char outbuf[256];
va_start(args, fmt);
len = vscnprintf(outbuf, sizeof(outbuf), fmt, args);
va_end(args);
outbuf[len] = 0;
putsnonl(outbuf);
return len;
}
#include <crc.h>
unsigned int crc16_table[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
unsigned short crc16(const unsigned char *buffer, int len)
{
unsigned short crc;
crc = 0;
while(len-- > 0)
crc = crc16_table[((crc >> 8) ^ (*buffer++)) & 0xFF] ^ (crc << 8);
return crc;
}
/* crc32.c -- compute the CRC-32 of a data stream
* Copyright (C) 1995-1998 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include <crc.h>
const unsigned int crc_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
0x2d02ef8dL
};
#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
#define DO2(buf) DO1(buf); DO1(buf);
#define DO4(buf) DO2(buf); DO2(buf);
#define DO8(buf) DO4(buf); DO4(buf);
unsigned int crc32(const unsigned char *buffer, unsigned int len)
{
unsigned int crc;
crc = 0;
crc = crc ^ 0xffffffffL;
while(len >= 8) {
DO8(buffer);
len -= 8;
}
if(len) do {
DO1(buffer);
} while(--len);
return crc ^ 0xffffffffL;
}
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
.section .text, "ax", @progbits
.global irq_enable, irq_isenabled, irq_setmask, irq_getmask, irq_pending, irq_ack
/* Parameter: 1=enable, 0=disable */
irq_enable:
wcsr IE, r1
ret
/* No parameter */
/* Return value: 1/0 */
irq_isenabled:
rcsr r1, IE
andi r1, r1, 1
ret
/* Parameter: the mask */
irq_setmask:
wcsr IM, r1
ret
/* No parameter */
/* Return value: the mask */
irq_getmask:
rcsr r1, IM
ret
/* No parameter */
/* Return value: pending IRQs */
irq_pending:
rcsr r1, IP
ret
/* Parameter: the mask */
irq_ack:
wcsr IP, r1
ret
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
* Copyright (C) Linux kernel developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <limits.h>
/**
* strchr - Find the first occurrence of a character in a string
* @s: The string to be searched
* @c: The character to search for
*/
char *strchr(const char *s, int c)
{
for (; *s != (char)c; ++s)
if (*s == '\0')
return NULL;
return (char *)s;
}
/**
* strrchr - Find the last occurrence of a character in a string
* @s: The string to be searched
* @c: The character to search for
*/
char *strrchr(const char *s, int c)
{
const char *p = s + strlen(s);
do {
if (*p == (char)c)
return (char *)p;
} while (--p >= s);
return NULL;
}
/**
* strnchr - Find a character in a length limited string
* @s: The string to be searched
* @count: The number of characters to be searched
* @c: The character to search for
*/
char *strnchr(const char *s, size_t count, int c)
{
for (; count-- && *s != '\0'; ++s)
if (*s == (char)c)
return (char *)s;
return NULL;
}
/**
* strcpy - Copy a %NUL terminated string
* @dest: Where to copy the string to
* @src: Where to copy the string from
*/
char *strcpy(char *dest, const char *src)
{
char *tmp = dest;
while ((*dest++ = *src++) != '\0')
/* nothing */;
return tmp;
}
/**
* strncpy - Copy a length-limited, %NUL-terminated string
* @dest: Where to copy the string to
* @src: Where to copy the string from
* @count: The maximum number of bytes to copy
*
* The result is not %NUL-terminated if the source exceeds
* @count bytes.
*
* In the case where the length of @src is less than that of
* count, the remainder of @dest will be padded with %NUL.
*
*/
char *strncpy(char *dest, const char *src, size_t count)
{
char *tmp = dest;
while (count) {
if ((*tmp = *src) != 0)
src++;
tmp++;
count--;
}
return dest;
}
/**
* strcmp - Compare two strings
* @cs: One string
* @ct: Another string
*/
int strcmp(const char *cs, const char *ct)
{
signed char __res;
while (1) {
if ((__res = *cs - *ct++) != 0 || !*cs++)
break;
}
return __res;
}
/**
* strncmp - Compare two strings using the first characters only
* @cs: One string
* @ct: Another string
* @count: Number of characters
*/
int strncmp(const char *cs, const char *ct, size_t count)
{
signed char __res;
size_t n;
n = 0;
__res = 0;
while (n < count) {
if ((__res = *cs - *ct++) != 0 || !*cs++)
break;
n++;
}
return __res;
}
/**
* strlen - Find the length of a string
* @s: The string to be sized
*/
size_t strlen(const char *s)
{
const char *sc;
for (sc = s; *sc != '\0'; ++sc)
/* nothing */;
return sc - s;
}
/**
* strnlen - Find the length of a length-limited string
* @s: The string to be sized
* @count: The maximum number of bytes to search
*/
size_t strnlen(const char *s, size_t count)
{
const char *sc;
for (sc = s; count-- && *sc != '\0'; ++sc)
/* nothing */;
return sc - s;
}
/**
* memcmp - Compare two areas of memory
* @cs: One area of memory
* @ct: Another area of memory
* @count: The size of the area.
*/
int memcmp(const void *cs, const void *ct, size_t count)
{
const unsigned char *su1, *su2;
int res = 0;
for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
if ((res = *su1 - *su2) != 0)
break;
return res;
}
/**
* memset - Fill a region of memory with the given value
* @s: Pointer to the start of the area.
* @c: The byte to fill the area with
* @count: The size of the area.
*/
void *memset(void *s, int c, size_t count)
{
char *xs = s;
while (count--)
*xs++ = c;
return s;
}
/**
* memcpy - Copies one area of memory to another
* @dest: Destination
* @src: Source
* @n: The size to copy.
*/
void *memcpy(void *dest, const void *src, size_t n)
{
char *_dest = (char *)dest;
char *_src = (char *)src;
size_t i;
for(i=0;i<n;i++)
_dest[i] = _src[i];
return dest;
}
/**
* memmove - Copies one area of memory to another, overlap possible
* @dest: Destination
* @src: Source
* @n: The size to copy.
*/
void *memmove(void *dest, const void *src, size_t count)
{
char *tmp, *s;
if(dest <= src) {
tmp = (char *) dest;
s = (char *) src;
while(count--)
*tmp++ = *s++;
} else {
tmp = (char *)dest + count;
s = (char *)src + count;
while(count--)
*--tmp = *--s;
}
return dest;
}
/**
* strtoul - convert a string to an unsigned long
* @nptr: The start of the string
* @endptr: A pointer to the end of the parsed string will be placed here
* @base: The number base to use
*/
unsigned long strtoul(const char *nptr, char **endptr, int base)
{
unsigned long result = 0,value;
if (!base) {
base = 10;
if (*nptr == '0') {
base = 8;
nptr++;
if ((toupper(*nptr) == 'X') && isxdigit(nptr[1])) {
nptr++;
base = 16;
}
}
} else if (base == 16) {
if (nptr[0] == '0' && toupper(nptr[1]) == 'X')
nptr += 2;
}
while (isxdigit(*nptr) &&
(value = isdigit(*nptr) ? *nptr-'0' : toupper(*nptr)-'A'+10) < base) {
result = result*base + value;
nptr++;
}
if (endptr)
*endptr = (char *)nptr;
return result;
}
/**
* strtol - convert a string to a signed long
* @nptr: The start of the string
* @endptr: A pointer to the end of the parsed string will be placed here
* @base: The number base to use
*/
long strtol(const char *nptr, char **endptr, int base)
{
if(*nptr=='-')
return -strtoul(nptr+1,endptr,base);
return strtoul(nptr,endptr,base);
}
int skip_atoi(const char **s)
{
int i=0;
while (isdigit(**s))
i = i*10 + *((*s)++) - '0';
return i;
}
char *number(char *buf, char *end, unsigned long num, int base, int size, int precision, int type)
{
char c,sign,tmp[66];
const char *digits;
static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int i;
digits = (type & PRINTF_LARGE) ? large_digits : small_digits;
if (type & PRINTF_LEFT)
type &= ~PRINTF_ZEROPAD;
if (base < 2 || base > 36)
return NULL;
c = (type & PRINTF_ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & PRINTF_SIGN) {
if ((signed long) num < 0) {
sign = '-';
num = - (signed long) num;
size--;
} else if (type & PRINTF_PLUS) {
sign = '+';
size--;
} else if (type & PRINTF_SPACE) {
sign = ' ';
size--;
}
}
if (type & PRINTF_SPECIAL) {
if (base == 16)
size -= 2;
else if (base == 8)
size--;
}
i = 0;
if (num == 0)
tmp[i++]='0';
else while (num != 0) {
tmp[i++] = digits[num % base];
num = num / base;
}
if (i > precision)
precision = i;
size -= precision;
if (!(type&(PRINTF_ZEROPAD+PRINTF_LEFT))) {
while(size-->0) {
if (buf < end)
*buf = ' ';
++buf;
}
}
if (sign) {
if (buf < end)
*buf = sign;
++buf;
}
if (type & PRINTF_SPECIAL) {
if (base==8) {
if (buf < end)
*buf = '0';
++buf;
} else if (base==16) {
if (buf < end)
*buf = '0';
++buf;
if (buf < end)
*buf = digits[33];
++buf;
}
}
if (!(type & PRINTF_LEFT)) {
while (size-- > 0) {
if (buf < end)
*buf = c;
++buf;
}
}
while (i < precision--) {
if (buf < end)
*buf = '0';
++buf;
}
while (i-- > 0) {
if (buf < end)
*buf = tmp[i];
++buf;
}
while (size-- > 0) {
if (buf < end)
*buf = ' ';
++buf;
}
return buf;
}
/**
* vscnprintf - Format a string and place it in a buffer
* @buf: The buffer to place the result into
* @size: The size of the buffer, including the trailing null space
* @fmt: The format string to use
* @args: Arguments for the format string
*
* The return value is the number of characters which have been written into
* the @buf not including the trailing '\0'. If @size is <= 0 the function
* returns 0.
*
* Call this function if you are already dealing with a va_list.
* You probably want scnprintf() instead.
*/
int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
{
int i;
i=vsnprintf(buf,size,fmt,args);
return (i >= size) ? (size - 1) : i;
}
/**
* snprintf - Format a string and place it in a buffer
* @buf: The buffer to place the result into
* @size: The size of the buffer, including the trailing null space
* @fmt: The format string to use
* @...: Arguments for the format string
*
* The return value is the number of characters which would be
* generated for the given input, excluding the trailing null,
* as per ISO C99. If the return is greater than or equal to
* @size, the resulting string is truncated.
*/
int snprintf(char * buf, size_t size, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i=vsnprintf(buf,size,fmt,args);
va_end(args);
return i;
}
/**
* scnprintf - Format a string and place it in a buffer
* @buf: The buffer to place the result into
* @size: The size of the buffer, including the trailing null space
* @fmt: The format string to use
* @...: Arguments for the format string
*
* The return value is the number of characters written into @buf not including
* the trailing '\0'. If @size is <= 0 the function returns 0.
*/
int scnprintf(char * buf, size_t size, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i = vsnprintf(buf, size, fmt, args);
va_end(args);
return (i >= size) ? (size - 1) : i;
}
/**
* vsprintf - Format a string and place it in a buffer
* @buf: The buffer to place the result into
* @fmt: The format string to use
* @args: Arguments for the format string
*
* The function returns the number of characters written
* into @buf. Use vsnprintf() or vscnprintf() in order to avoid
* buffer overflows.
*
* Call this function if you are already dealing with a va_list.
* You probably want sprintf() instead.
*/
int vsprintf(char *buf, const char *fmt, va_list args)
{
return vsnprintf(buf, INT_MAX, fmt, args);
}
/**
* sprintf - Format a string and place it in a buffer
* @buf: The buffer to place the result into
* @fmt: The format string to use
* @...: Arguments for the format string
*
* The function returns the number of characters written
* into @buf. Use snprintf() or scnprintf() in order to avoid
* buffer overflows.
*/
int sprintf(char * buf, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i=vsnprintf(buf, INT_MAX, fmt, args);
va_end(args);
return i;
}
/**
* rand - Returns a pseudo random number
*/
static unsigned int seed;
unsigned int rand()
{
seed = 129 * seed + 907633385;
return seed;
}
/* Integer arithmetic support for Lattice Mico32.
Contributed by Jon Beniston <jon@beniston.com>
Copyright (C) 2009 Free Software Foundation, Inc.
This file is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#ifndef LIBGCC_LM32_H
#define LIBGCC_LM32_H
/* Types. */
typedef unsigned char UQItype __attribute__ ((mode (QI)));
typedef long SItype __attribute__ ((mode (SI)));
typedef unsigned long USItype __attribute__ ((mode (SI)));
/* Prototypes. */
USItype __mulsi3 (USItype a, USItype b);
USItype __udivmodsi4 (USItype num, USItype den, int modwanted);
SItype __divsi3 (SItype a, SItype b);
SItype __modsi3 (SItype a, SItype b);
USItype __udivsi3 (USItype a, USItype b);
USItype __umodsi3 (USItype a, USItype b);
#endif /* LIBGCC_LM32_H */
/*
===============================================================================
This C header file is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://http.cs.berkeley.edu/~jhauser/
arithmetic/softfloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) they include prominent notice that the work is derivative, and (2) they
include prominent notice akin to these three paragraphs for those parts of
this code that are retained.
===============================================================================
*/
/*
-------------------------------------------------------------------------------
Common integer types and flags.
-------------------------------------------------------------------------------
*/
/*
-------------------------------------------------------------------------------
One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
-------------------------------------------------------------------------------
*/
#define BIGENDIAN
/*
-------------------------------------------------------------------------------
The macro `BITS64' can be defined to indicate that 64-bit integer types are
supported by the compiler.
-------------------------------------------------------------------------------
*/
//#define BITS64
/*
-------------------------------------------------------------------------------
Each of the following `typedef's defines the most convenient type that holds
integers of at least as many bits as specified. For example, `uint8' should
be the most convenient type that can hold unsigned integers of as many as
8 bits. The `flag' type must be able to hold either a 0 or 1. For most
implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
to the same as `int'.
-------------------------------------------------------------------------------
*/
typedef int flag;
typedef int uint8;
typedef int int8;
typedef int uint16;
typedef int int16;
typedef unsigned int uint32;
typedef signed int int32;
#ifdef BITS64
typedef unsigned long long int bits64;
typedef signed long long int sbits64;
#endif
/*
-------------------------------------------------------------------------------
Each of the following `typedef's defines a type that holds integers
of _exactly_ the number of bits specified. For instance, for most
implementation of C, `bits16' and `sbits16' should be `typedef'ed to
`unsigned short int' and `signed short int' (or `short int'), respectively.
-------------------------------------------------------------------------------
*/
typedef unsigned char bits8;
typedef signed char sbits8;
typedef unsigned short int bits16;
typedef signed short int sbits16;
typedef unsigned int bits32;
typedef signed int sbits32;
#ifdef BITS64
typedef unsigned long long int uint64;
typedef signed long long int int64;
#endif
#ifdef BITS64
/*
-------------------------------------------------------------------------------
The `LIT64' macro takes as its argument a textual integer literal and if
necessary ``marks'' the literal as having a 64-bit integer type. For
example, the Gnu C Compiler (`gcc') requires that 64-bit literals be
appended with the letters `LL' standing for `long long', which is `gcc's
name for the 64-bit integer type. Some compilers may allow `LIT64' to be
defined as the identity macro: `#define LIT64( a ) a'.
-------------------------------------------------------------------------------
*/
#define LIT64( a ) a##LL
#endif
/*
-------------------------------------------------------------------------------
The macro `INLINE' can be used before functions that should be inlined. If
a compiler does not support explicit inlining, this macro should be defined
to be `static'.
-------------------------------------------------------------------------------
*/
#define INLINE extern inline
/*
-------------------------------------------------------------------------------
Symbolic Boolean literals.
-------------------------------------------------------------------------------
*/
enum {
FALSE = 0,
TRUE = 1
};
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <irq.h>
#include <uart.h>
#include <hw/sysctl.h>
#include <system.h>
__attribute__((noreturn)) void reboot()
{
uart_force_sync(1); /* flush UART buffers */
irq_setmask(0);
irq_enable(0);
CSR_SYSTEM_ID = 1; /* Writing to CSR_SYSTEM_ID causes a system reset */
while(1);
}
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <uart.h>
#include <irq.h>
#include <hw/uart.h>
#include <hw/interrupts.h>
/*
* Buffer sizes must be a power of 2 so that modulos can be computed
* with logical AND.
* RX functions are written in such a way that they do not require locking.
* TX functions already implement locking.
*/
#define UART_RINGBUFFER_SIZE_RX 4096
#define UART_RINGBUFFER_MASK_RX (UART_RINGBUFFER_SIZE_RX-1)
static char rx_buf[UART_RINGBUFFER_SIZE_RX];
static volatile unsigned int rx_produce;
static volatile unsigned int rx_consume;
void uart_async_isr_rx()
{
irq_ack(IRQ_UARTRX);
rx_buf[rx_produce] = CSR_UART_RXTX;
rx_produce = (rx_produce + 1) & UART_RINGBUFFER_MASK_RX;
}
char readchar()
{
char c;
while(rx_consume == rx_produce);
c = rx_buf[rx_consume];
rx_consume = (rx_consume + 1) & UART_RINGBUFFER_MASK_RX;
return c;
}
int readchar_nonblock()
{
return (rx_consume != rx_produce);
}
#define UART_RINGBUFFER_SIZE_TX 131072
#define UART_RINGBUFFER_MASK_TX (UART_RINGBUFFER_SIZE_TX-1)
static char tx_buf[UART_RINGBUFFER_SIZE_TX];
static unsigned int tx_produce;
static unsigned int tx_consume;
static volatile int tx_cts;
static int force_sync;
void uart_async_isr_tx()
{
irq_ack(IRQ_UARTTX);
if(tx_produce != tx_consume) {
CSR_UART_RXTX = tx_buf[tx_consume];
tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX;
} else
tx_cts = 1;
}
void writechar(char c)
{
unsigned int oldmask = 0;
/* Synchronization required because of CTS */
oldmask = irq_getmask();
irq_setmask(oldmask & (~IRQ_UARTTX));
if(force_sync) {
CSR_UART_RXTX = c;
while(!(irq_pending() & IRQ_UARTTX));
irq_ack(IRQ_UARTTX);
} else {
if(tx_cts) {
tx_cts = 0;
CSR_UART_RXTX = c;
} else {
tx_buf[tx_produce] = c;
tx_produce = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX;
}
}
irq_setmask(oldmask);
}
void uart_async_init()
{
unsigned int mask;
rx_produce = 0;
rx_consume = 0;
tx_produce = 0;
tx_consume = 0;
tx_cts = 1;
irq_ack(IRQ_UARTRX|IRQ_UARTTX);
mask = irq_getmask();
mask |= IRQ_UARTRX|IRQ_UARTTX;
irq_setmask(mask);
}
void uart_force_sync(int f)
{
if(f) while(!tx_cts);
force_sync = f;
}
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <uart.h>
#include <irq.h>
#include <hw/uart.h>
#include <hw/interrupts.h>
void writechar(char c)
{
CSR_UART_RXTX = c;
while(!(irq_pending() & IRQ_UARTTX));
irq_ack(IRQ_UARTTX);
}
char readchar()
{
char c;
while(!(irq_pending() & IRQ_UARTRX));
irq_ack(IRQ_UARTRX);
c = CSR_UART_RXTX;
return c;
}
int readchar_nonblock()
{
if(irq_pending() & IRQ_UARTRX)
return 1;
else
return 0;
}
void uart_force_sync(int f)
{
}
/*
* Milkymist VJ SoC (Software)
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
* Copyright (C) Linux kernel developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
/**
* vsnprintf - Format a string and place it in a buffer
* @buf: The buffer to place the result into
* @size: The size of the buffer, including the trailing null space
* @fmt: The format string to use
* @args: Arguments for the format string
*
* The return value is the number of characters which would
* be generated for the given input, excluding the trailing
* '\0', as per ISO C99. If you want to have the exact
* number of characters written into @buf as return value
* (not including the trailing '\0'), use vscnprintf(). If the
* return is greater than or equal to @size, the resulting
* string is truncated.
*
* Call this function if you are already dealing with a va_list.
* You probably want snprintf() instead.
*/
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
{
int len;
unsigned long long num;
int i, base;
char *str, *end, c;
const char *s;
int flags; /* flags to number() */
int field_width; /* width of output field */
int precision; /* min. # of digits for integers; max
number of chars for from string */
int qualifier; /* 'h', 'l', or 'L' for integer fields */
/* 'z' support added 23/7/1999 S.H. */
/* 'z' changed to 'Z' --davidm 1/25/99 */
/* 't' added for ptrdiff_t */
/* Reject out-of-range values early. Large positive sizes are
used for unknown buffer sizes. */
if (unlikely((int) size < 0))
return 0;
str = buf;
end = buf + size;
/* Make sure end is always >= buf */
if (end < buf) {
end = ((void *)-1);
size = end - buf;
}
for (; *fmt ; ++fmt) {
if (*fmt != '%') {
if (str < end)
*str = *fmt;
++str;
continue;
}
/* process flags */
flags = 0;
repeat:
++fmt; /* this also skips first '%' */
switch (*fmt) {
case '-': flags |= PRINTF_LEFT; goto repeat;
case '+': flags |= PRINTF_PLUS; goto repeat;
case ' ': flags |= PRINTF_SPACE; goto repeat;
case '#': flags |= PRINTF_SPECIAL; goto repeat;
case '0': flags |= PRINTF_ZEROPAD; goto repeat;
}
/* get field width */
field_width = -1;
if (isdigit(*fmt))
field_width = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
field_width = va_arg(args, int);
if (field_width < 0) {
field_width = -field_width;
flags |= PRINTF_LEFT;
}
}
/* get the precision */
precision = -1;
if (*fmt == '.') {
++fmt;
if (isdigit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
precision = va_arg(args, int);
}
if (precision < 0)
precision = 0;
}
/* get the conversion qualifier */
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
*fmt =='Z' || *fmt == 'z' || *fmt == 't') {
qualifier = *fmt;
++fmt;
if (qualifier == 'l' && *fmt == 'l') {
qualifier = 'L';
++fmt;
}
}
/* default base */
base = 10;
switch (*fmt) {
case 'c':
if (!(flags & PRINTF_LEFT)) {
while (--field_width > 0) {
if (str < end)
*str = ' ';
++str;
}
}
c = (unsigned char) va_arg(args, int);
if (str < end)
*str = c;
++str;
while (--field_width > 0) {
if (str < end)
*str = ' ';
++str;
}
continue;
case 's':
s = va_arg(args, char *);
if (s == NULL)
s = "<NULL>";
len = strnlen(s, precision);
if (!(flags & PRINTF_LEFT)) {
while (len < field_width--) {
if (str < end)
*str = ' ';
++str;
}
}
for (i = 0; i < len; ++i) {
if (str < end)
*str = *s;
++str; ++s;
}
while (len < field_width--) {
if (str < end)
*str = ' ';
++str;
}
continue;
case 'p':
if (field_width == -1) {
field_width = 2*sizeof(void *);
flags |= PRINTF_ZEROPAD;
}
str = number(str, end,
(unsigned long) va_arg(args, void *),
16, field_width, precision, flags);
continue;
case 'n':
/* FIXME:
* What does C99 say about the overflow case here? */
if (qualifier == 'l') {
long * ip = va_arg(args, long *);
*ip = (str - buf);
} else if (qualifier == 'Z' || qualifier == 'z') {
size_t * ip = va_arg(args, size_t *);
*ip = (str - buf);
} else {
int * ip = va_arg(args, int *);
*ip = (str - buf);
}
continue;
case '%':
if (str < end)
*str = '%';
++str;
continue;
/* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
break;
case 'X':
flags |= PRINTF_LARGE;
case 'x':
base = 16;
break;
case 'd':
case 'i':
flags |= PRINTF_SIGN;
case 'u':
break;
default:
if (str < end)
*str = '%';
++str;
if (*fmt) {
if (str < end)
*str = *fmt;
++str;
} else {
--fmt;
}
continue;
}
if (qualifier == 'L')
num = va_arg(args, long long);
else if (qualifier == 'l') {
num = va_arg(args, unsigned long);
if (flags & PRINTF_SIGN)
num = (signed long) num;
} else if (qualifier == 'Z' || qualifier == 'z') {
num = va_arg(args, size_t);
} else if (qualifier == 't') {
num = va_arg(args, ptrdiff_t);
} else if (qualifier == 'h') {
num = (unsigned short) va_arg(args, int);
if (flags & PRINTF_SIGN)
num = (signed short) num;
} else {
num = va_arg(args, unsigned int);
if (flags & PRINTF_SIGN)
num = (signed int) num;
}
str = number(str, end, num, base,
field_width, precision, flags);
}
if (size > 0) {
if (str < end)
*str = '\0';
else
end[-1] = '\0';
}
/* the trailing null byte doesn't count towards the total */
return str-buf;
}
#!/bin/bash
make -C libbase depend
make -C bios depend
TARGETS=bin2hex crc32 flterm
all: $(TARGETS)
%: %.c
gcc -O2 -Wall -I. -s -o $@ $<
.PHONY: clean
clean:
rm -f $(TARGETS) *.o
/*
* Milkymist VJ SoC
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
int pad;
FILE *fdi, *fdo;
unsigned char w[4];
if(argc != 4) {
fprintf(stderr, "Usage: bin2hex <infile> <outfile> <size>");
return 1;
}
pad = atoi(argv[3]);
if(pad <= 0) {
fprintf(stderr, "Incorrect size");
return 1;
}
fdi = fopen(argv[1], "rb");
if(!fdi) {
perror("Unable to open input file");
return 1;
}
fdo = fopen(argv[2], "w");
if(!fdo) {
perror("Unable to open output file");
fclose(fdi);
return 1;
}
while(1) {
if(fread(w, 4, 1, fdi) <= 0) break;
fprintf(fdo, "%02hhx%02hhx%02hhx%02hhx\n", w[0], w[1], w[2], w[3]);
pad--;
}
fclose(fdi);
if(pad<0)
fprintf(stderr, "Warning: Input binary is larger than specified size");
for(i=0;i<pad;i++)
fprintf(fdo, "00000000\n");
if(fclose(fdo) != 0) {
perror("Unable to close output file");
return 1;
}
return 0;
}
/*
* CRC32 computation tool
* 2009, Sebastien Bourdeauducq - http://lekernel.net
* This file is part of Milkymist.
*/
/* crc32.c -- compute the CRC-32 of a data stream
* Copyright (C) 1995-1998 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
const unsigned int crc_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
0x2d02ef8dL
};
#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
#define DO2(buf) DO1(buf); DO1(buf);
#define DO4(buf) DO2(buf); DO2(buf);
#define DO8(buf) DO4(buf); DO4(buf);
static unsigned int crc32(const unsigned char *buffer, unsigned int len)
{
unsigned int crc;
crc = 0;
crc = crc ^ 0xffffffffL;
while(len >= 8) {
DO8(buffer);
len -= 8;
}
if(len) do {
DO1(buffer);
} while(--len);
return crc ^ 0xffffffffL;
}
int main(int argc, char *argv[])
{
int fd;
unsigned char *buffer;
unsigned int length;
unsigned int crc;
if(
(argc != 2)
&& ((argc != 3) && !strcmp(argv[2], "write"))
) {
fprintf(stderr, "Usage: crc32 <filename> [write]\n");
return 1;
}
fd = open(argv[1], O_RDONLY);
if(fd == -1) {
perror("open");
return 1;
}
length = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
buffer = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, 0);
if(!buffer) {
perror("mmap");
close(fd);
return 1;
}
crc = crc32(buffer, length);
printf("CRC32 (%s): %08x\n", argv[1], crc);
munmap(buffer, length);
close(fd);
if(argc == 3) {
/* Write the CRC32 in big endian at the end of the file */
char b[4];
fd = open(argv[1], O_WRONLY|O_APPEND);
if(fd == -1) {
perror("open");
return 1;
}
b[0] = (crc & 0xff000000) >> 24;
b[1] = (crc & 0x00ff0000) >> 16;
b[2] = (crc & 0x0000ff00) >> 8;
b[3] = (crc & 0x000000ff) >> 0;
write(fd, &b[0], 4);
close(fd);
}
return 0;
}
/*
* Milkymist VJ SoC
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <string.h>
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#include <fcntl.h>
#include <getopt.h>
#include <sfl.h>
#define DEFAULT_KERNELADR (0x40000000)
#define DEFAULT_CMDLINEADR (0x41000000)
#define DEFAULT_INITRDADR (0x41002000)
unsigned int crc16_table[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
static unsigned short crc16(const void *_buffer, int len)
{
const unsigned char *buffer = (const unsigned char *)_buffer;
unsigned short crc;
crc = 0;
while(len-- > 0)
crc = crc16_table[((crc >> 8) ^ (*buffer++)) & 0xFF] ^ (crc << 8);
return crc;
}
static int write_exact(int fd, const char *data, unsigned int length)
{
int r;
while(length > 0) {
r = write(fd, data, length);
if(r <= 0) return 0;
length -= r;
data += r;
}
return 1;
}
/* length, cmd and payload must be filled in */
static int send_frame(int serialfd, struct sfl_frame *frame)
{
unsigned short int crc;
int retry;
char reply;
crc = crc16(&frame->cmd, frame->length+1);
frame->crc[0] = (crc & 0xff00) >> 8;
frame->crc[1] = (crc & 0x00ff);
retry = 0;
do {
if(!write_exact(serialfd, (char *)frame, frame->length+4)) {
perror("[FLTERM] Unable to write to serial port.");
return 0;
}
/* Get the reply from the device */
read(serialfd, &reply, 1); /* TODO: timeout */
switch(reply) {
case SFL_ACK_SUCCESS:
retry = 0;
break;
case SFL_ACK_CRCERROR:
retry = 1;
break;
default:
fprintf(stderr, "[FLTERM] Got unknown reply '%c' from the device, aborting.\n", reply);
return 0;
}
} while(retry);
return 1;
}
static int upload_fd(int serialfd, const char *name, int firmwarefd, unsigned int load_address)
{
struct sfl_frame frame;
int readbytes;
int length;
int position;
unsigned int current_address;
struct timeval t0;
struct timeval t1;
int millisecs;
length = lseek(firmwarefd, 0, SEEK_END);
lseek(firmwarefd, 0, SEEK_SET);
printf("[FLTERM] Uploading %s (%d bytes)...\n", name, length);
gettimeofday(&t0, NULL);
current_address = load_address;
position = 0;
while(1) {
printf("%d%%\r", 100*position/length);
fflush(stdout);
readbytes = read(firmwarefd, &frame.payload[4], sizeof(frame.payload) - 4);
if(readbytes < 0) {
perror("[FLTERM] Unable to read image.");
return -1;
}
if(readbytes == 0) break;
frame.length = readbytes+4;
frame.cmd = SFL_CMD_LOAD;
frame.payload[0] = (current_address & 0xff000000) >> 24;
frame.payload[1] = (current_address & 0x00ff0000) >> 16;
frame.payload[2] = (current_address & 0x0000ff00) >> 8;
frame.payload[3] = (current_address & 0x000000ff);
if(!send_frame(serialfd, &frame)) return -1;
current_address += readbytes;
position += readbytes;
}
gettimeofday(&t1, NULL);
millisecs = (t1.tv_sec - t0.tv_sec)*1000 + (t1.tv_usec - t0.tv_usec)/1000;
printf("[FLTERM] Upload complete (%.1fKB/s).\n", 1000.0*(double)length/((double)millisecs*1024.0));
return length;
}
static const char sfl_magic_req[SFL_MAGIC_LEN] = SFL_MAGIC_REQ;
static const char sfl_magic_ack[SFL_MAGIC_LEN] = SFL_MAGIC_ACK;
static void answer_magic(int serialfd,
const char *kernel_image, unsigned int kernel_address,
const char *cmdline, unsigned int cmdline_address,
const char *initrd_image, unsigned int initrd_address)
{
int kernelfd, initrdfd;
struct sfl_frame frame;
printf("[FLTERM] Received firmware download request from the device.\n");
kernelfd = open(kernel_image, O_RDONLY);
if(kernelfd == -1) {
perror("[FLTERM] Unable to open kernel image (request ignored).");
return;
}
initrdfd = -1;
if(initrd_image != NULL) {
initrdfd = open(initrd_image, O_RDONLY);
if(initrdfd == -1) {
perror("[FLTERM] Unable to open initrd image (request ignored).");
close(kernelfd);
return;
}
}
write_exact(serialfd, sfl_magic_ack, SFL_MAGIC_LEN);
upload_fd(serialfd, "kernel", kernelfd, kernel_address);
if(cmdline != NULL) {
int len;
printf("[FLTERM] Setting kernel command line: '%s'.\n", cmdline);
len = strlen(cmdline)+1;
if(len > (254-4)) {
fprintf(stderr, "[FLTERM] Kernel command line too long, load aborted.\n");
close(initrdfd);
close(kernelfd);
return;
}
frame.length = len+4;
frame.cmd = SFL_CMD_LOAD;
frame.payload[0] = (cmdline_address & 0xff000000) >> 24;
frame.payload[1] = (cmdline_address & 0x00ff0000) >> 16;
frame.payload[2] = (cmdline_address & 0x0000ff00) >> 8;
frame.payload[3] = (cmdline_address & 0x000000ff);
strcpy((char *)&frame.payload[4], cmdline);
send_frame(serialfd, &frame);
frame.length = 4;
frame.cmd = SFL_CMD_CMDLINE;
frame.payload[0] = (cmdline_address & 0xff000000) >> 24;
frame.payload[1] = (cmdline_address & 0x00ff0000) >> 16;
frame.payload[2] = (cmdline_address & 0x0000ff00) >> 8;
frame.payload[3] = (cmdline_address & 0x000000ff);
send_frame(serialfd, &frame);
}
if(initrdfd != -1) {
int len;
len = upload_fd(serialfd, "initrd", initrdfd, initrd_address);
if(len <= 0) return;
frame.length = 4;
frame.cmd = SFL_CMD_INITRDSTART;
frame.payload[0] = (initrd_address & 0xff000000) >> 24;
frame.payload[1] = (initrd_address & 0x00ff0000) >> 16;
frame.payload[2] = (initrd_address & 0x0000ff00) >> 8;
frame.payload[3] = (initrd_address & 0x000000ff);
send_frame(serialfd, &frame);
initrd_address += len-1;
frame.length = 4;
frame.cmd = SFL_CMD_INITRDEND;
frame.payload[0] = (initrd_address & 0xff000000) >> 24;
frame.payload[1] = (initrd_address & 0x00ff0000) >> 16;
frame.payload[2] = (initrd_address & 0x0000ff00) >> 8;
frame.payload[3] = (initrd_address & 0x000000ff);
send_frame(serialfd, &frame);
}
/* Send the jump command */
printf("[FLTERM] Booting the device.\n");
frame.length = 4;
frame.cmd = SFL_CMD_JUMP;
frame.payload[0] = (kernel_address & 0xff000000) >> 24;
frame.payload[1] = (kernel_address & 0x00ff0000) >> 16;
frame.payload[2] = (kernel_address & 0x0000ff00) >> 8;
frame.payload[3] = (kernel_address & 0x000000ff);
if(!send_frame(serialfd, &frame)) return;
printf("[FLTERM] Done.\n");
close(initrdfd);
close(kernelfd);
}
static void do_terminal(char *serial_port,
int doublerate,
const char *kernel_image, unsigned int kernel_address,
const char *cmdline, unsigned int cmdline_address,
const char *initrd_image, unsigned int initrd_address)
{
int serialfd;
struct termios my_termios;
char c;
int recognized;
struct pollfd fds[2];
int flags;
/* Open and configure the serial port */
serialfd = open(serial_port, O_RDWR|O_NOCTTY);
if(serialfd == -1) {
perror("Unable to open serial port");
return;
}
/* Thanks to Julien Schmitt (GTKTerm) for figuring out the correct parameters
* to put into that weird struct.
*/
tcgetattr(serialfd, &my_termios);
my_termios.c_cflag = doublerate ? B230400 : B115200;
my_termios.c_cflag |= CS8;
my_termios.c_cflag |= CREAD;
my_termios.c_iflag = IGNPAR | IGNBRK;
my_termios.c_cflag |= CLOCAL;
my_termios.c_oflag = 0;
my_termios.c_lflag = 0;
my_termios.c_cc[VTIME] = 0;
my_termios.c_cc[VMIN] = 1;
tcsetattr(serialfd, TCSANOW, &my_termios);
tcflush(serialfd, TCOFLUSH);
tcflush(serialfd, TCIFLUSH);
/* Prepare the fdset for poll() */
fds[0].fd = 0;
fds[0].events = POLLIN;
fds[1].fd = serialfd;
fds[1].events = POLLIN;
recognized = 0;
flags = fcntl(serialfd, F_GETFL, 0);
while(1) {
fds[0].revents = 0;
fds[1].revents = 0;
/* poll() behaves strangely when the serial port descriptor is in
* blocking mode. So work around this.
*/
fcntl(serialfd, F_SETFL, flags|O_NONBLOCK);
if(poll(&fds[0], 2, -1) < 0) break;
fcntl(serialfd, F_SETFL, flags);
if(fds[0].revents & POLLIN) {
read(0, &c, 1);
if(write(serialfd, &c, 1) <= 0) break;
}
if(fds[1].revents & POLLIN) {
if(read(serialfd, &c, 1) <= 0) break;
write(0, &c, 1);
if(c == sfl_magic_req[recognized]) {
recognized++;
if(recognized == SFL_MAGIC_LEN) {
/* We've got the magic string ! */
recognized = 0;
answer_magic(serialfd,
kernel_image, kernel_address,
cmdline, cmdline_address,
initrd_image, initrd_address);
}
} else {
if(c == sfl_magic_req[0]) recognized = 1; else recognized = 0;
}
}
}
close(serialfd);
}
enum {
OPTION_PORT,
OPTION_DOUBLERATE,
OPTION_KERNEL,
OPTION_KERNELADR,
OPTION_CMDLINE,
OPTION_CMDLINEADR,
OPTION_INITRD,
OPTION_INITRDADR
};
static const struct option options[] = {
{
.name = "port",
.has_arg = 1,
.val = OPTION_PORT
},
{
.name = "double-rate",
.has_arg = 0,
.val = OPTION_DOUBLERATE
},
{
.name = "kernel",
.has_arg = 1,
.val = OPTION_KERNEL
},
{
.name = "kernel-adr",
.has_arg = 1,
.val = OPTION_KERNELADR
},
{
.name = "cmdline",
.has_arg = 1,
.val = OPTION_CMDLINE
},
{
.name = "cmdline-adr",
.has_arg = 1,
.val = OPTION_CMDLINEADR
},
{
.name = "initrd",
.has_arg = 1,
.val = OPTION_INITRD
},
{
.name = "initrd-adr",
.has_arg = 1,
.val = OPTION_INITRDADR
},
{
.name = NULL
}
};
static void print_usage()
{
fprintf(stderr, "Serial boot program for the Milkymist VJ SoC - v. 1.1\n");
fprintf(stderr, "Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq\n\n");
fprintf(stderr, "This program is free software: you can redistribute it and/or modify\n");
fprintf(stderr, "it under the terms of the GNU General Public License as published by\n");
fprintf(stderr, "the Free Software Foundation, version 3 of the License.\n\n");
fprintf(stderr, "Usage: flterm --port <port> [--double-rate]\n");
fprintf(stderr, " --kernel <kernel_image> [--kernel-adr <address>]\n");
fprintf(stderr, " [--cmdline <cmdline> [--cmdline-adr <address>]]\n");
fprintf(stderr, " [--initrd <initrd_image> [--initrd-adr <address>]]\n\n");
printf("Default load addresses:\n");
fprintf(stderr, " kernel: 0x%08x\n", DEFAULT_KERNELADR);
fprintf(stderr, " cmdline: 0x%08x\n", DEFAULT_CMDLINEADR);
fprintf(stderr, " initrd: 0x%08x\n", DEFAULT_INITRDADR);
}
int main(int argc, char *argv[])
{
int opt;
char *serial_port;
int doublerate;
char *kernel_image;
unsigned int kernel_address;
char *cmdline;
unsigned int cmdline_address;
char *initrd_image;
unsigned int initrd_address;
char *endptr;
struct termios otty, ntty;
/* Fetch command line arguments */
serial_port = NULL;
doublerate = 0;
kernel_image = NULL;
kernel_address = DEFAULT_KERNELADR;
cmdline = NULL;
cmdline_address = DEFAULT_CMDLINEADR;
initrd_image = NULL;
initrd_address = DEFAULT_INITRDADR;
while((opt = getopt_long(argc, argv, "", options, NULL)) != -1) {
if(opt == '?') {
print_usage();
return 1;
}
switch(opt) {
case OPTION_PORT:
free(serial_port);
serial_port = strdup(optarg);
break;
case OPTION_DOUBLERATE:
doublerate = 1;
break;
case OPTION_KERNEL:
free(kernel_image);
kernel_image = strdup(optarg);
break;
case OPTION_KERNELADR:
kernel_address = strtoul(optarg, &endptr, 0);
if(*endptr != 0) kernel_address = 0;
break;
case OPTION_CMDLINE:
free(cmdline);
cmdline = strdup(optarg);
break;
case OPTION_CMDLINEADR:
cmdline_address = strtoul(optarg, &endptr, 0);
if(*endptr != 0) cmdline_address = 0;
break;
case OPTION_INITRD:
free(initrd_image);
initrd_image = strdup(optarg);
break;
case OPTION_INITRDADR:
initrd_address = strtoul(optarg, &endptr, 0);
if(*endptr != 0) initrd_address = 0;
break;
}
}
if((serial_port == NULL) || (kernel_image == NULL)) {
print_usage();
return 1;
}
/* Banner */
printf("[FLTERM] Starting...\n");
/* Set up stdin/out */
tcgetattr(0, &otty);
ntty = otty;
ntty.c_lflag &= ~(ECHO | ICANON);
tcsetattr(0, TCSANOW, &ntty);
/* Do the bulk of the work */
do_terminal(serial_port, doublerate,
kernel_image, kernel_address,
cmdline, cmdline_address,
initrd_image, initrd_address);
/* Restore stdin/out into their previous state */
tcsetattr(0, TCSANOW, &otty);
return 0;
}
/*
* Milkymist VJ SoC
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SFL_H
#define __SFL_H
#define SFL_MAGIC_LEN 14
#define SFL_MAGIC_REQ "sL5DdSMmkekro\n"
#define SFL_MAGIC_ACK "z6IHG7cYDID6o\n"
struct sfl_frame {
unsigned char length;
unsigned char crc[2];
unsigned char cmd;
unsigned char payload[255];
} __attribute__((packed));
/* General commands */
#define SFL_CMD_ABORT 0x00
#define SFL_CMD_LOAD 0x01
#define SFL_CMD_JUMP 0x02
/* Linux-specific commands */
#define SFL_CMD_CMDLINE 0x03
#define SFL_CMD_INITRDSTART 0x04
#define SFL_CMD_INITRDEND 0x05
/* Replies */
#define SFL_ACK_SUCCESS 'K'
#define SFL_ACK_CRCERROR 'C'
#define SFL_ACK_UNKNOWN 'U'
#define SFL_ACK_ERROR 'E'
#endif /* __SFL_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment