FPGA/cx4: rework CPU FSM (ALU still missing)

This commit is contained in:
ikari 2011-10-23 20:56:07 +02:00
parent e57c4aa450
commit fb9a28bf38

View File

@ -34,7 +34,7 @@ module cx4(
output BUS_RRQ,
input BUS_RDY,
output cx4_active
);
);
reg [2:0] cx4_busy;
parameter BUSY_CACHE = 2'b00;
@ -162,6 +162,9 @@ initial begin
end
assign BUS_RRQ = CACHE_BUS_RRQr | DMA_BUS_RRQr;
reg cpu_go_en_r;
initial cpu_go_en_r = 1'b0;
initial begin
cx4_mmio_r1f50 = 8'h33;
cx4_mmio_r1f51 = 1'b0;
@ -230,7 +233,10 @@ always @(posedge CLK) begin
5'h0c: cx4_mmio_r1f4c <= DI[1:0]; // 1f4c
5'h0d: cx4_mmio_pgmpage[7:0] <= DI; // 1f4d
5'h0e: cx4_mmio_pgmpage[14:8] <= DI[6:0]; // 1f4e
5'h0f: cx4_mmio_pc <= DI; // 1f4f
5'h0f: begin
cx4_mmio_pc <= DI; // 1f4f
cpu_go_en_r <= 1'b1;
end
5'h10: cx4_mmio_r1f50 <= DI & 8'h77; // 1f50
5'h11: cx4_mmio_r1f51 <= DI[0]; // 1f51
5'h12: cx4_mmio_r1f52 <= DI[0]; // 1f52
@ -238,6 +244,7 @@ always @(posedge CLK) begin
end else begin
CACHE_TRIG_ENr <= 1'b0;
DMA_TRIG_ENr <= 1'b0;
cpu_go_en_r <= 1'b0;
end
end
@ -245,10 +252,6 @@ always @(posedge CLK) begin
if(VECTOR_WR_EN) vector[ADDR[4:0]] <= DI;
end
always @(posedge CLK) begin
if(GPR_WR_EN) gpr[ADDR[5:0]] <= DI;
end
reg [4:0] CACHE_ST;
parameter ST_CACHE_IDLE = 5'b00001;
parameter ST_CACHE_START = 5'b00010;
@ -272,7 +275,7 @@ wire [22:0] MAPPED_DMA_SRC_ADDR = {DMA_SRC_ADDRr[23:16],DMA_SRC_ADDRr[14:0]};
assign BUS_ADDR = cx4_busy[BUSY_CACHE] ? MAPPED_CACHE_SRC_ADDR
: cx4_busy[BUSY_DMA] ? MAPPED_DMA_SRC_ADDR
: 24'h000000 /* XXX cx4_bus_addr */;
: 24'h800000 /* XXX cx4_bus_addr */;
reg cx4_pgmrom_we;
initial cx4_pgmrom_we = 1'b0;
@ -322,9 +325,16 @@ always @(posedge CLK) begin
endcase
end
reg cx4_datram_we;
initial cx4_datram_we = 1'b0;
reg [11:0] cx4_datram_addr;
reg cx4_dma_datram_we;
reg cx4_cpu_datram_we;
initial cx4_dma_datram_we = 1'b0;
initial cx4_cpu_datram_we = 1'b0;
wire cx4_datram_we = cx4_dma_datram_we | cx4_cpu_datram_we;
reg [11:0] cx4_dma_datram_addr;
reg [11:0] cx4_cpu_datram_addr;
wire [11:0] cx4_datram_addr = cx4_busy[BUSY_DMA] ? cx4_dma_datram_addr : cx4_cpu_datram_addr;
reg [23:0] cx4_cpu_datram_di;
wire [23:0] cx4_datram_di = cx4_busy[BUSY_DMA] ? BUS_DI : cx4_cpu_datram_di;
reg [15:0] dma_count;
initial dma_count = 16'b0;
@ -338,8 +348,7 @@ always @(posedge CLK) begin
ST_DMA_START: begin
cx4_busy[BUSY_DMA] <= 1'b1;
DMA_SRC_ADDRr <= cx4_mmio_dmasrc;
/* XXX Rename to DMA_TGT_ADDRr and switch */
cx4_datram_addr <= (cx4_mmio_dmatgt & 24'h000fff);
cx4_dma_datram_addr <= (cx4_mmio_dmatgt & 24'h000fff);
DMA_ST <= ST_DMA_WAIT;
dma_count <= cx4_mmio_dmalen;
DMA_BUS_RRQr <= 1'b1;
@ -348,16 +357,14 @@ always @(posedge CLK) begin
DMA_BUS_RRQr <= 1'b0;
if(~DMA_BUS_RRQr & BUS_RDY) begin
DMA_ST <= ST_DMA_ADDR;
/* XXX Rename to DMA_TGT_WEr and switch */
cx4_datram_we <= 1'b1;
cx4_dma_datram_we <= 1'b1;
dma_count <= dma_count - 1;
end else DMA_ST <= ST_DMA_WAIT;
end
ST_DMA_ADDR: begin
/* XXX Rename to DMA_TGT_WEr and switch */
cx4_datram_we <= 1'b0;
cx4_dma_datram_we <= 1'b0;
DMA_SRC_ADDRr <= DMA_SRC_ADDRr + 1;
cx4_datram_addr <= cx4_datram_addr + 1;
cx4_dma_datram_addr <= cx4_dma_datram_addr + 1;
if(dma_count == 16'h0000) begin
cx4_busy[BUSY_DMA] <= 1'b0;
DMA_ST <= ST_DMA_IDLE;
@ -372,7 +379,7 @@ end
/***************************
=========== CPU ===========
***************************/
reg [7:0] CPU_STATE;
reg [4:0] CPU_STATE;
reg cpu_page;
reg [7:0] cpu_pc;
reg [8:0] cpu_stack [7:0];
@ -396,57 +403,80 @@ reg fl_z;
reg fl_c;
reg [15:0] cpu_p;
reg [9:0] cx4_datrom_addr;
wire [9:0] cx4_datrom_addr = cpu_a[9:0];
wire [23:0] cx4_datrom_do;
wire [7:0] cx4_datram_do;
parameter ST_CPU_IDLE = 8'b00000001;
parameter ST_CPU_0 = 8'b00000010;
parameter ST_CPU_1 = 8'b00000100;
parameter ST_CPU_2 = 8'b00001000;
parameter ST_CPU_3 = 8'b00010000;
parameter ST_CPU_IDLE = 5'b00001;
parameter ST_CPU_0 = 5'b00010;
parameter ST_CPU_1 = 5'b00100;
parameter ST_CPU_2 = 5'b01000;
parameter ST_CPU_3 = 5'b10000;
initial CPU_STATE <= ST_CPU_IDLE;
parameter OP_ALU = 4'b0000;
parameter OP_LD = 4'b0001;
parameter OP_ST = 4'b0010;
parameter OP_JP = 4'b0011;
parameter OP_SWP = 4'b0100;
parameter OP_HLT = 4'b0101;
parameter OP_BUS = 4'b0110;
parameter OP_STA = 4'b0111;
parameter OP_NOP = 4'b1111;
parameter OP_NOP = 4'b0000;
parameter OP_JP = 4'b0001;
parameter OP_SKIP = 4'b0010;
parameter OP_RT = 4'b0011;
parameter OP_LD = 4'b0100;
parameter OP_ST = 4'b0101;
parameter OP_SWP = 4'b0110;
parameter OP_RDROM = 4'b0111;
parameter OP_RDRAM = 4'b1000;
parameter OP_WRRAM = 4'b1001;
parameter OP_ALU = 4'b1010;
parameter OP_MUL = 4'b1011;
parameter OP_WAI = 4'b1100;
parameter OP_BUS = 4'b1101;
parameter OP_HLT = 4'b1110;
wire [6:0] op_id = cpu_op_w[15:10];
reg [7:0] op_param;
reg [2:0] op;
reg [3:0] op;
reg [1:0] op_sa;
reg op_imm;
reg op_p;
reg op_call;
reg op_jump;
reg cond_true;
reg cpu_go_rq;
reg condtrue;
reg cpu_bus_rq;
always @(posedge CLK) begin
case(CPU_STATE)
ST_CPU_IDLE: begin
if(cpu_go_rq) begin
if(cpu_go_en_r) begin
cpu_pc <= cx4_mmio_pc;
op <= OP_NOP;
CPU_STATE <= ST_CPU_2;
cx4_busy[BUSY_CPU] <= 1'b1;
end
else CPU_STATE <= ST_CPU_IDLE;
end
ST_CPU_0: begin // Phase 0:
CPU_STATE <= ST_CPU_1;
if(op == OP_HLT) begin
cx4_busy[BUSY_CPU] <= 1'b0;
CPU_STATE <= ST_CPU_IDLE;
end
else CPU_STATE <= ST_CPU_1;
case(op)
OP_ALU, OP_LD, OP_SWP: begin
if(cpu_op[15:10] == 6'b111000) cpu_idb <= cpu_a; // reg[imm] <- a
else if(op_imm) cpu_idb <= {16'b0, op_param};
OP_JP: begin
case(cpu_op[11:10])
2'b10: condtrue <= 1'b1;
2'b11: condtrue <= fl_z;
2'b00: condtrue <= fl_c;
2'b01: condtrue <= fl_n;
endcase
end
OP_SKIP: begin
case(cpu_op[9:8])
2'b01: condtrue <= (fl_c == cpu_op[0]);
2'b10: condtrue <= (fl_z == cpu_op[0]);
2'b11: condtrue <= (fl_n == cpu_op[0]);
endcase
end
OP_LD, OP_SWP, OP_ALU, OP_MUL: begin
if(op_imm) cpu_idb <= {16'b0, op_param};
else casex(op_param)
8'h00: cpu_idb <= cpu_a;
8'h01: cpu_idb <= cpu_acch;
@ -471,84 +501,80 @@ always @(posedge CLK) begin
endcase
end
end
OP_JP: begin
casex(cpu_op[12:8])
5'b010xx: cond_true <= 1'b1;
5'b011xx: cond_true <= fl_z;
5'b100xx: cond_true <= fl_c;
5'b101xx: cond_true <= fl_n;
5'b00101: cond_true <= (fl_c == cpu_op[0]);
5'b00110: cond_true <= (fl_z == cpu_op[0]);
5'b00111: cond_true <= (fl_n == cpu_op[0]);
default: cond_true <= 1'b1;
OP_ST: begin
cpu_idb <= cpu_a;
end
OP_RDRAM, OP_WRRAM: begin
if(op_imm) cpu_ramaddr <= {16'b0, op_param};
else casex(op_param)
8'h00: cx4_cpu_datram_addr <= cpu_a;
8'h01: cx4_cpu_datram_addr <= cpu_acch;
8'h02: cx4_cpu_datram_addr <= cpu_accl;
8'h03: cx4_cpu_datram_addr <= cpu_busdata;
8'h08: cx4_cpu_datram_addr <= cpu_romdata;
8'h0c: cx4_cpu_datram_addr <= cpu_ramdata;
8'h13: cx4_cpu_datram_addr <= cpu_busaddr;
8'h1c: cx4_cpu_datram_addr <= cpu_ramaddr;
8'h5x: cx4_cpu_datram_addr <= const[op_param[3:0]];
8'h6x: cx4_cpu_datram_addr <= {gpr[op_param[3:0]*3+2],
gpr[op_param[3:0]*3+1],
gpr[op_param[3:0]*3]};
default: cx4_cpu_datram_addr <= 24'b0;
endcase
end
OP_BUS: cpu_bus_rq <= 1'b1;
endcase
end
ST_CPU_1: begin
CPU_STATE <= ST_CPU_2;
case(op)
OP_LD: begin
cx4_datram_addr <= op_imm ? op_param : (cpu_ramaddr + cpu_idb);
cx4_datrom_addr <= cpu_a[9:0];
end
OP_ST: begin
cx4_datram_addr <= op_imm ? op_param : (cpu_ramaddr + cpu_idb);
cx4_datram_we <= 1'b1;
end
OP_JP: begin
if(cond_true) begin
casex(cpu_op[12:11])
2'b01, 2'b10: begin
// TODO if(op_p)
if(condtrue) begin
if(op_call) begin
cpu_stack[cpu_sp] <= {cpu_page, cpu_pc+1};
cpu_sp <= cpu_sp - 1;
cpu_stack[cpu_sp] <= cpu_pc + 1;
cpu_sp <= cpu_sp + 1;
end
cpu_pc <= op_param;
end
2'b00: begin
end
OP_SKIP: begin
if(condtrue) begin
cpu_pc <= cpu_pc + 2;
end
2'b11: begin
if(cpu_op[13]) begin
{cpu_page, cpu_pc} <= cpu_stack[cpu_sp+1];
cpu_sp <= cpu_sp + 1;
end else begin
if(BUS_RDY) cpu_pc <= cpu_pc + 1;
end
OP_RT: begin
cpu_pc <= cpu_stack[cpu_sp - 1];
cpu_sp <= cpu_sp - 1;
end
OP_LD, OP_ST, OP_SWP, OP_RDROM, OP_RDRAM, OP_WRRAM, OP_ALU, OP_MUL, OP_BUS:
cpu_pc <= cpu_pc + 1;
OP_WAI: if(BUS_RDY) cpu_pc <= cpu_pc + 1;
default: cpu_pc <= cpu_pc + 1;
endcase
end
end
OP_BUS: cpu_bus_rq <= 1'b0;
endcase
end
ST_CPU_2: begin
CPU_STATE <= ST_CPU_3;
case(op)
OP_ST: begin
cx4_datram_we <= 1'b0;
end
OP_LD: begin
casex(cpu_op[11:8])
4'b0x00: cpu_a <= cpu_idb;
4'b0x11: cpu_p <= cpu_idb;
4'b1100: cpu_p[7:0] <= op_param;
4'b1101: cpu_p[15:8] <= op_param;
endcase
end
ST_CPU_3: begin
CPU_STATE <= ST_CPU_0;
case(op)
OP_LD, OP_SWP: begin
casex(cpu_op[15:8])
8'b01100x00: cpu_a <= cpu_idb;
8'b01100x11: cpu_p <= cpu_idb;
8'b01111100: cpu_p[7:0] <= op_param;
8'b01111101: cpu_p[15:8] <= op_param;
8'b01110000: cpu_romdata <= cx4_datrom_do;
8'b01101x00: cpu_ramdata[7:0] <= cx4_datram_do;
8'b01101x01: cpu_ramdata[15:8] <= cx4_datram_do;
8'b01101x10: cpu_ramdata[23:16] <= cx4_datram_do;
8'b11110000, 8'b11100000: begin
if(cpu_op[12]) cpu_a <= cpu_idb;
OP_ST: begin
casex(op_param)
8'h00: cpu_a <= cpu_idb;
8'h01: cpu_acch <= cpu_idb;
8'h02: cpu_accl <= cpu_idb;
8'h03: cpu_busdata <= cpu_idb;
8'h08: cpu_romdata <= cpu_idb;
8'h0c: cpu_ramdata <= cpu_idb;
8'h13: cpu_busaddr <= cpu_idb;
8'h1c: cpu_ramaddr <= cpu_idb;
endcase
end
OP_SWP: begin
casex(op_param)
8'h00: cpu_a <= cpu_a;
8'h01: cpu_acch <= cpu_a;
@ -558,38 +584,103 @@ always @(posedge CLK) begin
8'h0c: cpu_ramdata <= cpu_a;
8'h13: cpu_busaddr <= cpu_a;
8'h1c: cpu_ramaddr <= cpu_a;
8'h6x: {gpr[op_param[3:0]*3+2],
gpr[op_param[3:0]*3+1],
gpr[op_param[3:0]*3]} <= cpu_a;
endcase
end
OP_RDROM: cpu_romdata <= cx4_datrom_do;
OP_RDRAM: cpu_ramdata <= cx4_datram_do;
OP_WRRAM: begin
case(cpu_op[9:8])
2'b00: cx4_cpu_datram_di[7:0] <= cpu_ramdata[7:0];
2'b01: cx4_cpu_datram_di[15:8] <= cpu_ramdata[15:8];
2'b10: cx4_cpu_datram_di[23:16] <= cpu_ramdata[23:16];
endcase
cx4_cpu_datram_we <= 1'b1;
end
OP_ALU: begin
/* XXX TODO FUCK YEAH ALU */
end
OP_BUS: cpu_bus_rq <= 1'b1;
endcase
end
ST_CPU_3: begin
CPU_STATE <= ST_CPU_0;
case(op)
OP_SWP: cpu_a <= cpu_idb;
OP_WRRAM: cx4_cpu_datram_we <= 1'b0;
OP_ALU: begin
/* XXX TODO FUCKING FLAGS */
end
OP_MUL: begin
cpu_acch <= cpu_mul_result[47:24];
cpu_accl <= cpu_mul_result[23:0];
fl_z <= (cpu_mul_result == 48'b0);
fl_n <= cpu_mul_result[47];
end
OP_BUS: cpu_bus_rq <= 1'b0;
endcase
cpu_op <= cpu_op_w;
op_param <= cpu_op_w[7:0];
op <= &(op_id) ? OP_HLT
:(op_id[5:4] == 2'b00) ? OP_JP
:(op_id[5:2] == 4'b0110
|| op_id[5:2] == 4'b0111
) ? OP_LD
:(op_id[5:1] == 5'b11101) ? OP_ST
:(op_id[5:1] == 5'b01000) ? OP_BUS
:(op_id[5:3] == 3'b010
|| op_id[5:3] == 3'b100
|| op_id[5:3] == 3'b101
|| op_id[5:3] == 3'b110) ? OP_ALU
: (op_id == 6'b111100 || op_id == 6'b111000) ? OP_SWP
: OP_NOP;
casex(cpu_op_w[15:11])
5'b00000: op <= OP_NOP;
5'b00x01: op <= OP_JP;
5'b00x10: op <= OP_JP;
5'b00100: op <= OP_SKIP;
5'b00111: op <= OP_RT;
5'b01100: op <= OP_LD;
5'b01111: op <= OP_LD;
5'b11100: op <= OP_ST;
5'b11110: op <= OP_SWP;
5'b01110: op <= OP_RDROM;
5'b01101: op <= OP_RDRAM;
5'b11101: op <= OP_WRRAM;
5'b01001: op <= OP_ALU;
5'b01010: op <= OP_ALU;
5'b01011: op <= OP_ALU;
5'b10000: op <= OP_ALU;
5'b10001: op <= OP_ALU;
5'b10010: op <= OP_ALU;
5'b10101: op <= OP_ALU;
5'b10110: op <= OP_ALU;
5'b10111: op <= OP_ALU;
5'b11000: op <= OP_ALU;
5'b11001: op <= OP_ALU;
5'b11010: op <= OP_ALU;
5'b11011: op <= OP_ALU;
5'b10011: op <= OP_MUL;
5'b00011: op <= OP_WAI;
5'b01000: op <= OP_BUS;
5'b11111: op <= OP_HLT;
endcase
op_imm <= cpu_op_w[10];
op_sa <= cpu_op_w[9:8];
op_p <= cpu_op_w[9];
op_call <= cpu_op_w[13];
cond_true <= 1'b0;
end
endcase
end
// gpr write, either by CPU or by MMIO
always @(posedge CLK) begin
if(CPU_STATE == ST_CPU_2
&& (op == OP_SWP)
&& (op_param[7:4] == 8'h6)) begin
gpr[op_param[3:0]*3+2] <= cpu_a[23:16];
gpr[op_param[3:0]*3+1] <= cpu_a[15:8];
gpr[op_param[3:0]*3] <= cpu_a[7:0];
end
else if(CPU_STATE == ST_CPU_2
&& (op == OP_ST)
&& (op_param[7:4] == 8'h6)) begin
gpr[op_param[3:0]*3+2] <= cpu_idb[23:16];
gpr[op_param[3:0]*3+1] <= cpu_idb[15:8];
gpr[op_param[3:0]*3] <= cpu_idb[7:0];
end
else if(GPR_WR_EN) gpr[ADDR[5:0]] <= DI;
end
/***************************
=========== MEM ===========
@ -613,7 +704,7 @@ cx4_datram cx4_datram (
.clkb(CLK), // input clkb
.web(cx4_datram_we), // input [0 : 0] web
.addrb(cx4_datram_addr), // input [11 : 0] addrb
.dinb(BUS_DI), // input [7 : 0] dinb
.dinb(cx4_datram_di), // input [7 : 0] dinb
.doutb(cx4_datram_do) // output [7 : 0] doutb
);
@ -630,7 +721,7 @@ cx4_pgmrom cx4_pgmrom (
cx4_mul cx4_mul (
.clk(CLK), // input clk
.a(cpu_a), // input [23 : 0] a
.b(cpu_mul_src), // input [23 : 0] b
.b(cpu_idb), // input [23 : 0] b
.p(cpu_mul_result) // output [47 : 0] p
);
endmodule