Line 34... |
Line 34... |
//
|
//
|
// *Author(s):
|
// *Author(s):
|
// - Olivier Girard, olgirard@gmail.com
|
// - Olivier Girard, olgirard@gmail.com
|
//
|
//
|
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
// $Rev: 134 $
|
// $Rev: 103 $
|
// $LastChangedBy: olivier.girard $
|
// $LastChangedBy: olivier.girard $
|
// $LastChangedDate: 2012-03-22 21:31:06 +0100 (Thu, 22 Mar 2012) $
|
// $LastChangedDate: 2011-03-05 15:44:48 +0100 (Sat, 05 Mar 2011) $
|
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
`ifdef OMSP_NO_INCLUDE
|
`ifdef OMSP_NO_INCLUDE
|
`else
|
`else
|
`include "openMSP430_defines.v"
|
`include "openMSP430_defines.v"
|
`endif
|
`endif
|
|
|
module omsp_frontend (
|
module omsp_frontend (
|
|
|
// OUTPUTs
|
// OUTPUTs
|
dbg_halt_st, // Halt/Run status from CPU
|
cpu_halt_st, // Halt/Run status from CPU
|
decode_noirq, // Frontend decode instruction
|
decode_noirq, // Frontend decode instruction
|
e_state, // Execution state
|
e_state, // Execution state
|
exec_done, // Execution completed
|
exec_done, // Execution completed
|
inst_ad, // Decoded Inst: destination addressing mode
|
inst_ad, // Decoded Inst: destination addressing mode
|
inst_as, // Decoded Inst: source addressing mode
|
inst_as, // Decoded Inst: source addressing mode
|
Line 66... |
Line 66... |
inst_src, // Decoded Inst: source (one hot)
|
inst_src, // Decoded Inst: source (one hot)
|
inst_type, // Decoded Instruction type
|
inst_type, // Decoded Instruction type
|
irq_acc, // Interrupt request accepted (one-hot signal)
|
irq_acc, // Interrupt request accepted (one-hot signal)
|
mab, // Frontend Memory address bus
|
mab, // Frontend Memory address bus
|
mb_en, // Frontend Memory bus enable
|
mb_en, // Frontend Memory bus enable
|
|
mclk_dma_enable, // DMA Sub-System Clock enable
|
|
mclk_dma_wkup, // DMA Sub-System Clock wake-up (asynchronous)
|
mclk_enable, // Main System Clock enable
|
mclk_enable, // Main System Clock enable
|
mclk_wkup, // Main System Clock wake-up (asynchronous)
|
mclk_wkup, // Main System Clock wake-up (asynchronous)
|
nmi_acc, // Non-Maskable interrupt request accepted
|
nmi_acc, // Non-Maskable interrupt request accepted
|
pc, // Program counter
|
pc, // Program counter
|
pc_nxt, // Next PC value (for CALL & IRQ)
|
pc_nxt, // Next PC value (for CALL & IRQ)
|
|
|
// INPUTs
|
// INPUTs
|
cpu_en_s, // Enable CPU code execution (synchronous)
|
cpu_en_s, // Enable CPU code execution (synchronous)
|
|
cpu_halt_cmd, // Halt CPU command
|
cpuoff, // Turns off the CPU
|
cpuoff, // Turns off the CPU
|
dbg_halt_cmd, // Halt CPU command
|
|
dbg_reg_sel, // Debug selected register for rd/wr access
|
dbg_reg_sel, // Debug selected register for rd/wr access
|
|
dma_en, // Direct Memory Access enable (high active)
|
|
dma_wkup, // DMA Sub-System Wake-up (asynchronous and non-glitchy)
|
fe_pmem_wait, // Frontend wait for Instruction fetch
|
fe_pmem_wait, // Frontend wait for Instruction fetch
|
gie, // General interrupt enable
|
gie, // General interrupt enable
|
irq, // Maskable interrupts
|
irq, // Maskable interrupts
|
mclk, // Main system clock
|
mclk, // Main system clock
|
mdb_in, // Frontend Memory data bus input
|
mdb_in, // Frontend Memory data bus input
|
Line 95... |
Line 99... |
wkup // System Wake-up (asynchronous)
|
wkup // System Wake-up (asynchronous)
|
);
|
);
|
|
|
// OUTPUTs
|
// OUTPUTs
|
//=========
|
//=========
|
output dbg_halt_st; // Halt/Run status from CPU
|
output cpu_halt_st; // Halt/Run status from CPU
|
output decode_noirq; // Frontend decode instruction
|
output decode_noirq; // Frontend decode instruction
|
output [3:0] e_state; // Execution state
|
output [3:0] e_state; // Execution state
|
output exec_done; // Execution completed
|
output exec_done; // Execution completed
|
output [7:0] inst_ad; // Decoded Inst: destination addressing mode
|
output [7:0] inst_ad; // Decoded Inst: destination addressing mode
|
output [7:0] inst_as; // Decoded Inst: source addressing mode
|
output [7:0] inst_as; // Decoded Inst: source addressing mode
|
Line 115... |
Line 119... |
output [15:0] inst_src; // Decoded Inst: source (one hot)
|
output [15:0] inst_src; // Decoded Inst: source (one hot)
|
output [2:0] inst_type; // Decoded Instruction type
|
output [2:0] inst_type; // Decoded Instruction type
|
output [`IRQ_NR-3:0] irq_acc; // Interrupt request accepted (one-hot signal)
|
output [`IRQ_NR-3:0] irq_acc; // Interrupt request accepted (one-hot signal)
|
output [15:0] mab; // Frontend Memory address bus
|
output [15:0] mab; // Frontend Memory address bus
|
output mb_en; // Frontend Memory bus enable
|
output mb_en; // Frontend Memory bus enable
|
|
output mclk_dma_enable; // DMA Sub-System Clock enable
|
|
output mclk_dma_wkup; // DMA Sub-System Clock wake-up (asynchronous)
|
output mclk_enable; // Main System Clock enable
|
output mclk_enable; // Main System Clock enable
|
output mclk_wkup; // Main System Clock wake-up (asynchronous)
|
output mclk_wkup; // Main System Clock wake-up (asynchronous)
|
output nmi_acc; // Non-Maskable interrupt request accepted
|
output nmi_acc; // Non-Maskable interrupt request accepted
|
output [15:0] pc; // Program counter
|
output [15:0] pc; // Program counter
|
output [15:0] pc_nxt; // Next PC value (for CALL & IRQ)
|
output [15:0] pc_nxt; // Next PC value (for CALL & IRQ)
|
|
|
// INPUTs
|
// INPUTs
|
//=========
|
//=========
|
input cpu_en_s; // Enable CPU code execution (synchronous)
|
input cpu_en_s; // Enable CPU code execution (synchronous)
|
|
input cpu_halt_cmd; // Halt CPU command
|
input cpuoff; // Turns off the CPU
|
input cpuoff; // Turns off the CPU
|
input dbg_halt_cmd; // Halt CPU command
|
|
input [3:0] dbg_reg_sel; // Debug selected register for rd/wr access
|
input [3:0] dbg_reg_sel; // Debug selected register for rd/wr access
|
|
input dma_en; // Direct Memory Access enable (high active)
|
|
input dma_wkup; // DMA Sub-System Wake-up (asynchronous and non-glitchy)
|
input fe_pmem_wait; // Frontend wait for Instruction fetch
|
input fe_pmem_wait; // Frontend wait for Instruction fetch
|
input gie; // General interrupt enable
|
input gie; // General interrupt enable
|
input [`IRQ_NR-3:0] irq; // Maskable interrupts
|
input [`IRQ_NR-3:0] irq; // Maskable interrupts
|
input mclk; // Main system clock
|
input mclk; // Main system clock
|
input [15:0] mdb_in; // Frontend Memory data bus input
|
input [15:0] mdb_in; // Frontend Memory data bus input
|
Line 237... |
Line 245... |
wire [2:0] inst_type_nxt;
|
wire [2:0] inst_type_nxt;
|
wire is_const;
|
wire is_const;
|
reg [15:0] sconst_nxt;
|
reg [15:0] sconst_nxt;
|
reg [3:0] e_state_nxt;
|
reg [3:0] e_state_nxt;
|
|
|
// CPU on/off through the debug interface or cpu_en port
|
// CPU on/off through an external interface (debug or mstr) or cpu_en port
|
wire cpu_halt_cmd = dbg_halt_cmd | ~cpu_en_s;
|
wire cpu_halt_req = cpu_halt_cmd | ~cpu_en_s;
|
|
|
// States Transitions
|
// States Transitions
|
always @(i_state or inst_sz or inst_sz_nxt or pc_sw_wr or exec_done or
|
always @(i_state or inst_sz or inst_sz_nxt or pc_sw_wr or exec_done or
|
irq_detect or cpuoff or cpu_halt_cmd or e_state)
|
irq_detect or cpuoff or cpu_halt_req or e_state)
|
case(i_state)
|
case(i_state)
|
I_IDLE : i_state_nxt = (irq_detect & ~cpu_halt_cmd) ? I_IRQ_FETCH :
|
I_IDLE : i_state_nxt = (irq_detect & ~cpu_halt_req) ? I_IRQ_FETCH :
|
(~cpuoff & ~cpu_halt_cmd) ? I_DEC : I_IDLE;
|
(~cpuoff & ~cpu_halt_req) ? I_DEC : I_IDLE;
|
I_IRQ_FETCH: i_state_nxt = I_IRQ_DONE;
|
I_IRQ_FETCH: i_state_nxt = I_IRQ_DONE;
|
I_IRQ_DONE : i_state_nxt = I_DEC;
|
I_IRQ_DONE : i_state_nxt = I_DEC;
|
I_DEC : i_state_nxt = irq_detect ? I_IRQ_FETCH :
|
I_DEC : i_state_nxt = irq_detect ? I_IRQ_FETCH :
|
(cpuoff | cpu_halt_cmd) & exec_done ? I_IDLE :
|
(cpuoff | cpu_halt_req) & exec_done ? I_IDLE :
|
cpu_halt_cmd & (e_state==E_IDLE) ? I_IDLE :
|
cpu_halt_req & (e_state==E_IDLE) ? I_IDLE :
|
pc_sw_wr ? I_DEC :
|
pc_sw_wr ? I_DEC :
|
~exec_done & ~(e_state==E_IDLE) ? I_DEC : // Wait in decode state
|
~exec_done & ~(e_state==E_IDLE) ? I_DEC : // Wait in decode state
|
(inst_sz_nxt!=2'b00) ? I_EXT1 : I_DEC; // until execution is completed
|
(inst_sz_nxt!=2'b00) ? I_EXT1 : I_DEC; // until execution is completed
|
I_EXT1 : i_state_nxt = pc_sw_wr ? I_DEC :
|
I_EXT1 : i_state_nxt = pc_sw_wr ? I_DEC :
|
(inst_sz!=2'b01) ? I_EXT2 : I_DEC;
|
(inst_sz!=2'b01) ? I_EXT2 : I_DEC;
|
Line 272... |
Line 280... |
// Utility signals
|
// Utility signals
|
wire decode_noirq = ((i_state==I_DEC) & (exec_done | (e_state==E_IDLE)));
|
wire decode_noirq = ((i_state==I_DEC) & (exec_done | (e_state==E_IDLE)));
|
wire decode = decode_noirq | irq_detect;
|
wire decode = decode_noirq | irq_detect;
|
wire fetch = ~((i_state==I_DEC) & ~(exec_done | (e_state==E_IDLE))) & ~(e_state_nxt==E_IDLE);
|
wire fetch = ~((i_state==I_DEC) & ~(exec_done | (e_state==E_IDLE))) & ~(e_state_nxt==E_IDLE);
|
|
|
// Debug interface cpu status
|
// Halt/Run CPU status
|
reg dbg_halt_st;
|
reg cpu_halt_st;
|
always @(posedge mclk or posedge puc_rst)
|
always @(posedge mclk or posedge puc_rst)
|
if (puc_rst) dbg_halt_st <= 1'b0;
|
if (puc_rst) cpu_halt_st <= 1'b0;
|
else dbg_halt_st <= cpu_halt_cmd & (i_state_nxt==I_IDLE);
|
else cpu_halt_st <= cpu_halt_req & (i_state_nxt==I_IDLE);
|
|
|
|
|
//=============================================================================
|
//=============================================================================
|
// 4) INTERRUPT HANDLING & SYSTEM WAKEUP
|
// 4) INTERRUPT HANDLING & SYSTEM WAKEUP
|
//=============================================================================
|
//=============================================================================
|
Line 294... |
Line 302... |
always @(posedge mclk or posedge puc_rst)
|
always @(posedge mclk or posedge puc_rst)
|
if (puc_rst) inst_irq_rst <= 1'b1;
|
if (puc_rst) inst_irq_rst <= 1'b1;
|
else if (exec_done) inst_irq_rst <= 1'b0;
|
else if (exec_done) inst_irq_rst <= 1'b0;
|
|
|
// Detect other interrupts
|
// Detect other interrupts
|
assign irq_detect = (nmi_pnd | ((|irq | wdt_irq) & gie)) & ~cpu_halt_cmd & ~dbg_halt_st & (exec_done | (i_state==I_IDLE));
|
assign irq_detect = (nmi_pnd | ((|irq | wdt_irq) & gie)) & ~cpu_halt_req & ~cpu_halt_st & (exec_done | (i_state==I_IDLE));
|
|
|
`ifdef CLOCK_GATING
|
`ifdef CLOCK_GATING
|
wire mclk_irq_num;
|
wire mclk_irq_num;
|
omsp_clock_gate clock_gate_irq_num (.gclk(mclk_irq_num),
|
omsp_clock_gate clock_gate_irq_num (.gclk(mclk_irq_num),
|
.clk (mclk), .enable(irq_detect), .scan_enable(scan_enable));
|
.clk (mclk), .enable(irq_detect), .scan_enable(scan_enable));
|
`else
|
`else
|
|
wire UNUSED_scan_enable = scan_enable;
|
wire mclk_irq_num = mclk;
|
wire mclk_irq_num = mclk;
|
`endif
|
`endif
|
|
|
// Combine all IRQs
|
// Combine all IRQs
|
`ifdef IRQ_16
|
`ifdef IRQ_16
|
wire [62:0] irq_all = {nmi_pnd, irq, 48'h0000_0000_0000} |
|
wire [62:0] irq_all = {nmi_pnd, irq, 48'h0000_0000_0000} |
|
`else
|
`else
|
`ifdef IRQ_32
|
`ifdef IRQ_32
|
wire [62:0] irq_all = {nmi_pnd, irq, 32'h0000} |
|
wire [62:0] irq_all = {nmi_pnd, irq, 32'h0000_0000} |
|
`else
|
`else
|
`ifdef IRQ_64
|
`ifdef IRQ_64
|
wire [62:0] irq_all = {nmi_pnd, irq} |
|
wire [62:0] irq_all = {nmi_pnd, irq} |
|
`endif
|
`endif
|
`endif
|
`endif
|
Line 359... |
Line 368... |
omsp_and_gate and_mirq_wkup (.y(mirq_wkup), .a(wkup | wdt_wkup), .b(gie));
|
omsp_and_gate and_mirq_wkup (.y(mirq_wkup), .a(wkup | wdt_wkup), .b(gie));
|
|
|
// Combined asynchronous wakeup detection from nmi & irq (masked if the cpu is disabled)
|
// Combined asynchronous wakeup detection from nmi & irq (masked if the cpu is disabled)
|
omsp_and_gate and_mclk_wkup (.y(mclk_wkup), .a(nmi_wkup | mirq_wkup), .b(cpu_en_s));
|
omsp_and_gate and_mclk_wkup (.y(mclk_wkup), .a(nmi_wkup | mirq_wkup), .b(cpu_en_s));
|
|
|
|
// Wakeup condition from DMA interface
|
|
`ifdef DMA_IF_EN
|
|
wire mclk_dma_enable = dma_en & cpu_en_s;
|
|
omsp_and_gate and_mclk_dma_wkup (.y(mclk_dma_wkup), .a(dma_wkup), .b(cpu_en_s));
|
|
`else
|
|
assign mclk_dma_wkup = 1'b0;
|
|
assign mclk_dma_enable = 1'b0;
|
|
wire UNUSED_dma_en = dma_en;
|
|
wire UNUSED_dma_wkup = dma_wkup;
|
|
`endif
|
`else
|
`else
|
|
|
// In the CPUOFF feature is disabled, the wake-up and enable signals are always 1
|
// In the CPUOFF feature is disabled, the wake-up and enable signals are always 1
|
|
assign mclk_dma_wkup = 1'b1;
|
|
assign mclk_dma_enable = 1'b1;
|
assign mclk_wkup = 1'b1;
|
assign mclk_wkup = 1'b1;
|
assign mclk_enable = 1'b1;
|
assign mclk_enable = 1'b1;
|
|
wire UNUSED_dma_en = dma_en;
|
|
wire UNUSED_wkup = wkup;
|
|
wire UNUSED_wdt_wkup = wdt_wkup;
|
|
wire UNUSED_nmi_wkup = nmi_wkup;
|
|
wire UNUSED_dma_wkup = dma_wkup;
|
`endif
|
`endif
|
|
|
//=============================================================================
|
//=============================================================================
|
// 5) FETCH INSTRUCTION
|
// 5) FETCH INSTRUCTION
|
//=============================================================================
|
//=============================================================================
|
Line 399... |
Line 425... |
|
|
always @(posedge mclk_pc or posedge puc_rst)
|
always @(posedge mclk_pc or posedge puc_rst)
|
if (puc_rst) pc <= 16'h0000;
|
if (puc_rst) pc <= 16'h0000;
|
else pc <= pc_nxt;
|
else pc <= pc_nxt;
|
|
|
// Check if ROM has been busy in order to retry ROM access
|
// Check if Program-Memory has been busy in order to retry Program-Memory access
|
reg pmem_busy;
|
reg pmem_busy;
|
always @(posedge mclk or posedge puc_rst)
|
always @(posedge mclk or posedge puc_rst)
|
if (puc_rst) pmem_busy <= 1'b0;
|
if (puc_rst) pmem_busy <= 1'b0;
|
else pmem_busy <= fe_pmem_wait;
|
else pmem_busy <= fe_pmem_wait;
|
|
|
// Memory interface
|
// Memory interface
|
wire [15:0] mab = pc_nxt;
|
wire [15:0] mab = pc_nxt;
|
wire mb_en = fetch | pc_sw_wr | (i_state==I_IRQ_FETCH) | pmem_busy | (dbg_halt_st & ~cpu_halt_cmd);
|
wire mb_en = fetch | pc_sw_wr | (i_state==I_IRQ_FETCH) | pmem_busy | (cpu_halt_st & ~cpu_halt_req);
|
|
|
|
|
//
|
//
|
// 5.2) INSTRUCTION REGISTER
|
// 5.2) INSTRUCTION REGISTER
|
//--------------------------------
|
//--------------------------------
|
Line 613... |
Line 639... |
else inst_dest_bin <= ir[3:0];
|
else inst_dest_bin <= ir[3:0];
|
`else
|
`else
|
else if (decode) inst_dest_bin <= ir[3:0];
|
else if (decode) inst_dest_bin <= ir[3:0];
|
`endif
|
`endif
|
|
|
wire [15:0] inst_dest = dbg_halt_st ? one_hot16(dbg_reg_sel) :
|
wire [15:0] inst_dest = cpu_halt_st ? one_hot16(dbg_reg_sel) :
|
inst_type[`INST_JMP] ? 16'h0001 :
|
inst_type[`INST_JMP] ? 16'h0001 :
|
inst_so[`IRQ] |
|
inst_so[`IRQ] |
|
inst_so[`PUSH] |
|
inst_so[`PUSH] |
|
inst_so[`CALL] ? 16'h0002 :
|
inst_so[`CALL] ? 16'h0002 :
|
one_hot16(inst_dest_bin);
|
one_hot16(inst_dest_bin);
|
Line 776... |
Line 802... |
|
|
// Operation size
|
// Operation size
|
reg inst_bw;
|
reg inst_bw;
|
always @(posedge mclk or posedge puc_rst)
|
always @(posedge mclk or posedge puc_rst)
|
if (puc_rst) inst_bw <= 1'b0;
|
if (puc_rst) inst_bw <= 1'b0;
|
else if (decode) inst_bw <= ir[6] & ~inst_type_nxt[`INST_JMP] & ~irq_detect & ~cpu_halt_cmd;
|
else if (decode) inst_bw <= ir[6] & ~inst_type_nxt[`INST_JMP] & ~irq_detect & ~cpu_halt_req;
|
|
|
// Extended instruction size
|
// Extended instruction size
|
assign inst_sz_nxt = {1'b0, (inst_as_nxt[`IDX] | inst_as_nxt[`SYMB] | inst_as_nxt[`ABS] | inst_as_nxt[`IMM])} +
|
assign inst_sz_nxt = {1'b0, (inst_as_nxt[`IDX] | inst_as_nxt[`SYMB] | inst_as_nxt[`ABS] | inst_as_nxt[`IMM])} +
|
{1'b0, ((inst_ad_nxt[`IDX] | inst_ad_nxt[`SYMB] | inst_ad_nxt[`ABS]) & ~inst_type_nxt[`INST_SO])};
|
{1'b0, ((inst_ad_nxt[`IDX] | inst_ad_nxt[`SYMB] | inst_ad_nxt[`ABS]) & ~inst_type_nxt[`INST_SO])};
|
always @(posedge mclk_decode or posedge puc_rst)
|
always @(posedge mclk_decode or posedge puc_rst)
|
Line 835... |
Line 861... |
if (puc_rst) exec_dext_rdy <= 1'b0;
|
if (puc_rst) exec_dext_rdy <= 1'b0;
|
else if (e_state==E_DST_RD) exec_dext_rdy <= 1'b0;
|
else if (e_state==E_DST_RD) exec_dext_rdy <= 1'b0;
|
else if (inst_dext_rdy) exec_dext_rdy <= 1'b1;
|
else if (inst_dext_rdy) exec_dext_rdy <= 1'b1;
|
|
|
// Execution first state
|
// Execution first state
|
wire [3:0] e_first_state = ~dbg_halt_st & inst_so_nxt[`IRQ] ? E_IRQ_0 :
|
wire [3:0] e_first_state = ~cpu_halt_st & inst_so_nxt[`IRQ] ? E_IRQ_0 :
|
cpu_halt_cmd | (i_state==I_IDLE) ? E_IDLE :
|
cpu_halt_req | (i_state==I_IDLE) ? E_IDLE :
|
cpuoff ? E_IDLE :
|
cpuoff ? E_IDLE :
|
src_acalc_pre ? E_SRC_AD :
|
src_acalc_pre ? E_SRC_AD :
|
src_rd_pre ? E_SRC_RD :
|
src_rd_pre ? E_SRC_RD :
|
dst_acalc_pre ? E_DST_AD :
|
dst_acalc_pre ? E_DST_AD :
|
dst_rd_pre ? E_DST_RD : E_EXEC;
|
dst_rd_pre ? E_DST_RD : E_EXEC;
|