diff --git a/gl b/gl new file mode 100644 index 0000000..e69de29 diff --git a/roms/IBM Logo.ch8 b/roms/IBM Logo.ch8 new file mode 100644 index 0000000..113338e Binary files /dev/null and b/roms/IBM Logo.ch8 differ diff --git a/roms/test_opcode.8o b/roms/test_opcode.8o new file mode 100644 index 0000000..6756767 --- /dev/null +++ b/roms/test_opcode.8o @@ -0,0 +1,205 @@ +:alias x0 v8 +:alias x1 v9 +:alias x2 vA +:alias y vB +: imageok + 0xEA 0xAC 0xAA 0xEA +: imagefalse + 0xCE 0xAA 0xAA 0xAE +: im0 + 0xE0 0xA0 0xA0 0xE0 +: im1 + 0xC0 0x40 0x40 0xE0 +: im2 + 0xE0 0x20 0xC0 0xE0 +: im3 + 0xE0 0x60 0x20 0xE0 +: im4 + 0xA0 0xE0 0x20 0x20 +: im5 + 0x60 0x40 0x20 0x40 +: im6 + 0xE0 0x80 0xE0 0xE0 +: im7 + 0xE0 0x20 0x20 0x20 +: im8 + 0xE0 0xE0 0xA0 0xE0 +: im9 + 0xE0 0xE0 0x20 0xE0 +: imA + 0x40 0xA0 0xE0 0xA0 +: imE + 0xE0 0xC0 0x80 0xE0 +: imF + 0xE0 0x80 0xC0 0x80 +: imX + 0xA0 0x40 0xA0 0xA0 + +:macro drawop A B { +i := A +sprite x0 y 4 +i := B +sprite x1 y 4 +} + +: testAX +#test Ax +i := imageok +sprite x2 y 4 +return + +: test1x +i := imageok +sprite x2 y 4 +jump endtest + +: main +x0 := 1 +x1 := 5 +x2 := 10 +y := 1 +v5 := 42 +v6 := 43 +#test 3x +drawop im3 imX +i := imageok +if v6 != 43 then i := imagefalse +sprite x2 y 4 +#test 4x +y := 6 +drawop im4 imX +i := imagefalse +if v5 == 42 then i := imageok +sprite x2 y 4 +#test 5x +y := 11 +drawop im5 imX +i := imagefalse +if v5 != v6 then i := imageok +sprite x2 y 4 +#test 7x +y := 16 +drawop im7 imX +i := imagefalse +v6 += 255 +if v6 == 42 then i := imageok +sprite x2 y 4 +#test 9x +y := 21 +drawop im9 imX +i := imagefalse +if v5 == v6 then i := imageok +sprite x2 y 4 +#test AX +y := 26 +drawop imA imX +testAX +#test 0E +x0 := 23 +x1 := 27 +x2 := 32 +y := 1 +drawop im0 imE +i := imageok +sprite x2 y 4 +#test 8xy0 +y := 6 +drawop im8 im0 +i := imagefalse +v7 := v5 +if v7 == 42 then i := imageok +sprite x2 y 4 +#test 8xy1 +y := 11 +drawop im8 im1 +i := imagefalse +v7 := 42 +v7 |= y +if v7 == 43 then i := imageok +sprite x2 y 4 +#test 8xy2 +y := 16 +drawop im8 im2 +i := imagefalse +v6 := 120 +v7 := 31 +v7 &= v6 +if v7 == 24 then i := imageok +sprite x2 y 4 +#test 8xy3 +y := 21 +drawop im8 im3 +i := imagefalse +v6 := 120 +v7 := 31 +v7 ^= v6 +if v7 == 103 then i := imageok +sprite x2 y 4 +#test 8xy4 +y := 26 +drawop im8 im4 +i := imagefalse +v6 := 140 +v7 := 140 +v7 += v6 +if v7 == 24 then i := imageok +sprite x2 y 4 +#test 8xy5 +x0 := 44 +x1 := 48 +x2 := 52 +y := 1 +drawop im8 im5 +i := imagefalse +v6 := 140 +v7 := 120 +v7 -= v6 +if v7 == 236 then i := imageok +sprite x2 y 4 +#test 8xy6 +y := 6 +drawop im8 im6 +i := imagefalse +v6 := 224 +v6 <<= v6 +if v6 == 192 then i := imageok +sprite x2 y 4 +#test 8xyE +y := 11 +drawop im8 imE +i := imagefalse +v6 := 15 +v6 >>= v6 +if v6 == 7 then i := imageok +sprite x2 y 4 +#test Fx55,Fx65 +y := 16 +drawop imF im5 +i := 1000 +v0 := 0 +v1 := 48 +save v1 +i := 1001 +load v0 +i := imagefalse +if v0 == 48 then i := imageok +sprite x2 y 4 +#test Fx33 +y := 21 +drawop imF im3 +i := 1000 +v6 := 137 +bcd v6 +load v2 +i := imageok +if v0 != 1 then i := imagefalse +if v1 != 3 then i := imagefalse +if v2 != 7 then i := imagefalse +sprite x2 y 4 +#test 1x +y := 26 +drawop im1 imX +jump test1x +: endtest +loop +again diff --git a/roms/test_opcode.ch8 b/roms/test_opcode.ch8 new file mode 100644 index 0000000..f540f69 Binary files /dev/null and b/roms/test_opcode.ch8 differ diff --git a/sgl b/sgl new file mode 100644 index 0000000..e69de29 diff --git a/src/chip8.v b/src/chip8.v index ff3868e..8260d58 100644 --- a/src/chip8.v +++ b/src/chip8.v @@ -3,29 +3,30 @@ import rand const font := [ - [0xF0, 0x90, 0x90, 0x90, 0xF0], // 0 - [0x20, 0x60, 0x20, 0x20, 0x70], // 1 - [0xF0, 0x10, 0xF0, 0x80, 0xF0], // 2 - [0xF0, 0x10, 0xF0, 0x10, 0xF0], // 3 - [0x90, 0x90, 0xF0, 0x10, 0x10], // 4 - [0xF0, 0x80, 0xF0, 0x10, 0xF0], // 5 - [0xF0, 0x80, 0xF0, 0x90, 0xF0], // 6 - [0xF0, 0x10, 0x20, 0x40, 0x40], // 7 - [0xF0, 0x90, 0xF0, 0x90, 0xF0], // 8 - [0xF0, 0x90, 0xF0, 0x10, 0xF0], // 9 - [0xF0, 0x90, 0xF0, 0x90, 0x90], // A - [0xE0, 0x90, 0xE0, 0x90, 0xE0], // B - [0xF0, 0x80, 0x80, 0x80, 0xF0], // C - [0xE0, 0x90, 0x90, 0x90, 0xE0], // D - [0xF0, 0x80, 0xF0, 0x80, 0xF0], // E - [0xF0, 0x80, 0xF0, 0x80, 0x80], // F + [u8(0xF0), u8(0x90), u8(0x90), u8(0x90), u8(0xF0)], // 0 + [u8(0x20), u8(0x60), u8(0x20), u8(0x20), u8(0x70)], // 1 + [u8(0xF0), u8(0x10), u8(0xF0), u8(0x80), u8(0xF0)], // 2 + [u8(0xF0), u8(0x10), u8(0xF0), u8(0x10), u8(0xF0)], // 3 + [u8(0x90), u8(0x90), u8(0xF0), u8(0x10), u8(0x10)], // 4 + [u8(0xF0), u8(0x80), u8(0xF0), u8(0x10), u8(0xF0)], // 5 + [u8(0xF0), u8(0x80), u8(0xF0), u8(0x90), u8(0xF0)], // 6 + [u8(0xF0), u8(0x10), u8(0x20), u8(0x40), u8(0x40)], // 7 + [u8(0xF0), u8(0x90), u8(0xF0), u8(0x90), u8(0xF0)], // 8 + [u8(0xF0), u8(0x90), u8(0xF0), u8(0x10), u8(0xF0)], // 9 + [u8(0xF0), u8(0x90), u8(0xF0), u8(0x90), u8(0x90)], // A + [u8(0xE0), u8(0x90), u8(0xE0), u8(0x90), u8(0xE0)], // B + [u8(0xF0), u8(0x80), u8(0x80), u8(0x80), u8(0xF0)], // C + [u8(0xE0), u8(0x90), u8(0x90), u8(0x90), u8(0xE0)], // D + [u8(0xF0), u8(0x80), u8(0xF0), u8(0x80), u8(0xF0)], // E + [u8(0xF0), u8(0x80), u8(0xF0), u8(0x80), u8(0x80)], // F ] struct Screen{ - pub mut: + pub: display_width int = 64 display_height int = 32 - display [64][32]u8 + mut: + display [32][64]u8 } const mem_size = 4096 @@ -37,44 +38,52 @@ struct Chip8{ ram [mem_size]u8 v [num_of_registers]u8 screen Screen - pc u16 + pc u16 = 0x200 i int stack Stack delay_timer u8 } fn (mut chip Chip8) start_cpu(){ - + + chip.screen = Screen{} + + mut index := 0 // load font in the memory for sprite in font { - for byte_sprite in sprite { - chip.set_ram(u8(byte_sprite)) - } + chip.set_ram(sprite, index) } } fn (mut chip Chip8) run(){ - instruction := chip.fetch() - chip.decode_and_run(instruction) + + for{ + mut instruction := chip.fetch() + println(instruction) + chip.decode_and_run(instruction) + } } -fn (mut chip Chip8) set_ram(instruction u8) { - chip.ram[chip.pc] = instruction + +fn (mut chip Chip8) set_ram(instructions []u8, index int) { + + mut j := index + for i := 0; i < instructions.len; i++ { + chip.ram[j] = instructions[i] + j++ + } } -fn (chip Chip8) get_instruction() u8{ - instruction := chip.ram[chip.pc] - return instruction -} - -fn (chip Chip8) fetch() u16{ +fn (mut chip Chip8) fetch() u16{ mut instruction := u16(0x00) - mut half_instruction := chip.get_instruction() + mut half_instruction := chip.ram[chip.pc] + instruction = instruction | half_instruction instruction = instruction << 8 - half_instruction = chip.get_instruction() + half_instruction = chip.ram[chip.pc + 1] + instruction = instruction | half_instruction return instruction @@ -86,6 +95,7 @@ fn (mut chip Chip8) decode_and_run(instruction u16) { mut opcode_msb := instruction & 0xF000 mut opcode_lsb := instruction & 0x00FF + mut is_jump := false match opcode_msb{ @@ -99,8 +109,8 @@ fn (mut chip Chip8) decode_and_run(instruction u16) { 0x00E0 { - for i in 0..chip.screen.display_width { - for j in 0..chip.screen.display_height { + for i := 0; i < chip.screen.display_height; i++{ + for j := 0; j < chip.screen.display_width; j++ { chip.screen.display[i][j] = 0 } } @@ -116,6 +126,7 @@ fn (mut chip Chip8) decode_and_run(instruction u16) { 0x1000 { nnn = instruction & 0x0FFF chip.pc = u8(nnn) + is_jump = true // Jumps to address NNN } @@ -125,6 +136,7 @@ fn (mut chip Chip8) decode_and_run(instruction u16) { chip.stack.push(chip.pc) chip.pc = u16(nnn) + is_jump = true // Calls subroutine at NNN } @@ -153,7 +165,7 @@ fn (mut chip Chip8) decode_and_run(instruction u16) { } 0x6000 { - x = instruction & 0xF00 + x = (instruction & 0xF00) >> 8 nn = instruction & 0x00FF chip.v[x] = u8(nn) @@ -161,7 +173,7 @@ fn (mut chip Chip8) decode_and_run(instruction u16) { } 0x7000 { - x = instruction & 0xF00 + x = (instruction & 0xF00) >> 8 nn = instruction & 0x00FF chip.v[x] += u8(nn) @@ -273,6 +285,7 @@ fn (mut chip Chip8) decode_and_run(instruction u16) { nnn = instruction & 0x0FFF chip.pc = u16(nnn + chip.v[0]) + is_jump = true } 0xC000 { @@ -289,23 +302,33 @@ fn (mut chip Chip8) decode_and_run(instruction u16) { y = (instruction & 0x00F0) >> 4 n = (instruction & 0x000F) + mut regvy := u8(chip.v[y] % chip.screen.display_height) + mut regvx := u8(chip.v[x] % chip.screen.display_width) + chip.v[f] = 0 for y_coord := 0; y_coord < n; y_coord++ { - - regvy := chip.v[y + y_coord] & chip.screen.display_height-1 - + + + regn := chip.ram[chip.i + y_coord] + for x_coord := 0; x_coord < 8; x_coord++ { - regvx := chip.v[x + x_coord] & chip.screen.display_width-1 + if (regvx + x_coord) < chip.screen.display_width && (regvy + y_coord) < chip.screen.display_height { + + if regn & (0x80 >> x_coord) == 1 && chip.screen.display[regvy + y_coord][regvx + x_coord] == 1 { + chip.v[f] = 1 + chip.screen.display[regvy + y_coord][regvx + x_coord] = 0 + } - if chip.screen.display[regvx + y_coord][regvy + x_coord] == 1 { - chip.v[f] = 1 - chip.screen.display[regvx + y_coord][regvy + x_coord] = 0 + + chip.screen.display[regvy + y_coord][regvx + x_coord] = chip.ram[chip.i + y_coord] + + regvx = u8(chip.v[x + x_coord] % chip.screen.display_width) } - - chip.screen.display[regvx + y_coord][regvy + x_coord] = chip.ram[chip.i + y_coord] } + + regvy = u8(chip.v[y + y_coord] % chip.screen.display_height) } } @@ -372,6 +395,6 @@ fn (mut chip Chip8) decode_and_run(instruction u16) { panic('Invalid instruction!') } } - + if !is_jump { chip.pc += 2 } } diff --git a/src/main.v b/src/main.v index c8b84db..fa92195 100644 --- a/src/main.v +++ b/src/main.v @@ -12,11 +12,10 @@ struct Emulator{ is_graphic bool = is_graphic() } -fn (emulator Emulator) draw_block(i int, j int, mut ctx gg.Context) { - emulator.graphic.draw_rect_filled(f32((j - 1) * 20) + 1, f32((i - 1) * 20), f32(20 - 1), f32(20 - 1), gx.rgb(255,255,255)) +fn (mut emulator Emulator) draw_block(i f32, j f32) { + emulator.graphic.draw_rect_filled(f32((j - 1) * 20) + 14, f32((i - 1) * 20), f32(20 - 1), f32(20 - 1), gx.rgb(255,255,255)) } - fn (mut emulator Emulator) load_rom() !{ arguments := os.args.clone() @@ -29,9 +28,9 @@ fn (mut emulator Emulator) load_rom() !{ println(' Loading ROM in the memory...\n') load_animate() - for instruction in file.read_bytes_at(1024, 0) { - emulator.chip8.set_ram(u8(instruction)) - } + mut instructions := file.read_bytes_at(1024, 0) + mut index := 0x200 + emulator.chip8.set_ram(instructions, index) println('ROM successfully loaded into memory!') @@ -40,29 +39,21 @@ fn (mut emulator Emulator) load_rom() !{ } } -fn (mut emulator Emulator) draw_screen(){ - - emulator.graphic.begin() +fn draw_screen(mut emulator Emulator){ display_height := emulator.chip8.screen.display_height display_width := emulator.chip8.screen.display_width - mut buf := []u8{len: display_height*display_width} - mut i := 0 + for y := 0; y < display_height; y++ { + for x := 0; x < display_width; x++ { - for y := 0; y < emulator.chip8.screen.display_height; y++ { - for x := 0; x < emulator.chip8.screen.display_width; x++ { - pixel := emulator.chip8.screen.display[y][x] - buf[i] = u8((0xFFFFFF00 * pixel) | 0x000000FF); - i++ + if pixel == 1 { + emulator.draw_block(f32(y*10), f32(x*10)) + } } } - - emulator.graphic.create_image_from_memory(unsafe{ &buf[0] }, buf.len) or { panic(err) } - emulator.graphic.end() - } fn (mut emulator Emulator) show_display(){ @@ -147,18 +138,14 @@ fn is_graphic() bool{ return os.environ()['DISPLAY'] != '' } +fn frame(){ + print('oi') +} + fn main() { - mut emulator := Emulator{ - + mut emulator := &Emulator{ chip8 : Chip8{} - - graphic : gg.new_context( - bg_color: gx.rgb(0, 0, 0) - width: 1280 - height: 640 - window_title: 'V CHIP-8 Emulator' - ) } if emulator.is_graphic { @@ -166,9 +153,16 @@ fn main() { emulator.load_rom()! emulator.chip8.start_cpu() emulator.chip8.run() - - emulator.draw_screen() - emulator.show_display() + print('oi') + emulator.graphic = gg.new_context( + bg_color: gx.rgb(0, 0, 0) + width: 1280 + height: 640 + window_title: 'V CHIP-8 Emulator' + frame_fn : draw_screen + user_data: emulator + ) + //emulator.show_display() }else{ panic('System is not graphic!') } diff --git a/src/utils.v b/src/utils.v index 70077fb..e050abe 100644 --- a/src/utils.v +++ b/src/utils.v @@ -33,7 +33,7 @@ fn load_animate() { mut bars := ['|','/','-','\\'] - for i := 0; i < 4000; i++ { + for i := 0; i < 2000; i++ { print('[${bars[i%4]}]\r ') time.sleep(400000) }