1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2025-01-10 16:29:48 +00:00

Merge branch 'master' of github.com:sehugg/8bitworkshop

This commit is contained in:
Steven Hugg 2018-09-09 09:56:50 -04:00
commit 5d9a169442
7 changed files with 123 additions and 102 deletions

View File

@ -21,14 +21,14 @@
`define OP_SBB 4'hf `define OP_SBB 4'hf
module ALU(A, B, Y, aluop, carry); module ALU(A, B, carry, aluop, Y);
parameter N = 8; parameter N = 8; // default width = 8 bits
input [N-1:0] A; input [N-1:0] A; // A input
input [N-1:0] B; input [N-1:0] B; // B input
output [N:0] Y; input carry; // carry input
input [3:0] aluop; input [3:0] aluop; // alu operation
input carry; output [N:0] Y; // Y output + carry
always @(*) always @(*)
case (aluop) case (aluop)
@ -312,8 +312,8 @@ module test_CPU16_top(
.org 0x8000 .org 0x8000
.len 256 .len 256
mov sp,@$6fff mov sp,@$6fff
mov dx,@Fib mov dx,@Fib
jsr dx jsr dx
reset reset
Fib: Fib:
mov ax,#1 mov ax,#1
@ -322,8 +322,8 @@ Loop:
mov cx,ax mov cx,ax
add ax,bx add ax,bx
mov bx,cx mov bx,cx
push ax push ax
pop ax pop ax
mov [42],ax mov [42],ax
mov ax,[42] mov ax,[42]
bcc Loop bcc Loop

View File

@ -5,30 +5,30 @@
// ALU operations // ALU operations
`define OP_ZERO 4'h0 `define OP_ZERO 4'h0
`define OP_LOAD_A 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
`define OP_LSR 4'h5 `define OP_LSR 4'h5
`define OP_ROL 4'h6 `define OP_ROL 4'h6
`define OP_ROR 4'h7 `define OP_ROR 4'h7
`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_LOAD_B 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
`define OP_SBB 4'hf `define OP_SBB 4'hf
// ALU module
module ALU(A, B, carry, aluop, Y);
module ALU(A, B, Y, aluop, carry); parameter N = 8; // default width = 8 bits
input [N-1:0] A; // A input
parameter N = 8; input [N-1:0] B; // B input
input [N-1:0] A; input carry; // carry input
input [N-1:0] B; input [3:0] aluop; // alu operation
output [N:0] Y; output [N:0] Y; // Y output + carry
input [3:0] aluop;
input carry;
always @(*) always @(*)
case (aluop) case (aluop)
@ -178,11 +178,6 @@ module CPU(clk, reset, address, data_in, data_out, write);
write <= 1; write <= 1;
state <= S_SELECT; state <= S_SELECT;
end end
// clear carry
8'b10001000: begin
carry <= 0;
state <= S_SELECT;
end
// swap A,B // swap A,B
8'b10000001: begin 8'b10000001: begin
A <= B; A <= B;

View File

@ -17,7 +17,7 @@ module LFSR(clk, reset, enable, lfsr);
always @(posedge clk) always @(posedge clk)
begin begin
if (reset) if (reset)
lfsr <= {lfsr[NBITS-2:0], ~lfsr[0]}; lfsr <= {lfsr[NBITS-2:0], 1'b1}; // reset loads with all 1s
else if (enable) else if (enable)
lfsr <= {lfsr[NBITS-2:0], 1'b0} ^ (feedback ? TAPS : 0); lfsr <= {lfsr[NBITS-2:0], 1'b0} ^ (feedback ? TAPS : 0);
end end

View File

@ -37,29 +37,31 @@ module racing_game_cpu_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
output [3:0] rgb; output [3:0] rgb;
`endif `endif
parameter PADDLE_X = 0; parameter PADDLE_X = 0; // paddle X coordinate
parameter PADDLE_Y = 1; parameter PADDLE_Y = 1; // paddle Y coordinate
parameter PLAYER_X = 2; parameter PLAYER_X = 2; // player X coordinate
parameter PLAYER_Y = 3; parameter PLAYER_Y = 3; // player Y coordinate
parameter ENEMY_X = 4; parameter ENEMY_X = 4; // enemy X coordinate
parameter ENEMY_Y = 5; parameter ENEMY_Y = 5; // enemy Y coordinate
parameter ENEMY_DIR = 6; parameter ENEMY_DIR = 6; // enemy direction (1, -1)
parameter SPEED = 7; parameter SPEED = 7; // player speed
parameter TRACKPOS_LO = 8; parameter TRACKPOS_LO = 8; // track position (lo byte)
parameter TRACKPOS_HI = 9; parameter TRACKPOS_HI = 9; // track position (hi byte)
parameter IN_HPOS = 8'h40; parameter IN_HPOS = 8'h40; // CRT horizontal position
parameter IN_VPOS = 8'h41; parameter IN_VPOS = 8'h41; // CRT vertical position
// flags: [0, 0, collision, vsync, hsync, vpaddle, hpaddle, display_on]
parameter IN_FLAGS = 8'h42; parameter IN_FLAGS = 8'h42;
reg [7:0] ram[0:63]; reg [7:0] ram[64]; // 64 bytes of RAM
reg [7:0] rom[0:127]; reg [7:0] rom[128]; // 128 bytes of ROM
output wire [7:0] address_bus; output wire [7:0] address_bus; // CPU address bus
output reg [7:0] to_cpu; output reg [7:0] to_cpu; // data bus to CPU
output wire [7:0] from_cpu; output wire [7:0] from_cpu; // data bus from CPU
output wire write_enable; output wire write_enable; // write enable bit from CPU
// 8-bit CPU module
CPU cpu(.clk(clk), CPU cpu(.clk(clk),
.reset(reset), .reset(reset),
.address(address_bus), .address(address_bus),
@ -67,10 +69,12 @@ module racing_game_cpu_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
.data_out(from_cpu), .data_out(from_cpu),
.write(write_enable)); .write(write_enable));
// RAM write from CPU
always @(posedge clk) always @(posedge clk)
if (write_enable) if (write_enable)
ram[address_bus[5:0]] <= from_cpu; ram[address_bus[5:0]] <= from_cpu;
// RAM read from CPU
always @(*) always @(*)
casez (address_bus) casez (address_bus)
// RAM // RAM
@ -84,7 +88,8 @@ module racing_game_cpu_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
8'b1???????: to_cpu = rom[address_bus[6:0]]; 8'b1???????: to_cpu = rom[address_bus[6:0]];
default: to_cpu = 8'bxxxxxxxx; default: to_cpu = 8'bxxxxxxxx;
endcase endcase
// sync generator module
hvsync_generator hvsync_gen( hvsync_generator hvsync_gen(
.clk(clk), .clk(clk),
.reset(0), .reset(0),
@ -95,23 +100,28 @@ module racing_game_cpu_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
.vpos(vpos) .vpos(vpos)
); );
// flags for player sprite renderer module
wire player_vstart = {1'0,ram[PLAYER_Y]} == vpos; wire player_vstart = {1'0,ram[PLAYER_Y]} == vpos;
wire player_hstart = {1'0,ram[PLAYER_X]} == hpos; wire player_hstart = {1'0,ram[PLAYER_X]} == hpos;
wire player_gfx; wire player_gfx;
wire player_is_drawing; wire player_is_drawing;
// flags for enemy sprite renderer module
wire enemy_vstart = {1'0,ram[ENEMY_Y]} == vpos; wire enemy_vstart = {1'0,ram[ENEMY_Y]} == vpos;
wire enemy_hstart = {1'0,ram[ENEMY_X]} == hpos; wire enemy_hstart = {1'0,ram[ENEMY_X]} == hpos;
wire enemy_gfx; wire enemy_gfx;
wire enemy_is_drawing; wire enemy_is_drawing;
// flags shared between sprite renderer modules
wire [3:0] car_sprite_yofs; wire [3:0] car_sprite_yofs;
wire [7:0] car_sprite_bits; wire [7:0] car_sprite_bits;
// car bitmap ROM
car_bitmap car( car_bitmap car(
.yofs(car_sprite_yofs), .yofs(car_sprite_yofs),
.bits(car_sprite_bits)); .bits(car_sprite_bits));
// player sprite renderer
sprite_renderer player_renderer( sprite_renderer player_renderer(
.clk(clk), .clk(clk),
.vstart(player_vstart), .vstart(player_vstart),
@ -122,6 +132,7 @@ module racing_game_cpu_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
.gfx(player_gfx), .gfx(player_gfx),
.in_progress(player_is_drawing)); .in_progress(player_is_drawing));
// enemy sprite renderer
sprite_renderer enemy_renderer( sprite_renderer enemy_renderer(
.clk(clk), .clk(clk),
.vstart(enemy_vstart), .vstart(enemy_vstart),
@ -132,31 +143,36 @@ module racing_game_cpu_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
.gfx(enemy_gfx), .gfx(enemy_gfx),
.in_progress(player_is_drawing)); .in_progress(player_is_drawing));
// collision detection logic
reg frame_collision; reg frame_collision;
always @(posedge clk) always @(posedge clk)
if (player_gfx && (enemy_gfx || track_gfx)) if (player_gfx && (enemy_gfx || track_gfx))
frame_collision <= 1; frame_collision <= 1;
else if (vpos==0) else if (vpos==0)
frame_collision <= 0; frame_collision <= 0;
// track graphics
wire track_offside = (hpos[7:5]==0) || (hpos[7:5]==7); wire track_offside = (hpos[7:5]==0) || (hpos[7:5]==7);
wire track_shoulder = (hpos[7:3]==3) || (hpos[7:3]==28); wire track_shoulder = (hpos[7:3]==3) || (hpos[7:3]==28);
wire track_gfx = (vpos[5:1]!=ram[TRACKPOS_LO][5:1]) && track_offside; wire track_gfx = (vpos[5:1]!=ram[TRACKPOS_LO][5:1]) && track_offside;
// RGB output
wire r = display_on && (player_gfx || enemy_gfx || track_shoulder); wire r = display_on && (player_gfx || enemy_gfx || track_shoulder);
wire g = display_on && (player_gfx || track_gfx); wire g = display_on && (player_gfx || track_gfx);
wire b = display_on && (enemy_gfx || track_shoulder); wire b = display_on && (enemy_gfx || track_shoulder);
assign rgb = {1'b0,b,g,r}; assign rgb = {1'b0,b,g,r};
//////////// CPU program code
`ifdef EXT_INLINE_ASM `ifdef EXT_INLINE_ASM
initial begin initial begin
rom = '{ rom = '{
__asm __asm
.arch femto8 .arch femto8 ; FEMTO-8 architecture
.org 128 .org 128 ; origin = 128 ($80)
.len 128 .len 128 ; length = 128 ($80)
; define constants
.define PADDLE_X 0 .define PADDLE_X 0
.define PADDLE_Y 1 .define PADDLE_Y 1
.define PLAYER_X 2 .define PLAYER_X 2
@ -180,82 +196,88 @@ module racing_game_cpu_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
.define F_COLLIDE 32 .define F_COLLIDE 32
Start: Start:
lda #128 lda #128 ; load initial positions
sta PLAYER_X sta PLAYER_X ; player_x = 128
sta ENEMY_X sta ENEMY_X ; enemy_x = 128
sta ENEMY_Y sta ENEMY_Y ; enemy_y = 128
lda #180 lda #180
sta PLAYER_Y sta PLAYER_Y ; player_y = 180
zero A zero A
sta SPEED sta SPEED ; player speed = 0
inc A inc A
sta ENEMY_DIR sta ENEMY_DIR ; enemy dir = 1 (right)
; test hpaddle flag ; read horizontal paddle position
DisplayLoop: DisplayLoop:
lda #F_HPADDLE lda #F_HPADDLE ; paddle flag -> A
ldb #IN_FLAGS ldb #IN_FLAGS ; addr of IN_FLAGS -> B
and none,[B] and none,[B] ; read B, AND with A
bz DisplayLoop bz DisplayLoop ; loop until paddle flag set
; [vpos] -> paddle_x
ldb #IN_VPOS ldb #IN_VPOS
mov A,[B] mov A,[B] ; load vertical position -> A
sta PLAYER_X sta PLAYER_X ; store player x position
; wait for vsync=1 then vsync=0 ; wait for vsync
lda #F_VSYNC lda #F_VSYNC
ldb #IN_FLAGS ldb #IN_FLAGS
WaitForVsyncOn: WaitForVsyncOn:
and none,[B] and none,[B]
bz WaitForVsyncOn bz WaitForVsyncOn ; wait until VSYNC on
WaitForVsyncOff: WaitForVsyncOff:
and none,[B] and none,[B]
bnz WaitForVsyncOff bnz WaitForVsyncOff ; wait until VSYNC off
; check collision ; check collision
lda #F_COLLIDE lda #F_COLLIDE
ldb #IN_FLAGS ldb #IN_FLAGS
and none,[B] and none,[B] ; collision flag set?
bz NoCollision bz NoCollision ; skip ahead if not
; load slow speed
lda #16 lda #16
sta SPEED sta SPEED ; speed = 16
NoCollision: NoCollision:
; update speed ; update speed
ldb #SPEED ldb #SPEED
mov A,[B] mov A,[B] ; speed -> A
inc A inc A ; increment speed
; don't store if == 0 bz MaxSpeed ; speed wraps to 0?
bz MaxSpeed sta SPEED ; no, store speed
sta SPEED
MaxSpeed: MaxSpeed:
mov A,[B] mov A,[B] ; reload speed -> A
lsr A
lsr A lsr A
lsr A lsr A
lsr A lsr A
lsr A ; divide speed by 16
; add to lo byte of track pos ; add to lo byte of track pos
ldb #TRACKPOS_LO ldb #TRACKPOS_LO
add B,[B] add B,[B] ; B <- speed/16 + trackpos_lo
swapab swapab ; swap A <-> B
sta TRACKPOS_LO sta TRACKPOS_LO ; A -> trackpos_lo
swapab swapab ; swap A <-> B again
bcc NoCarry ; carry flag from earlier add op
; add to hi byte of track pos
ldb #TRACKPOS_HI
mov B,[B] ; B <- trackpos_hi
inc b ; increment B
swapab ; swap A <-> B
sta TRACKPOS_HI ; A -> trackpos_hi
swapab ; swap A <-> B again
NoCarry:
; update enemy vert pos ; update enemy vert pos
ldb #ENEMY_Y ldb #ENEMY_Y
add A,[B] add A,[B]
sta ENEMY_Y sta ENEMY_Y ; enemy_y = enemy_y + speed/16
; update enemy horiz pos ; update enemy horiz pos
ldb #ENEMY_X ldb #ENEMY_X
mov A,[B] mov A,[B]
ldb #ENEMY_DIR ldb #ENEMY_DIR
add A,[B] add A,[B]
sta ENEMY_X sta ENEMY_X ; enemy_x = enemy_x + enemy_dir
sub A,#64 sub A,#64
and A,#127 and A,#127 ; A <- (enemy_x-64) & 127
bnz SkipXReverse bnz SkipXReverse ; skip if enemy_x is in range
; load ENEMY_DIR and negate ; load ENEMY_DIR and negate
zero A zero A
sub A,[B] sub A,[B]
sta ENEMY_DIR sta ENEMY_DIR ; enemy_dir = -enemy_dir
; back to display loop
SkipXReverse: SkipXReverse:
; back to display loop
jmp DisplayLoop jmp DisplayLoop
__endasm __endasm
}; };

View File

@ -65,13 +65,14 @@ module sprite_bitmap_top(clk, reset, hsync, vsync, rgb);
.yofs(car_sprite_yofs), .yofs(car_sprite_yofs),
.bits(car_sprite_bits)); .bits(car_sprite_bits));
// start Y counter when we hit the top border (player_y)
always @(posedge hsync) always @(posedge hsync)
// start sprite?
if (vpos == player_y) if (vpos == player_y)
car_sprite_yofs <= 15; car_sprite_yofs <= 15;
else if (car_sprite_yofs != 0) else if (car_sprite_yofs != 0)
car_sprite_yofs <= car_sprite_yofs - 1; car_sprite_yofs <= car_sprite_yofs - 1;
// restart X counter when we hit the left border (player_x)
always @(posedge clk) always @(posedge clk)
if (hpos == player_x) if (hpos == player_x)
car_sprite_xofs <= 15; car_sprite_xofs <= 15;

View File

@ -140,7 +140,7 @@ module tank_game_top(clk, reset, hsync, vsync, rgb, switches_p1, switches_p2);
); );
// multiplex player 1 and 2 load times during hsync // multiplex player 1 and 2 load times during hsync
wire p2sel = hpos[3]; wire p2sel = hpos > 280;
// sprite ROM inputs for each player // sprite ROM inputs for each player
wire [7:0] tank1_sprite_addr; wire [7:0] tank1_sprite_addr;
wire [7:0] tank2_sprite_addr; wire [7:0] tank2_sprite_addr;

View File

@ -1284,6 +1284,9 @@ function compileVerilator(step) {
var errors = []; var errors = [];
var asmlines = []; var asmlines = [];
step.code = compileInlineASM(step.code, platform, step, errors, asmlines); step.code = compileInlineASM(step.code, platform, step, errors, asmlines);
if (errors.length) {
return {errors:errors};
}
var code = step.code; var code = step.code;
var match_fn = makeErrorMatcher(errors, /%(.+?): (.+?:)?(\d+)?[:]?\s*(.+)/i, 3, 4); var match_fn = makeErrorMatcher(errors, /%(.+?): (.+?:)?(\d+)?[:]?\s*(.+)/i, 3, 4);
var verilator_mod = verilator_bin({ var verilator_mod = verilator_bin({