1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-06-25 15:29:34 +00:00

moved around ALU ops, 16-bit cpu, reg/wire

This commit is contained in:
Steven Hugg 2018-02-18 18:19:20 -06:00
parent f6d320a05b
commit 20ddb8a11f
16 changed files with 375 additions and 235 deletions

View File

@ -3,7 +3,7 @@
module seven_segment_decoder(digit, segments); module seven_segment_decoder(digit, segments);
input [3:0] digit; input [3:0] digit;
output [6:0] segments; output reg [6:0] segments;
always @(*) always @(*)
case(digit) case(digit)
@ -26,7 +26,7 @@ module segments_to_bitmap(segments, line, bits);
input [6:0] segments; input [6:0] segments;
input [2:0] line; input [2:0] line;
output [4:0] bits; output reg [4:0] bits;
always @(*) always @(*)
case (line) case (line)

View File

@ -5,20 +5,25 @@
/* /*
00000aaa 0++++bbb operation A+B->A 00000aaa 0++++bbb operation A+B->A
00001ttt ######## conditional branch 00001aaa 0++++bbb operation A+[B]->A
00100aaa ######## load constant 00011aaa 0++++000 operation A+imm16 -> A
00101aaa ######## load memory 00101aaa ######## load zero page
00110aaa ######## store memory 00110aaa ######## store zero page
01000aaa #####bbb load [B+#] -> A 01001aaa #####bbb load [B+#] -> A
01010aaa #####bbb store A -> [B+#] 01010aaa #####bbb store A -> [B+#]
10+++aaa 10+++aaa dual unary operation 01101aaa 0++++000 operation A+[imm16] -> A
01110aaa 00cccbbb store A -> [B+#], C -> IP
1000tttt ######## conditional branch
11+++aaa ######## immediate binary operation 11+++aaa ######## immediate binary operation
*/ */
module CPU16(clk, reset, address, data_in, data_out, write); module CPU16(clk, reset, halt, busy,
address, data_in, data_out, write);
input clk; input clk;
input reset; input reset;
input halt;
output busy;
output [15:0] address; output [15:0] address;
input [15:0] data_in; input [15:0] data_in;
output [15:0] data_out; output [15:0] data_out;
@ -37,26 +42,30 @@ module CPU16(clk, reset, address, data_in, data_out, write);
reg [3:0] aluop; reg [3:0] aluop;
wire [2:0] rdest = opcode[10:8]; wire [2:0] rdest = opcode[10:8];
wire [2:0] rsrc = opcode[2:0]; wire [2:0] rsrc = opcode[2:0];
wire Bload = opcode[11]; // TODO wire Bconst = opcode[15]; // TODO
wire Bload = opcode[11]; // TODO
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_COMPUTE = 3; localparam S_COMPUTE = 3;
localparam SP = 6; // stack ptr = register 6
localparam IP = 7; // IP = register 7 localparam IP = 7; // IP = register 7
ALU #(16) alu( ALU #(16) alu(
.A(regs[rdest]), .A(regs[rdest]),
.B(regs[rsrc]), .B(Bconst ? {8'b0, opcode[7:0]}
: Bload ? data_in
: regs[rsrc]),
.Y(Y), .Y(Y),
.aluop(aluop), .aluop(aluop),
.carry(carry)); .carry(carry));
always @(posedge clk) always @(posedge clk)
if (reset) begin if (reset) begin
state <= 0; state <= S_RESET;
write <= 0; busy <= 1;
end else begin end else begin
case (state) case (state)
// state 0: reset // state 0: reset
@ -67,46 +76,102 @@ module CPU16(clk, reset, address, data_in, data_out, write);
end end
// state 1: select opcode address // state 1: select opcode address
S_SELECT: begin S_SELECT: begin
address <= regs[IP];
regs[IP] <= regs[IP] + 1;
write <= 0; write <= 0;
state <= S_DECODE; if (halt) begin
busy <= 1;
state <= S_SELECT;
end else begin
busy <= 0;
address <= regs[IP];
regs[IP] <= regs[IP] + 1;
state <= S_DECODE;
end
end end
// state 2: read/decode opcode // state 2: read/decode opcode
S_DECODE: begin S_DECODE: begin
opcode <= data_in; // (only use opcode next cycle) opcode <= data_in; // (only use opcode next cycle)
casez (data_in) casez (data_in)
// 00000aaa 0++++bbb operation A+B->A // 00000aaa0++++bbb operation A+B->A
16'b00000???0???????: begin 16'b00000???0???????: begin
aluop <= data_in[6:3]; aluop <= data_in[6:3];
state <= S_COMPUTE; state <= S_COMPUTE;
end end
// 00100aaa ######## load constant // 00001aaa01+++bbb operation A+[B]->A
16'b00100???????????: begin 16'b00001???01??????: begin
regs[rdest] <= {8'b0, data_in[7:0]}; address <= regs[data_in[2:0]];
state <= S_SELECT; aluop <= data_in[6:3];
state <= S_COMPUTE;
if (data_in[2:0] == SP)
regs[SP] <= regs[SP] + 1;
end end
// 00101aaa ######## load memory // 00011aaa0++++000 operation A+imm16 -> A
16'b00011???0????000: begin
address <= regs[IP];
regs[IP] <= regs[IP] + 1;
aluop <= data_in[6:3];
state <= S_COMPUTE;
end
// 11+++aaa######## immediate binary operation
16'b11??????????????: begin
aluop <= data_in[14:11];
state <= S_COMPUTE;
end
// 00101aaa######## load ZP memory
16'b00101???????????: begin 16'b00101???????????: begin
address <= {8'b0, data_in[7:0]}; address <= {8'b0, data_in[7:0]};
aluop <= `OP_LOAD_B; aluop <= `OP_LOAD_B;
state <= S_COMPUTE; state <= S_COMPUTE;
end end
// 00110aaa ######## store memory // 00110aaa######## store ZP memory
16'b00110???????????: begin 16'b00110???????????: begin
address <= {8'b0, data_in[7:0]}; address <= {8'b0, data_in[7:0]};
data_out <= regs[data_in[10:8]]; data_out <= regs[data_in[10:8]];
write <= 1; write <= 1;
state <= S_SELECT; state <= S_SELECT;
end end
// 00001ttt ######## conditional branch // 01001aaa#####bbb [B+#] -> A
16'b00001???????????: begin 16'b01001???????????: begin
address <= regs[data_in[2:0]] + 16'($signed(data_in[7:3]));
aluop <= `OP_LOAD_B;
state <= S_COMPUTE;
if (data_in[2:0] == SP)
regs[SP] <= regs[SP] + 1;
end
// 01010aaa#####bbb store A -> [B+#]
16'b01010???????????: begin
address <= regs[data_in[2:0]] + 16'($signed(data_in[7:3]));
data_out <= regs[data_in[10:8]];
write <= 1;
state <= S_SELECT;
if (data_in[2:0] == SP)
regs[SP] <= regs[SP] - 1;
end
// 01011aaa0++++000 operation A+[imm16] -> A
16'b01011????????000: begin
address <= regs[IP];
regs[IP] <= regs[IP] + 1;
aluop <= data_in[6:3];
state <= S_COMPUTE;
end
// 01110aaa00cccbbb store A -> [B+#], C -> IP
16'b01110???00??????: begin
address <= regs[data_in[2:0]] + 16'($signed(data_in[7:3]));
data_out <= regs[data_in[10:8]];
write <= 1;
state <= S_SELECT;
if (data_in[2:0] == SP)
regs[SP] <= regs[SP] - 1;
regs[IP] <= regs[data_in[5:3]];
end
// 1000????######## conditional branch
16'b1000????????????: begin
if ( if (
(data_in[8] && (data_in[10] == carry)) || (data_in[8] && (data_in[11] == carry)) ||
(data_in[9] && (data_in[10] == zero))) (data_in[9] && (data_in[11] == zero)) ||
(data_in[10] && (data_in[11] == neg)))
begin begin
// relative branch, sign extended // relative branch, sign extended
regs[IP] <= regs[IP] + { {8{data_in[7]}}, data_in[7:0]}; regs[IP] <= regs[IP] + 16'($signed(data_in[7:0]));
end end
state <= S_SELECT; state <= S_SELECT;
end end
@ -142,18 +207,22 @@ module test_CPU16_top(
output write_enable, output write_enable,
output [15:0] IP, output [15:0] IP,
output zero, output zero,
output carry output carry,
output busy
); );
reg [15:0] ram[0:65535]; reg [15:0] ram[0:65535];
reg [15:0] rom[0:65535]; reg [15:0] rom[0:255];
assign IP = cpu.regs[7]; assign IP = cpu.regs[7];
assign zero = cpu.zero; assign zero = cpu.zero;
assign carry = cpu.carry; assign carry = cpu.carry;
CPU16 cpu(.clk(clk), CPU16 cpu(
.clk(clk),
.reset(reset), .reset(reset),
.halt(0),
.busy(busy),
.address(address_bus), .address(address_bus),
.data_in(to_cpu), .data_in(to_cpu),
.data_out(from_cpu), .data_out(from_cpu),
@ -168,7 +237,36 @@ module test_CPU16_top(
if (address_bus[15] == 0) if (address_bus[15] == 0)
to_cpu = ram[address_bus]; to_cpu = ram[address_bus];
else else
to_cpu = rom[address_bus]; to_cpu = rom[address_bus[7:0]];
`ifdef EXT_INLINE_ASM
initial begin
rom = '{
__asm
.arch femto16
.org 0x8000
.len 256
mov dx,@Fib
jsr dx
reset
Fib:
mov ax,#1
mov bx,#0
mov sp,@$6fff
Loop:
mov cx,ax
add ax,bx
mov bx,cx
push ax
pop ax
mov [42],ax
mov ax,[42]
bcc Loop
rts
__endasm
};
end
`endif
endmodule endmodule

View File

@ -2,8 +2,8 @@
`define ALU_H `define ALU_H
// ALU operations // ALU operations
`define OP_LOAD_A 4'h0 `define OP_ZERO 4'h0
`define OP_LOAD_B 4'h1 `define OP_LOAD_A 4'h1
`define OP_INC 4'h2 `define OP_INC 4'h2
`define OP_DEC 4'h3 `define OP_DEC 4'h3
`define OP_ASL 4'h4 `define OP_ASL 4'h4
@ -13,7 +13,7 @@
`define OP_OR 4'h8 `define OP_OR 4'h8
`define OP_AND 4'h9 `define OP_AND 4'h9
`define OP_XOR 4'ha `define OP_XOR 4'ha
`define OP_ZERO 4'hb `define OP_LOAD_B 4'hb
`define OP_ADD 4'hc `define OP_ADD 4'hc
`define OP_SUB 4'hd `define OP_SUB 4'hd
`define OP_ADC 4'he `define OP_ADC 4'he
@ -32,8 +32,8 @@ module ALU(A, B, Y, aluop, carry);
always @(*) always @(*)
case (aluop) case (aluop)
// unary operations // unary operations
`OP_ZERO: Y = 0;
`OP_LOAD_A: Y = {1'b0, A}; `OP_LOAD_A: Y = {1'b0, A};
`OP_LOAD_B: Y = {1'b0, B};
`OP_INC: Y = A + 1; `OP_INC: Y = A + 1;
`OP_DEC: Y = A - 1; `OP_DEC: Y = A - 1;
// unary operations that generate and/or use carry // unary operations that generate and/or use carry
@ -45,7 +45,7 @@ module ALU(A, B, Y, aluop, carry);
`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_ZERO: Y = 0; `OP_LOAD_B: Y = {1'b0, B};
// binary operations that generate and/or use carry // binary operations that generate and/or use carry
`OP_ADD: Y = A + B; `OP_ADD: Y = A + B;
`OP_SUB: Y = A - B; `OP_SUB: Y = A - B;

View File

@ -7,9 +7,10 @@ module digits10_case(digit, yofs, bits);
input [3:0] digit; input [3:0] digit;
input [2:0] yofs; input [2:0] yofs;
output [4:0] bits; output reg [4:0] bits;
wire [6:0] caseexpr = {digit,yofs}; wire [6:0] caseexpr = {digit,yofs};
always @(*) always @(*)
case (caseexpr)/*{w:5,h:5,count:10}*/ case (caseexpr)/*{w:5,h:5,count:10}*/
7'o00: bits = 5'b11111; 7'o00: bits = 5'b11111;

View File

@ -0,0 +1,38 @@
{
"name":"femto8",
"width":16,
"vars":{
"reg":{"bits":3, "toks":["ax", "bx", "cx", "dx", "ex", "fx", "sp", "ip"]},
"unop":{"bits":3, "toks":["zero","loada","inc","dec","asl","lsr","rol","ror"]},
"binop":{"bits":3, "toks":["or","and","xor","mov","add","sub","adc","sbb"]},
"imm8":{"bits":8},
"imm16":{"bits":16},
"rel8":{"bits":8, "iprel":true, "ipofs":1}
},
"rules":[
{"fmt":"~binop ~reg,~reg", "bits":["00000",1,"01",0,2]},
{"fmt":"~unop ~reg", "bits":["00000",1,"00",0,"000"]},
{"fmt":"~binop ~reg,[~reg]", "bits":["00001",1,"01",0,2]},
{"fmt":"mov [~reg],~reg", "bits":["01010",1,"00000",0]},
{"fmt":"mov ~reg,[~imm8]", "bits":["00101",0,1]},
{"fmt":"mov [~imm8],~reg", "bits":["00110",1,0]},
{"fmt":"~binop ~reg,#~imm8", "bits":["11",0,1,2]},
{"fmt":"~binop ~reg,@~imm16","bits":["00011",1,"01",0,"000",2]},
{"fmt":"~binop ~reg,[~imm16]", "bits":["01011",1,"01",0,"000",2]},
{"fmt":"push ~reg", "bits":["01010",0,"00000","110"]},
{"fmt":"pop ~reg", "bits":["01001",0,"00001","110"]},
{"fmt":"rts", "bits":["01001","111","00001","110"]},
{"fmt":"jsr ~reg", "bits":["01110","111","00",0,"110"]},
{"fmt":"bcc ~rel8", "bits":["10000001",0]},
{"fmt":"bcs ~rel8", "bits":["10001001",0]},
{"fmt":"bnz ~rel8", "bits":["10000010",0]},
{"fmt":"bz ~rel8", "bits":["10001010",0]},
{"fmt":"bpl ~rel8", "bits":["10000100",0]},
{"fmt":"bmi ~rel8", "bits":["10001100",0]},
{"fmt":"reset", "bits":["1011100011111111"]}
]
}

View File

@ -1,7 +1,8 @@
`undef EXT_INLINE_ASM
`include "hvsync_generator.v" `include "hvsync_generator.v"
`include "sprite_bitmap.v"
`include "sprite_renderer.v"
`include "cpu8.v" `include "cpu8.v"
`include "cpu16.v"
`define EXT_INLINE_ASM
// uncomment to see scope view // uncomment to see scope view
//`define DEBUG //`define DEBUG
@ -9,13 +10,11 @@
module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle, module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
address_bus, to_cpu, from_cpu, write_enable address_bus, to_cpu, from_cpu, write_enable
`ifdef DEBUG `ifdef DEBUG
, output [7:0] A , output [15:0] IP
, output [7:0] B
, output [7:0] IP
, output carry , output carry
, output zero , output zero
`else `else
,rgb , rgb
`endif `endif
); );
@ -26,9 +25,7 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
wire [8:0] hpos; wire [8:0] hpos;
wire [8:0] vpos; wire [8:0] vpos;
`ifdef DEBUG `ifdef DEBUG
assign IP = cpu.IP; assign IP = cpu.regs[cpu.IP];
assign A = cpu.A;
assign B = cpu.B;
assign carry = cpu.carry; assign carry = cpu.carry;
assign zero = cpu.zero; assign zero = cpu.zero;
`else `else
@ -38,18 +35,19 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
parameter IN_HPOS = 8'b01000000; parameter IN_HPOS = 8'b01000000;
parameter IN_VPOS = 8'b01000001; parameter IN_VPOS = 8'b01000001;
parameter IN_FLAGS = 8'b01000010; parameter IN_FLAGS = 8'b01000010;
parameter IN_VPU = 8'b01000011;
reg [7:0] ram[0:63]; reg [15:0] ram[0:32767];
reg [7:0] rom[0:127]; reg [15:0] rom[0:1023];
output wire [7:0] address_bus; output wire [15:0] address_bus;
output reg [7:0] to_cpu; output reg [15:0] to_cpu;
output wire [7:0] from_cpu; output wire [15:0] from_cpu;
output wire write_enable; output wire write_enable;
CPU cpu(.clk(clk), CPU16 cpu(.clk(clk),
.reset(reset), .reset(reset),
.hold(hold),
.busy(busy),
.address(address_bus), .address(address_bus),
.data_in(to_cpu), .data_in(to_cpu),
.data_out(from_cpu), .data_out(from_cpu),
@ -57,47 +55,23 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
always @(posedge clk) always @(posedge clk)
if (write_enable) begin if (write_enable) begin
casez (address_bus) ram[address_bus[14:0]] <= from_cpu;
// VPU lo byte
8'b0001000: begin
vpu_write[15:8] <= from_cpu;
end
// VPU hi byte
8'b0001001: begin
vpu_write[7:0] <= from_cpu;
end
// VPU write
8'b0001010: begin
vpu_ram[vpu_write] <= from_cpu[7:4];
vpu_ram[vpu_write+1] <= from_cpu[3:0];
vpu_write <= vpu_write + 2;
end
// VPU move
8'b0001011: begin
// sign extend
vpu_write <= {
vpu_write[15:8] + { {4{from_cpu[7]}}, from_cpu[7:4] },
vpu_write[7:0] + { {4{from_cpu[3]}}, from_cpu[3:0] }
};
end
default: ram[address_bus[5:0]] <= from_cpu;
endcase
end end
always @(*) always @(*)
casez (address_bus) if (address_bus[15])
// RAM to_cpu = rom[address_bus[9:0]];
8'b00??????: to_cpu = ram[address_bus[5:0]]; else if (&address_bus[14:8]) begin
// special read registers casez (address_bus[7:0])
IN_HPOS: to_cpu = hpos[7:0]; // special read registers
IN_VPOS: to_cpu = vpos[7:0]; IN_HPOS: to_cpu = {8'b0, hpos[7:0]};
IN_FLAGS: to_cpu = {3'b0, IN_VPOS: to_cpu = {8'b0, vpos[7:0]};
vsync, hsync, vpaddle, hpaddle, display_on}; IN_FLAGS: to_cpu = {11'b0,
IN_VPU: to_cpu = {vpu_ram[vpu_write], vpu_ram[vpu_write+1]}; vsync, hsync, vpaddle, hpaddle, display_on};
// ROM default: to_cpu = 0;
8'b1???????: to_cpu = rom[address_bus[7:0] + 128]; endcase
default: ; end else
endcase to_cpu = ram[address_bus[14:0]];
hvsync_generator hvsync_gen( hvsync_generator hvsync_gen(
.clk(clk), .clk(clk),
@ -109,38 +83,49 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
.vpos(vpos) .vpos(vpos)
); );
reg [3:0] vpu_ram[0:65535]; // video DMA access
reg [15:0] vpu_read; reg hold;
reg [15:0] vpu_write; wire busy;
reg [3:0] rgb; reg [15:0] vline[0:31]; // 32x16 bits = 256 4-color pixels
reg [4:0] vindex;
reg [15:0] vshift;
reg [3:0] palette[0:3] = '{0,1,4,7};
always @(posedge clk) begin always @(posedge clk) begin
if (!hpos[8] && !vpos[8]) begin // has CPU released the bus?
rgb <= vpu_ram[vpu_read]; if (busy) begin
vpu_read <= vpu_read + 1; // write from main RAM -> scanline RAM
end else begin vline[vindex] <= ram[{2'b10,vpos[7:0],vindex}];
// end of scanline read?
if (&vindex)
hold <= 0; // release CPU
vindex <= vindex + 1; // next address
end else if (hpos >= 256 && hpos < 256+4 && vpos < 240) begin
hold <= 1; // start DMA mode, hold CPU
end else if (!hpos[8] && vpos < 240) begin
// load next word from vline buffer
if (0 == hpos[2:0]) begin
vshift <= vline[vindex];
vindex <= vindex + 1;
end else
vshift <= vshift >> 2;
// decode scanline RAM to RGB output
rgb <= palette[vshift[1:0]];
end else
rgb <= 0; rgb <= 0;
if (vpos[8])
vpu_read <= 0;
end
end end
`ifdef EXT_INLINE_ASM `ifdef EXT_INLINE_ASM
initial begin initial begin
rom = '{ rom = '{
__asm __asm
.arch femto8 .arch femto16
.org 128 .org 32768
.len 128 .len 1024
.define VPU_LO 8 .define IN_HPOS $7f00
.define VPU_HI 9 .define IN_VPOS $7f01
.define VPU_WRITE 10 .define IN_FLAGS $7f02
.define VPU_MOVE 11
.define IN_HPOS $40
.define IN_VPOS $41
.define IN_FLAGS $42
.define F_DISPLAY 1 .define F_DISPLAY 1
.define F_HPADDLE 2 .define F_HPADDLE 2
@ -149,31 +134,15 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
.define F_VSYNC 16 .define F_VSYNC 16
Start: Start:
zero A mov ax,#0
sta VPU_LO mov bx,ax
sta VPU_HI Loop:
sta 0 xor ax,[bx]
DisplayLoop: mov [bx],ax
zero B inc bx
mov A,[b] inc ax
sta VPU_WRITE bnz Loop
sta VPU_MOVE reset
sta VPU_WRITE
sta VPU_MOVE
sta VPU_WRITE
sta VPU_MOVE
lda #F_VSYNC
ldb #IN_FLAGS
and none,[B]
bz DisplayLoop
WaitVsync:
and none,[B]
bnz WaitVsync
zero B
mov A,[b]
inc A
sta 0
jmp DisplayLoop
__endasm __endasm
}; };
end end

View File

@ -5,10 +5,10 @@ module hvsync_generator(clk, reset, hsync, vsync, display_on, hpos, vpos);
input clk; input clk;
input reset; input reset;
output hsync, vsync; output reg hsync, vsync;
output display_on; output display_on;
output [8:0] hpos; output reg [8:0] hpos;
output [8:0] vpos; output reg [8:0] vpos;
// constant declarations for TV-simulator sync parameters // constant declarations for TV-simulator sync parameters
// horizontal // horizontal

View File

@ -7,10 +7,10 @@
module player_stats(reset, score0, score1, lives, incscore, declives); module player_stats(reset, score0, score1, lives, incscore, declives);
input reset; input reset;
output [3:0] score0; output reg [3:0] score0;
output [3:0] score1; output reg [3:0] score1;
input incscore; input incscore;
output [3:0] lives; output reg [3:0] lives;
input declives; input declives;
always @(posedge incscore or posedge reset) always @(posedge incscore or posedge reset)
@ -45,8 +45,8 @@ module scoreboard_generator(score0, score1, lives, vpos, hpos, board_gfx);
input [8:0] hpos; input [8:0] hpos;
output board_gfx; output board_gfx;
wire [3:0] score_digit; reg [3:0] score_digit;
wire [4:0] score_bits; reg [4:0] score_bits;
always @(*) always @(*)
begin begin

View File

@ -81,6 +81,7 @@ module sprite_bitmap_top(clk, reset, hsync, vsync, rgb);
wire [3:0] car_bit = car_sprite_xofs>=8 ? wire [3:0] car_bit = car_sprite_xofs>=8 ?
15-car_sprite_xofs: 15-car_sprite_xofs:
car_sprite_xofs; car_sprite_xofs;
wire car_gfx = car_sprite_bits[car_bit[2:0]]; wire car_gfx = car_sprite_bits[car_bit[2:0]];
wire r = display_on && car_gfx; wire r = display_on && car_gfx;

View File

@ -63,7 +63,7 @@ module sprite_multiple_top(clk, hsync, vsync, rgb, hpaddle, vpaddle);
sprite_renderer enemy_renderer( sprite_renderer enemy_renderer(
.clk(clk), .clk(clk),
.vstart(enemy_vstart), .vstart(enemy_vstart),
.load(hpos == 257), .load(hpos == 258),
.hstart(enemy_hstart), .hstart(enemy_hstart),
.rom_addr(car_sprite_yofs), .rom_addr(car_sprite_yofs),
.rom_bits(car_sprite_bits), .rom_bits(car_sprite_bits),

View File

@ -7,20 +7,24 @@
module sprite_renderer(clk, vstart, load, hstart, rom_addr, 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;
output [3:0] rom_addr; input vstart; // start drawing (top border)
input [7:0] rom_bits; input load; // ok to load sprite data?
output gfx; input hstart; // start drawing scanline (left border)
output in_progress; output [3:0] rom_addr; // select ROM address
input [7:0] rom_bits; // input bits from ROM
output gfx; // output pixel
output in_progress; // 0 if waiting for vstart
assign in_progress = state != WAIT_FOR_VSTART; assign in_progress = state != WAIT_FOR_VSTART;
reg [2:0] state; reg [2:0] state; // current state #
reg [3:0] ycount; reg [3:0] ycount; // number of scanlines drawn so far
reg [3:0] xcount; reg [3:0] xcount; // number of horiz. pixels in this line
reg [7:0] outbits; reg [7:0] outbits; // register to store bits from ROM
// states
localparam WAIT_FOR_VSTART = 0; localparam WAIT_FOR_VSTART = 0;
localparam WAIT_FOR_LOAD = 1; localparam WAIT_FOR_LOAD = 1;
localparam LOAD1_SETUP = 2; localparam LOAD1_SETUP = 2;
@ -32,46 +36,49 @@ module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits,
begin begin
case (state) case (state)
WAIT_FOR_VSTART: begin WAIT_FOR_VSTART: begin
ycount <= 0; ycount <= 0; // initialize vertical count
// set a default value (blank) for pixel output gfx <= 0; // default pixel value (off)
// note: multiple non-blocking assignments are vendor-specific // wait for vstart, then next state
gfx <= 0; if (vstart)
if (vstart) state <= WAIT_FOR_LOAD; state <= WAIT_FOR_LOAD;
end end
WAIT_FOR_LOAD: begin WAIT_FOR_LOAD: begin
xcount <= 0; xcount <= 0; // initialize horiz. count
gfx <= 0; gfx <= 0;
if (load) state <= LOAD1_SETUP; // wait for load, then next state
if (load)
state <= LOAD1_SETUP;
end end
LOAD1_SETUP: begin LOAD1_SETUP: begin
rom_addr <= ycount; rom_addr <= ycount; // load ROM address
gfx <= 0;
state <= LOAD1_FETCH; state <= LOAD1_FETCH;
end end
LOAD1_FETCH: begin LOAD1_FETCH: begin
outbits[7:0] <= rom_bits; outbits <= rom_bits; // latch bits from ROM
gfx <= 0;
state <= WAIT_FOR_HSTART; state <= WAIT_FOR_HSTART;
end end
WAIT_FOR_HSTART: begin WAIT_FOR_HSTART: begin
if (hstart) state <= DRAW; // wait for hstart, then start drawing
gfx <= 0; if (hstart)
state <= DRAW;
end end
DRAW: begin DRAW: begin
// mirror graphics left/right // get pixel, mirroring graphics left/right
gfx <= outbits[xcount<8 ? xcount[2:0] : ~xcount[2:0]]; gfx <= outbits[xcount<8 ? xcount[2:0] : ~xcount[2:0]];
xcount <= xcount + 1; xcount <= xcount + 1;
// finished drawing horizontal slice?
if (xcount == 15) begin // pre-increment value if (xcount == 15) begin // pre-increment value
ycount <= ycount + 1; ycount <= ycount + 1;
// finished drawing sprite?
if (ycount == 15) // pre-increment value if (ycount == 15) // pre-increment value
state <= WAIT_FOR_VSTART; // done drawing sprite state <= WAIT_FOR_VSTART; // done drawing sprite
else else
state <= WAIT_FOR_LOAD; // done drawing this scanline state <= WAIT_FOR_LOAD; // done drawing this scanline
end end
end end
// unknown state -- reset
default: begin default: begin
state <= 0; // TODO: reset state <= WAIT_FOR_VSTART;
gfx <= 0;
end end
endcase endcase
end end
@ -105,33 +112,33 @@ module test_top(clk, hsync, vsync, rgb, hpaddle, vpaddle);
.vpos(vpos) .vpos(vpos)
); );
wire [3:0] car_sprite_yofs; wire [3:0] car_sprite_addr;
wire [7:0] car_sprite_bits; wire [7:0] car_sprite_bits;
car_bitmap car( car_bitmap car(
.yofs(car_sprite_yofs), .yofs(car_sprite_addr),
.bits(car_sprite_bits)); .bits(car_sprite_bits));
wire vstart = {1'd0,player_y} == vpos; wire vstart = {1'd0,player_y} == vpos;
wire hstart = {1'd0,player_x} == hpos; wire hstart = {1'd0,player_x} == hpos;
wire car_gfx; wire car_gfx;
wire unused; wire in_progress;
sprite_renderer renderer( sprite_renderer renderer(
.clk(clk), .clk(clk),
.vstart(vstart), .vstart(vstart),
.load(hsync), .load(hsync),
.hstart(hstart), .hstart(hstart),
.rom_addr(car_sprite_yofs), .rom_addr(car_sprite_addr),
.rom_bits(car_sprite_bits), .rom_bits(car_sprite_bits),
.gfx(car_gfx), .gfx(car_gfx),
.in_progress(unused)); .in_progress(in_progress));
always @(posedge hsync) always @(posedge hpaddle)
begin paddle_x <= vpos[7:0];
if (!hpaddle) paddle_x <= vpos[7:0];
if (!vpaddle) paddle_y <= vpos[7:0]; always @(posedge vpaddle)
end paddle_y <= vpos[7:0];
always @(posedge vsync) always @(posedge vsync)
begin begin
@ -141,7 +148,7 @@ module test_top(clk, hsync, vsync, rgb, hpaddle, vpaddle);
wire r = display_on && car_gfx; wire r = display_on && car_gfx;
wire g = display_on && car_gfx; wire g = display_on && car_gfx;
wire b = display_on && car_gfx; wire b = display_on && in_progress;
assign rgb = {b,g,r}; assign rgb = {b,g,r};
endmodule endmodule

View File

@ -8,7 +8,7 @@ module tank_bitmap(addr, bits);
input [7:0] addr; input [7:0] addr;
output [7:0] bits; output [7:0] bits;
reg [15:0] bitarray[256]; reg [15:0] bitarray[0:255];
assign bits = (addr[0]) ? bitarray[addr>>1][15:8] : bitarray[addr>>1][7:0]; assign bits = (addr[0]) ? bitarray[addr>>1][15:8] : bitarray[addr>>1][7:0];
@ -109,7 +109,9 @@ module sprite_renderer2(clk, vstart, load, hstart, rom_addr, rom_bits,
output [4:0] rom_addr; output [4:0] rom_addr;
input [7:0] rom_bits; input [7:0] rom_bits;
output gfx; output gfx;
output busy = state != WAIT_FOR_VSTART; output busy;
assign busy = state != WAIT_FOR_VSTART;
reg [2:0] state; reg [2:0] state;
reg [3:0] ycount; reg [3:0] ycount;
@ -178,6 +180,7 @@ module sprite_renderer2(clk, vstart, load, hstart, rom_addr, rom_bits,
endmodule endmodule
module rotation_selector(rotation, bitmap_num, hmirror, vmirror); module rotation_selector(rotation, bitmap_num, hmirror, vmirror);
input [3:0] rotation; input [3:0] rotation;
output [2:0] bitmap_num; output [2:0] bitmap_num;
output hmirror, vmirror; output hmirror, vmirror;
@ -208,23 +211,6 @@ module rotation_selector(rotation, bitmap_num, hmirror, vmirror);
endmodule endmodule
function signed [7:0] sin_16x4;
input [3:0] in;
integer y;
case (in[1:0])
0: y = 0;
1: y = 3;
2: y = 5;
3: y = 6;
endcase
case (in[3:2])
0: sin_16x4 = 8'(y);
1: sin_16x4 = 8'(7-y);
2: sin_16x4 = 8'(-y);
3: sin_16x4 = 8'(y-7);
endcase
endfunction
module tank_controller(clk, reset, hpos, vpos, hsync, vsync, module tank_controller(clk, reset, hpos, vpos, hsync, vsync,
sprite_addr, sprite_bits, gfx, sprite_addr, sprite_bits, gfx,
playfield, playfield,
@ -305,9 +291,33 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync,
end end
end end
// set if collision; cleared at vsync
reg collision_detected; reg collision_detected;
always @(posedge collision_gfx or posedge vsync or posedge reset)
collision_detected <= collision_gfx; always @(posedge clk)
if (collision_gfx)
collision_detected <= collision_gfx;
else if (vsync)
collision_detected <= 0;
// sine lookup (4 bits input, 4 signed bits output)
function signed [3:0] sin_16x4;
input [3:0] in;
integer y;
case (in[1:0])
0: y = 0;
1: y = 3;
2: y = 5;
3: y = 6;
endcase
case (in[3:2])
0: sin_16x4 = 4'(y);
1: sin_16x4 = 4'(7-y);
2: sin_16x4 = 4'(-y);
3: sin_16x4 = 4'(y-7);
endcase
endfunction
always @(posedge hsync or posedge reset) always @(posedge hsync or posedge reset)
if (reset) begin if (reset) begin

View File

@ -180,13 +180,13 @@ var VerilogPlatform = function(mainElement, options) {
var self = this; var self = this;
var video, audio; var video, audio;
var useAudio = false; var useAudio = false;
var videoWidth = 256+16; var videoWidth = 256+20;
var videoHeight = 240+16; var videoHeight = 240+20;
var maxVideoBlankLines = 80; var maxVideoBlankLines = 40; // vertical hold
var idata, timer; var idata, timer;
var gen; var gen;
var frameRate = 60; var frameRate = 60;
var AUDIO_FREQ = (256+23+7+23)*262*60; // 4857480 var AUDIO_FREQ = (256+23+7+23)*262*60; // 4857480 Hz
var current_output; var current_output;
var paddle_x = 0; var paddle_x = 0;
var paddle_y = 0; var paddle_y = 0;
@ -235,6 +235,7 @@ var VerilogPlatform = function(mainElement, options) {
if (inspect_obj && inspect_sym) { if (inspect_obj && inspect_sym) {
var COLOR_BIT_OFF = 0xffff3333; var COLOR_BIT_OFF = 0xffff3333;
var COLOR_BIT_ON = 0xffffffff; var COLOR_BIT_ON = 0xffffffff;
/*
for (var y=0; y<videoHeight; y++) { for (var y=0; y<videoHeight; y++) {
var val = inspect_data[y * videoWidth]; var val = inspect_data[y * videoWidth];
var i = y * videoWidth + 16; var i = y * videoWidth + 16;
@ -244,6 +245,14 @@ var VerilogPlatform = function(mainElement, options) {
val >>= 1; val >>= 1;
} while (val != 0); } while (val != 0);
} }
*/
var i = 0;
for (var y=0; y<videoHeight; y++) {
for (var x=0; x<videoWidth; x++) {
var val = inspect_data[i];
idata[i++] = (val & 1) ? COLOR_BIT_ON : COLOR_BIT_OFF;
}
}
} }
} }
@ -441,7 +450,6 @@ var VerilogPlatform = function(mainElement, options) {
}); });
audio = new SampleAudio(AUDIO_FREQ); audio = new SampleAudio(AUDIO_FREQ);
idata = video.getFrameData(); idata = video.getFrameData();
// TODO: 15.7 kHz?
timer = new AnimationTimer(frameRate, function() { timer = new AnimationTimer(frameRate, function() {
if (!self.isRunning()) if (!self.isRunning())
return; return;

View File

@ -534,7 +534,7 @@ function setCompileOutput(data) {
editor.setGutterMarker(info.line-1, "gutter-offset", textel); editor.setGutterMarker(info.line-1, "gutter-offset", textel);
} }
if (info.insns) { if (info.insns) {
var insnstr = info.insns.length > 8 ? ("...") : info.insns; var insnstr = info.insns.length > 9 ? ("...") : info.insns;
var textel = document.createTextNode(insnstr); var textel = document.createTextNode(insnstr);
editor.setGutterMarker(info.line-1, "gutter-bytes", textel); editor.setGutterMarker(info.line-1, "gutter-bytes", textel);
if (info.iscode) { if (info.iscode) {

View File

@ -70,16 +70,18 @@ var Assembler = function(spec) {
} }
function preprocessRules() { function preprocessRules() {
if (spec.width)
width = spec.width|0;
for (var i=0; i<spec.rules.length; i++) for (var i=0; i<spec.rules.length; i++)
rule2regex(spec.rules[i], spec.vars); rule2regex(spec.rules[i], spec.vars);
} }
if (spec) preprocessRules(); if (spec) preprocessRules();
function warning(msg) { function warning(msg, line) {
errors.push({msg:msg, line:linenum}); errors.push({msg:msg, line:line?line:linenum});
} }
function fatal(msg) { function fatal(msg, line) {
warning(msg); warning(msg, line);
aborted = true; aborted = true;
} }
function hex(v, nd) { function hex(v, nd) {
@ -106,7 +108,8 @@ var Assembler = function(spec) {
} }
} }
function parseConst(s) { function parseConst(s, nbits) {
// TODO: check bit length
if (!s.length) if (!s.length)
return s; return s;
else if (s.startsWith("$")) else if (s.startsWith("$"))
@ -128,8 +131,7 @@ var Assembler = function(spec) {
var id = m[b+1]; var id = m[b+1];
var v = spec.vars[rule.varlist[b]]; var v = spec.vars[rule.varlist[b]];
if (!v) { if (!v) {
warning("Could not find matching identifier for '" + m[0] + "'"); return {error:"Could not find matching identifier for '" + m[0] + "'"};
return;
} }
n = v.bits; n = v.bits;
if (v.toks) { if (v.toks) {
@ -137,7 +139,7 @@ var Assembler = function(spec) {
if (x < 0) if (x < 0)
return null; return null;
} else { } else {
x = parseConst(id); x = parseConst(id, n);
// is it a label? add fixup // is it a label? add fixup
if (isNaN(x)) { if (isNaN(x)) {
fixups.push({sym:id, ofs:ip, bitlen:n, bitofs:oplen, line:linenum, iprel:!!v.iprel, ipofs:(v.ipofs+0)}); fixups.push({sym:id, ofs:ip, bitlen:n, bitofs:oplen, line:linenum, iprel:!!v.iprel, ipofs:(v.ipofs+0)});
@ -147,7 +149,7 @@ var Assembler = function(spec) {
} }
var mask = (1<<n)-1; var mask = (1<<n)-1;
if ((x&mask) != x) if ((x&mask) != x)
warning("Value " + x + " could not fit in " + n + " bits"); return {error:"Value " + x + " does not fit in " + n + " bits"};
opcode = (opcode << n) | x; opcode = (opcode << n) | x;
oplen += n; oplen += n;
} }
@ -206,18 +208,21 @@ var Assembler = function(spec) {
return; // empty line return; // empty line
// look at each rule in order // look at each rule in order
if (!spec) { fatal("Need to load .spec first"); return; } if (!spec) { fatal("Need to load .spec first"); return; }
var lastError;
for (var i=0; i<spec.rules.length; i++) { for (var i=0; i<spec.rules.length; i++) {
var rule = spec.rules[i]; var rule = spec.rules[i];
var m = rule.re.exec(line); var m = rule.re.exec(line);
if (m) { if (m) {
var result = self.buildInstruction(rule, m); var result = self.buildInstruction(rule, m);
if (result) { if (result && result.nbits) {
addBytes(result); addBytes(result);
return result; return result;
} else if (result && result.error) {
lastError = result.error;
} }
} }
} }
warning("Could not decode instruction: " + line); warning(lastError ? lastError : ("Could not decode instruction: " + line));
} }
self.finish = function() { self.finish = function() {
@ -226,15 +231,18 @@ var Assembler = function(spec) {
var fix = fixups[i]; var fix = fixups[i];
var sym = symbols[fix.sym]; var sym = symbols[fix.sym];
if (sym) { if (sym) {
var ofs = fix.ofs + (fix.bitofs>>3); var ofs = fix.ofs + Math.floor(fix.bitofs/width);
var shift = fix.bitofs&7; var shift = fix.bitofs & (width-1);
var mask = ((1<<fix.bitlen)-1); var mask = ((1<<fix.bitlen)-1);
var value = parseConst(sym.value); var value = parseConst(sym.value, fix.bitlen);
if (fix.iprel) value -= fix.ofs + fix.ipofs; if (fix.iprel)
value -= fix.ofs + fix.ipofs;
if (value > mask || value < -mask)
warning("Symbol " + fix.sym + " (" + value + ") does not fit in " + fix.bitlen + " bits", fix.line);
value &= mask; value &= mask;
// TODO: check range // TODO: check range
// TODO: span multiple words? // TODO: span multiple words?
outwords[ofs - origin] ^= value; outwords[ofs - origin] ^= value; // TODO: << shift?
} else { } else {
warning("Symbol '" + fix.sym + "' not found"); warning("Symbol '" + fix.sym + "' not found");
} }

View File

@ -23,12 +23,12 @@ describe('Assemble', function() {
.define F_VSYNC 16 .define F_VSYNC 16
Start: Start:
zero A zero A ; comment
sta VPU_LO sta VPU_LO
sta VPU_HI sta VPU_HI
sta 0 sta 0
DisplayLoop:
zero B DisplayLoop:zero B
mov A,[b] mov A,[b]
sta VPU_WRITE sta VPU_WRITE
sta VPU_MOVE sta VPU_MOVE