mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-06-20 08:29:30 +00:00
preset updates; shadow text for scope view
This commit is contained in:
parent
661bbb0ced
commit
9c25aed9fa
|
@ -6,7 +6,7 @@
|
||||||
`define OP_XOR 4'h4
|
`define OP_XOR 4'h4
|
||||||
`define OP_INC 4'h5
|
`define OP_INC 4'h5
|
||||||
`define OP_DEC 4'h6
|
`define OP_DEC 4'h6
|
||||||
`define OP_NOP 4'h7
|
`define OP_ZERO 4'h7
|
||||||
// operations that generate carry
|
// operations that generate carry
|
||||||
`define OP_ADD 4'h8
|
`define OP_ADD 4'h8
|
||||||
`define OP_SUB 4'h9
|
`define OP_SUB 4'h9
|
||||||
|
@ -24,35 +24,57 @@ module ALU(
|
||||||
case (aluop)
|
case (aluop)
|
||||||
`OP_LOAD_A: Y = {1'b0, A};
|
`OP_LOAD_A: Y = {1'b0, A};
|
||||||
`OP_LOAD_B: Y = {1'b0, B};
|
`OP_LOAD_B: Y = {1'b0, B};
|
||||||
`OP_ADD: Y = A + B;
|
|
||||||
`OP_SUB: Y = A - B;
|
|
||||||
`OP_INC: Y = A + 1;
|
|
||||||
`OP_DEC: Y = A - 1;
|
|
||||||
`OP_ASL: Y = A + A;
|
|
||||||
`OP_LSR: Y = {A[0], A >> 1};
|
|
||||||
`OP_OR: Y = {1'b0, A | B};
|
`OP_OR: Y = {1'b0, A | B};
|
||||||
`OP_AND: Y = {1'b0, A & B};
|
`OP_AND: Y = {1'b0, A & B};
|
||||||
`OP_XOR: Y = {1'b0, A ^ B};
|
`OP_XOR: Y = {1'b0, A ^ B};
|
||||||
|
`OP_INC: Y = A + 1;
|
||||||
|
`OP_DEC: Y = A - 1;
|
||||||
|
`OP_ZERO: Y = 0;
|
||||||
|
|
||||||
|
`OP_ADD: Y = A + B;
|
||||||
|
`OP_SUB: Y = A - B;
|
||||||
|
`OP_ASL: Y = A + A;
|
||||||
|
`OP_LSR: Y = {A[0], A >> 1};
|
||||||
default: Y = 9'bx;
|
default: Y = 9'bx;
|
||||||
endcase
|
endcase
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
/*
|
||||||
|
Bits Description
|
||||||
|
|
||||||
|
00ddaaaa A @ B -> dest
|
||||||
|
01ddaaaa A @ immediate -> dest
|
||||||
|
11ddaaaa A @ read [B] -> dest
|
||||||
|
10000001 swap A <-> B
|
||||||
|
1001nnnn A -> write [nnnn]
|
||||||
|
1010tttt conditional branch
|
||||||
|
|
||||||
|
dd = destination (00=A, 01=B, 10=IP, 11=none)
|
||||||
|
aaaa = ALU operation (@ operator)
|
||||||
|
nnnn = 4-bit constant
|
||||||
|
tttt = flags test for conditional branch
|
||||||
|
*/
|
||||||
|
|
||||||
|
// destinations for COMPUTE instructions
|
||||||
`define DEST_A 2'b00
|
`define DEST_A 2'b00
|
||||||
`define DEST_B 2'b01
|
`define DEST_B 2'b01
|
||||||
`define DEST_IP 2'b10
|
`define DEST_IP 2'b10
|
||||||
`define DEST_NOP 2'b11
|
`define DEST_NOP 2'b11
|
||||||
|
// instruction macros
|
||||||
`define I_COMPUTE(dest,op) { 2'b00, 2'(dest), 4'(op) }
|
`define I_COMPUTE(dest,op) { 2'b00, 2'(dest), 4'(op) }
|
||||||
`define I_COMPUTE_IMM(dest,op) { 2'b01, 2'(dest), 4'(op) }
|
`define I_COMPUTE_IMM(dest,op) { 2'b01, 2'(dest), 4'(op) }
|
||||||
`define I_COMPUTE_READB(dest,op) { 2'b11, 2'(dest), 4'(op) }
|
`define I_COMPUTE_READB(dest,op) { 2'b11, 2'(dest), 4'(op) }
|
||||||
`define I_CONST_IMM_A { 2'b01, `DEST_A, `OP_LOAD_B }
|
`define I_CONST_IMM_A { 2'b01, `DEST_A, `OP_LOAD_B }
|
||||||
`define I_CONST_IMM_B { 2'b01, `DEST_B, `OP_LOAD_B }
|
`define I_CONST_IMM_B { 2'b01, `DEST_B, `OP_LOAD_B }
|
||||||
`define I_JUMP_IMM { 2'b01, `DEST_IP, `OP_LOAD_B }
|
`define I_JUMP_IMM { 2'b01, `DEST_IP, `OP_LOAD_B }
|
||||||
`define I_STORE_A_TO_B { 8'b10000000 }
|
`define I_STORE_A(addr) { 4'b1001, 4'(addr) }
|
||||||
`define I_CONST_SHORT_A(addr) { 4'b01010, 4'(addr) }
|
`define I_BRANCH_IF_CARRY(carry) { 4'b1010, 2'b00, 1'(carry), 1'b1 }
|
||||||
`define I_CONST_SHORT_B(addr) { 4'b01011, 4'(addr) }
|
`define I_SWAP_AB { 8'b10000001 }
|
||||||
`define I_BRANCH_IF_CARRY(carry) { 6'b100100, 1'(carry), 1'b1 }
|
`define I_RESET { 8'b10111111 }
|
||||||
`define I_RESET { 8'b10000001 }
|
// convenience macros
|
||||||
|
`define I_ZERO_A `I_COMPUTE(`DEST_A, `OP_ZERO)
|
||||||
|
`define I_ZERO_B `I_COMPUTE(`DEST_B, `OP_ZERO)
|
||||||
|
|
||||||
module CPU(
|
module CPU(
|
||||||
input clk,
|
input clk,
|
||||||
|
@ -75,7 +97,7 @@ module CPU(
|
||||||
reg [7:0] opcode;
|
reg [7:0] opcode;
|
||||||
wire [3:0] aluop = opcode[3:0];
|
wire [3:0] aluop = opcode[3:0];
|
||||||
wire [1:0] opdest = opcode[5:4];
|
wire [1:0] opdest = opcode[5:4];
|
||||||
wire memalu = opcode[6];
|
wire B_or_data = opcode[6];
|
||||||
|
|
||||||
localparam S_RESET = 0;
|
localparam S_RESET = 0;
|
||||||
localparam S_SELECT = 1;
|
localparam S_SELECT = 1;
|
||||||
|
@ -83,7 +105,7 @@ module CPU(
|
||||||
localparam S_COMPUTE = 3;
|
localparam S_COMPUTE = 3;
|
||||||
localparam S_READ_IP = 4;
|
localparam S_READ_IP = 4;
|
||||||
|
|
||||||
ALU alu(.A(A), .B(memalu?data_in:B), .Y(Y), .aluop(aluop));
|
ALU alu(.A(A), .B(B_or_data?data_in:B), .Y(Y), .aluop(aluop));
|
||||||
|
|
||||||
always @(posedge clk)
|
always @(posedge clk)
|
||||||
if (reset) begin
|
if (reset) begin
|
||||||
|
@ -118,20 +140,26 @@ module CPU(
|
||||||
IP <= IP + 1;
|
IP <= IP + 1;
|
||||||
state <= S_COMPUTE;
|
state <= S_COMPUTE;
|
||||||
end
|
end
|
||||||
// ALU A + [B] -> dest
|
// ALU A + read [B] -> dest
|
||||||
8'b11??????: begin
|
8'b11??????: begin
|
||||||
address <= B;
|
address <= B;
|
||||||
state <= S_COMPUTE;
|
state <= S_COMPUTE;
|
||||||
end
|
end
|
||||||
// A -> write [B]
|
// A -> write [aluop]
|
||||||
8'b10000000: begin
|
8'b1001????: begin
|
||||||
address <= B;
|
address <= {4'b0, aluop};
|
||||||
data_out <= A;
|
data_out <= A;
|
||||||
write <= 1;
|
write <= 1;
|
||||||
state <= S_SELECT;
|
state <= S_SELECT;
|
||||||
end
|
end
|
||||||
|
// swap A,B
|
||||||
|
8'b10000001: begin
|
||||||
|
A <= B;
|
||||||
|
B <= A;
|
||||||
|
state <= S_SELECT;
|
||||||
|
end
|
||||||
// conditional branch
|
// conditional branch
|
||||||
8'b1001????: begin
|
8'b1010????: begin
|
||||||
if (
|
if (
|
||||||
(data_in[0] && (data_in[1] == carry)) ||
|
(data_in[0] && (data_in[1] == carry)) ||
|
||||||
(data_in[2] && (data_in[3] == zero)))
|
(data_in[2] && (data_in[3] == zero)))
|
||||||
|
@ -143,16 +171,6 @@ module CPU(
|
||||||
end
|
end
|
||||||
IP <= IP + 1; // skip immediate
|
IP <= IP + 1; // skip immediate
|
||||||
end
|
end
|
||||||
// aluop -> A
|
|
||||||
8'b1010????: begin
|
|
||||||
A <= {4'b0, data_in[3:0]};
|
|
||||||
state <= S_SELECT;
|
|
||||||
end
|
|
||||||
// aluop -> B
|
|
||||||
8'b1011????: begin
|
|
||||||
B <= {4'b0, data_in[3:0]};
|
|
||||||
state <= S_SELECT;
|
|
||||||
end
|
|
||||||
// fall-through RESET
|
// fall-through RESET
|
||||||
default: begin
|
default: begin
|
||||||
state <= S_RESET; // reset
|
state <= S_RESET; // reset
|
||||||
|
@ -197,8 +215,8 @@ module test_CPU_top(
|
||||||
output [7:0] B
|
output [7:0] B
|
||||||
);
|
);
|
||||||
|
|
||||||
reg [7:0] ram[127:0];
|
reg [7:0] ram[0:127];
|
||||||
reg [7:0] rom[127:0];
|
reg [7:0] rom[0:127];
|
||||||
|
|
||||||
assign IP = cpu.IP;
|
assign IP = cpu.IP;
|
||||||
assign A = cpu.A;
|
assign A = cpu.A;
|
||||||
|
@ -221,17 +239,18 @@ module test_CPU_top(
|
||||||
to_cpu = rom[address_bus[6:0]];
|
to_cpu = rom[address_bus[6:0]];
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
// ROM starts at address 0x80
|
rom = '{
|
||||||
rom['h00] = `I_CONST_IMM_A;
|
`I_ZERO_A,
|
||||||
rom['h01] = 1;
|
`I_CONST_IMM_B,
|
||||||
rom['h02] = `I_CONST_SHORT_B(0);
|
1,
|
||||||
rom['h03] = `I_COMPUTE(`DEST_A, `OP_ADD);
|
`I_COMPUTE(`DEST_A, `OP_ADD), // addr 4
|
||||||
rom['h04] = `I_COMPUTE(`DEST_B, `OP_ADD);
|
`I_SWAP_AB,
|
||||||
rom['h05] = `I_STORE_A_TO_B;
|
`I_BRANCH_IF_CARRY(0),
|
||||||
//rom['h06] = `I_JUMP_IMM;
|
3 + 'h80, // correct for ROM offset
|
||||||
rom['h06] = `I_BRANCH_IF_CARRY(0);
|
`I_RESET,
|
||||||
rom['h07] = 3 + 'h80; // correct for ROM offset
|
// leftover elements
|
||||||
rom['h08] = `I_RESET;
|
120{0}
|
||||||
|
};
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
|
|
||||||
`define OP_LOAD_A 4'h0
|
`define OP_LOAD_A 4'h0
|
||||||
`define OP_LOAD_B 4'h1
|
`define OP_LOAD_B 4'h1
|
||||||
`define OP_ADD 4'h2
|
`define OP_OR 4'h2
|
||||||
`define OP_SUB 4'h3
|
`define OP_AND 4'h3
|
||||||
`define OP_INC 4'h4
|
`define OP_XOR 4'h4
|
||||||
`define OP_DEC 4'h5
|
`define OP_INC 4'h5
|
||||||
`define OP_ASL 4'h6
|
`define OP_DEC 4'h6
|
||||||
`define OP_LSR 4'h7
|
`define OP_NOP 4'h7
|
||||||
`define OP_OR 4'h8
|
// operations that generate carry
|
||||||
`define OP_AND 4'h9
|
`define OP_ADD 4'h8
|
||||||
`define OP_XOR 4'ha
|
`define OP_SUB 4'h9
|
||||||
|
`define OP_ASL 4'ha
|
||||||
|
`define OP_LSR 4'hb
|
||||||
|
|
||||||
module ALU(
|
module ALU(
|
||||||
input [7:0] A,
|
input [7:0] A,
|
||||||
|
@ -22,27 +24,51 @@ module ALU(
|
||||||
case (aluop)
|
case (aluop)
|
||||||
`OP_LOAD_A: Y = {1'b0, A};
|
`OP_LOAD_A: Y = {1'b0, A};
|
||||||
`OP_LOAD_B: Y = {1'b0, B};
|
`OP_LOAD_B: Y = {1'b0, B};
|
||||||
`OP_ADD: Y = A + B;
|
|
||||||
`OP_SUB: Y = A - B;
|
|
||||||
`OP_INC: Y = A + 1;
|
|
||||||
`OP_DEC: Y = A - 1;
|
|
||||||
`OP_ASL: Y = {A[7], A + A};
|
|
||||||
`OP_LSR: Y = {A[0], A >> 1};
|
|
||||||
`OP_OR: Y = {1'b0, A | B};
|
`OP_OR: Y = {1'b0, A | B};
|
||||||
`OP_AND: Y = {1'b0, A & B};
|
`OP_AND: Y = {1'b0, A & B};
|
||||||
`OP_XOR: Y = {1'b0, A ^ B};
|
`OP_XOR: Y = {1'b0, A ^ B};
|
||||||
|
`OP_INC: Y = A + 1;
|
||||||
|
`OP_DEC: Y = A - 1;
|
||||||
|
|
||||||
|
`OP_ADD: Y = A + B;
|
||||||
|
`OP_SUB: Y = A - B;
|
||||||
|
`OP_ASL: Y = A + A;
|
||||||
|
`OP_LSR: Y = {A[0], A >> 1};
|
||||||
default: Y = 9'bx;
|
default: Y = 9'bx;
|
||||||
endcase
|
endcase
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
`define REG_A 1'b0
|
/*
|
||||||
`define REG_B 1'b1
|
Bits Description
|
||||||
`define I_CONST(r,x) { 2'b00, r, x }
|
|
||||||
`define I_LOAD_ADDR(r,addr) { 3'b010, r, addr }
|
00ddaaaa A + B -> dest
|
||||||
`define I_STORE_ADDR(r,addr) { 3'b011, r, addr }
|
01ddaaaa A + immediate -> dest
|
||||||
`define I_COMPUTE(r,op) { 3'b100, r, op }
|
11ddaaaa A + read [B] -> dest
|
||||||
`define I_RESET 8'hff
|
10000001 swap A <-> B
|
||||||
|
1001nnnn A -> write [nnnn]
|
||||||
|
1010tttt conditional branch
|
||||||
|
|
||||||
|
dd = destination (00=A, 01=B, 10=IP, 11=none)
|
||||||
|
aaaa = ALU operation (replaces + operator)
|
||||||
|
nnnn = 4-bit constant
|
||||||
|
tttt = flags test for conditional branch
|
||||||
|
*/
|
||||||
|
|
||||||
|
`define DEST_A 2'b00
|
||||||
|
`define DEST_B 2'b01
|
||||||
|
`define DEST_IP 2'b10
|
||||||
|
`define DEST_NOP 2'b11
|
||||||
|
`define I_COMPUTE(dest,op) { 2'b00, 2'(dest), 4'(op) }
|
||||||
|
`define I_COMPUTE_IMM(dest,op) { 2'b01, 2'(dest), 4'(op) }
|
||||||
|
`define I_COMPUTE_READB(dest,op) { 2'b11, 2'(dest), 4'(op) }
|
||||||
|
`define I_CONST_IMM_A { 2'b01, `DEST_A, `OP_LOAD_B }
|
||||||
|
`define I_CONST_IMM_B { 2'b01, `DEST_B, `OP_LOAD_B }
|
||||||
|
`define I_JUMP_IMM { 2'b01, `DEST_IP, `OP_LOAD_B }
|
||||||
|
`define I_STORE_A(addr) { 4'b1001, 4'(addr) }
|
||||||
|
`define I_BRANCH_IF_CARRY(carry) { 4'b1010, 2'b00, 1'(carry), 1'b1 }
|
||||||
|
`define I_SWAP_AB { 8'b10000001 }
|
||||||
|
`define I_RESET { 8'b10111111 }
|
||||||
|
|
||||||
module CPU(
|
module CPU(
|
||||||
input clk,
|
input clk,
|
||||||
|
@ -53,9 +79,7 @@ module CPU(
|
||||||
output write
|
output write
|
||||||
);
|
);
|
||||||
|
|
||||||
reg [7:0] ip;
|
reg [7:0] IP;
|
||||||
reg [7:0] opcode;
|
|
||||||
reg [3:0] aluop;
|
|
||||||
reg [7:0] A, B;
|
reg [7:0] A, B;
|
||||||
reg [8:0] Y;
|
reg [8:0] Y;
|
||||||
reg [2:0] state;
|
reg [2:0] state;
|
||||||
|
@ -63,17 +87,19 @@ module CPU(
|
||||||
reg carry;
|
reg carry;
|
||||||
reg zero;
|
reg zero;
|
||||||
wire [1:0] flags = { zero, carry };
|
wire [1:0] flags = { zero, carry };
|
||||||
|
|
||||||
|
reg [7:0] opcode;
|
||||||
|
wire [3:0] aluop = opcode[3:0];
|
||||||
|
wire [1:0] opdest = opcode[5:4];
|
||||||
|
wire memalu = opcode[6];
|
||||||
|
|
||||||
localparam S_RESET = 0;
|
localparam S_RESET = 0;
|
||||||
localparam S_SELECT = 1;
|
localparam S_SELECT = 1;
|
||||||
localparam S_DECODE = 2;
|
localparam S_DECODE = 2;
|
||||||
localparam S_LOAD_ADDR = 3;
|
localparam S_COMPUTE = 3;
|
||||||
localparam S_STORE_ADDR = 4;
|
localparam S_READ_IP = 4;
|
||||||
localparam S_COMPUTE = 5;
|
|
||||||
|
|
||||||
wire load_const = opcode[3:1] == 3'b111;
|
ALU alu(.A(A), .B(memalu?data_in:B), .Y(Y), .aluop(aluop));
|
||||||
|
|
||||||
ALU alu(.A(A), .B(B), .Y(Y), .aluop(aluop));
|
|
||||||
|
|
||||||
always @(posedge clk)
|
always @(posedge clk)
|
||||||
if (reset) begin
|
if (reset) begin
|
||||||
|
@ -83,75 +109,87 @@ module CPU(
|
||||||
case (state)
|
case (state)
|
||||||
// state 0: reset
|
// state 0: reset
|
||||||
S_RESET: begin
|
S_RESET: begin
|
||||||
ip <= 8'h80;
|
IP <= 8'h80;
|
||||||
write <= 0;
|
write <= 0;
|
||||||
state <= S_SELECT;
|
state <= S_SELECT;
|
||||||
end
|
end
|
||||||
// state 1: select opcode address
|
// state 1: select opcode address
|
||||||
S_SELECT: begin
|
S_SELECT: begin
|
||||||
address <= ip;
|
address <= IP;
|
||||||
ip <= ip + 1;
|
IP <= IP + 1;
|
||||||
write <= 0;
|
write <= 0;
|
||||||
state <= S_DECODE;
|
state <= S_DECODE;
|
||||||
end
|
end
|
||||||
// state 2: read/decode opcode
|
// state 2: read/decode opcode
|
||||||
S_DECODE: begin
|
S_DECODE: begin
|
||||||
|
opcode <= data_in;
|
||||||
casez (data_in)
|
casez (data_in)
|
||||||
8'b00??????: begin // load constant
|
// ALU A + B -> dest
|
||||||
if (data_in[5])
|
8'b00??????: begin
|
||||||
B <= {3'b0, data_in[4:0]};
|
|
||||||
else
|
|
||||||
A <= {3'b0, data_in[4:0]};
|
|
||||||
state <= S_SELECT;
|
|
||||||
end
|
|
||||||
8'b010?????: begin // read memory
|
|
||||||
address <= {4'b0, data_in[3:0]};
|
|
||||||
state <= S_LOAD_ADDR;
|
|
||||||
end
|
|
||||||
8'b011?????: begin // write memory
|
|
||||||
address <= {4'b0, data_in[3:0]};
|
|
||||||
state <= S_STORE_ADDR;
|
|
||||||
end
|
|
||||||
8'b100?????: begin // compute w/ ALU
|
|
||||||
aluop <= data_in[3:0];
|
|
||||||
state <= S_COMPUTE;
|
state <= S_COMPUTE;
|
||||||
end
|
end
|
||||||
8'b101000??: begin // branch if flag set/clear
|
// ALU A + immediate -> dest
|
||||||
if ((data_in[0] ? carry : zero) ^ data_in[1])
|
8'b01??????: begin
|
||||||
ip <= A;
|
address <= IP;
|
||||||
|
IP <= IP + 1;
|
||||||
|
state <= S_COMPUTE;
|
||||||
|
end
|
||||||
|
// ALU A + read [B] -> dest
|
||||||
|
8'b11??????: begin
|
||||||
|
address <= B;
|
||||||
|
state <= S_COMPUTE;
|
||||||
|
end
|
||||||
|
// A -> write [aluop]
|
||||||
|
8'b1001????: begin
|
||||||
|
address <= {4'b0, aluop};
|
||||||
|
data_out <= A;
|
||||||
|
write <= 1;
|
||||||
state <= S_SELECT;
|
state <= S_SELECT;
|
||||||
end
|
end
|
||||||
|
// swap A,B
|
||||||
|
8'b10000001: begin
|
||||||
|
A <= B;
|
||||||
|
B <= A;
|
||||||
|
state <= S_SELECT;
|
||||||
|
end
|
||||||
|
// conditional branch
|
||||||
|
8'b1010????: begin
|
||||||
|
if (
|
||||||
|
(data_in[0] && (data_in[1] == carry)) ||
|
||||||
|
(data_in[2] && (data_in[3] == zero)))
|
||||||
|
begin
|
||||||
|
address <= IP;
|
||||||
|
state <= S_READ_IP;
|
||||||
|
end else begin
|
||||||
|
state <= S_SELECT;
|
||||||
|
end
|
||||||
|
IP <= IP + 1; // skip immediate
|
||||||
|
end
|
||||||
|
// fall-through RESET
|
||||||
default: begin
|
default: begin
|
||||||
state <= S_RESET; // reset
|
state <= S_RESET; // reset
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
opcode <= data_in;
|
|
||||||
end
|
end
|
||||||
// state 3: load address
|
// state 3: compute ALU op and flags
|
||||||
S_LOAD_ADDR: begin
|
|
||||||
if (opcode[4])
|
|
||||||
B <= data_in;
|
|
||||||
else
|
|
||||||
A <= data_in;
|
|
||||||
state <= S_SELECT;
|
|
||||||
end
|
|
||||||
// state 4: store address
|
|
||||||
S_STORE_ADDR: begin
|
|
||||||
if (opcode[4])
|
|
||||||
data_out <= B;
|
|
||||||
else
|
|
||||||
data_out <= A;
|
|
||||||
write <= 1;
|
|
||||||
state <= S_SELECT;
|
|
||||||
end
|
|
||||||
// state 5: compute ALU op and flags
|
|
||||||
S_COMPUTE: begin
|
S_COMPUTE: begin
|
||||||
if (opcode[4])
|
// transfer ALU output to destination
|
||||||
B <= Y[7:0];
|
case (opdest)
|
||||||
else
|
`DEST_A: A <= Y[7:0];
|
||||||
A <= Y[7:0];
|
`DEST_B: B <= Y[7:0];
|
||||||
carry <= Y[8];
|
`DEST_IP: IP <= Y[7:0];
|
||||||
|
`DEST_NOP: ;
|
||||||
|
endcase
|
||||||
|
// set carry for certain operations (code >= 8)
|
||||||
|
if (aluop[3]) carry <= Y[8];
|
||||||
|
// set zero flag
|
||||||
zero <= ~|Y;
|
zero <= ~|Y;
|
||||||
|
// repeat CPU loop
|
||||||
|
state <= S_SELECT;
|
||||||
|
end
|
||||||
|
// state 4: read new IP from memory (immediate mode)
|
||||||
|
S_READ_IP: begin
|
||||||
|
IP <= data_in;
|
||||||
state <= S_SELECT;
|
state <= S_SELECT;
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
|
@ -165,11 +203,18 @@ module test_CPU_top(
|
||||||
output [7:0] address_bus,
|
output [7:0] address_bus,
|
||||||
output reg [7:0] to_cpu,
|
output reg [7:0] to_cpu,
|
||||||
output [7:0] from_cpu,
|
output [7:0] from_cpu,
|
||||||
output write_enable
|
output write_enable,
|
||||||
|
output [7:0] IP,
|
||||||
|
output [7:0] A,
|
||||||
|
output [7:0] B
|
||||||
);
|
);
|
||||||
|
|
||||||
reg [7:0] ram[127:0];
|
reg [7:0] ram[0:127];
|
||||||
reg [7:0] rom[127:0];
|
reg [7:0] rom[0:127];
|
||||||
|
|
||||||
|
assign IP = cpu.IP;
|
||||||
|
assign A = cpu.A;
|
||||||
|
assign B = cpu.B;
|
||||||
|
|
||||||
CPU cpu(.clk(clk),
|
CPU cpu(.clk(clk),
|
||||||
.reset(reset),
|
.reset(reset),
|
||||||
|
@ -188,16 +233,19 @@ module test_CPU_top(
|
||||||
to_cpu = rom[address_bus[6:0]];
|
to_cpu = rom[address_bus[6:0]];
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
// address 0x80
|
rom = '{
|
||||||
rom['h00] = `I_CONST(`REG_A, 5'h1f);
|
`I_CONST_IMM_A,
|
||||||
rom['h01] = `I_COMPUTE(`REG_A, `OP_ASL);
|
0,
|
||||||
rom['h02] = `I_COMPUTE(`REG_A, `OP_ASL);
|
`I_CONST_IMM_B,
|
||||||
rom['h03] = `I_COMPUTE(`REG_A, `OP_ASL);
|
1,
|
||||||
rom['h04] = `I_COMPUTE(`REG_A, `OP_ASL);
|
`I_COMPUTE(`DEST_A, `OP_ADD), // addr 4
|
||||||
rom['h05] = `I_COMPUTE(`REG_B, `OP_LOAD_A);
|
`I_SWAP_AB,
|
||||||
rom['h06] = `I_STORE_ADDR(`REG_B, 4'd1);
|
`I_BRANCH_IF_CARRY(0),
|
||||||
rom['h07] = `I_LOAD_ADDR(`REG_B, 4'd1);
|
4 + 'h80, // correct for ROM offset
|
||||||
rom['h08] = `I_RESET;
|
`I_RESET,
|
||||||
|
// leftover elements
|
||||||
|
119{0}
|
||||||
|
};
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -10,80 +10,99 @@ module car_bitmap(yofs, bits);
|
||||||
assign bits = bitarray[yofs];
|
assign bits = bitarray[yofs];
|
||||||
|
|
||||||
initial begin/*{w:8,h:16}*/
|
initial begin/*{w:8,h:16}*/
|
||||||
bitarray[0] = 8'b110000;
|
bitarray[0] = 8'b1100;
|
||||||
bitarray[1] = 8'b1110111;
|
bitarray[1] = 8'b11001100;
|
||||||
bitarray[2] = 8'b11100110;
|
bitarray[2] = 8'b11111100;
|
||||||
bitarray[3] = 8'b11111111;
|
bitarray[3] = 8'b11101100;
|
||||||
bitarray[4] = 8'b11100110;
|
bitarray[4] = 8'b11100000;
|
||||||
bitarray[5] = 8'b1100111;
|
bitarray[5] = 8'b1100000;
|
||||||
bitarray[6] = 8'b110000;
|
bitarray[6] = 8'b1110000;
|
||||||
bitarray[7] = 8'b110000;
|
bitarray[7] = 8'b110000;
|
||||||
bitarray[8] = 8'b110000;
|
bitarray[8] = 8'b110000;
|
||||||
bitarray[9] = 8'b1110000;
|
bitarray[9] = 8'b110000;
|
||||||
bitarray[10] = 8'b1100000;
|
bitarray[10] = 8'b1100111;
|
||||||
bitarray[11] = 8'b11100000;
|
bitarray[11] = 8'b11100110;
|
||||||
bitarray[12] = 8'b11101100;
|
bitarray[12] = 8'b11111111;
|
||||||
bitarray[13] = 8'b11111100;
|
bitarray[13] = 8'b11100110;
|
||||||
bitarray[14] = 8'b11001100;
|
bitarray[14] = 8'b1110111;
|
||||||
bitarray[15] = 8'b1100;
|
bitarray[15] = 8'b110000;
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
module sprite_renderer(clk, vstart, load, hstart, rom_yofs, rom_bits,
|
module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits,
|
||||||
gfx, in_progress);
|
gfx, in_progress);
|
||||||
|
|
||||||
input clk, vstart, load, hstart;
|
input clk, vstart, load, hstart;
|
||||||
output [3:0] rom_yofs;
|
output [3:0] rom_addr;
|
||||||
input [7:0] rom_bits;
|
input [7:0] rom_bits;
|
||||||
output gfx;
|
output gfx;
|
||||||
output in_progress = yactive;
|
output in_progress = state != WAIT_FOR_VSTART;
|
||||||
|
|
||||||
|
reg [2:0] state;
|
||||||
reg [3:0] ycount;
|
reg [3:0] ycount;
|
||||||
reg [3:0] xcount;
|
reg [3:0] xcount;
|
||||||
reg yactive;
|
|
||||||
reg xactive;
|
|
||||||
reg loading;
|
|
||||||
|
|
||||||
reg [7:0] outbits;
|
reg [7:0] outbits;
|
||||||
|
|
||||||
|
localparam WAIT_FOR_VSTART = 0;
|
||||||
|
localparam WAIT_FOR_LOAD = 1;
|
||||||
|
localparam LOAD1_SETUP = 2;
|
||||||
|
localparam LOAD1_FETCH = 3;
|
||||||
|
localparam WAIT_FOR_HSTART = 4;
|
||||||
|
localparam DRAW = 5;
|
||||||
|
|
||||||
always @(posedge clk)
|
always @(posedge clk)
|
||||||
begin
|
begin
|
||||||
// set a default value (blank) for pixel output
|
case (state)
|
||||||
// note: multiple non-blocking assignments are vendor-specific
|
WAIT_FOR_VSTART: begin
|
||||||
gfx <= 0;
|
ycount <= 0;
|
||||||
// load next line? set ROM address
|
// set a default value (blank) for pixel output
|
||||||
if (yactive && load) begin
|
// note: multiple non-blocking assignments are vendor-specific
|
||||||
rom_yofs <= ~ycount;
|
gfx <= 0;
|
||||||
loading <= 1;
|
if (vstart) state <= WAIT_FOR_LOAD;
|
||||||
// ROM address was set, now latch bits from bus
|
end
|
||||||
end else if (loading) begin
|
WAIT_FOR_LOAD: begin
|
||||||
outbits <= rom_bits;
|
xcount <= 0;
|
||||||
loading <= 0;
|
gfx <= 0;
|
||||||
ycount <= ycount + 1;
|
if (load) state <= LOAD1_SETUP;
|
||||||
// start sprite at this vertical scanline
|
end
|
||||||
end else if (vstart) begin
|
LOAD1_SETUP: begin
|
||||||
yactive <= 1;
|
rom_addr <= ycount;
|
||||||
//ycount <= 0;
|
gfx <= 0;
|
||||||
// start sprite at this horizontal clock
|
state <= LOAD1_FETCH;
|
||||||
end else if (hstart && yactive) begin
|
end
|
||||||
xactive <= 1;
|
LOAD1_FETCH: begin
|
||||||
//xcount <= 0;
|
outbits[7:0] <= rom_bits;
|
||||||
// both X & Y active, set pixel output
|
gfx <= 0;
|
||||||
end else if (xactive && yactive)
|
state <= WAIT_FOR_HSTART;
|
||||||
begin
|
end
|
||||||
|
WAIT_FOR_HSTART: begin
|
||||||
|
if (hstart) state <= DRAW;
|
||||||
|
gfx <= 0;
|
||||||
|
end
|
||||||
|
DRAW: begin
|
||||||
// mirror graphics left/right
|
// mirror graphics left/right
|
||||||
gfx <= outbits[xcount[3]?~xcount[2:0]:xcount[2:0]];
|
gfx <= outbits[xcount<8 ? xcount[2:0] : ~xcount[2:0]];
|
||||||
xcount <= xcount + 1;
|
xcount <= xcount + 1;
|
||||||
if (xcount == 15) begin // pre-increment value
|
if (xcount == 15) begin // pre-increment value
|
||||||
xactive <= 0; // done drawing this scanline
|
ycount <= ycount + 1;
|
||||||
if (ycount == 0) // post-increment value
|
if (ycount == 15) // pre-increment value
|
||||||
yactive <= 0; // done drawing sprite
|
state <= WAIT_FOR_VSTART; // done drawing sprite
|
||||||
|
else
|
||||||
|
state <= WAIT_FOR_LOAD; // done drawing this scanline
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
default: begin
|
||||||
|
state <= 0; // TODO: reset
|
||||||
|
gfx <= 0;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
module test_top(clk, hsync, vsync, rgb, hpaddle, vpaddle);
|
module test_top(clk, hsync, vsync, rgb, hpaddle, vpaddle);
|
||||||
|
|
||||||
input clk;
|
input clk;
|
||||||
|
@ -127,7 +146,7 @@ module test_top(clk, hsync, vsync, rgb, hpaddle, vpaddle);
|
||||||
.vstart(vstart),
|
.vstart(vstart),
|
||||||
.load(hsync),
|
.load(hsync),
|
||||||
.hstart(hstart),
|
.hstart(hstart),
|
||||||
.rom_yofs(car_sprite_yofs),
|
.rom_addr(car_sprite_yofs),
|
||||||
.rom_bits(car_sprite_bits),
|
.rom_bits(car_sprite_bits),
|
||||||
.gfx(car_gfx),
|
.gfx(car_gfx),
|
||||||
.in_progress(unused));
|
.in_progress(unused));
|
||||||
|
|
|
@ -159,6 +159,15 @@ function PixelEditor(parentDiv, fmt, palette, initialData, thumbnails) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setPixels(p) {
|
||||||
|
var i = 0;
|
||||||
|
for (var y=0; y<height; y++) {
|
||||||
|
for (var x=0; x<width; x++) {
|
||||||
|
setPixel(x, y, p[i++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.rotate = function(deg) {
|
this.rotate = function(deg) {
|
||||||
console.log("rotate " + deg);
|
console.log("rotate " + deg);
|
||||||
var s1 = Math.sin(deg * Math.PI / 180);
|
var s1 = Math.sin(deg * Math.PI / 180);
|
||||||
|
@ -175,12 +184,35 @@ function PixelEditor(parentDiv, fmt, palette, initialData, thumbnails) {
|
||||||
p[i++] = col;
|
p[i++] = col;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i = 0;
|
setPixels(p);
|
||||||
|
commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.flipy = function() {
|
||||||
|
console.log("flipy");
|
||||||
|
var p = self.getImageColors();
|
||||||
|
var i = 0;
|
||||||
for (var y=0; y<height; y++) {
|
for (var y=0; y<height; y++) {
|
||||||
for (var x=0; x<width; x++) {
|
for (var x=0; x<width; x++) {
|
||||||
setPixel(x, y, p[i++]);
|
var col = getPixel(x, height-1-y);
|
||||||
|
p[i++] = col;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setPixels(p);
|
||||||
|
commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.flipx = function() {
|
||||||
|
console.log("flipx");
|
||||||
|
var p = self.getImageColors();
|
||||||
|
var i = 0;
|
||||||
|
for (var y=0; y<height; y++) {
|
||||||
|
for (var x=0; x<width; x++) {
|
||||||
|
var col = getPixel(width-1-x, y);
|
||||||
|
p[i++] = col;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setPixels(p);
|
||||||
commit();
|
commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -472,6 +504,14 @@ function pixelEditorKeypress(e) {
|
||||||
case 36: // End
|
case 36: // End
|
||||||
currentPixelEditor.rotate(45);
|
currentPixelEditor.rotate(45);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
switch (e.charCode) {
|
||||||
|
case 104:
|
||||||
|
currentPixelEditor.flipx();
|
||||||
|
break;
|
||||||
|
case 118:
|
||||||
|
currentPixelEditor.flipy();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.log(e);
|
console.log(e);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -297,6 +297,24 @@ var VerilogPlatform = function(mainElement, options) {
|
||||||
gen.__unreset();
|
gen.__unreset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shadowText(ctx, txt, x, y) {
|
||||||
|
ctx.shadowColor = "black";
|
||||||
|
ctx.shadowBlur = 0;
|
||||||
|
ctx.shadowOffsetY = -1;
|
||||||
|
ctx.shadowOffsetX = 0;
|
||||||
|
ctx.fillText(txt, x, y);
|
||||||
|
ctx.shadowOffsetY = 1;
|
||||||
|
ctx.shadowOffsetX = 0;
|
||||||
|
ctx.fillText(txt, x, y);
|
||||||
|
ctx.shadowOffsetY = 0;
|
||||||
|
ctx.shadowOffsetX = -1;
|
||||||
|
ctx.fillText(txt, x, y);
|
||||||
|
ctx.shadowOffsetY = 0;
|
||||||
|
ctx.shadowOffsetX = 1;
|
||||||
|
ctx.fillText(txt, x, y);
|
||||||
|
ctx.shadowOffsetX = 0;
|
||||||
|
}
|
||||||
|
|
||||||
function updateScopeFrame() {
|
function updateScopeFrame() {
|
||||||
var arr = ports_and_signals;
|
var arr = ports_and_signals;
|
||||||
if (!arr) return;
|
if (!arr) return;
|
||||||
|
@ -348,17 +366,18 @@ var VerilogPlatform = function(mainElement, options) {
|
||||||
ctx.fillStyle = name == inspect_sym ? "yellow" : "white";
|
ctx.fillStyle = name == inspect_sym ? "yellow" : "white";
|
||||||
name = name.replace(/__DOT__/g,'.');
|
name = name.replace(/__DOT__/g,'.');
|
||||||
ctx.textAlign = 'left';
|
ctx.textAlign = 'left';
|
||||||
ctx.fillText(name, 1, yposlist[i]);
|
ctx.fillStyle = "white";
|
||||||
|
shadowText(ctx, name, 1, yposlist[i]);
|
||||||
if (scope_time_x > 0) {
|
if (scope_time_x > 0) {
|
||||||
ctx.textAlign = 'right';
|
ctx.textAlign = 'right';
|
||||||
var value = arr.length * scope_time_x + i + jstart;
|
var value = arr.length * scope_time_x + i + jstart;
|
||||||
ctx.fillText(""+trace_buffer[value], videoWidth-1, yposlist[i]);
|
shadowText(ctx, ""+trace_buffer[value], videoWidth-1, yposlist[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// draw scope line & label
|
// draw scope line & label
|
||||||
if (scope_time_x > 0) {
|
if (scope_time_x > 0) {
|
||||||
ctx.fillStyle = "cyan";
|
ctx.fillStyle = "cyan";
|
||||||
ctx.fillText(""+(scope_time_x+scope_x_offset),
|
shadowText(ctx, ""+(scope_time_x+scope_x_offset),
|
||||||
(scope_time_x>10)?(scope_time_x-2):(scope_time_x+20), videoHeight-2);
|
(scope_time_x>10)?(scope_time_x-2):(scope_time_x+20), videoHeight-2);
|
||||||
ctx.fillRect(scope_time_x, 0, 1, 4000);
|
ctx.fillRect(scope_time_x, 0, 1, 4000);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user