URL
https://opencores.org/ocsvn/eco32/eco32/trunk
Subversion Repositories eco32
Compare Revisions
- This comparison shows the changes necessary to convert path
/eco32/trunk
- from Rev 307 to Rev 308
- ↔ Reverse comparison
Rev 307 → Rev 308
/fpga/mc-vl/src/ram/ram.v
0,0 → 1,72
// |
// ram.v -- simulate external RAM |
// 8M x 32 bit = 32 MB |
// |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
// |
// use this set of parameters for minimal access times |
// |
//`define RD_CYCLES 4'd2 // # cycles for read, min = 2 |
//`define WR_CYCLES 4'd2 // # cycles for write, min = 2 |
|
// |
// use this set of parameters for realistic access times |
// |
`define RD_CYCLES 4'd14 // # cycles for read, min = 2 |
`define WR_CYCLES 4'd6 // # cycles for write, min = 2 |
|
|
module ram(clk, rst, |
stb, we, addr, |
data_in, data_out, ack); |
input clk; |
input rst; |
input stb; |
input we; |
input [24:2] addr; |
input [31:0] data_in; |
output reg [31:0] data_out; |
output ack; |
|
reg [31:0] mem[0:8388607]; |
reg [3:0] counter; |
|
always @(posedge clk) begin |
if (stb) begin |
if (we) begin |
// write cycle |
mem[addr] <= data_in; |
end else begin |
// read cycle |
data_out <= mem[addr]; |
end |
end |
end |
|
always @(posedge clk) begin |
if (rst) begin |
counter[3:0] <= 4'h0; |
end else begin |
if (counter[3:0] == 4'h0) begin |
if (stb & ~we) begin |
// a read may need some clock cycles |
counter[3:0] <= `RD_CYCLES - 1; |
end |
if (stb & we) begin |
// a write may need some clock cycles |
counter[3:0] <= `WR_CYCLES - 1; |
end |
end else begin |
counter[3:0] <= counter[3:0] - 1; |
end |
end |
end |
|
assign ack = (counter[3:0] == 4'h1) ? 1 : 0; |
|
endmodule |
/fpga/mc-vl/src/kbd/kbd.v
0,0 → 1,93
// |
// kbd.v -- PS/2 keyboard interface |
// |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
module kbd(clk, rst, |
stb, we, addr, |
data_in, data_out, |
ack, irq); |
input clk; |
input rst; |
input stb; |
input we; |
input addr; |
input [7:0] data_in; |
output [7:0] data_out; |
output ack; |
output irq; |
|
reg [39:0] kbd_data[0:255]; // space for 256 data requests |
reg [7:0] kbd_data_index; // next location to read |
wire [39:0] next_full; // 40 bits from kbd_data |
wire [31:0] next_time; // 32 bits delta clock ticks |
wire [7:0] next_code; // 8 bits character code |
reg [31:0] counter; // delta tick counter |
wire next_rdy; // delta time expired |
|
reg [7:0] data; |
reg rdy; |
reg ien; |
reg [7:2] other_bits; |
|
initial begin |
$readmemh("kbd.dat", kbd_data); |
end |
|
assign next_full[39:0] = kbd_data[kbd_data_index]; |
assign next_time[31:0] = next_full[39:8]; |
assign next_code[7:0] = next_full[7:0]; |
|
always @(posedge clk) begin |
if (rst) begin |
kbd_data_index <= 0; |
counter <= 0; |
end else begin |
if (counter == 0) begin |
counter <= next_time; |
end else |
if (counter == 1) begin |
kbd_data_index <= kbd_data_index + 1; |
counter <= counter - 1; |
end else begin |
if (counter != 32'hFFFFFFFF) begin |
counter <= counter - 1; |
end |
end |
end |
end |
|
assign next_rdy = (counter == 1) ? 1 : 0; |
|
always @(posedge clk) begin |
if (rst) begin |
data <= 8'h00; |
rdy <= 0; |
ien <= 0; |
other_bits <= 6'b000000; |
end else begin |
if (next_rdy) begin |
data <= next_code; |
end |
if (next_rdy == 1 || |
(stb == 1 && we == 0 && addr == 1)) begin |
rdy <= next_rdy; |
end |
if (stb == 1 && we == 1 && addr == 0) begin |
rdy <= data_in[0]; |
ien <= data_in[1]; |
other_bits <= data_in[7:2]; |
end |
end |
end |
|
assign data_out = |
(addr == 0) ? { other_bits[7:2], ien, rdy } : data[7:0]; |
assign ack = stb; |
assign irq = ien & rdy; |
|
endmodule |
/fpga/mc-vl/src/clk_rst/clk_rst.v
0,0 → 1,37
// |
// clk_rst.v -- clock and reset generator |
// |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
module clk_rst(clk_in, rst_in_n, |
clk, rst); |
input clk_in; |
input rst_in_n; |
output clk; |
output rst; |
|
reg rst_p_n; |
reg rst_s_n; |
reg [3:0] cnt; |
|
assign clk = clk_in; |
|
always @(posedge clk) begin |
rst_p_n <= rst_in_n; |
rst_s_n <= rst_p_n; |
if (rst_s_n == 0) begin |
cnt <= 4'h0; |
end else begin |
if (cnt != 4'hF) begin |
cnt <= cnt + 1; |
end |
end |
end |
|
assign rst = (cnt == 4'hF) ? 0 : 1; |
|
endmodule |
/fpga/mc-vl/src/tmr/tmr.v
0,0 → 1,94
// |
// tmr.v -- programmable timer |
// |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
module tmr(clk, rst, |
stb, we, addr, |
data_in, data_out, |
ack, irq); |
input clk; |
input rst; |
input stb; |
input we; |
input [3:2] addr; |
input [31:0] data_in; |
output reg [31:0] data_out; |
output ack; |
output irq; |
|
reg [31:0] counter; |
reg [31:0] divisor; |
reg divisor_loaded; |
reg expired; |
reg alarm; |
reg ien; |
|
always @(posedge clk) begin |
if (divisor_loaded) begin |
counter <= divisor; |
expired <= 0; |
end else begin |
if (counter == 32'h00000001) begin |
counter <= divisor; |
expired <= 1; |
end else begin |
counter <= counter - 1; |
expired <= 0; |
end |
end |
end |
|
always @(posedge clk) begin |
if (rst) begin |
divisor <= 32'hFFFFFFFF; |
divisor_loaded <= 1; |
alarm <= 0; |
ien <= 0; |
end else begin |
if (expired) begin |
alarm <= 1; |
end else begin |
if (stb == 1 && we == 1 && addr[3:2] == 2'b00) begin |
// ctrl |
alarm <= data_in[0]; |
ien <= data_in[1]; |
end |
if (stb == 1 && we == 1 && addr[3:2] == 2'b01) begin |
// divisor |
divisor <= data_in; |
divisor_loaded <= 1; |
end else begin |
divisor_loaded <= 0; |
end |
end |
end |
end |
|
always @(*) begin |
case (addr[3:2]) |
2'b00: |
// ctrl |
data_out = { 28'h0000000, 2'b00, ien, alarm }; |
2'b01: |
// divisor |
data_out = divisor; |
2'b10: |
// counter |
data_out = counter; |
2'b11: |
// not used |
data_out = 32'hxxxxxxxx; |
default: |
data_out = 32'hxxxxxxxx; |
endcase |
end |
|
assign ack = stb; |
assign irq = ien & alarm; |
|
endmodule |
/fpga/mc-vl/src/dsp/dsp.v
0,0 → 1,42
// |
// dsp.v -- character display interface |
// |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
module dsp(clk, rst, |
stb, we, addr, |
data_in, data_out, ack); |
input clk; |
input rst; |
input stb; |
input we; |
input [13:2] addr; |
input [15:0] data_in; |
output [15:0] data_out; |
output ack; |
|
integer dsp_out; // file handle for display output |
|
reg [15:0] mem[0:4095]; // 32 x 128 attr/char display memory |
|
initial begin |
dsp_out = $fopen("dsp.out", "w"); |
end |
|
always @(posedge clk) begin |
if (stb & we) begin |
mem[addr[13:2]] <= data_in[15:0]; |
$fdisplay(dsp_out, |
"row = %d, col = %d, attr = 0x%h, char = 0x%h", |
addr[13:9], addr[8:2], data_in[15:8], data_in[7:0]); |
end |
end |
|
assign data_out[15:0] = mem[addr[13:2]]; |
assign ack = stb; |
|
endmodule |
/fpga/mc-vl/src/cpu/cpu_core.v
0,0 → 1,2933
// |
// cpu_core.v -- the ECO32 CPU core |
// |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
module cpu_core(clk, rst, |
bus_stb, bus_we, bus_size, bus_addr, |
bus_din, bus_dout, bus_ack, bus_irq); |
input clk; // system clock |
input rst; // system reset |
output bus_stb; // bus strobe |
output bus_we; // bus write enable |
output [1:0] bus_size; // 00: byte, 01: halfword, 10: word |
output [31:0] bus_addr; // bus address |
input [31:0] bus_din; // bus data input, for reads |
output [31:0] bus_dout; // bus data output, for writes |
input bus_ack; // bus acknowledge |
input [15:0] bus_irq; // bus interrupt requests |
|
// program counter |
wire [31:0] pc; // program counter |
wire pc_we; // pc write enable |
wire [2:0] pc_src; // pc source selector |
wire [31:0] pc_next; // value written into pc |
|
// bus & mmu |
wire [31:0] mar; // memory address register |
wire mar_we; // mar write enable |
wire ma_src /* verilator isolate_assignments */; |
// memory address source selector |
wire [2:0] mmu_fnc; // mmu function |
wire [31:0] virt_addr; // virtual address |
wire [31:0] phys_addr; // physical address |
wire [31:0] mdor; // memory data out register |
wire mdor_we; // mdor write enable |
wire [31:0] mdir; // memory data in register |
wire mdir_we; // mdir write enable |
wire mdir_sx; // mdir sign-extend |
|
// instruction register & decoder |
wire ir_we; // ir write enable |
wire [5:0] opcode; // opcode part of ir |
wire [4:0] reg1; // register 1 part of ir |
wire [4:0] reg2; // register 2 part of ir |
wire [4:0] reg3; // register 3 part of ir |
wire [31:0] sx16; // sign-extended 16-bit immediate |
wire [31:0] zx16; // zero-extended 16-bit immediate |
wire [31:0] hi16; // high 16-bit immediate |
wire [31:0] sx16s2; // sign-extended 16-bit immediate << 2 |
wire [31:0] sx26s2; // sign-extended 26-bit immediate << 2 |
|
// register file |
wire [4:0] reg_a1; // register address 1 |
wire [31:0] reg_do1; // register data out 1 |
wire [1:0] reg_src2; // register source 2 selector |
wire [4:0] reg_a2; // register address 2 |
wire [31:0] reg_do2; // register data out 2 |
wire reg_we2; // register write enable 2 |
wire reg_we2_prot; // register write enable 2, |
// protected against writes with a2 = 0 |
wire [2:0] reg_di2_src; // register data in 2 source selector |
wire [31:0] reg_di2; // register data in 2 |
|
// alu, shift, and muldiv units |
wire alu_src1; // alu source 1 selector |
wire [31:0] alu_op1; // alu operand 1 |
wire [2:0] alu_src2; // alu source 2 selector |
wire [31:0] alu_op2; // alu operand 2 |
wire [2:0] alu_fnc; // alu function |
wire [31:0] alu_res; // alu result |
wire alu_equ; // alu operand 1 = operand 2 |
wire alu_ult; // alu operand 1 < operand 2 (unsigned) |
wire alu_slt; // alu operand 1 < operand 2 (signed) |
wire [1:0] shift_fnc; // shift function |
wire [31:0] shift_res; // shift result |
wire [2:0] muldiv_fnc; // muldiv function |
wire muldiv_start; // muldiv should start |
wire muldiv_done; // muldiv has finished |
wire muldiv_error; // muldiv detected division by zero |
wire [31:0] muldiv_res; // muldiv result |
|
// special registers |
wire [2:0] sreg_num; // special register number |
wire sreg_we; // special register write enable |
wire [31:0] sreg_di; // special register data in |
wire [31:0] sreg_do; // special register data out |
wire [31:0] psw; // special register 0 (psw) contents |
wire psw_we; // psw write enable |
wire [31:0] psw_new; // new psw contents |
wire [31:0] tlb_index; // special register 1 (tlb index) contents |
wire tlb_index_we; // tlb index write enable |
wire [31:0] tlb_index_new; // new tlb index contents |
wire [31:0] tlb_entry_hi; // special register 2 (tlb entry hi) contents |
wire tlb_entry_hi_we; // tlb entry hi write enable |
wire [31:0] tlb_entry_hi_new; // new tlb entry hi contents |
wire [31:0] tlb_entry_lo; // special register 3 (tlb entry lo) contents |
wire tlb_entry_lo_we; // tlb entry lo write enable |
wire [31:0] tlb_entry_lo_new; // new tlb entry lo contents |
wire [31:0] mmu_bad_addr; // special register 4 (mmu bad addr) contents |
wire mmu_bad_addr_we; // mmu bad addr write enable |
wire [31:0] mmu_bad_addr_new; // new mmu bad addr contents |
wire [31:0] mmu_bad_accs; // special register 5 (mmu bad accs) contents |
wire mmu_bad_accs_we; // mmu bad accs write enable |
wire [31:0] mmu_bad_accs_new; // new mmu bad accs contents |
|
// mmu & tlb |
wire tlb_kmissed; // page not found in tlb, MSB of addr is 1 |
wire tlb_umissed; // page not found in tlb, MSB of addr is 0 |
wire tlb_invalid; // tlb entry is invalid |
wire tlb_wrtprot; // frame is write-protected |
|
//------------------------------------------------------------ |
|
// program counter |
assign pc_next = (pc_src == 3'b000) ? alu_res : |
(pc_src == 3'b001) ? 32'hE0000000 : |
(pc_src == 3'b010) ? 32'hE0000004 : |
(pc_src == 3'b011) ? 32'hC0000004 : |
(pc_src == 3'b100) ? 32'hE0000008 : |
(pc_src == 3'b101) ? 32'hC0000008 : |
32'hxxxxxxxx; |
pc pc_1(clk, pc_we, pc_next, pc); |
|
// bus & mmu |
mar mar_1(clk, mar_we, alu_res, mar); |
assign virt_addr = (ma_src == 0) ? pc : mar; |
mmu mmu_1(clk, rst, mmu_fnc, virt_addr, phys_addr, |
tlb_index, tlb_index_new, |
tlb_entry_hi, tlb_entry_hi_new, |
tlb_entry_lo, tlb_entry_lo_new, |
tlb_kmissed, tlb_umissed, |
tlb_invalid, tlb_wrtprot); |
assign bus_addr = phys_addr; |
mdor mdor_1(clk, mdor_we, reg_do2, mdor); |
assign bus_dout = mdor; |
mdir mdir_1(clk, mdir_we, bus_din, bus_size, mdir_sx, mdir); |
|
// instruction register & decoder |
ir ir_1(clk, |
ir_we, bus_din, |
opcode, reg1, reg2, reg3, |
sx16, zx16, hi16, sx16s2, sx26s2); |
|
// register file |
assign reg_a1 = reg1; |
assign reg_a2 = (reg_src2 == 2'b00) ? reg2 : |
(reg_src2 == 2'b01) ? reg3 : |
(reg_src2 == 2'b10) ? 5'b11111 : |
(reg_src2 == 2'b11) ? 5'b11110 : |
5'bxxxxx; |
assign reg_we2_prot = reg_we2 & (| reg_a2[4:0]); |
assign reg_di2 = (reg_di2_src == 3'b000) ? alu_res : |
(reg_di2_src == 3'b001) ? shift_res : |
(reg_di2_src == 3'b010) ? muldiv_res : |
(reg_di2_src == 3'b011) ? mdir : |
(reg_di2_src == 3'b100) ? sreg_do : |
32'hxxxxxxxx; |
regs regs_1(clk, |
reg_a1, reg_do1, |
reg_a2, reg_do2, reg_we2_prot, reg_di2); |
|
// alu, shift, and muldiv units |
assign alu_op1 = (alu_src1 == 0) ? pc : reg_do1; |
assign alu_op2 = (alu_src2 == 3'b000) ? 32'h00000004 : |
(alu_src2 == 3'b001) ? reg_do2 : |
(alu_src2 == 3'b010) ? sx16 : |
(alu_src2 == 3'b011) ? zx16 : |
(alu_src2 == 3'b100) ? hi16 : |
(alu_src2 == 3'b101) ? sx16s2 : |
(alu_src2 == 3'b110) ? sx26s2 : |
32'hxxxxxxxx; |
alu alu_1(alu_op1, alu_op2, alu_fnc, |
alu_res, alu_equ, alu_ult, alu_slt); |
shift shift_1(clk, alu_op1, alu_op2[4:0], shift_fnc, shift_res); |
muldiv muldiv_1(clk, alu_op1, alu_op2, muldiv_fnc, muldiv_start, |
muldiv_done, muldiv_error, muldiv_res); |
|
// special registers |
assign sreg_num = zx16[2:0]; |
assign sreg_di = reg_do2; |
sregs sregs_1(clk, rst, |
sreg_num, sreg_we, sreg_di, sreg_do, |
psw, psw_we, psw_new, |
tlb_index, tlb_index_we, tlb_index_new, |
tlb_entry_hi, tlb_entry_hi_we, tlb_entry_hi_new, |
tlb_entry_lo, tlb_entry_lo_we, tlb_entry_lo_new, |
mmu_bad_addr, mmu_bad_addr_we, mmu_bad_addr_new, |
mmu_bad_accs, mmu_bad_accs_we, mmu_bad_accs_new); |
assign mmu_bad_addr_new = virt_addr; |
assign mmu_bad_accs_we = mmu_bad_addr_we; |
assign mmu_bad_accs_new = { 29'b0, bus_we, bus_size[1:0] }; |
|
// ctrl |
ctrl ctrl_1(clk, rst, |
opcode, alu_equ, alu_ult, alu_slt, |
bus_ack, bus_stb, bus_we, bus_size, |
pc_src, pc_we, |
mar_we, ma_src, mmu_fnc, |
mdor_we, mdir_we, mdir_sx, ir_we, |
reg_src2, reg_di2_src, reg_we2, |
alu_src1, alu_src2, alu_fnc, shift_fnc, |
muldiv_fnc, muldiv_start, |
muldiv_done, muldiv_error, |
sreg_we, bus_irq, psw, psw_we, psw_new, |
virt_addr[31], virt_addr[1], virt_addr[0], |
tlb_kmissed, tlb_umissed, |
tlb_invalid, tlb_wrtprot, |
tlb_index_we, tlb_entry_hi_we, |
tlb_entry_lo_we, mmu_bad_addr_we); |
|
endmodule |
|
|
//-------------------------------------------------------------- |
// ctrl -- the finite state machine within the CPU |
//-------------------------------------------------------------- |
|
|
module ctrl(clk, rst, |
opcode, alu_equ, alu_ult, alu_slt, |
bus_ack, bus_stb, bus_we, bus_size, |
pc_src, pc_we, |
mar_we, ma_src, mmu_fnc, |
mdor_we, mdir_we, mdir_sx, ir_we, |
reg_src2, reg_di2_src, reg_we2, |
alu_src1, alu_src2, alu_fnc, shift_fnc, |
muldiv_fnc, muldiv_start, |
muldiv_done, muldiv_error, |
sreg_we, bus_irq, psw, psw_we, psw_new, |
va_31, va_1, va_0, |
tlb_kmissed, tlb_umissed, |
tlb_invalid, tlb_wrtprot, |
tlb_index_we, tlb_entry_hi_we, |
tlb_entry_lo_we, mmu_bad_addr_we); |
input clk; |
input rst; |
input [5:0] opcode; |
input alu_equ; |
input alu_ult; |
input alu_slt; |
input bus_ack; |
output reg bus_stb; |
output reg bus_we; |
output reg [1:0] bus_size; |
output reg [2:0] pc_src; |
output reg pc_we; |
output reg mar_we; |
output reg ma_src; |
output reg [2:0] mmu_fnc; |
output reg mdor_we; |
output reg mdir_we; |
output reg mdir_sx; |
output reg ir_we; |
output reg [1:0] reg_src2; |
output reg [2:0] reg_di2_src; |
output reg reg_we2; |
output reg alu_src1; |
output reg [2:0] alu_src2; |
output reg [2:0] alu_fnc; |
output reg [1:0] shift_fnc; |
output reg [2:0] muldiv_fnc; |
output reg muldiv_start; |
input muldiv_done; |
input muldiv_error; |
output reg sreg_we; |
input [15:0] bus_irq; |
input [31:0] psw; |
output reg psw_we; |
output reg [31:0] psw_new; |
input va_31, va_1, va_0; |
input tlb_kmissed; |
input tlb_umissed; |
input tlb_invalid; |
input tlb_wrtprot; |
output reg tlb_index_we; |
output reg tlb_entry_hi_we; |
output reg tlb_entry_lo_we; |
output reg mmu_bad_addr_we; |
|
wire type_rrr; // instr type is RRR |
wire type_rrs; // instr type is RRS |
wire type_rrh; // instr type is RRH |
wire type_rhh; // instr type is RHH |
wire type_rrb; // instr type is RRB |
wire type_j; // instr type is J |
wire type_jr; // instr type is JR |
wire type_link; // instr saves PC+4 in $31 |
wire type_ld; // instr loads data |
wire type_st; // instr stores data |
wire type_ldst; // instr loads or stores data |
wire [1:0] ldst_size; // load/store transfer size |
wire type_shift; // instr uses the shift unit |
wire type_muldiv; // instr uses the muldiv unit |
wire type_fast; // instr is not shift or muldiv |
wire type_mvfs; // instr is mvfs |
wire type_mvts; // instr is mvts |
wire type_rfx; // instr is rfx |
wire type_trap; // instr is trap |
wire type_tb; // instr is a TLB instr |
reg [4:0] state; // cpu internal state |
// 0: reset |
// 1: fetch instr (addr xlat) |
// 2: decode instr |
// increment pc by 4 |
// possibly store pc+4 in $31 |
// 3: execute RRR-type instr |
// 4: execute RRS-type instr |
// 5: execute RRH-type instr |
// 6: execute RHH-type instr |
// 7: execute RRB-type instr (1) |
// 8: execute RRB-type instr (2) |
// 9: execute J-type instr |
// 10: execute JR-type instr |
// 11: execute LDST-type instr (1) |
// 12: execute LD-type instr (addr xlat) |
// 13: execute LD-type instr (3) |
// 14: execute ST-type instr (addr xlat) |
// 15: interrupt |
// 16: extra state for RRR shift instr |
// 17: extra state for RRH shift instr |
// 18: extra state for RRR muldiv instr |
// 19: extra state for RRS muldiv instr |
// 20: extra state for RRH muldiv instr |
// 21: execute mvfs instr |
// 22: execute mvts instr |
// 23: execute rfx instr |
// 24: irq_trigger check for mvts and rfx |
// 25: exception (locus is PC-4) |
// 26: exception (locus is PC) |
// 27: execute TLB instr |
// 28: fetch instr (bus cycle) |
// 29: execute LD-type instr (bus cycle) |
// 30: execute ST-type instr (bus cycle) |
// all other: unused |
reg branch; // take the branch iff true |
wire [15:0] irq_pending; // the vector of pending unmasked irqs |
wire irq_trigger; // true iff any pending irq is present |
// and interrupts are globally enabled |
reg [3:0] irq_priority; // highest priority of pending interrupts |
reg [3:0] exc_priority; // exception, when entering state 25 or 26 |
reg [7:0] bus_count; // counter to detect bus timeout |
wire bus_timeout; // bus timeout detected |
wire exc_prv_addr; // privileged address exception detected |
wire exc_ill_addr; // illegal address exception detected |
wire exc_tlb_but_wrtprot; // any tlb exception but write protection |
wire exc_tlb_any; // any tlb exception |
|
//------------------------------------------------------------ |
|
// decode instr type |
assign type_rrr = ((opcode == 6'h00) || |
(opcode == 6'h02) || |
(opcode == 6'h04) || |
(opcode == 6'h06) || |
(opcode == 6'h08) || |
(opcode == 6'h0A) || |
(opcode == 6'h0C) || |
(opcode == 6'h0E) || |
(opcode == 6'h10) || |
(opcode == 6'h12) || |
(opcode == 6'h14) || |
(opcode == 6'h16) || |
(opcode == 6'h18) || |
(opcode == 6'h1A) || |
(opcode == 6'h1C)) ? 1 : 0; |
assign type_rrs = ((opcode == 6'h01) || |
(opcode == 6'h03) || |
(opcode == 6'h05) || |
(opcode == 6'h09) || |
(opcode == 6'h0D)) ? 1 : 0; |
assign type_rrh = ((opcode == 6'h07) || |
(opcode == 6'h0B) || |
(opcode == 6'h0F) || |
(opcode == 6'h11) || |
(opcode == 6'h13) || |
(opcode == 6'h15) || |
(opcode == 6'h17) || |
(opcode == 6'h19) || |
(opcode == 6'h1B) || |
(opcode == 6'h1D)) ? 1 : 0; |
assign type_rhh = (opcode == 6'h1F) ? 1 : 0; |
assign type_rrb = ((opcode == 6'h20) || |
(opcode == 6'h21) || |
(opcode == 6'h22) || |
(opcode == 6'h23) || |
(opcode == 6'h24) || |
(opcode == 6'h25) || |
(opcode == 6'h26) || |
(opcode == 6'h27) || |
(opcode == 6'h28) || |
(opcode == 6'h29)) ? 1 : 0; |
assign type_j = ((opcode == 6'h2A) || |
(opcode == 6'h2C)) ? 1 : 0; |
assign type_jr = ((opcode == 6'h2B) || |
(opcode == 6'h2D)) ? 1 : 0; |
assign type_link = ((opcode == 6'h2C) || |
(opcode == 6'h2D)) ? 1 : 0; |
assign type_ld = ((opcode == 6'h30) || |
(opcode == 6'h31) || |
(opcode == 6'h32) || |
(opcode == 6'h33) || |
(opcode == 6'h34)) ? 1 : 0; |
assign type_st = ((opcode == 6'h35) || |
(opcode == 6'h36) || |
(opcode == 6'h37)) ? 1 : 0; |
assign type_ldst = type_ld | type_st; |
assign ldst_size = ((opcode == 6'h30) || |
(opcode == 6'h35)) ? 2'b10 : |
((opcode == 6'h31) || |
(opcode == 6'h32) || |
(opcode == 6'h36)) ? 2'b01 : |
((opcode == 6'h33) || |
(opcode == 6'h34) || |
(opcode == 6'h37)) ? 2'b00 : |
2'bxx; |
assign type_shift = ((opcode == 6'h18) || |
(opcode == 6'h19) || |
(opcode == 6'h1A) || |
(opcode == 6'h1B) || |
(opcode == 6'h1C) || |
(opcode == 6'h1D)) ? 1 : 0; |
assign type_muldiv = ((opcode == 6'h04) || |
(opcode == 6'h05) || |
(opcode == 6'h06) || |
(opcode == 6'h07) || |
(opcode == 6'h08) || |
(opcode == 6'h09) || |
(opcode == 6'h0A) || |
(opcode == 6'h0B) || |
(opcode == 6'h0C) || |
(opcode == 6'h0D) || |
(opcode == 6'h0E) || |
(opcode == 6'h0F)) ? 1 : 0; |
assign type_fast = ~(type_shift | type_muldiv); |
assign type_mvfs = (opcode == 6'h38) ? 1 : 0; |
assign type_mvts = (opcode == 6'h39) ? 1 : 0; |
assign type_rfx = (opcode == 6'h2F) ? 1 : 0; |
assign type_trap = (opcode == 6'h2E) ? 1 : 0; |
assign type_tb = ((opcode == 6'h3A) || |
(opcode == 6'h3B) || |
(opcode == 6'h3C) || |
(opcode == 6'h3D)) ? 1 : 0; |
|
// state machine |
always @(posedge clk) begin |
if (rst == 1) begin |
state <= 0; |
end else begin |
case (state) |
5'd0: // reset |
begin |
state <= 5'd1; |
end |
5'd1: // fetch instr (addr xlat) |
begin |
if (exc_prv_addr) begin |
state <= 26; |
exc_priority <= 4'd9; |
end else |
if (exc_ill_addr) begin |
state <= 26; |
exc_priority <= 4'd8; |
end else begin |
state <= 5'd28; |
end |
end |
5'd2: // decode instr |
// increment pc by 4 |
// possibly store pc+4 in $31 |
begin |
if (type_rrr) begin |
// RRR-type instruction |
state <= 5'd3; |
end else |
if (type_rrs) begin |
// RRS-type instruction |
state <= 5'd4; |
end else |
if (type_rrh) begin |
// RRH-type instruction |
state <= 5'd5; |
end else |
if (type_rhh) begin |
// RHH-type instruction |
state <= 5'd6; |
end else |
if (type_rrb) begin |
// RRB-type instr |
state <= 5'd7; |
end else |
if (type_j) begin |
// J-type instr |
state <= 5'd9; |
end else |
if (type_jr) begin |
// JR-type instr |
state <= 5'd10; |
end else |
if (type_ldst) begin |
// LDST-type instr |
state <= 5'd11; |
end else |
if (type_mvfs) begin |
// mvfs instr |
state <= 5'd21; |
end else |
if (type_mvts) begin |
// mvts instr |
if (psw[26] == 1) begin |
state <= 5'd25; |
exc_priority <= 4'd2; |
end else begin |
state <= 5'd22; |
end |
end else |
if (type_rfx) begin |
// rfx instr |
if (psw[26] == 1) begin |
state <= 5'd25; |
exc_priority <= 4'd2; |
end else begin |
state <= 5'd23; |
end |
end else |
if (type_trap) begin |
// trap instr |
state <= 5'd25; |
exc_priority <= 4'd4; |
end else |
if (type_tb) begin |
// TLB instr |
if (psw[26] == 1) begin |
state <= 5'd25; |
exc_priority <= 4'd2; |
end else begin |
state <= 5'd27; |
end |
end else begin |
// illegal instruction |
state <= 5'd25; |
exc_priority <= 4'd1; |
end |
end |
5'd3: // execute RRR-type instr |
begin |
if (type_muldiv) begin |
state <= 5'd18; |
end else |
if (type_shift) begin |
state <= 5'd16; |
end else begin |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end |
end |
5'd4: // execute RRS-type instr |
begin |
if (type_muldiv) begin |
state <= 5'd19; |
end else begin |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end |
end |
5'd5: // execute RRH-type instr |
begin |
if (type_muldiv) begin |
state <= 5'd20; |
end else |
if (type_shift) begin |
state <= 5'd17; |
end else begin |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end |
end |
5'd6: // execute RHH-type instr |
begin |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end |
5'd7: // execute RRB-type instr (1) |
begin |
if (branch) begin |
state <= 5'd8; |
end else begin |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end |
end |
5'd8: // execute RRB-type instr (2) |
begin |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end |
5'd9: // execute J-type instr |
begin |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end |
5'd10: // execute JR-type instr |
begin |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end |
5'd11: // execute LDST-type instr (1) |
begin |
if (type_ld) begin |
state <= 5'd12; |
end else begin |
state <= 5'd14; |
end |
end |
5'd12: // execute LD-type instr (addr xlat) |
begin |
if (exc_prv_addr) begin |
state <= 25; |
exc_priority <= 4'd9; |
end else |
if (exc_ill_addr) begin |
state <= 25; |
exc_priority <= 4'd8; |
end else begin |
state <= 5'd29; |
end |
end |
5'd13: // execute LD-type instr (3) |
begin |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end |
5'd14: // execute ST-type instr (addr xlat) |
begin |
if (exc_prv_addr) begin |
state <= 25; |
exc_priority <= 4'd9; |
end else |
if (exc_ill_addr) begin |
state <= 25; |
exc_priority <= 4'd8; |
end else begin |
state <= 5'd30; |
end |
end |
5'd15: // interrupt |
begin |
state <= 5'd1; |
end |
5'd16: // extra state for RRR shift instr |
begin |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end |
5'd17: // extra state for RRH shift instr |
begin |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end |
5'd18: // extra state for RRR muldiv instr |
begin |
if (muldiv_done) begin |
if (muldiv_error) begin |
state <= 5'd25; |
exc_priority <= 4'd3; |
end else |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end else begin |
state <= 5'd18; |
end |
end |
5'd19: // extra state for RRS muldiv instr |
begin |
if (muldiv_done) begin |
if (muldiv_error) begin |
state <= 5'd25; |
exc_priority <= 4'd3; |
end else |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end else begin |
state <= 5'd19; |
end |
end |
5'd20: // extra state for RRH muldiv instr |
begin |
if (muldiv_done) begin |
if (muldiv_error) begin |
state <= 5'd25; |
exc_priority <= 4'd3; |
end else |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end else begin |
state <= 5'd20; |
end |
end |
5'd21: // execute mvfs instr |
begin |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end |
5'd22: // execute mvts instr |
begin |
state <= 5'd24; |
end |
5'd23: // execute rfx instr |
begin |
state <= 5'd24; |
end |
5'd24: // irq_trigger check for mvts and rfx |
begin |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end |
5'd25: // exception (locus is PC-4) |
begin |
state <= 5'd1; |
end |
5'd26: // exception (locus is PC) |
begin |
state <= 5'd1; |
end |
5'd27: // execute TLB instr |
begin |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end |
5'd28: // fetch instr (bus cycle) |
begin |
if (tlb_kmissed == 1 || tlb_umissed == 1) begin |
state <= 5'd26; |
exc_priority <= 4'd5; |
end else |
if (tlb_invalid == 1) begin |
state <= 5'd26; |
exc_priority <= 4'd7; |
end else |
if (bus_ack == 0) begin |
if (bus_timeout == 1) begin |
state <= 5'd26; |
exc_priority <= 4'd0; |
end else begin |
state <= 5'd28; |
end |
end else begin |
state <= 5'd2; |
end |
end |
5'd29: // execute LD-type instr (bus cycle) |
begin |
if (tlb_kmissed == 1 || tlb_umissed == 1) begin |
state <= 5'd25; |
exc_priority <= 4'd5; |
end else |
if (tlb_invalid == 1) begin |
state <= 5'd25; |
exc_priority <= 4'd7; |
end else |
if (bus_ack == 0) begin |
if (bus_timeout == 1) begin |
state <= 5'd25; |
exc_priority <= 4'd0; |
end else begin |
state <= 5'd29; |
end |
end else begin |
state <= 5'd13; |
end |
end |
5'd30: // execute ST-type instr (bus cycle) |
begin |
if (tlb_kmissed == 1 || tlb_umissed == 1) begin |
state <= 5'd25; |
exc_priority <= 4'd5; |
end else |
if (tlb_invalid == 1) begin |
state <= 5'd25; |
exc_priority <= 4'd7; |
end else |
if (tlb_wrtprot == 1) begin |
state <= 5'd25; |
exc_priority <= 4'd6; |
end else |
if (bus_ack == 0) begin |
if (bus_timeout == 1) begin |
state <= 5'd25; |
exc_priority <= 4'd0; |
end else begin |
state <= 5'd30; |
end |
end else begin |
if (irq_trigger) begin |
state <= 5'd15; |
end else begin |
state <= 5'd1; |
end |
end |
end |
default: // all other states: unused |
begin |
state <= 5'd0; |
end |
endcase |
end |
end |
|
// bus timeout detector |
assign bus_timeout = (bus_count == 8'h00) ? 1 : 0; |
always @(posedge clk) begin |
if (bus_stb == 1 && bus_ack == 0) begin |
// bus is waiting |
bus_count <= bus_count - 1; |
end else begin |
// bus is not waiting |
bus_count <= 8'hFF; |
end |
end |
|
// output logic |
always @(*) begin |
case (state) |
5'd0: // reset |
begin |
pc_src = 3'b001; |
pc_we = 1'b1; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd1: // fetch instr (addr xlat) |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'b0; |
mmu_fnc = (exc_prv_addr | exc_ill_addr) ? 3'b000 : 3'b001; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'b0; // get bad_accs right in case of exc |
bus_size = 2'b10; // enable illegal address detection |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = exc_prv_addr | exc_ill_addr; |
end |
5'd2: // decode instr |
// increment pc by 4 |
// possibly store pc+4 in $31 |
begin |
pc_src = 3'b000; |
pc_we = 1'b1; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = (type_link == 1) ? 2'b10 : |
(type_rfx == 1) ? 2'b11 : |
2'b00; |
reg_di2_src = (type_link == 1) ? 3'b000 : 3'bxxx; |
reg_we2 = (type_link == 1) ? 1'b1 : 1'b0; |
alu_src1 = 1'b0; |
alu_src2 = 3'b000; |
alu_fnc = 3'b000; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd3: // execute RRR-type instr |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'b01; |
reg_di2_src = 3'b000; |
reg_we2 = type_fast; |
alu_src1 = 1'b1; |
alu_src2 = 3'b001; |
alu_fnc = { opcode[4], opcode[2], opcode[1] }; |
shift_fnc = { opcode[2], opcode[1] }; |
muldiv_fnc = { opcode[3], opcode[2], opcode[1] }; |
muldiv_start = type_muldiv; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd4: // execute RRS-type instr |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'b00; |
reg_di2_src = 3'b000; |
reg_we2 = type_fast; |
alu_src1 = 1'b1; |
alu_src2 = 3'b010; |
alu_fnc = { opcode[4], opcode[2], opcode[1] }; |
shift_fnc = 2'bxx; |
muldiv_fnc = { opcode[3], opcode[2], opcode[1] }; |
muldiv_start = type_muldiv; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd5: // execute RRH-type instr |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'b00; |
reg_di2_src = 3'b000; |
reg_we2 = type_fast; |
alu_src1 = 1'b1; |
alu_src2 = 3'b011; |
alu_fnc = { opcode[4], opcode[2], opcode[1] }; |
shift_fnc = { opcode[2], opcode[1] }; |
muldiv_fnc = { opcode[3], opcode[2], opcode[1] }; |
muldiv_start = type_muldiv; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd6: // execute RHH-type instr |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'b00; |
reg_di2_src = 3'b000; |
reg_we2 = 1'b1; |
alu_src1 = 1'bx; |
alu_src2 = 3'b100; |
alu_fnc = 3'b011; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd7: // execute RRB-type instr (1) |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'b1; |
alu_src2 = 3'b001; |
alu_fnc = 3'b001; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd8: // execute RRB-type instr (2) |
begin |
pc_src = 3'b000; |
pc_we = 1'b1; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'b0; |
alu_src2 = 3'b101; |
alu_fnc = 3'b000; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd9: // execute J-type instr |
begin |
pc_src = 3'b000; |
pc_we = 1'b1; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'b0; |
alu_src2 = 3'b110; |
alu_fnc = 3'b000; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd10: // execute JR-type instr |
begin |
pc_src = 3'b000; |
pc_we = 1'b1; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'b1; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'b010; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd11: // execute LDST-type instr (1) |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b1; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b1; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'b1; |
alu_src2 = 3'b010; |
alu_fnc = 3'b000; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd12: // execute LD-type instr (addr xlat) |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'b1; |
mmu_fnc = (exc_prv_addr | exc_ill_addr) ? 3'b000 : 3'b001; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'b0; // get bad_accs right in case of exc |
bus_size = ldst_size; // enable illegal address detection |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = exc_prv_addr | exc_ill_addr; |
end |
5'd13: // execute LD-type instr (3) |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = ldst_size; |
mdir_we = 1'b0; |
mdir_sx = opcode[0]; |
ir_we = 1'b0; |
reg_src2 = 2'b00; |
reg_di2_src = 3'b011; |
reg_we2 = 1'b1; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd14: // execute ST-type instr (addr xlat) |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'b1; |
mmu_fnc = (exc_prv_addr | exc_ill_addr) ? 3'b000 : 3'b001; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'b1; // get bad_accs right in case of exc |
bus_size = ldst_size; // enable illegal address detection |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = exc_prv_addr | exc_ill_addr; |
end |
5'd15: // interrupt |
begin |
pc_src = (psw[27] == 0) ? 3'b010 : 3'b011; |
pc_we = 1'b1; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'b11; |
reg_di2_src = 3'b000; |
reg_we2 = 1'b1; |
alu_src1 = 1'b0; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'b010; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b1; |
psw_new = { |
psw[31:28], |
psw[27], |
1'b0, psw[26], psw[25], |
1'b0, psw[23], psw[22], |
1'b0, irq_priority, |
psw[15:0] |
}; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd16: // extra state for RRR shift instr |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'b01; |
reg_di2_src = 3'b001; |
reg_we2 = 1'b1; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd17: // extra state for RRH shift instr |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'b00; |
reg_di2_src = 3'b001; |
reg_we2 = 1'b1; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd18: // extra state for RRR muldiv instr |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'b01; |
reg_di2_src = 3'b010; |
reg_we2 = muldiv_done & ~muldiv_error; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd19: // extra state for RRS muldiv instr |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'b00; |
reg_di2_src = 3'b010; |
reg_we2 = muldiv_done & ~muldiv_error; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd20: // extra state for RRH muldiv instr |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'b00; |
reg_di2_src = 3'b010; |
reg_we2 = muldiv_done & ~muldiv_error; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd21: // execute mvfs instr |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'b00; |
reg_di2_src = 3'b100; |
reg_we2 = 1'b1; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd22: // execute mvts instr |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b1; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd23: // execute rfx instr |
begin |
pc_src = 3'b000; |
pc_we = 1'b1; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'bx; |
alu_src2 = 3'b001; |
alu_fnc = 3'b011; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b1; |
psw_new = { |
psw[31:28], |
psw[27], |
psw[25], psw[24], psw[24], |
psw[22], psw[21], psw[21], |
psw[20:16], |
psw[15:0] |
}; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd24: // irq_trigger check for mvts and rfx |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd25: // exception (locus is PC-4) |
begin |
pc_src = (psw[27] != 0) ? |
((tlb_umissed != 0) ? 3'b101 : 3'b011) : |
((tlb_umissed != 0) ? 3'b100 : 3'b010); |
pc_we = 1'b1; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'b11; |
reg_di2_src = 3'b000; |
reg_we2 = 1'b1; |
alu_src1 = 1'b0; |
alu_src2 = 3'b000; |
alu_fnc = 3'b001; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b1; |
psw_new = { |
psw[31:28], |
psw[27], |
1'b0, psw[26], psw[25], |
1'b0, psw[23], psw[22], |
1'b1, exc_priority, |
psw[15:0] |
}; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd26: // exception (locus is PC) |
begin |
pc_src = (psw[27] != 0) ? |
((tlb_umissed != 0) ? 3'b101 : 3'b011) : |
((tlb_umissed != 0) ? 3'b100 : 3'b010); |
pc_we = 1'b1; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'b11; |
reg_di2_src = 3'b000; |
reg_we2 = 1'b1; |
alu_src1 = 1'b0; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'b010; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b1; |
psw_new = { |
psw[31:28], |
psw[27], |
1'b0, psw[26], psw[25], |
1'b0, psw[23], psw[22], |
1'b1, exc_priority, |
psw[15:0] |
}; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = 1'b0; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd27: // execute TLB instr |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'bx; |
mmu_fnc = opcode[2:0]; |
mdor_we = 1'b0; |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = (opcode[2:0] == 3'b010) ? 1 : 0; |
tlb_entry_hi_we = (opcode[2:0] == 3'b100) ? 1 : 0; |
tlb_entry_lo_we = (opcode[2:0] == 3'b100) ? 1 : 0; |
mmu_bad_addr_we = 1'b0; |
end |
5'd28: // fetch instr (bus cycle) |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'b0; // hold vaddr for latching in bad addr reg |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = ~exc_tlb_but_wrtprot; |
bus_we = 1'b0; |
bus_size = 2'b10; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b1; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = exc_tlb_but_wrtprot; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = exc_tlb_but_wrtprot; |
end |
5'd29: // execute LD-type instr (bus cycle) |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'b1; // hold vaddr for latching in bad addr reg |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = ~exc_tlb_but_wrtprot; |
bus_we = 1'b0; |
bus_size = ldst_size; |
mdir_we = 1'b1; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = exc_tlb_but_wrtprot; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = exc_tlb_but_wrtprot; |
end |
5'd30: // execute ST-type instr (bus cycle) |
begin |
pc_src = 3'bxxx; |
pc_we = 1'b0; |
mar_we = 1'b0; |
ma_src = 1'b1; // hold vaddr for latching in bad addr reg |
mmu_fnc = 3'b000; |
mdor_we = 1'b0; |
bus_stb = ~exc_tlb_any; |
bus_we = 1'b1; |
bus_size = ldst_size; |
mdir_we = 1'b0; |
mdir_sx = 1'bx; |
ir_we = 1'b0; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'b0; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'b0; |
sreg_we = 1'b0; |
psw_we = 1'b0; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'b0; |
tlb_entry_hi_we = exc_tlb_any; |
tlb_entry_lo_we = 1'b0; |
mmu_bad_addr_we = exc_tlb_any; |
end |
default: // all other states: unused |
begin |
pc_src = 3'bxxx; |
pc_we = 1'bx; |
mar_we = 1'bx; |
ma_src = 1'bx; |
mmu_fnc = 3'bxxx; |
mdor_we = 1'bx; |
bus_stb = 1'bx; |
bus_we = 1'bx; |
bus_size = 2'bxx; |
mdir_we = 1'bx; |
mdir_sx = 1'bx; |
ir_we = 1'bx; |
reg_src2 = 2'bxx; |
reg_di2_src = 3'bxxx; |
reg_we2 = 1'bx; |
alu_src1 = 1'bx; |
alu_src2 = 3'bxxx; |
alu_fnc = 3'bxxx; |
shift_fnc = 2'bxx; |
muldiv_fnc = 3'bxxx; |
muldiv_start = 1'bx; |
sreg_we = 1'bx; |
psw_we = 1'bx; |
psw_new = 32'hxxxxxxxx; |
tlb_index_we = 1'bx; |
tlb_entry_hi_we = 1'bx; |
tlb_entry_lo_we = 1'bx; |
mmu_bad_addr_we = 1'bx; |
end |
endcase |
end |
|
// branch logic |
always @(*) begin |
casex ( { opcode[3:0], alu_equ, alu_ult, alu_slt } ) |
// eq |
7'b00000xx: branch = 0; |
7'b00001xx: branch = 1; |
// ne |
7'b00010xx: branch = 1; |
7'b00011xx: branch = 0; |
// le |
7'b00100x0: branch = 0; |
7'b00101xx: branch = 1; |
7'b0010xx1: branch = 1; |
// leu |
7'b001100x: branch = 0; |
7'b00111xx: branch = 1; |
7'b0011x1x: branch = 1; |
// lt |
7'b0100xx0: branch = 0; |
7'b0100xx1: branch = 1; |
// ltu |
7'b0101x0x: branch = 0; |
7'b0101x1x: branch = 1; |
// ge |
7'b0110xx0: branch = 1; |
7'b0110xx1: branch = 0; |
// geu |
7'b0111x0x: branch = 1; |
7'b0111x1x: branch = 0; |
// gt |
7'b10000x0: branch = 1; |
7'b10001xx: branch = 0; |
7'b1000xx1: branch = 0; |
// gtu |
7'b100100x: branch = 1; |
7'b10011xx: branch = 0; |
7'b1001x1x: branch = 0; |
// other |
default: branch = 1'bx; |
endcase |
end |
|
// interrupts |
assign irq_pending = bus_irq[15:0] & psw[15:0]; |
assign irq_trigger = (| irq_pending) & psw[23]; |
always @(*) begin |
if ((| irq_pending[15:8]) != 0) begin |
if ((| irq_pending[15:12]) != 0) begin |
if ((| irq_pending[15:14]) != 0) begin |
if (irq_pending[15] != 0) begin |
irq_priority = 4'd15; |
end else begin |
irq_priority = 4'd14; |
end |
end else begin |
if (irq_pending[13] != 0) begin |
irq_priority = 4'd13; |
end else begin |
irq_priority = 4'd12; |
end |
end |
end else begin |
if ((| irq_pending[11:10]) != 0) begin |
if (irq_pending[11] != 0) begin |
irq_priority = 4'd11; |
end else begin |
irq_priority = 4'd10; |
end |
end else begin |
if (irq_pending[9] != 0) begin |
irq_priority = 4'd9; |
end else begin |
irq_priority = 4'd8; |
end |
end |
end |
end else begin |
if ((| irq_pending[7:4]) != 0) begin |
if ((| irq_pending[7:6]) != 0) begin |
if (irq_pending[7] != 0) begin |
irq_priority = 4'd7; |
end else begin |
irq_priority = 4'd6; |
end |
end else begin |
if (irq_pending[5] != 0) begin |
irq_priority = 4'd5; |
end else begin |
irq_priority = 4'd4; |
end |
end |
end else begin |
if ((| irq_pending[3:2]) != 0) begin |
if (irq_pending[3] != 0) begin |
irq_priority = 4'd3; |
end else begin |
irq_priority = 4'd2; |
end |
end else begin |
if (irq_pending[1] != 0) begin |
irq_priority = 4'd1; |
end else begin |
irq_priority = 4'd0; |
end |
end |
end |
end |
end |
|
// exceptions |
assign exc_prv_addr = psw[26] & va_31; |
assign exc_ill_addr = (bus_size[0] & va_0) | |
(bus_size[1] & va_0) | |
(bus_size[1] & va_1); |
assign exc_tlb_but_wrtprot = tlb_kmissed | tlb_umissed | tlb_invalid; |
assign exc_tlb_any = exc_tlb_but_wrtprot | tlb_wrtprot; |
|
endmodule |
|
|
//-------------------------------------------------------------- |
// pc -- the program counter |
//-------------------------------------------------------------- |
|
|
module pc(clk, pc_we, pc_next, pc); |
input clk; |
input pc_we; |
input [31:0] pc_next; |
output reg [31:0] pc; |
|
always @(posedge clk) begin |
if (pc_we == 1) begin |
pc <= pc_next; |
end |
end |
|
endmodule |
|
|
//-------------------------------------------------------------- |
// mar -- the memory address register |
//-------------------------------------------------------------- |
|
|
module mar(clk, mar_we, mar_next, mar); |
input clk; |
input mar_we; |
input [31:0] mar_next; |
output reg [31:0] mar; |
|
always @(posedge clk) begin |
if (mar_we == 1) begin |
mar <= mar_next; |
end |
end |
|
endmodule |
|
|
//-------------------------------------------------------------- |
// mdor -- the memory data out register |
//-------------------------------------------------------------- |
|
|
module mdor(clk, mdor_we, mdor_next, mdor); |
input clk; |
input mdor_we; |
input [31:0] mdor_next; |
output reg [31:0] mdor; |
|
always @(posedge clk) begin |
if (mdor_we == 1) begin |
mdor <= mdor_next; |
end |
end |
|
endmodule |
|
|
//-------------------------------------------------------------- |
// mdir -- the memory data in register |
//-------------------------------------------------------------- |
|
|
module mdir(clk, mdir_we, mdir_next, size, sx, mdir); |
input clk; |
input mdir_we; |
input [31:0] mdir_next; |
input [1:0] size; |
input sx; |
output reg [31:0] mdir; |
|
reg [31:0] data; |
|
always @(posedge clk) begin |
if (mdir_we == 1) begin |
data <= mdir_next; |
end |
end |
|
always @(*) begin |
case ({ size, sx }) |
3'b000: |
begin |
mdir[31:0] = { 24'h000000, data[7:0] }; |
end |
3'b001: |
begin |
if (data[7] == 1) begin |
mdir[31:0] = { 24'hFFFFFF, data[7:0] }; |
end else begin |
mdir[31:0] = { 24'h000000, data[7:0] }; |
end |
end |
3'b010: |
begin |
mdir[31:0] = { 16'h0000, data[15:0] }; |
end |
3'b011: |
begin |
if (data[15] == 1) begin |
mdir[31:0] = { 16'hFFFF, data[15:0] }; |
end else begin |
mdir[31:0] = { 16'h0000, data[15:0] }; |
end |
end |
default: |
begin |
mdir[31:0] = data[31:0]; |
end |
endcase |
end |
|
endmodule |
|
|
//-------------------------------------------------------------- |
// ir -- the instruction register and decoder |
//-------------------------------------------------------------- |
|
|
module ir(clk, |
ir_we, instr, |
opcode, reg1, reg2, reg3, |
sx16, zx16, hi16, sx16s2, sx26s2); |
input clk; |
input ir_we; |
input [31:0] instr; |
output [5:0] opcode; |
output [4:0] reg1; |
output [4:0] reg2; |
output [4:0] reg3; |
output [31:0] sx16; |
output [31:0] zx16; |
output [31:0] hi16; |
output [31:0] sx16s2; |
output [31:0] sx26s2; |
|
reg [31:0] ir; |
wire [15:0] copy_sign_16; // 16-bit copy of a 16-bit immediate's sign |
wire [3:0] copy_sign_26; // 4-bit copy of a 26-bit immediate's sign |
|
always @(posedge clk) begin |
if (ir_we) begin |
ir <= instr; |
end |
end |
|
assign opcode[5:0] = ir[31:26]; |
assign reg1[4:0] = ir[25:21]; |
assign reg2[4:0] = ir[20:16]; |
assign reg3[4:0] = ir[15:11]; |
assign copy_sign_16[15:0] = (ir[15] == 1) ? 16'hFFFF : 16'h0000; |
assign copy_sign_26[3:0] = (ir[25] == 1) ? 4'hF : 4'h0; |
assign sx16[31:0] = { copy_sign_16[15:0], ir[15:0] }; |
assign zx16[31:0] = { 16'h0000, ir[15:0] }; |
assign hi16[31:0] = { ir[15:0], 16'h0000 }; |
assign sx16s2[31:0] = { copy_sign_16[13:0], ir[15:0], 2'b00 }; |
assign sx26s2[31:0] = { copy_sign_26[3:0], ir[25:0], 2'b00 }; |
|
endmodule |
|
|
//-------------------------------------------------------------- |
// regs -- the register file |
//-------------------------------------------------------------- |
|
|
module regs(clk, |
rn1, do1, |
rn2, do2, we2, di2); |
input clk; |
input [4:0] rn1; |
output reg [31:0] do1; |
input [4:0] rn2; |
output reg [31:0] do2; |
input we2; |
input [31:0] di2; |
|
reg [31:0] r[0:31]; |
|
always @(posedge clk) begin |
do1 <= r[rn1]; |
if (we2 == 0) begin |
do2 <= r[rn2]; |
end else begin |
do2 <= di2; |
r[rn2] <= di2; |
end |
end |
|
initial begin |
r[ 0] = 32'h00000000; |
r[ 1] = 32'h0D4D67E6; |
r[ 2] = 32'h6D6228D3; |
r[ 3] = 32'h3ECC6079; |
r[ 4] = 32'h0E7D6D32; |
r[ 5] = 32'h1D44B8B0; |
r[ 6] = 32'h54933EA7; |
r[ 7] = 32'h3C61EE4A; |
r[ 8] = 32'h29BD08C8; |
r[ 9] = 32'h652410B0; |
r[10] = 32'h4759259C; |
r[11] = 32'h6EF16AF0; |
r[12] = 32'h0FCCE109; |
r[13] = 32'h27831A1D; |
r[14] = 32'h2F08AF2C; |
r[15] = 32'h23FD21A9; |
r[16] = 32'h025DE15E; |
r[17] = 32'h2AE04E89; |
r[18] = 32'h42DD7B30; |
r[19] = 32'h3882589B; |
r[20] = 32'h0E7CABCF; |
r[21] = 32'h5C2B25B6; |
r[22] = 32'h5141A5D0; |
r[23] = 32'h57B145A6; |
r[24] = 32'h53156391; |
r[25] = 32'h0769F305; |
r[26] = 32'h77C54BE2; |
r[27] = 32'h4757CF59; |
r[28] = 32'h6897853E; |
r[29] = 32'h68A03DC3; |
r[30] = 32'h68F59ED5; |
r[31] = 32'h23DCCF7B; |
end |
|
endmodule |
|
|
//-------------------------------------------------------------- |
// alu -- the arithmetic/logic unit |
//-------------------------------------------------------------- |
|
|
module alu(a, b, fnc, |
res, equ, ult, slt); |
input [31:0] a; |
input [31:0] b; |
input [2:0] fnc; |
output [31:0] res; |
output equ; |
output ult; |
output slt; |
|
wire [32:0] a1; |
wire [32:0] b1; |
reg [32:0] res1; |
|
assign a1 = { 1'b0, a }; |
assign b1 = { 1'b0, b }; |
|
always @(*) begin |
case (fnc) |
3'b000: res1 = a1 + b1; |
3'b001: res1 = a1 - b1; |
3'b010: res1 = a1; |
3'b011: res1 = b1; |
3'b100: res1 = a1 & b1; |
3'b101: res1 = a1 | b1; |
3'b110: res1 = a1 ^ b1; |
3'b111: res1 = a1 ~^ b1; |
default: res1 = 33'hxxxxxxxx; |
endcase |
end |
|
assign res = res1[31:0]; |
assign equ = ~| res1[31:0]; |
assign ult = res1[32]; |
assign slt = res1[32] ^ a[31] ^ b[31]; |
|
endmodule |
|
|
//-------------------------------------------------------------- |
// shift -- the shift unit |
//-------------------------------------------------------------- |
|
|
module shift(clk, data_in, shamt, fnc, data_out); |
input clk; |
input [31:0] data_in; |
input [4:0] shamt; |
input [1:0] fnc; |
output reg [31:0] data_out; |
|
always @(posedge clk) begin |
if (fnc == 2'b00) begin |
// sll |
data_out <= data_in << shamt; |
end else |
if (fnc == 2'b01) begin |
// slr |
data_out <= data_in >> shamt; |
end else |
if (fnc == 2'b10) begin |
// sar |
if (data_in[31] == 1) begin |
data_out <= ~(32'hFFFFFFFF >> shamt) | |
(data_in >> shamt); |
end else begin |
data_out <= data_in >> shamt; |
end |
end else begin |
data_out <= 32'hxxxxxxxx; |
end |
end |
|
endmodule |
|
|
//-------------------------------------------------------------- |
// muldiv -- the multiplier/divide unit |
//-------------------------------------------------------------- |
|
|
module muldiv(clk, a, b, fnc, start, done, error, res); |
input clk; |
input [31:0] a; |
input [31:0] b; |
input [2:0] fnc; |
input start; |
output reg done; |
output reg error; |
output reg [31:0] res; |
|
// fnc = 000 op = undefined |
// 001 undefined |
// 010 mul |
// 011 mulu |
// 100 div |
// 101 divu |
// 110 rem |
// 111 remu |
|
reg div; |
reg rem; |
reg [5:0] count; |
reg a_neg; |
reg b_neg; |
reg [31:0] b_abs; |
reg [64:0] q; |
wire [64:1] s; |
wire [64:0] d; |
|
assign s[64:32] = q[64:32] + { 1'b0, b_abs }; |
assign s[31: 1] = q[31: 1]; |
assign d[64:32] = q[64:32] - { 1'b0, b_abs }; |
assign d[31: 0] = q[31: 0]; |
|
always @(posedge clk) begin |
if (start == 1) begin |
if (fnc[2] == 1 && (| b[31:0]) == 0) begin |
// division by zero |
done <= 1; |
error <= 1; |
end else begin |
// operands are ok |
done <= 0; |
error <= 0; |
end |
div <= fnc[2]; |
rem <= fnc[1]; |
count <= 6'd0; |
if (fnc[0] == 0 && a[31] == 1) begin |
// negate first operand |
a_neg <= 1; |
if (fnc[2] == 0) begin |
// initialize q for multiplication |
q[64:32] <= 33'b0; |
q[31: 0] <= ~a + 1; |
end else begin |
// initialize q for division and remainder |
q[64:33] <= 32'b0; |
q[32: 1] <= ~a + 1; |
q[ 0: 0] <= 1'b0; |
end |
end else begin |
// use first operand as is |
a_neg <= 0; |
if (fnc[2] == 0) begin |
// initialize q for multiplication |
q[64:32] <= 33'b0; |
q[31: 0] <= a; |
end else begin |
// initialize q for division and remainder |
q[64:33] <= 32'b0; |
q[32: 1] <= a; |
q[ 0: 0] <= 1'b0; |
end |
end |
if (fnc[0] == 0 && b[31] == 1) begin |
// negate second operand |
b_neg <= 1; |
b_abs <= ~b + 1; |
end else begin |
// use second operand as is |
b_neg <= 0; |
b_abs <= b; |
end |
end else begin |
if (done == 0) begin |
// algorithm not yet finished |
if (div == 0) begin |
// |
// multiplication |
// |
if (count == 6'd32) begin |
// last step |
done <= 1; |
if (a_neg == b_neg) begin |
res <= q[31:0]; |
end else begin |
res <= ~q[31:0] + 1; |
end |
end else begin |
// all other steps |
count <= count + 1; |
if (q[0] == 1) begin |
q <= { 1'b0, s[64:1] }; |
end else begin |
q <= { 1'b0, q[64:1] }; |
end |
end |
end else begin |
// |
// division and remainder |
// |
if (count == 6'd32) begin |
// last step |
done <= 1; |
if (rem == 0) begin |
// result <= quotient |
if (a_neg == b_neg) begin |
res <= q[31:0]; |
end else begin |
res <= ~q[31:0] + 1; |
end |
end else begin |
// result <= remainder |
if (a_neg == 0) begin |
res <= q[64:33]; |
end else begin |
res <= ~q[64:33] + 1; |
end |
end |
end else begin |
// all other steps |
count <= count + 1; |
if (d[64] == 0) begin |
q <= { d[63:0], 1'b1 }; |
end else begin |
q <= { q[63:0], 1'b0 }; |
end |
end |
end |
end |
end |
end |
|
endmodule |
|
|
//-------------------------------------------------------------- |
// sregs -- the special registers |
//-------------------------------------------------------------- |
|
|
module sregs(clk, rst, |
rn, we, din, dout, |
psw, psw_we, psw_new, |
tlb_index, tlb_index_we, tlb_index_new, |
tlb_entry_hi, tlb_entry_hi_we, tlb_entry_hi_new, |
tlb_entry_lo, tlb_entry_lo_we, tlb_entry_lo_new, |
mmu_bad_addr, mmu_bad_addr_we, mmu_bad_addr_new, |
mmu_bad_accs, mmu_bad_accs_we, mmu_bad_accs_new); |
input clk; |
input rst; |
input [2:0] rn; |
input we; |
input [31:0] din; |
output [31:0] dout; |
output [31:0] psw; |
input psw_we; |
input [31:0] psw_new; |
output [31:0] tlb_index; |
input tlb_index_we; |
input [31:0] tlb_index_new; |
output [31:0] tlb_entry_hi; |
input tlb_entry_hi_we; |
input [31:0] tlb_entry_hi_new; |
output [31:0] tlb_entry_lo; |
input tlb_entry_lo_we; |
input [31:0] tlb_entry_lo_new; |
output [31:0] mmu_bad_addr; |
input mmu_bad_addr_we; |
input [31:0] mmu_bad_addr_new; |
output [31:0] mmu_bad_accs; |
input mmu_bad_accs_we; |
input [31:0] mmu_bad_accs_new; |
|
// rn = 000 register = PSW |
// 001 TLB index |
// 010 TLB entry high |
// 011 TLB entry low |
// 100 MMU bad address |
// 101 MMU bad access |
// 110 - not used - |
// 111 - not used - |
|
reg [31:0] sr[0:7]; |
|
assign dout = sr[rn]; |
assign psw = sr[0]; |
assign tlb_index = sr[1]; |
assign tlb_entry_hi = sr[2]; |
assign tlb_entry_lo = sr[3]; |
assign mmu_bad_addr = sr[4]; |
assign mmu_bad_accs = sr[5]; |
|
always @(posedge clk) begin |
if (rst == 1) begin |
sr[0] <= 32'h00000000; |
end else begin |
if (we == 1) begin |
sr[rn] <= din; |
end else begin |
if (psw_we) begin |
sr[0] <= psw_new; |
end |
if (tlb_index_we) begin |
sr[1] <= tlb_index_new; |
end |
if (tlb_entry_hi_we) begin |
sr[2] <= tlb_entry_hi_new; |
end |
if (tlb_entry_lo_we) begin |
sr[3] <= tlb_entry_lo_new; |
end |
if (mmu_bad_addr_we) begin |
sr[4] <= mmu_bad_addr_new; |
end |
if (mmu_bad_accs_we) begin |
sr[5] <= mmu_bad_accs_new; |
end |
end |
end |
end |
|
initial begin |
sr[0] = 32'h00000000; // PSW |
sr[1] = 32'h00000007; // Index |
sr[2] = 32'h612D9000; // EntryHi |
sr[3] = 32'h30DAF001; // EntryLo |
sr[4] = 32'h219DCF7C; // BadAddr |
sr[5] = 32'h00000005; // BadAccs |
sr[6] = 32'h00000000; // -- not used -- |
sr[7] = 32'h00000000; // -- not used -- |
end |
|
endmodule |
|
|
//-------------------------------------------------------------- |
// mmu -- the memory management unit |
//-------------------------------------------------------------- |
|
|
module mmu(clk, rst, fnc, virt, phys, |
tlb_index, tlb_index_new, |
tlb_entry_hi, tlb_entry_hi_new, |
tlb_entry_lo, tlb_entry_lo_new, |
tlb_kmissed, tlb_umissed, |
tlb_invalid, tlb_wrtprot); |
input clk; |
input rst; |
input [2:0] fnc; |
input [31:0] virt; |
output [31:0] phys; |
input [31:0] tlb_index; |
output [31:0] tlb_index_new; |
input [31:0] tlb_entry_hi; |
output [31:0] tlb_entry_hi_new; |
input [31:0] tlb_entry_lo; |
output [31:0] tlb_entry_lo_new; |
output tlb_kmissed; |
output tlb_umissed; |
output tlb_invalid; |
output tlb_wrtprot; |
|
// fnc = 000 no operation, hold output |
// 001 map virt to phys address |
// 010 tbs |
// 011 tbwr |
// 100 tbri |
// 101 tbwi |
// 110 undefined |
// 111 undefined |
|
wire map; |
wire tbs; |
wire tbwr; |
wire tbri; |
wire tbwi; |
reg [19:0] page; |
reg [11:0] offset; |
wire [19:0] tlb_page; |
wire tlb_miss; |
wire [4:0] tlb_found; |
wire tlb_enable; |
wire [19:0] tlb_frame; |
wire tlb_wbit; |
wire tlb_vbit; |
wire [4:0] rw_index; |
wire [19:0] r_page; |
wire [19:0] r_frame; |
wire w_enable; |
wire [19:0] w_page; |
wire [19:0] w_frame; |
wire direct; |
wire [17:0] frame; |
reg [4:0] random_index; |
reg tlb_miss_delayed; |
|
// decode function |
assign map = (fnc == 3'b001) ? 1 : 0; |
assign tbs = (fnc == 3'b010) ? 1 : 0; |
assign tbwr = (fnc == 3'b011) ? 1 : 0; |
assign tbri = (fnc == 3'b100) ? 1 : 0; |
assign tbwi = (fnc == 3'b101) ? 1 : 0; |
|
// latch virtual address |
always @(posedge clk) begin |
if (map == 1) begin |
page <= virt[31:12]; |
offset <= virt[11:0]; |
end |
end |
|
// create tlb instance |
assign tlb_page = (tbs == 1) ? tlb_entry_hi[31:12] : virt[31:12]; |
assign tlb_enable = map; |
assign tlb_wbit = tlb_frame[1]; |
assign tlb_vbit = tlb_frame[0]; |
assign rw_index = (tbwr == 1) ? random_index : tlb_index[4:0]; |
assign tlb_index_new = { tlb_miss, 26'b0, tlb_found }; |
assign tlb_entry_hi_new = { ((tbri == 1) ? r_page : page), |
tlb_entry_hi[11:0] }; |
assign tlb_entry_lo_new = { tlb_entry_lo[31:30], r_frame[19:2], |
tlb_entry_lo[11:2], r_frame[1:0] }; |
assign w_enable = tbwr | tbwi; |
assign w_page = tlb_entry_hi[31:12]; |
assign w_frame = { tlb_entry_lo[29:12], tlb_entry_lo[1:0] }; |
tlb tlb_1(tlb_page, tlb_miss, tlb_found, |
clk, tlb_enable, tlb_frame, |
rw_index, r_page, r_frame, |
w_enable, w_page, w_frame); |
|
// construct physical address |
assign direct = (page[19:18] == 2'b11) ? 1 : 0; |
assign frame = (direct == 1) ? page[17:0] : tlb_frame[19:2]; |
assign phys = { 2'b00, frame, offset }; |
|
// generate "random" index |
always @(posedge clk) begin |
if (rst == 1) begin |
// the index register is counting down |
// so we must start at topmost index |
random_index <= 5'd31; |
end else begin |
// decrement index register "randomly" |
// (whenever there is a mapping operation) |
// skip "fixed" entries (0..3) |
if (map == 1) begin |
if (random_index == 5'd4) begin |
random_index <= 5'd31; |
end else begin |
random_index <= random_index - 1; |
end |
end |
end |
end |
|
// generate TLB exceptions |
always @(posedge clk) begin |
if (map == 1) begin |
tlb_miss_delayed <= tlb_miss; |
end |
end |
assign tlb_kmissed = tlb_miss_delayed & ~direct & page[19]; |
assign tlb_umissed = tlb_miss_delayed & ~direct & ~page[19]; |
assign tlb_invalid = ~tlb_vbit & ~direct; |
assign tlb_wrtprot = ~tlb_wbit & ~direct; |
|
endmodule |
|
|
//-------------------------------------------------------------- |
// tlb -- the translation lookaside buffer |
//-------------------------------------------------------------- |
|
|
module tlb(page_in, miss, found, |
clk, enable, frame_out, |
rw_index, r_page, r_frame, |
w_enable, w_page, w_frame); |
input [19:0] page_in; |
output miss; |
output [4:0] found; |
input clk; |
input enable; |
output reg [19:0] frame_out; |
input [4:0] rw_index; |
output reg [19:0] r_page; |
output reg [19:0] r_frame; |
input w_enable; |
input [19:0] w_page; |
input [19:0] w_frame; |
|
reg [19:0] page[0:31]; |
reg [19:0] frame[0:31]; |
|
wire [19:0] p00, p01, p02, p03; |
wire [19:0] p04, p05, p06, p07; |
wire [19:0] p08, p09, p10, p11; |
wire [19:0] p12, p13, p14, p15; |
wire [19:0] p16, p17, p18, p19; |
wire [19:0] p20, p21, p22, p23; |
wire [19:0] p24, p25, p26, p27; |
wire [19:0] p28, p29, p30, p31; |
wire [31:0] match; |
|
assign p00 = page[ 0]; |
assign p01 = page[ 1]; |
assign p02 = page[ 2]; |
assign p03 = page[ 3]; |
assign p04 = page[ 4]; |
assign p05 = page[ 5]; |
assign p06 = page[ 6]; |
assign p07 = page[ 7]; |
assign p08 = page[ 8]; |
assign p09 = page[ 9]; |
assign p10 = page[10]; |
assign p11 = page[11]; |
assign p12 = page[12]; |
assign p13 = page[13]; |
assign p14 = page[14]; |
assign p15 = page[15]; |
assign p16 = page[16]; |
assign p17 = page[17]; |
assign p18 = page[18]; |
assign p19 = page[19]; |
assign p20 = page[20]; |
assign p21 = page[21]; |
assign p22 = page[22]; |
assign p23 = page[23]; |
assign p24 = page[24]; |
assign p25 = page[25]; |
assign p26 = page[26]; |
assign p27 = page[27]; |
assign p28 = page[28]; |
assign p29 = page[29]; |
assign p30 = page[30]; |
assign p31 = page[31]; |
|
assign match[ 0] = (page_in == p00) ? 1 : 0; |
assign match[ 1] = (page_in == p01) ? 1 : 0; |
assign match[ 2] = (page_in == p02) ? 1 : 0; |
assign match[ 3] = (page_in == p03) ? 1 : 0; |
assign match[ 4] = (page_in == p04) ? 1 : 0; |
assign match[ 5] = (page_in == p05) ? 1 : 0; |
assign match[ 6] = (page_in == p06) ? 1 : 0; |
assign match[ 7] = (page_in == p07) ? 1 : 0; |
assign match[ 8] = (page_in == p08) ? 1 : 0; |
assign match[ 9] = (page_in == p09) ? 1 : 0; |
assign match[10] = (page_in == p10) ? 1 : 0; |
assign match[11] = (page_in == p11) ? 1 : 0; |
assign match[12] = (page_in == p12) ? 1 : 0; |
assign match[13] = (page_in == p13) ? 1 : 0; |
assign match[14] = (page_in == p14) ? 1 : 0; |
assign match[15] = (page_in == p15) ? 1 : 0; |
assign match[16] = (page_in == p16) ? 1 : 0; |
assign match[17] = (page_in == p17) ? 1 : 0; |
assign match[18] = (page_in == p18) ? 1 : 0; |
assign match[19] = (page_in == p19) ? 1 : 0; |
assign match[20] = (page_in == p20) ? 1 : 0; |
assign match[21] = (page_in == p21) ? 1 : 0; |
assign match[22] = (page_in == p22) ? 1 : 0; |
assign match[23] = (page_in == p23) ? 1 : 0; |
assign match[24] = (page_in == p24) ? 1 : 0; |
assign match[25] = (page_in == p25) ? 1 : 0; |
assign match[26] = (page_in == p26) ? 1 : 0; |
assign match[27] = (page_in == p27) ? 1 : 0; |
assign match[28] = (page_in == p28) ? 1 : 0; |
assign match[29] = (page_in == p29) ? 1 : 0; |
assign match[30] = (page_in == p30) ? 1 : 0; |
assign match[31] = (page_in == p31) ? 1 : 0; |
|
assign miss = ~(| match[31:0]); |
|
assign found[0] = match[ 1] | match[ 3] | match[ 5] | match[ 7] | |
match[ 9] | match[11] | match[13] | match[15] | |
match[17] | match[19] | match[21] | match[23] | |
match[25] | match[27] | match[29] | match[31]; |
assign found[1] = match[ 2] | match[ 3] | match[ 6] | match[ 7] | |
match[10] | match[11] | match[14] | match[15] | |
match[18] | match[19] | match[22] | match[23] | |
match[26] | match[27] | match[30] | match[31]; |
assign found[2] = match[ 4] | match[ 5] | match[ 6] | match[ 7] | |
match[12] | match[13] | match[14] | match[15] | |
match[20] | match[21] | match[22] | match[23] | |
match[28] | match[29] | match[30] | match[31]; |
assign found[3] = match[ 8] | match[ 9] | match[10] | match[11] | |
match[12] | match[13] | match[14] | match[15] | |
match[24] | match[25] | match[26] | match[27] | |
match[28] | match[29] | match[30] | match[31]; |
assign found[4] = match[16] | match[17] | match[18] | match[19] | |
match[20] | match[21] | match[22] | match[23] | |
match[24] | match[25] | match[26] | match[27] | |
match[28] | match[29] | match[30] | match[31]; |
|
always @(posedge clk) begin |
if (enable == 1) begin |
frame_out <= frame[found]; |
end |
end |
|
always @(posedge clk) begin |
if (w_enable == 1) begin |
page[rw_index] <= w_page; |
frame[rw_index] <= w_frame; |
end else begin |
r_page <= page[rw_index]; |
r_frame <= frame[rw_index]; |
end |
end |
|
initial begin |
page[ 0] = 20'h66A83; |
page[ 1] = 20'h491A4; |
page[ 2] = 20'h4EA81; |
page[ 3] = 20'h474DF; |
page[ 4] = 20'h32C24; |
page[ 5] = 20'h36C3D; |
page[ 6] = 20'h2D5E0; |
page[ 7] = 20'h6B26E; |
page[ 8] = 20'h73720; |
page[ 9] = 20'h52CE1; |
page[10] = 20'h51C40; |
page[11] = 20'h45B54; |
page[12] = 20'h688A2; |
page[13] = 20'h78200; |
page[14] = 20'h40DD7; |
page[15] = 20'h6FBD3; |
page[16] = 20'h3ACE2; |
page[17] = 20'h79E77; |
page[18] = 20'h1E68F; |
page[19] = 20'h123FC; |
page[20] = 20'h5D12B; |
page[21] = 20'h7AE2E; |
page[22] = 20'h0AB01; |
page[23] = 20'h629AD; |
page[24] = 20'h56DF6; |
page[25] = 20'h2D5B6; |
page[26] = 20'h03871; |
page[27] = 20'h2DE48; |
page[28] = 20'h45346; |
page[29] = 20'h14304; |
page[30] = 20'h36247; |
page[31] = 20'h49349; |
frame[ 0] = 20'h9375F; |
frame[ 1] = 20'h7D446; |
frame[ 2] = 20'h248ED; |
frame[ 3] = 20'h5D3E2; |
frame[ 4] = 20'hFEE70; |
frame[ 5] = 20'h1F072; |
frame[ 6] = 20'hFADAA; |
frame[ 7] = 20'h3A521; |
frame[ 8] = 20'hCDF43; |
frame[ 9] = 20'h22812; |
frame[10] = 20'hB996C; |
frame[11] = 20'hA3418; |
frame[12] = 20'hC178E; |
frame[13] = 20'h089B7; |
frame[14] = 20'h84A2A; |
frame[15] = 20'h1D44A; |
frame[16] = 20'hC51CA; |
frame[17] = 20'hC00CE; |
frame[18] = 20'hA5BD5; |
frame[19] = 20'hB2D1D; |
frame[20] = 20'hE2F07; |
frame[21] = 20'hA61DF; |
frame[22] = 20'h6D26B; |
frame[23] = 20'h9660E; |
frame[24] = 20'hF5608; |
frame[25] = 20'h685EF; |
frame[26] = 20'h04C01; |
frame[27] = 20'h31E17; |
frame[28] = 20'hAAA36; |
frame[29] = 20'h6B6B3; |
frame[30] = 20'h8E714; |
frame[31] = 20'hDBA8C; |
end |
|
endmodule |
/fpga/mc-vl/src/cpu/cpu_bus.v
0,0 → 1,222
// |
// cpu_bus.v -- the ECO32 CPU bus interface |
// |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
module cpu_bus(clk, rst, |
bus_stb, bus_we, bus_addr, |
bus_din, bus_dout, bus_ack, bus_irq, |
cpu_stb, cpu_we, cpu_size, cpu_addr, |
cpu_din, cpu_dout, cpu_ack, cpu_irq); |
// bus interface |
input clk; |
input rst; |
output reg bus_stb; |
output reg bus_we; |
output reg [31:2] bus_addr; |
input [31:0] bus_din; |
output reg [31:0] bus_dout; |
input bus_ack; |
input [15:0] bus_irq; |
// CPU interface |
input cpu_stb; |
input cpu_we; |
input [1:0] cpu_size; |
input [31:0] cpu_addr; |
output reg [31:0] cpu_din; |
input [31:0] cpu_dout; |
output reg cpu_ack; |
output [15:0] cpu_irq; |
|
reg state; |
reg next_state; |
reg [31:0] wbuf; |
reg wbuf_we; |
reg [31:0] wbuf_in; |
|
// ctrl |
always @(posedge clk) begin |
if (rst) begin |
state <= 0; |
end else begin |
state <= next_state; |
end |
end |
|
// output |
always @(*) begin |
case (state) |
1'b0: |
if (~cpu_stb) begin |
// no bus activity from cpu |
bus_stb = 1'b0; |
bus_we = 1'bx; |
bus_addr[31:2] = 30'bx; |
bus_dout[31:0] = 32'bx; |
cpu_din[31:0] = 32'bx; |
cpu_ack = 1'b0; |
next_state = 1'b0; |
wbuf_we = 1'b0; |
wbuf_in[31:0] = 32'bx; |
end else begin |
// bus activated by cpu |
if (~cpu_we) begin |
// cpu read cycle |
if (~cpu_size[1]) begin |
if (~cpu_size[0]) begin |
// cpu read byte |
bus_stb = 1'b1; |
bus_we = 1'b0; |
bus_addr[31:2] = cpu_addr[31:2]; |
bus_dout[31:0] = 32'bx; |
if (~cpu_addr[1]) begin |
if (~cpu_addr[0]) begin |
cpu_din[31:0] = { 24'h0, bus_din[31:24] }; |
end else begin |
cpu_din[31:0] = { 24'h0, bus_din[23:16] }; |
end |
end else begin |
if (~cpu_addr[0]) begin |
cpu_din[31:0] = { 24'h0, bus_din[15: 8] }; |
end else begin |
cpu_din[31:0] = { 24'h0, bus_din[ 7: 0] }; |
end |
end |
cpu_ack = bus_ack; |
next_state = 1'b0; |
wbuf_we = 1'b0; |
wbuf_in[31:0] = 32'bx; |
end else begin |
// cpu read halfword |
bus_stb = 1'b1; |
bus_we = 1'b0; |
bus_addr[31:2] = cpu_addr[31:2]; |
bus_dout[31:0] = 32'bx; |
if (~cpu_addr[1]) begin |
cpu_din[31:0] = { 16'h0, bus_din[31:16] }; |
end else begin |
cpu_din[31:0] = { 16'h0, bus_din[15: 0] }; |
end |
cpu_ack = bus_ack; |
next_state = 1'b0; |
wbuf_we = 1'b0; |
wbuf_in[31:0] = 32'bx; |
end |
end else begin |
// cpu read word |
bus_stb = 1'b1; |
bus_we = 1'b0; |
bus_addr[31:2] = cpu_addr[31:2]; |
bus_dout[31:0] = 32'bx; |
cpu_din[31:0] = bus_din[31:0]; |
cpu_ack = bus_ack; |
next_state = 1'b0; |
wbuf_we = 1'b0; |
wbuf_in[31:0] = 32'bx; |
end |
end else begin |
// cpu write cycle |
if (~cpu_size[1]) begin |
if (~cpu_size[0]) begin |
// cpu write byte |
// part 1: read word into word buffer |
bus_stb = 1'b1; |
bus_we = 1'b0; |
bus_addr[31:2] = cpu_addr[31:2]; |
bus_dout[31:0] = 32'bx; |
cpu_din[31:0] = 32'bx; |
cpu_ack = 1'b0; |
if (~bus_ack) begin |
next_state = 1'b0; |
end else begin |
next_state = 1'b1; |
end |
wbuf_we = 1'b1; |
if (~cpu_addr[1]) begin |
if (~cpu_addr[0]) begin |
wbuf_in[31:0] = { cpu_dout[7:0], bus_din[23:16], |
bus_din[15:8], bus_din[7:0] }; |
end else begin |
wbuf_in[31:0] = { bus_din[31:24], cpu_dout[7:0], |
bus_din[15:8], bus_din[7:0] }; |
end |
end else begin |
if (~cpu_addr[0]) begin |
wbuf_in[31:0] = { bus_din[31:24], bus_din[23:16], |
cpu_dout[7:0], bus_din[7:0] }; |
end else begin |
wbuf_in[31:0] = { bus_din[31:24], bus_din[23:16], |
bus_din[15:8], cpu_dout[7:0] }; |
end |
end |
end else begin |
// cpu write halfword |
// part 1: read word into word buffer |
bus_stb = 1'b1; |
bus_we = 1'b0; |
bus_addr[31:2] = cpu_addr[31:2]; |
bus_dout[31:0] = 32'bx; |
cpu_din[31:0] = 32'bx; |
cpu_ack = 1'b0; |
if (~bus_ack) begin |
next_state = 1'b0; |
end else begin |
next_state = 1'b1; |
end |
wbuf_we = 1'b1; |
if (~cpu_addr[1]) begin |
wbuf_in[31:0] = { cpu_dout[15:0], bus_din[15:0] }; |
end else begin |
wbuf_in[31:0] = { bus_din[31:16], cpu_dout[15:0] }; |
end |
end |
end else begin |
// cpu write word |
bus_stb = 1'b1; |
bus_we = 1'b1; |
bus_addr[31:2] = cpu_addr[31:2]; |
bus_dout[31:0] = cpu_dout[31:0]; |
cpu_din[31:0] = 32'bx; |
cpu_ack = bus_ack; |
next_state = 1'b0; |
wbuf_we = 1'b0; |
wbuf_in[31:0] = 32'bx; |
end |
end |
end |
1'b1: |
begin |
// cpu write halfword or byte |
// part 2: write word from word buffer |
bus_stb = 1'b1; |
bus_we = 1'b1; |
bus_addr[31:2] = cpu_addr[31:2]; |
bus_dout[31:0] = wbuf[31:0]; |
cpu_din[31:0] = 32'bx; |
cpu_ack = bus_ack; |
if (~bus_ack) begin |
next_state = 1'b1; |
end else begin |
next_state = 1'b0; |
end |
wbuf_we = 1'b0; |
wbuf_in[31:0] = 32'bx; |
end |
endcase |
end |
|
// word buffer |
always @(posedge clk) begin |
if (wbuf_we) begin |
wbuf[31:0] <= wbuf_in[31:0]; |
end |
end |
|
// interrupt requests |
assign cpu_irq[15:0] = bus_irq[15:0]; |
|
endmodule |
/fpga/mc-vl/src/cpu/cpu.v
0,0 → 1,66
// |
// cpu.v -- the ECO32 CPU |
// |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
module cpu(clk, rst, |
bus_stb, bus_we, bus_addr, |
bus_din, bus_dout, bus_ack, |
bus_irq); |
input clk; // system clock |
input rst; // system reset |
output bus_stb; // bus strobe |
output bus_we; // bus write enable |
output [31:2] bus_addr; // bus address (word address) |
input [31:0] bus_din; // bus data input, for reads |
output [31:0] bus_dout; // bus data output, for writes |
input bus_ack; // bus acknowledge |
input [15:0] bus_irq; // bus interrupt requests |
|
wire cpu_stb; |
wire cpu_we; |
wire [1:0] cpu_size /* verilator isolate_assignments */; |
wire [31:0] cpu_addr; |
wire [31:0] cpu_din; |
wire [31:0] cpu_dout; |
wire cpu_ack; |
wire [15:0] cpu_irq; |
|
cpu_bus cpu_bus_1( |
.clk(clk), |
.rst(rst), |
.bus_stb(bus_stb), |
.bus_we(bus_we), |
.bus_addr(bus_addr[31:2]), |
.bus_din(bus_din[31:0]), |
.bus_dout(bus_dout[31:0]), |
.bus_ack(bus_ack), |
.bus_irq(bus_irq[15:0]), |
.cpu_stb(cpu_stb), |
.cpu_we(cpu_we), |
.cpu_size(cpu_size[1:0]), |
.cpu_addr(cpu_addr[31:0]), |
.cpu_din(cpu_din[31:0]), |
.cpu_dout(cpu_dout[31:0]), |
.cpu_ack(cpu_ack), |
.cpu_irq(cpu_irq[15:0]) |
); |
|
cpu_core cpu_core_1( |
.clk(clk), |
.rst(rst), |
.bus_stb(cpu_stb), |
.bus_we(cpu_we), |
.bus_size(cpu_size[1:0]), |
.bus_addr(cpu_addr[31:0]), |
.bus_din(cpu_din[31:0]), |
.bus_dout(cpu_dout[31:0]), |
.bus_ack(cpu_ack), |
.bus_irq(cpu_irq[15:0]) |
); |
|
endmodule |
/fpga/mc-vl/src/ser/ser.v
0,0 → 1,167
// |
// ser.v -- serial line interface |
// |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
`define TICKS_PER_CHAR 32'h00000200 // output speed |
|
|
module ser(i, // instance number |
clk, rst, |
stb, we, addr, |
data_in, data_out, |
ack, irq_r, irq_t); |
input i; |
input clk; |
input rst; |
input stb; |
input we; |
input [3:2] addr; |
input [7:0] data_in; |
output reg [7:0] data_out; |
output ack; |
output irq_r; |
output irq_t; |
|
wire wr_rcv_ctrl; |
wire rd_rcv_data; |
wire wr_xmt_ctrl; |
wire wr_xmt_data; |
|
reg [39:0] ser_data[0:255]; // space for 256 input requests |
reg [7:0] ser_data_index; // next location to read |
wire [39:0] next_full; // 40 bits from ser_data |
wire [31:0] next_time; // 32 bits delta clock ticks |
wire [7:0] next_code; // 8 bits character code |
reg [31:0] rcv_count; // input tick counter |
|
integer ser_out; // file handle for serial output |
reg [31:0] xmt_count; // output tick counter |
|
reg rcv_rdy; |
reg rcv_ien; |
reg [7:0] rcv_data; |
reg xmt_rdy; |
reg xmt_ien; |
reg [7:0] xmt_data; |
|
assign wr_rcv_ctrl = (stb == 1 && we == 1 && addr == 2'b00) ? 1 : 0; |
assign rd_rcv_data = (stb == 1 && we == 0 && addr == 2'b01) ? 1 : 0; |
assign wr_xmt_ctrl = (stb == 1 && we == 1 && addr == 2'b10) ? 1 : 0; |
assign wr_xmt_data = (stb == 1 && we == 1 && addr == 2'b11) ? 1 : 0; |
|
initial begin |
if (i == 0) begin |
$readmemh("ser0.dat", ser_data); |
end else begin |
$readmemh("ser1.dat", ser_data); |
end |
end |
|
assign next_full[39:0] = ser_data[ser_data_index]; |
assign next_time[31:0] = next_full[39:8]; |
assign next_code[7:0] = next_full[7:0]; |
|
always @(posedge clk) begin |
if (rst) begin |
ser_data_index <= 0; |
rcv_count <= 0; |
rcv_rdy <= 0; |
rcv_data <= 0; |
end else begin |
if (rcv_count == 0) begin |
rcv_count <= next_time; |
end else |
if (rcv_count == 1) begin |
ser_data_index <= ser_data_index + 1; |
rcv_count <= rcv_count - 1; |
rcv_rdy <= 1; |
rcv_data <= next_code; |
end else begin |
if (rcv_count != 32'hFFFFFFFF) begin |
rcv_count <= rcv_count - 1; |
end |
end |
end |
end |
|
always @(posedge clk) begin |
if (rd_rcv_data == 1 && rcv_count != 1) begin |
rcv_rdy <= 0; |
end |
end |
|
initial begin |
if (i == 0) begin |
ser_out = $fopen("ser0.out", "w"); |
end else begin |
ser_out = $fopen("ser1.out", "w"); |
end |
end |
|
always @(posedge clk) begin |
if (rst) begin |
xmt_count <= 0; |
xmt_rdy <= 1; |
xmt_data <= 0; |
end else begin |
if (wr_xmt_data) begin |
xmt_count <= `TICKS_PER_CHAR; |
xmt_rdy <= 0; |
xmt_data <= data_in; |
end else begin |
if (xmt_count == 1) begin |
xmt_count <= xmt_count - 1; |
xmt_rdy <= 1; |
$fdisplay(ser_out, "char = 0x%h", xmt_data); |
end else begin |
if (xmt_count != 0) begin |
xmt_count <= xmt_count - 1; |
end |
end |
end |
end |
end |
|
always @(posedge clk) begin |
if (rst) begin |
rcv_ien <= 0; |
xmt_ien <= 0; |
end else begin |
if (wr_rcv_ctrl) begin |
rcv_ien <= data_in[1]; |
end |
if (wr_xmt_ctrl) begin |
xmt_ien <= data_in[1]; |
end |
end |
end |
|
always @(*) begin |
case (addr[3:2]) |
2'b00: |
// rcv ctrl |
data_out = { 6'b000000, rcv_ien, rcv_rdy }; |
2'b01: |
// rcv data |
data_out = rcv_data; |
2'b10: |
// xmt ctrl |
data_out = { 6'b000000, xmt_ien, xmt_rdy }; |
2'b11: |
// xmt data (cannot be read) |
data_out = 8'hxx; |
default: |
data_out = 8'hxx; |
endcase |
end |
|
assign ack = stb; |
assign irq_r = rcv_ien & rcv_rdy; |
assign irq_t = xmt_ien & xmt_rdy; |
|
endmodule |
/fpga/mc-vl/src/eco32/eco32.v
0,0 → 1,275
// |
// eco32.v -- ECO32 top-level description |
// |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
module eco32(clk_in, rst_in_n); |
input clk_in; // clock input |
input rst_in_n; // reset input |
|
// clk_rst |
wire clk; // system clock |
wire rst; // system reset |
// cpu |
wire bus_stb /* verilator isolate_assignments */; |
// bus strobe |
wire bus_we; // bus write enable |
wire [31:2] bus_addr /* verilator isolate_assignments */; |
// bus address (word address) |
wire [31:0] bus_addr32; // bus address (byte address) |
wire [31:0] bus_din; // bus data input, for reads |
wire [31:0] bus_dout; // bus data output, for writes |
wire bus_ack; // bus acknowledge |
wire [15:0] bus_irq; // bus interrupt requests |
// ram |
wire ram_stb; // ram strobe |
wire [31:0] ram_dout; // ram data output |
wire ram_ack; // ram acknowledge |
// rom |
wire rom_stb; // rom strobe |
wire [31:0] rom_dout; // rom data output |
wire rom_ack; // rom acknowledge |
// i/o |
wire i_o_stb; // i/o strobe |
// tmr0 |
wire tmr0_stb; // tmr 0 strobe |
wire [31:0] tmr0_dout; // tmr 0 data output |
wire tmr0_ack; // tmr 0 acknowledge |
wire tmr0_irq; // tmr 0 interrupt request |
// tmr1 |
wire tmr1_stb; // tmr 1 strobe |
wire [31:0] tmr1_dout; // tmr 1 data output |
wire tmr1_ack; // tmr 1 acknowledge |
wire tmr1_irq; // tmr 1 interrupt request |
// dsp |
wire dsp_stb; // dsp strobe |
wire [15:0] dsp_dout; // dsp data output |
wire dsp_ack; // dsp acknowledge |
// kbd |
wire kbd_stb; // kbd strobe |
wire [7:0] kbd_dout; // kbd data output |
wire kbd_ack; // kbd acknowledge |
wire kbd_irq; // kbd interrupt request |
// ser0 |
wire ser0_stb; // ser 0 strobe |
wire [7:0] ser0_dout; // ser 0 data output |
wire ser0_ack; // ser 0 acknowledge |
wire ser0_irq_r; // ser 0 rcv interrupt request |
wire ser0_irq_t; // ser 0 xmt interrupt request |
// ser1 |
wire ser1_stb; // ser 1 strobe |
wire [7:0] ser1_dout; // ser 1 data output |
wire ser1_ack; // ser 1 acknowledge |
wire ser1_irq_r; // ser 1 rcv interrupt request |
wire ser1_irq_t; // ser 1 xmt interrupt request |
|
//-------------------------------------- |
// module instances |
//-------------------------------------- |
|
clk_rst clk_rst_1( |
.clk_in(clk_in), |
.rst_in_n(rst_in_n), |
.clk(clk), |
.rst(rst) |
); |
|
cpu cpu_1( |
.clk(clk), |
.rst(rst), |
.bus_stb(bus_stb), |
.bus_we(bus_we), |
.bus_addr(bus_addr[31:2]), |
.bus_din(bus_din[31:0]), |
.bus_dout(bus_dout[31:0]), |
.bus_ack(bus_ack), |
.bus_irq(bus_irq[15:0]) |
); |
|
// show the full 32-bit address in the simulation results |
assign bus_addr32[31:0] = { bus_addr[31:2], 2'b00 }; |
|
ram ram_1( |
.clk(clk), |
.rst(rst), |
.stb(ram_stb), |
.we(bus_we), |
.addr(bus_addr[24:2]), |
.data_in(bus_dout[31:0]), |
.data_out(ram_dout[31:0]), |
.ack(ram_ack) |
); |
|
rom rom_1( |
.clk(clk), |
.rst(rst), |
.stb(rom_stb), |
.we(bus_we), |
.addr(bus_addr[15:2]), |
.data_out(rom_dout[31:0]), |
.ack(rom_ack) |
); |
|
tmr tmr_1( |
.clk(clk), |
.rst(rst), |
.stb(tmr0_stb), |
.we(bus_we), |
.addr(bus_addr[3:2]), |
.data_in(bus_dout[31:0]), |
.data_out(tmr0_dout[31:0]), |
.ack(tmr0_ack), |
.irq(tmr0_irq) |
); |
|
tmr tmr_2( |
.clk(clk), |
.rst(rst), |
.stb(tmr1_stb), |
.we(bus_we), |
.addr(bus_addr[3:2]), |
.data_in(bus_dout[31:0]), |
.data_out(tmr1_dout[31:0]), |
.ack(tmr1_ack), |
.irq(tmr1_irq) |
); |
|
dsp dsp_1( |
.clk(clk), |
.rst(rst), |
.stb(dsp_stb), |
.we(bus_we), |
.addr(bus_addr[13:2]), |
.data_in(bus_dout[15:0]), |
.data_out(dsp_dout[15:0]), |
.ack(dsp_ack) |
); |
|
kbd kbd_1( |
.clk(clk), |
.rst(rst), |
.stb(kbd_stb), |
.we(bus_we), |
.addr(bus_addr[2]), |
.data_in(bus_dout[7:0]), |
.data_out(kbd_dout[7:0]), |
.ack(kbd_ack), |
.irq(kbd_irq) |
); |
|
ser ser_1( |
.i(0), |
.clk(clk), |
.rst(rst), |
.stb(ser0_stb), |
.we(bus_we), |
.addr(bus_addr[3:2]), |
.data_in(bus_dout[7:0]), |
.data_out(ser0_dout[7:0]), |
.ack(ser0_ack), |
.irq_r(ser0_irq_r), |
.irq_t(ser0_irq_t) |
); |
|
ser ser_2( |
.i(1), |
.clk(clk), |
.rst(rst), |
.stb(ser1_stb), |
.we(bus_we), |
.addr(bus_addr[3:2]), |
.data_in(bus_dout[7:0]), |
.data_out(ser1_dout[7:0]), |
.ack(ser1_ack), |
.irq_r(ser1_irq_r), |
.irq_t(ser1_irq_t) |
); |
|
//-------------------------------------- |
// address decoder |
//-------------------------------------- |
|
// RAM: architectural limit = 512 MB |
// implementation limit = 32 MB |
assign ram_stb = |
(bus_stb == 1 && bus_addr[31:29] == 3'b000 |
&& bus_addr[28:25] == 4'b0000) ? 1 : 0; |
|
// ROM: architectural limit = 256 MB |
// implementation limit = 64 KB |
assign rom_stb = |
(bus_stb == 1 && bus_addr[31:28] == 4'b0010 |
&& bus_addr[27:16] == 12'b000000000000) ? 1 : 0; |
|
// I/O: architectural limit = 256 MB |
assign i_o_stb = |
(bus_stb == 1 && bus_addr[31:28] == 4'b0011) ? 1 : 0; |
assign tmr0_stb = |
(i_o_stb == 1 && bus_addr[27:20] == 8'h00 |
&& bus_addr[19:12] == 8'h00) ? 1 : 0; |
assign tmr1_stb = |
(i_o_stb == 1 && bus_addr[27:20] == 8'h00 |
&& bus_addr[19:12] == 8'h01) ? 1 : 0; |
assign dsp_stb = |
(i_o_stb == 1 && bus_addr[27:20] == 8'h01) ? 1 : 0; |
assign kbd_stb = |
(i_o_stb == 1 && bus_addr[27:20] == 8'h02) ? 1 : 0; |
assign ser0_stb = |
(i_o_stb == 1 && bus_addr[27:20] == 8'h03 |
&& bus_addr[19:12] == 8'h00) ? 1 : 0; |
assign ser1_stb = |
(i_o_stb == 1 && bus_addr[27:20] == 8'h03 |
&& bus_addr[19:12] == 8'h01) ? 1 : 0; |
|
//-------------------------------------- |
// data and acknowledge multiplexers |
//-------------------------------------- |
|
assign bus_din[31:0] = |
(ram_stb == 1) ? ram_dout[31:0] : |
(rom_stb == 1) ? rom_dout[31:0] : |
(tmr0_stb == 1) ? tmr0_dout[31:0] : |
(tmr1_stb == 1) ? tmr1_dout[31:0] : |
(dsp_stb == 1) ? { 16'h0000, dsp_dout[15:0] } : |
(kbd_stb == 1) ? { 24'h000000, kbd_dout[7:0] } : |
(ser0_stb == 1) ? { 24'h000000, ser0_dout[7:0] } : |
(ser1_stb == 1) ? { 24'h000000, ser1_dout[7:0] } : |
32'h00000000; |
|
assign bus_ack = |
(ram_stb == 1) ? ram_ack : |
(rom_stb == 1) ? rom_ack : |
(tmr0_stb == 1) ? tmr0_ack : |
(tmr1_stb == 1) ? tmr1_ack : |
(dsp_stb == 1) ? dsp_ack : |
(kbd_stb == 1) ? kbd_ack : |
(ser0_stb == 1) ? ser0_ack : |
(ser1_stb == 1) ? ser1_ack : |
0; |
|
//-------------------------------------- |
// bus interrupt request assignments |
//-------------------------------------- |
|
assign bus_irq[15] = tmr1_irq; |
assign bus_irq[14] = tmr0_irq; |
assign bus_irq[13] = 0; |
assign bus_irq[12] = 0; |
assign bus_irq[11] = 0; |
assign bus_irq[10] = 0; |
assign bus_irq[ 9] = 0; |
assign bus_irq[ 8] = 0; |
assign bus_irq[ 7] = 0; |
assign bus_irq[ 6] = 0; |
assign bus_irq[ 5] = 0; |
assign bus_irq[ 4] = kbd_irq; |
assign bus_irq[ 3] = ser1_irq_r; |
assign bus_irq[ 2] = ser1_irq_t; |
assign bus_irq[ 1] = ser0_irq_r; |
assign bus_irq[ 0] = ser0_irq_t; |
|
endmodule |
/fpga/mc-vl/src/rom/rom.v
0,0 → 1,66
// |
// rom.v -- parallel flash ROM interface |
// 16K x 32 bit = 64 KB |
// |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
// |
// use this set of parameters for minimal access times |
// |
//`define RD_CYCLES 4'd2 // # cycles for read, min = 2 |
|
// |
// use this set of parameters for realistic access times |
// |
`define RD_CYCLES 4'd14 // # cycles for read, min = 2 |
|
|
module rom(clk, rst, |
stb, we, addr, |
data_out, ack); |
input clk; |
input rst; |
input stb; |
input we; |
input [15:2] addr; |
output reg [31:0] data_out; |
output ack; |
|
reg [31:0] mem[0:16383]; |
reg [3:0] counter; |
|
initial begin |
$readmemh("rom.dat", mem); |
end |
|
always @(posedge clk) begin |
if (stb) begin |
if (~we) begin |
// read cycle |
data_out <= mem[addr]; |
end |
end |
end |
|
always @(posedge clk) begin |
if (rst) begin |
counter[3:0] <= 4'h0; |
end else begin |
if (counter[3:0] == 4'h0) begin |
if (stb & ~we) begin |
// a read may need some clock cycles |
counter[3:0] <= `RD_CYCLES - 1; |
end |
end else begin |
counter[3:0] <= counter[3:0] - 1; |
end |
end |
end |
|
assign ack = (counter[3:0] == 4'h1) ? 1 : 0; |
|
endmodule |