📄 buscon.v
字号:
cs_l <= HI;
rd_l <= HI;
wr_l <= HI;
data_bus_wrL <= HI;
PC_loadH <= LO;
PC_incH <= LO;
SP_decH <= LO;
buscon_doneH <= LO;
buscon_state <= WAIT_4_REQ;
end else
case (buscon_state)
//
// WAIT_4_REQ
// wait for any read or write requests
WAIT_4_REQ: begin
// do the below whenver we're in this state
begin
buscon_doneH <= LO;
PC_loadH <= LO;
PC_incH <= LO;
SP_decH <= LO;
data_bus_wrL <= HI;
end
if (buscon_startH) begin
cs_l <= LO;
buscon_state <= ASSERT_RDWR;
end else begin
cs_l <= HI;
end
end
//
// Hold the Bus in this state for 1 tick
//
ASSERT_RDWR: begin
rd_l <= bus_wrH;
wr_l <= ~bus_wrH;
data_bus_wrL <= ~bus_wrH; // drive data bus with c_bus
buscon_state <= WAIT_4_READY;
end
//
// WAIT_4_READY
//
// Sample for wait-state request
// a wait state request is if readyH
// is not 1 (i.e. not ready)
//
WAIT_4_READY: begin
// if any of the ready_h or readyIN_h is low
// (i.e not ready) wait until it gets high
if (readyIN_h & ready_h ) begin
// Deassert most of the bus signals
begin
rd_l <= HI;
wr_l <= HI;
buscon_doneH <= HI;
end
// Update PC/SP. This occurs on the next cycle
// due to the piping
begin
PC_loadH <= PC_loadINH;
PC_incH <= PC_incINH;
SP_decH <= SP_decINH;
end
buscon_state <= WAIT_4_REQ;
end
end
endcase
//
// PC
// Program Counter
//
// The PC is a post-increment design.
// That is, it increments afre the current bus-cycle
// is over. The post-incrementing is by 1 usually,
// but there are times it is incremented by 2.
// This occurs when a failed branch
// opcode is detected. In this case, the next opcode
// to be fetched is branch + 3.
//
assign PC_incrementH = PC_incH | add2_to_PCH;
assign copy_thresholdH = reg_pc[`K-1] & ~boot_l & ~copy_completedH;
//
// This dictates how much the PC is to be incremented by.
// In the event of a failed branch-condition, the PC needs
// to be incremented by 2. At all other cases, the PC
// increments simply by 1
wire [`AW-1:0] pc_delta;
assign pc_delta = add2_to_PCH ? 2 : 1;
always @(posedge sys_clk or negedge sys_rst_l)
if (~sys_rst_l)
reg_pc <= {`AW{1'b0}}; // the reset value must be all 0's
else
// parallel statement
begin
if (copy_thresholdH) reg_pc <= {`AW{1'b0}};
// load
if (PC_loadH) reg_pc <= d_bus;
// post inctrement
if (PC_incrementH) reg_pc <= reg_pc + pc_delta;
end
//
// SP
//
// Stack Pointer is always initialized to 0xFFFF (the top
// of PC1's address space).
// For PUSH the stack is a post decrementer, that is,
// it pushes first then decrement.
// For POPs it increments first, then reads.
// The stack pointer is only 12 bits long.
//
wire SP_change;
wire [`SW-1:0] sp_delta;
assign SP_change = SP_incINH | SP_decH;
// This mux select between +1 or -1.
// This allows the use of only 1 adder
assign sp_delta = SP_incINH ? {{`SW-1{1'b0}},1'b1} : {`SW{1'b1}};
always @(posedge sys_clk or negedge sys_rst_l)
if (~sys_rst_l)
reg_sp <= {`SW{1'b1}}; // default reset value of sp is 0xFFFF
else
// if (SP_change) reg_sp <= reg_sp + sp_delta;
if (SP_incINH) reg_sp <= reg_sp + 1;
else if (SP_decH) reg_sp <= reg_sp -1;
//
// CMD[9:7] addx => {OPLHI,OPLO}=0 PC=1 SP=2 INT_VEC_LO=3 INT_VEC_HI=4 MEM_COPY=5
//
//
// This mux selectes the source of the address
// during the bus_cycle
//
//
always @(addx_mux or reg_pc or reg_sp or d_bus or reg_ax or reg_bx)
case (addx_mux)
3'b000: addx_bus = d_bus;
3'b001: addx_bus = reg_pc; // during MEM_COPY also use PC
3'b010: addx_bus = {{(16-`SW){1'b1}},reg_sp}; // SP is only 11 bits
3'b011: addx_bus = 16'h0010; // int vector Low addx
3'b100: addx_bus = 16'h0011; // int vector High addx
3'b101: addx_bus = {reg_bx,reg_ax};
default: addx_bus = 16'hxxxx;
endcase
//
// OPL
//
// Opcode Holding Register 8 bit
// This register holds the opcode fetched during the
// opcode-fetch cycle.
// Note that it is synchronous to the RISING EDGE OF
// RD signal.
//
always @(posedge code_rd_l or negedge sys_rst_l)
if (~sys_rst_l) reg_oplIn <= 8'h00;
else
if (LOAD_OPL_H) reg_oplIn <= data_bus_in;
else reg_oplIn <= reg_oplIn;
// when we're processing interrupt, no new opcode
// is loaded, thus the old opcode is still in opcode-reg
// and can messup the interrupt cycle. Thus, we clear it
// to 0.
assign reg_opl = interrupt_pendingH ? 0 : reg_oplIn;
//
// OPLO
//
// This register hold the low byte operand fetched
// from the memory.
// This regsiter holds the low byte of address
// or data from stack or from memory.
// Note that this is LEVEL TRIGGERED LATCH.
// this is because this register is the critical
// path for all ALU operations.
//
always @(posedge code_rd_l or negedge sys_rst_l)
if (~sys_rst_l) reg_oplo = 8'h00;
else
if (LOAD_OPLO_H) reg_oplo = data_bus_in;
else reg_oplo = reg_oplo;
//
// OPHI
//
// This register hold the low byte operand fetched
// from the memory.
// This register hold the high byte of address.
// Note that it is synchronous to the RISING EDGE OF
// RD signal.
//
always @(posedge code_rd_l or negedge sys_rst_l)
if (~sys_rst_l) reg_ophi = {`AW-9{1'b0}};
else
if (LOAD_OPHI_H ) reg_ophi = data_bus_in;
else reg_ophi = reg_ophi;
assign d_bus={reg_ophi,reg_oplo};
//
// copy_completedH gets to be set and remains set
// when reg_pc reaches half of the address space
// and boot_l is set low. Until then, it is low.
// Use this signal in conjunction with boot_l
// to qualify copying status.
//
always @(posedge sys_clk or negedge sys_rst_l)
if (~sys_rst_l)
copy_completedH <= 1'b0;
else if (~copy_completedH)
copy_completedH <= reg_pc[`K-1] & ~boot_l;
// **************************************************************
//
// I N T E R N A L B U S Y G E N E R A T I O N
//
// Internal readyIN_h generation.
// During the FLASH->SRAM copying process,
// we need to insert a number of the wait state so that
// the copy from the slow FLASH to SRAM can be done
// even with slow FLASH devices, yet running with high
// clock speed (>25MHz)
//
// **************************************************************
assign anyCS_l = sram_cs0_l & code_cs_l;
// State Machine State Definition
`define wait_to_start 1'b0
`define wait_to_complete 1'b1
//
// Wait-State Generating State Machine
//
always @(anyCS_l or wait_state_cntr or
wait_state or copy_completedH or boot_l)
begin
// default values
inc_wait_state_cntr = 0;
readyIN_h = 1'b1;
case (wait_state)
// In this state, wait for the right point of
// the bus-cycle to insert the first wait
// cycle. Insert the wait state only if, any of
// the CS are asserted and copy_completedH is
// still low. This signal will be low until the
// copy process is completed. And boot_l is low,
// that is, copy is requested.
`wait_to_start: begin
if (~anyCS_l & ~copy_completedH & ~boot_l) begin
next_wait_state = `wait_to_complete;
inc_wait_state_cntr = 1'b1;
// deassert readyINH_h (not ready, i.e. busy)
// only if copying is requested.
readyIN_h = boot_l;
end
else begin
next_wait_state = `wait_to_start;
end
end
// In this state keep readyINH_h deasserted (i.e.
// not ready) while the wait-state counter has
// not reached the limit.
`wait_to_complete:
if (wait_state_cntr == 2'b11) begin
next_wait_state = `wait_to_start;
end
else begin
next_wait_state = `wait_to_complete;
inc_wait_state_cntr = 1'b1;
readyIN_h = 1'b0;
end
default: begin
next_wait_state = 1'bx;
inc_wait_state_cntr = 1'bx;
readyIN_h = 1'bx;
end
endcase
end
// Next State State Assigment
always @(posedge sys_clk or negedge sys_rst_l)
if (~sys_rst_l) wait_state <= `wait_to_start;
else wait_state <= next_wait_state;
// Counter which is used to generated the wait-state
// ticks.
always @(posedge sys_clk or negedge sys_rst_l)
if (~sys_rst_l)
// reset the counter
wait_state_cntr <= 0;
else
// count up only if allowed
if (inc_wait_state_cntr)
wait_state_cntr <= wait_state_cntr + 1;
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -