├── .gitignore ├── resources ├── NuPogodi.fzz └── NuPogodi.png ├── .gitmodules ├── device ├── input.h ├── system.h ├── graphic.h ├── sound.h ├── def.h ├── sound.pio ├── input.c ├── rom.h ├── rom.c ├── graphic.c ├── sound.c └── system.c ├── main.c ├── cpu ├── operations.h ├── core.h ├── operations.c └── core.c ├── CMakeLists.txt ├── .github └── workflows │ └── release.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | build/ -------------------------------------------------------------------------------- /resources/NuPogodi.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artyomsoft/pico-nu-pogodi/HEAD/resources/NuPogodi.fzz -------------------------------------------------------------------------------- /resources/NuPogodi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/artyomsoft/pico-nu-pogodi/HEAD/resources/NuPogodi.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/pico-display-drivs"] 2 | path = lib/pico-display-drivs 3 | url = https://github.com/artyomsoft/pico-displayDrivs 4 | -------------------------------------------------------------------------------- /device/input.h: -------------------------------------------------------------------------------- 1 | #ifndef __INPUT_H__ 2 | #define __INPUT_H__ 3 | 4 | #include "def.h" 5 | 6 | extern u8 B; 7 | extern u8 BA; 8 | extern u32 process_input(); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /device/system.h: -------------------------------------------------------------------------------- 1 | #ifndef _GW_SYSTEM_H_ 2 | #define _GW_SYSTEM_H_ 3 | #include "def.h" 4 | 5 | int init(int argc, char **argv); 6 | int system_run(int clock_cycles); 7 | u32 get_buttons(); 8 | 9 | void writeR(u8 data); 10 | u8 readK(u8 S); 11 | u8 readBA(); 12 | u8 readB(); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /device/graphic.h: -------------------------------------------------------------------------------- 1 | #ifndef _GW_GRAPHIC_H_ 2 | #define _GW_GRAPHIC_H_ 3 | #include "def.h" 4 | 5 | #define GW_MASK_RGB565_R 0xF800 6 | #define GW_MASK_RGB565_G 0x07E0 7 | #define GW_MASK_RGB565_B 0x001F 8 | #define SEG_WHITE_COLOR 0xff 9 | #define SEG_BLACK_COLOR 0x0 10 | 11 | void render_to_framebuffer(uint16 *framebuffer); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /device/sound.h: -------------------------------------------------------------------------------- 1 | #ifndef _GW_SOUND_H_ 2 | #define _GW_SOUND_H_ 3 | #include "hardware/gpio.h" 4 | #include "pico/stdlib.h" 5 | 6 | #define SOUND_BUFFER_SIZE 256 7 | 8 | volatile extern uint8_t *current_buff; 9 | 10 | extern uint8_t buffer1[SOUND_BUFFER_SIZE]; 11 | extern uint8_t buffer2[SOUND_BUFFER_SIZE]; 12 | 13 | extern int init_sound(); 14 | 15 | #endif -------------------------------------------------------------------------------- /device/def.h: -------------------------------------------------------------------------------- 1 | #ifndef __GW_TYPE_DEFS_H__ 2 | #define __GW_TYPE_DEFS_H__ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define GW_LCD_WIDTH 320 10 | #define GW_LCD_HEIGHT 240 11 | #define GW_SCREEN_WIDTH 320 12 | #define GW_SCREEN_HEIGHT 240 13 | 14 | #define SYS_FREQ 32768U 15 | 16 | #define ROM_CPU_SM5A "SM5A_" 17 | 18 | typedef unsigned char byte; 19 | typedef unsigned char un8, u8, uint8; 20 | typedef unsigned short un16, u16, uint16; 21 | typedef unsigned int un32, u32, uint32; 22 | typedef uint64_t un64, u64, uint64; 23 | 24 | typedef signed char n8; 25 | typedef signed short n16; 26 | typedef signed int n32; 27 | typedef un16 word; 28 | typedef word addr; 29 | 30 | typedef int8_t s8; 31 | typedef int16_t s16; 32 | typedef int32_t s32; 33 | typedef int64_t s64; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /device/sound.pio: -------------------------------------------------------------------------------- 1 | .pio_version 0 2 | 3 | .program beeper_tx 4 | 5 | .wrap_target 6 | out pins, 1 [7] 7 | .wrap 8 | 9 | % c-sdk { 10 | #include "hardware/clocks.h" 11 | 12 | static inline void beeper_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx, uint baud) { 13 | 14 | pio_gpio_init(pio, pin_tx); 15 | 16 | pio_sm_config c = beeper_tx_program_get_default_config(offset); 17 | 18 | pio_sm_set_consecutive_pindirs(pio, sm, pin_tx, 1, true); 19 | 20 | sm_config_set_out_shift(&c, true, true, 1); 21 | 22 | sm_config_set_out_pins(&c, pin_tx, 1); 23 | 24 | sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); 25 | 26 | // SM transmits 1 bit per 8 execution cycles. 27 | float div = (float)clock_get_hz(clk_sys) / (baud * 8); 28 | sm_config_set_clkdiv(&c, div); 29 | 30 | pio_sm_init(pio, sm, offset, &c); 31 | pio_sm_set_enabled(pio, sm, true); 32 | } 33 | 34 | %} 35 | -------------------------------------------------------------------------------- /device/input.c: -------------------------------------------------------------------------------- 1 | #include "../cpu/core.h" 2 | #include "def.h" 3 | #include "pico/stdlib.h" 4 | 5 | u8 B = 1; 6 | u8 BA = 1; 7 | 8 | u32 process_input() { 9 | u32 result = 0; 10 | gpio_put(6, 1); 11 | gpio_put(7, 0); 12 | busy_wait_us_32(10); 13 | if (gpio_get(10)) { 14 | result = 1; 15 | } else if (gpio_get(11)) { 16 | result = 2; 17 | } else if (gpio_get(12)) { 18 | result = 3; 19 | } else if (gpio_get(13)) { 20 | result = 4; 21 | } 22 | gpio_put(6, 0); 23 | gpio_put(7, 1); 24 | busy_wait_us_32(10); 25 | if (gpio_get(10)) { 26 | result = 5; 27 | } else if (gpio_get(11)) { 28 | result = 6; 29 | } else if (gpio_get(12)) { 30 | result = 7; 31 | } else if (gpio_get(13)) { 32 | result = 8; 33 | } 34 | gpio_put(6, 0); 35 | gpio_put(7, 0); 36 | 37 | BA = !gpio_get(8); 38 | u8 a = !gpio_get(9); 39 | if (!a) { 40 | device_reset(); 41 | } 42 | return result; 43 | } -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | */ 6 | 7 | #include "device/sound.h" 8 | #include "device/system.h" 9 | #include "gfx.h" 10 | #include "hardware/clocks.h" 11 | #include "ili9341.h" 12 | #include "pico/multicore.h" 13 | #include "stdlib.h" 14 | #include 15 | 16 | #define TFT_SCLK 18 17 | #define TFT_MOSI 19 18 | #define TFT_MISO 255 // Not required, used for DC... 19 | #define TFT_DC 21 20 | #define TFT_RST 20 21 | #define TFT_CS 17 22 | #define TFT_BACKLIGHT 255 // hardwired to 3.3v 23 | 24 | #define TFT_WIDTH 320 25 | #define TFT_HEIGHT 240 26 | #define TFT_ROTATION 3 27 | 28 | int main() { 29 | // busy_wait_us_32(1000000); 30 | // set_sys_clock_hz(134217728, true); 31 | stdio_init_all(); 32 | // play_sound_dma(); 33 | LCD_setPins(TFT_DC, TFT_CS, TFT_RST, TFT_SCLK, TFT_MOSI); 34 | LCD_initDisplay(); 35 | LCD_setRotation(TFT_ROTATION); 36 | // // getchar(); 37 | init(1, NULL); 38 | } 39 | -------------------------------------------------------------------------------- /cpu/operations.h: -------------------------------------------------------------------------------- 1 | #ifndef _OPERATIONS_H_ 2 | #define _OPERATIONS_H_ 3 | void op_lax(); 4 | void op_adx(); 5 | void op_rm(); 6 | void op_sm(); 7 | void op_exc(); 8 | void op_exci(); 9 | void op_lda(); 10 | void op_excd(); 11 | void op_tmi(); 12 | void op_skip(); 13 | void op_atr(); 14 | void op_add(); 15 | void op_add11(); 16 | void op_coma(); 17 | void op_exbla(); 18 | void op_tal(); 19 | void op_tb(); 20 | void op_tc(); 21 | void op_tam(); 22 | void op_tis(); 23 | void op_ta0(); 24 | void op_tabl(); 25 | void op_lbl(); 26 | void op_rc(); 27 | void op_sc(); 28 | void op_kta(); 29 | void op_decb(); 30 | void op_rtn1(); 31 | void op_cend(); 32 | void op_dta(); 33 | void op_illegal(); 34 | void op_lb(); 35 | void op_incb(); 36 | void op_sbm(); 37 | void op_rbm(); 38 | void op_comcb(); 39 | void op_rtn0(); 40 | void op_ssr(); 41 | void op_tr(); 42 | void op_trs(); 43 | void op_atbp(); 44 | void op_ptw(); 45 | void op_tw(); 46 | void op_pdtw(); 47 | void op_dtw(); 48 | void op_wr(); 49 | void op_ws(); 50 | void op_exksa(); 51 | void op_exkfa(); 52 | void op_idiv(); 53 | void op_rmf(); 54 | void op_smf(); 55 | void op_comcn(); 56 | #endif -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set ( sourcefiles 2 | "main.c" 3 | "device/system.h" "device/system.c" 4 | "device/graphic.h" "device/graphic.c" 5 | "device/rom.h" "device/rom.c" 6 | "cpu/operations.h" "cpu/core.h" 7 | "cpu/operations.c" "cpu/core.c" 8 | "device/input.h" "device/input.c" 9 | "data/o.h" "device/sound.c" "device/sound.h" 10 | ) 11 | 12 | set(PROJECT pico_nu_pogodi) 13 | cmake_minimum_required(VERSION 3.12) 14 | include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake) 15 | project(${PROJECT} C CXX ASM) 16 | pico_sdk_init() 17 | 18 | 19 | 20 | add_executable(${PROJECT} ${sourcefiles}) 21 | add_subdirectory(lib/pico-display-drivs/ili9341) 22 | add_subdirectory(lib/pico-display-drivs/gfx) 23 | #add_subdirectory(pico-extras) 24 | target_include_directories(${PROJECT} PRIVATE 25 | ${CMAKE_CURRENT_LIST_DIR} 26 | ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required 27 | ) 28 | 29 | target_link_libraries(${PROJECT} pico_stdlib hardware_pio pico_multicore ili9341 gfx) 30 | target_include_directories(${PROJECT} PRIVATE "cpu" "gw" ".") 31 | pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/device/sound.pio) 32 | 33 | #pico_generate_pio_header(${PROJECT} device/beep_sound.pio) 34 | target_link_options(${PROJECT} PUBLIC LINKER:-Map=${PROJECT}.map) 35 | pico_enable_stdio_usb(${PROJECT} 1) 36 | pico_enable_stdio_uart(${PROJECT} 0) 37 | pico_add_extra_outputs(${PROJECT}) 38 | 39 | -------------------------------------------------------------------------------- /device/rom.h: -------------------------------------------------------------------------------- 1 | #ifndef _GW_ROMLOADER_H_ 2 | #define _GW_ROMLOADER_H_ 3 | #include "def.h" 4 | #include 5 | #include 6 | 7 | typedef struct gwromheader_s { 8 | char cpu_name[8]; 9 | char rom_signature[8]; 10 | u8 time_hour_address_msb; 11 | u8 time_hour_address_lsb; 12 | u8 time_min_address_msb; 13 | u8 time_min_address_lsb; 14 | u8 time_sec_address_msb; 15 | u8 time_sec_address_lsb; 16 | u8 time_hour_msb_pm; 17 | u8 byte_spare1; 18 | u32 flags; 19 | u32 background_pixel; 20 | u32 background_pixel_size; 21 | u32 segments_pixel; 22 | u32 segments_pixel_size; 23 | u32 segments_offset; 24 | u32 segments_offset_size; 25 | u32 segments_x; 26 | u32 segments_x_size; 27 | u32 segments_y; 28 | u32 segments_y_size; 29 | u32 segments_height; 30 | u32 segments_height_size; 31 | u32 segments_width; 32 | u32 segments_width_size; 33 | u32 melody; 34 | u32 melody_size; 35 | u32 program; 36 | u32 program_size; 37 | u32 keyboard; 38 | u32 keyboard_size; 39 | } gwromheader_t; 40 | 41 | extern u8 *rom_base; 42 | extern u16 *background; 43 | extern u8 *_segments; 44 | extern u16 *_segments_x; 45 | extern u16 *_segments_y; 46 | extern u16 *_segments_width; 47 | extern u16 *_segments_height; 48 | extern u32 *_segments_offset; 49 | extern u8 *program; 50 | extern u8 *melody; 51 | extern u32 *keyboard; 52 | extern bool rotate; 53 | 54 | extern gwromheader_t head; 55 | 56 | bool romloader(const u8 *rom, uint32 _len); 57 | #endif 58 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Create release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | release: 13 | name: Release pushed tag 14 | runs-on: ubuntu-22.04 15 | steps: 16 | - name: Checkout code 17 | uses: actions/checkout@v2 18 | with: 19 | submodules: recursive 20 | - name: Setup variables 21 | run: | 22 | VERSION=${{ github.ref_name }} 23 | echo "VERSION=${VERSION#v}" >> $GITHUB_ENV 24 | 25 | - name: Install dependencies 26 | run: | 27 | sudo apt update && sudo apt install cmake python3 build-essential gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib 28 | 29 | - name: Setup cmake 30 | uses: jwlawson/actions-setup-cmake@v2 31 | with: 32 | cmake-version: "3.17.x" 33 | - name: Use cmake 34 | run: cmake --version 35 | 36 | - name: Clone Pico SDK 37 | run: | 38 | git clone -b master https://github.com/raspberrypi/pico-sdk.git 39 | cd pico-sdk 40 | git submodule update --init --recursive 41 | 42 | - name: Set PICO_SDK_PATH 43 | run: echo "PICO_SDK_PATH=$(pwd)/pico-sdk" >> $GITHUB_ENV 44 | 45 | - name: Build Emulator 46 | run: | 47 | mkdir -p build 48 | cd build 49 | cmake .. -DPICO_COPY_TO_RAM=1 50 | make 51 | - name: Release with Notes 52 | uses: softprops/action-gh-release@v2 53 | with: 54 | files: | 55 | build/pico_nu_pogodi.uf2 56 | env: 57 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | -------------------------------------------------------------------------------- /device/rom.c: -------------------------------------------------------------------------------- 1 | #include "rom.h" 2 | #include "def.h" 3 | #include "system.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | gwromheader_t head; 10 | 11 | u8 *rom_base = NULL; 12 | u16 *background = NULL; 13 | u8 *_segments = NULL; 14 | u16 *_segments_x = NULL; 15 | u16 *_segments_y = NULL; 16 | u16 *_segments_width = NULL; 17 | u16 *_segments_height = NULL; 18 | u32 *_segments_offset = NULL; 19 | u8 *program = NULL; 20 | u8 *melody = NULL; 21 | u32 *keyboard = NULL; 22 | bool rotate = false; 23 | 24 | bool romloader(const u8 *_rom, uint32 _len) { 25 | u8 *src = (u8 *)_rom; 26 | u32 rom_size_src = _len; 27 | u32 rom_size_dest = _len; 28 | 29 | if (memcmp(src, ROM_CPU_SM5A, 3) == 0) { 30 | printf("Not compressed : header OK\n"); 31 | rom_size_src = _len; 32 | } else { 33 | printf("Unknow ROM format\n"); 34 | return false; 35 | } 36 | 37 | printf("romsize uncompressed = %d\n", rom_size_src); 38 | 39 | memcpy(&head, _rom, sizeof(head)); 40 | rom_size_dest = head.keyboard + head.keyboard_size; 41 | 42 | if (rom_size_src != rom_size_dest) { 43 | printf("ROM ERROR,size=%u,expected=%u\n", rom_size_src, rom_size_dest); 44 | return false; 45 | } else { 46 | printf("ROM size: OK\n"); 47 | } 48 | 49 | if (head.background_pixel_size != 0) 50 | background = (u16 *)&_rom[head.background_pixel]; 51 | else 52 | background = (u16 *)&_rom[rom_size_src]; 53 | 54 | _segments = (u8 *)&_rom[head.segments_pixel]; 55 | _segments_x = (u16 *)&_rom[head.segments_x]; 56 | _segments_y = (u16 *)&_rom[head.segments_y]; 57 | _segments_width = (u16 *)&_rom[head.segments_width]; 58 | _segments_height = (u16 *)&_rom[head.segments_height]; 59 | _segments_offset = (u32 *)&_rom[head.segments_offset]; 60 | program = (u8 *)&_rom[head.program]; 61 | keyboard = (u32 *)&_rom[head.keyboard]; 62 | 63 | if (head.melody_size != 0) 64 | melody = (u8 *)&_rom[head.melody]; 65 | 66 | return true; 67 | } 68 | -------------------------------------------------------------------------------- /cpu/core.h: -------------------------------------------------------------------------------- 1 | #ifndef _CORE_H_ 2 | #define _CORE_H_ 3 | #include "../device/def.h" 4 | 5 | extern u16 m_op, m_prev_op; 6 | extern u8 m_param; 7 | extern u16 m_a; 8 | extern u8 m_acc; 9 | extern u8 m_bl; 10 | extern u8 m_bm; 11 | extern u8 m_c; 12 | extern bool m_skip; 13 | extern bool m_k_active; 14 | extern bool m_halt; 15 | extern int m_clk_div; 16 | extern u16 m_div; 17 | extern bool m_1s; 18 | extern u8 m_l; 19 | extern bool m_bc; 20 | extern u8 m_ox[9]; 21 | extern u8 m_o[9]; 22 | extern u8 m_ox_state[9]; 23 | extern u8 m_o_state[9]; 24 | extern u8 m_mx; 25 | extern u8 trs_field; 26 | 27 | extern int m_datamask; 28 | extern int m_prgmask; 29 | extern u8 ram[128]; 30 | 31 | extern u16 m_pc, m_prev_pc; 32 | extern u16 m_op, m_prev_op; 33 | extern u8 m_param; 34 | extern int m_icount; 35 | extern u8 m_acc; 36 | extern u8 m_bl; 37 | extern u8 m_bm; 38 | extern u8 m_c; 39 | extern bool m_skip; 40 | extern u8 m_r, m_r_out; 41 | extern bool m_k_active; 42 | extern bool m_halt; 43 | extern int m_clk_div; 44 | extern u16 m_div; 45 | extern bool m_1s; 46 | extern u8 m_bp; 47 | extern bool m_bc; 48 | extern int m_o_pins; 49 | extern u8 m_ox[9]; 50 | extern u8 m_o[9]; 51 | extern u8 m_ox_state[9]; 52 | extern u8 m_o_state[9]; 53 | extern u8 m_cn; 54 | extern u8 m_mx; 55 | extern u8 m_cb; 56 | extern bool m_rsub; 57 | 58 | void execute_run(); 59 | void get_opcode_param(); 60 | void div_timer(int nb_inst); 61 | void update_segments_state(); 62 | void reset_vector(); 63 | void wakeup_vector(); 64 | bool wake_me_up(); 65 | 66 | void shift_w(); 67 | u8 get_digit(); 68 | void set_su(u8 su); 69 | u8 get_su(); 70 | int get_trs_field(); 71 | 72 | void do_branch(u8 pu, u8 pm, u8 pl); 73 | 74 | un8 read_byte_program(un16 rom_address); 75 | void increment_pc(); 76 | 77 | extern u8 ram_r(); 78 | extern void ram_w(u8 data); 79 | 80 | extern u8 m_read_ba(); 81 | extern u8 m_read_b(); 82 | 83 | un8 readb(un8 ram_address); 84 | void writeb(un8 ram_address, u8 ram_data); 85 | 86 | extern void m_write_r(un8); 87 | 88 | u8 bitmask(u16 param); 89 | 90 | void device_start(); 91 | void device_reset(); 92 | void device_run(); 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /device/graphic.c: -------------------------------------------------------------------------------- 1 | #include "graphic.h" 2 | #include "../cpu/core.h" 3 | #include "def.h" 4 | #include "rom.h" 5 | #include "system.h" 6 | #include 7 | 8 | uint16 *graphic_framebuffer = 0; 9 | uint16 *source_mixer = 0; 10 | uint8 SEG_TRANSPARENT_COLOR = 0; 11 | 12 | uint16 rgb_multiply_8bits(uint32 bg, uint32 sg) { 13 | uint32 bg_r = (bg & GW_MASK_RGB565_R) >> 11; 14 | uint32 bg_g = (bg & GW_MASK_RGB565_G) >> 5; 15 | uint32 bg_b = (bg & GW_MASK_RGB565_B); 16 | 17 | bg_r = (bg_r * sg) >> 8; 18 | bg_g = (bg_g * sg) >> 8; 19 | bg_b = (bg_b * sg) >> 8; 20 | return (uint16)(bg_r << 11) | (bg_g << 5) | bg_b; 21 | } 22 | 23 | void update_segment(uint8 segment_nb, bool segment_state) { 24 | uint32 segment = _segments_offset[segment_nb]; 25 | uint8 cur_pixel; 26 | int idx = 0; 27 | 28 | if (segment_state == 0) 29 | return; 30 | 31 | idx = segment & 0x1; 32 | segment = segment >> 1; 33 | uint8 *pixel; 34 | pixel = &_segments[segment]; 35 | 36 | uint16 segments_x = _segments_x[segment_nb]; 37 | uint16 segments_y = _segments_y[segment_nb]; 38 | uint16 segments_width = _segments_width[segment_nb]; 39 | uint16 segments_height = _segments_height[segment_nb]; 40 | 41 | for (int line = segments_y; line < segments_height + segments_y; line++) { 42 | for (int x = segments_x; x < segments_width + segments_x; x++) { 43 | if ((idx & 0x1) == 0) 44 | cur_pixel = pixel[idx >> 1] & 0xF0; 45 | else 46 | cur_pixel = pixel[idx >> 1] << 4; 47 | 48 | cur_pixel |= cur_pixel >> 4; 49 | idx++; 50 | 51 | if (cur_pixel != SEG_TRANSPARENT_COLOR) 52 | graphic_framebuffer[line * GW_SCREEN_WIDTH + x] = rgb_multiply_8bits( 53 | source_mixer[line * GW_SCREEN_WIDTH + x], cur_pixel); 54 | } 55 | } 56 | } 57 | 58 | void render_to_framebuffer(uint16 *framebuffer) { 59 | uint8 seg; 60 | graphic_framebuffer = framebuffer; 61 | memcpy(framebuffer, background, GW_SCREEN_WIDTH * GW_SCREEN_HEIGHT * 2); 62 | SEG_TRANSPARENT_COLOR = SEG_WHITE_COLOR; 63 | source_mixer = framebuffer; 64 | 65 | for (int h = 0; h < 2; h++) { 66 | for (int o = 0; o < m_o_pins; o++) { 67 | seg = h ? m_ox_state[o] : m_o_state[o]; 68 | update_segment(8 * o + 0 + h, m_bp ? ((seg & 0x1) != 0) : 0); 69 | update_segment(8 * o + 2 + h, m_bp ? ((seg & 0x2) != 0) : 0); 70 | update_segment(8 * o + 4 + h, m_bp ? ((seg & 0x4) != 0) : 0); 71 | update_segment(8 * o + 6 + h, m_bp ? ((seg & 0x8) != 0) : 0); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | This is a simple emulator of the Soviet game "Nu, Pogodi!" written for the Raspberry Pico. 4 | It is supposed to be implemented on perboard and optionally with 3D printed case. 5 | Old version which implemented for breadboad is in 1.0.x branch 6 | 7 | You can watch videos of how it works below. 8 | 9 | [![Nu, Pogodi! emulator vs original](https://img.youtube.com/vi/qAGqy1fqH50/0.jpg)](https://www.youtube.com/watch?v=qAGqy1fqH50) 10 | 11 | **Nu, Pogodi! emulator vs original** 12 | 13 | [![Nu, Pogodi! emulator gameplay](https://img.youtube.com/vi/n9CVoQ6EzJo/0.jpg)](https://www.youtube.com/watch?v=n9CVoQ6EzJo) 14 | 15 | **Nu, Pogodi! emulator gameplay** 16 | 17 | # Used components 18 | 19 | 1. Raspberry Pi Pico (I used the WiFi version, but the regular one or even a Chinese clone should work). 20 | 2. Perfboard 120x80. 21 | 3. 8 momentary tactile buttons. 22 | 4. 2 Button with position locking. 23 | 5. MSP2806/MSP2807 display. 24 | 6. Passive piezo speaker. 25 | 7. 100 Ohm resistor. 26 | 8. 1 kOhm resistor. 27 | 9. 2N222 transistor. 28 | 10. TP4056 based charging module (HW-373). 29 | 11. Li-po 503450 battery. 30 | 12. 3D prited case. 31 | 13. 10 Screws 2x8. 32 | 33 | # Schematic 34 | 35 | ![Schematic](https://github.com/artyomsoft/nu-pododi-pcb/blob/master/images/schematic-nu-pogodi.png) 36 | 37 | # How to build 38 | 39 | 1. Install dependencies 40 | ```bash 41 | $ sudo apt install cmake python3 build-essential gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib 42 | ``` 43 | 2. Navigate to the working directory 44 | ```bash 45 | $ cd ~ 46 | $ mkdir emulator && cd emulator 47 | ``` 48 | 3. Clone the Pico SDK 49 | ```bash 50 | $ git clone https://github.com/raspberrypi/pico-sdk 51 | $ cd pico-sdk 52 | $ git submodule update --init --recursive 53 | ``` 54 | 4. Clone the repository with the emulator 55 | ```bash 56 | $ cd .. 57 | $ git clone git@github.com:artyomsoft/pico-nu-pogodi.git 58 | $ cd pico-nu-pogodi 59 | $ git submodule update --init --recursive 60 | ``` 61 | 5. Build the emulator 62 | ```bash 63 | export PICO_SDK_PATH=$(pwd)/../pico-sdk 64 | mkdir -p build 65 | cd build 66 | cmake .. -DPICO_COPY_TO_RAM=1 67 | make 68 | ``` 69 | 6. Connect the Raspberry Pi Pico in bootloader mode and copy the pico_nupogodi.uf2 file to it 70 | 71 | ## Usefull links 72 | 73 | 1. [PCB and schematic](https://github.com/artyomsoft/nu-pododi-pcb) 74 | 2. [3D Models of the case](https://github.com/artyomsoft/nu-pogodi-case) 75 | 3. [These 3D Models ready for printing on MakerWorld](https://makerworld.com/en/models/1602053-nu-pogodi-game-emulator) 76 | -------------------------------------------------------------------------------- /device/sound.c: -------------------------------------------------------------------------------- 1 | #include "sound.h" 2 | #include "def.h" 3 | #include "hardware/pio.h" 4 | #include "sound.pio.h" 5 | #include 6 | 7 | #include "hardware/dma.h" 8 | 9 | volatile uint8_t *current_buff; 10 | 11 | uint8_t buffer1[SOUND_BUFFER_SIZE] __attribute__((aligned(SOUND_BUFFER_SIZE))); 12 | uint8_t buffer2[SOUND_BUFFER_SIZE] __attribute__((aligned(SOUND_BUFFER_SIZE))); 13 | 14 | #define PIO_TX_PIN 15 15 | 16 | int dma_chan1; 17 | int dma_chan2; 18 | 19 | volatile bool emulate = false; 20 | volatile bool draw = false; 21 | 22 | volatile uint8 *buffer_start = buffer1; 23 | 24 | void dma_handler() { 25 | static uint32 cnt = 0; 26 | if (dma_hw->ints0 & 1u << dma_chan1) { 27 | // Clear the interrupt request. 28 | dma_hw->ints0 = 1u << dma_chan1; 29 | emulate = true; 30 | buffer_start = buffer2; 31 | if (!(cnt++ % 8)) { 32 | draw = true; 33 | } 34 | } else if (dma_hw->ints0 & 1u << dma_chan2) { 35 | dma_hw->ints0 = 1u << dma_chan2; 36 | emulate = true; 37 | buffer_start = buffer1; 38 | if (!(cnt++ % 8)) { 39 | draw = true; 40 | } 41 | } 42 | } 43 | 44 | int init_sound() { 45 | 46 | const uint sm = 0; 47 | 48 | uint offset = pio_add_program(pio0, &beeper_tx_program); 49 | 50 | beeper_tx_program_init(pio0, sm, offset, PIO_TX_PIN, SYS_FREQ); 51 | 52 | dma_chan1 = dma_claim_unused_channel(true); 53 | dma_chan2 = dma_claim_unused_channel(true); 54 | 55 | dma_channel_config c1 = dma_channel_get_default_config(dma_chan1); 56 | channel_config_set_transfer_data_size(&c1, DMA_SIZE_8); 57 | channel_config_set_read_increment(&c1, true); 58 | channel_config_set_write_increment(&c1, false); 59 | channel_config_set_dreq(&c1, DREQ_PIO0_TX0); 60 | channel_config_set_ring(&c1, false, 8); 61 | channel_config_set_chain_to(&c1, dma_chan2); 62 | dma_channel_set_irq0_enabled(dma_chan1, true); 63 | dma_channel_configure(dma_chan1, &c1, &pio0_hw->txf[0], buffer1, 64 | SOUND_BUFFER_SIZE, false); 65 | 66 | dma_channel_config c2 = dma_channel_get_default_config(dma_chan2); 67 | channel_config_set_transfer_data_size(&c2, DMA_SIZE_8); 68 | channel_config_set_read_increment(&c2, true); 69 | channel_config_set_write_increment(&c2, false); 70 | channel_config_set_dreq(&c2, DREQ_PIO0_TX0); 71 | channel_config_set_ring(&c2, false, 8); 72 | channel_config_set_chain_to(&c2, dma_chan1); 73 | dma_channel_set_irq0_enabled(dma_chan2, true); 74 | dma_channel_configure(dma_chan2, &c2, &pio0_hw->txf[0], buffer2, 75 | SOUND_BUFFER_SIZE, false); 76 | 77 | // Configure the processor to run dma_handler() when DMA IRQ 0 is asserted 78 | irq_set_exclusive_handler(DMA_IRQ_0, dma_handler); 79 | irq_set_enabled(DMA_IRQ_0, true); 80 | dma_channel_start(dma_chan1); 81 | } 82 | -------------------------------------------------------------------------------- /device/system.c: -------------------------------------------------------------------------------- 1 | #include "system.h" 2 | #include "../cpu/core.h" 3 | #include "graphic.h" 4 | #include "ili9341.h" 5 | #include "input.h" 6 | #include "pico/multicore.h" 7 | #include "pico/stdlib.h" 8 | #include "pico/time.h" 9 | #include "rom.h" 10 | #include 11 | #include 12 | #include 13 | 14 | #include "sound.h" 15 | 16 | #include "../data/o.h" 17 | 18 | extern volatile bool emulate; 19 | extern volatile bool draw; 20 | extern volatile uint8 *buffer_start; 21 | 22 | int button; 23 | 24 | void writeR(u8 data) { 25 | if (data & 0x01) { 26 | *(current_buff++) = 255; 27 | } else { 28 | *(current_buff++) = 0; 29 | } 30 | }; 31 | 32 | u32 get_buttons() { return button; } 33 | u8 readB() { return B; } 34 | u8 readBA() { return BA; } 35 | u8 readK(u8 io_S) { 36 | if ((button == 5) && (io_S == 4)) { 37 | return 8; 38 | } else if ((button == 6) && (io_S == 4)) { 39 | return 4; 40 | } else if ((button == 7) && (io_S == 4)) { 41 | return 2; 42 | } else if ((button == 8) && (io_S == 4)) { 43 | return 1; 44 | } else if ((button == 1) && (io_S == 8)) { 45 | return 8; 46 | } else if ((button == 2) && (io_S == 8)) { 47 | return 4; 48 | } else if ((button == 3) && (io_S == 8)) { 49 | return 2; 50 | } else if ((button == 4) && (io_S == 8)) { 51 | return 1; 52 | } else { 53 | return 0; 54 | } 55 | } 56 | 57 | uint16_t fb[GW_LCD_WIDTH * GW_LCD_HEIGHT]; 58 | 59 | void render() { 60 | while (true) { 61 | if (draw) { 62 | render_to_framebuffer(fb); 63 | LCD_WriteBitmap(0, 0, GW_LCD_WIDTH, GW_LCD_HEIGHT, fb); 64 | draw = false; 65 | } 66 | } 67 | } 68 | 69 | int system_run(int clock_cycles) { 70 | m_k_active = (get_buttons() != 0); 71 | m_icount += (clock_cycles / 2); 72 | 73 | current_buff = buffer_start; 74 | device_run(); 75 | return m_icount * m_clk_div; 76 | } 77 | void mainloop() { 78 | 79 | device_start(); 80 | device_reset(); 81 | 82 | for (int i = 6; i < 14; i++) { 83 | gpio_init(i); 84 | } 85 | 86 | for (int i = 6; i < 8; i++) { 87 | gpio_set_dir(i, GPIO_OUT); 88 | } 89 | 90 | gpio_set_dir(8, GPIO_IN); 91 | gpio_pull_down(8); 92 | 93 | gpio_set_dir(9, GPIO_IN); 94 | gpio_pull_down(9); 95 | 96 | for (int i = 10; i < 14; i++) { 97 | gpio_set_dir(i, GPIO_IN); 98 | gpio_pull_down(i); 99 | } 100 | 101 | multicore_launch_core1(render); 102 | init_sound(); 103 | 104 | while (1) { 105 | if (emulate) { 106 | emulate = false; 107 | button = process_input(); 108 | system_run(SYS_FREQ / 128); 109 | } 110 | } 111 | } 112 | int init(int argc, char **argv) { 113 | u8 *rom = NULL; 114 | bool romflg = false; 115 | int size = 0; 116 | 117 | size = 179348; 118 | romflg = romloader(o_data, size); 119 | 120 | if (!romflg) 121 | return 1; 122 | mainloop(); 123 | 124 | return 0; 125 | } 126 | -------------------------------------------------------------------------------- /cpu/operations.c: -------------------------------------------------------------------------------- 1 | 2 | #include "operations.h" 3 | #include "../device/def.h" 4 | #include "../device/system.h" 5 | #include "core.h" 6 | #include 7 | 8 | void reset_vector() { do_branch(0, 0xf, 0); } 9 | void wakeup_vector() { 10 | m_cb = 0; 11 | do_branch(0, 0, 0); 12 | } 13 | void set_su(u8 su) { m_a = (m_a & ~0x3c0) | (su << 6 & 0x3c0); } 14 | 15 | u8 get_su() { return m_a >> 6 & 0xf; } 16 | 17 | int get_trs_field() { return trs_field; } 18 | 19 | void shift_w() { 20 | for (int i = 0; i < (m_o_pins - 1); i++) 21 | m_ox[i] = m_ox[i + 1]; 22 | } 23 | 24 | void update_segments_state() { 25 | for (int i = 0; i < m_o_pins; i++) { 26 | m_o_state[i] = m_o[i]; 27 | m_ox_state[i] = m_ox[i]; 28 | } 29 | } 30 | 31 | u8 get_digit() { 32 | static const u8 lut_digits[0x20] = {0xe, 0x0, 0xc, 0x8, 0x2, 0xa, 0xe, 0x2, 33 | 0xe, 0xa, 0x0, 0x0, 0x2, 0xa, 0x2, 0x2, 34 | 0xb, 0x9, 0x7, 0xf, 0xd, 0xe, 0xe, 0xb, 35 | 0xf, 0xf, 0x4, 0x0, 0xd, 0xe, 0x4, 0x0}; 36 | 37 | return lut_digits[m_cn << 4 | m_acc] | (~m_cn & m_mx); 38 | } 39 | void op_lb() { 40 | m_bm = m_op & 3; 41 | m_bl = (m_op >> 2 & 3) | ((m_op & 0xc) ? 8 : 0); 42 | } 43 | void op_incb() { 44 | m_bl = (m_bl + 1) & 0xf; 45 | m_skip = (m_bl == 8); 46 | } 47 | void op_decb() { 48 | m_bl = (m_bl - 1) & 0xf; 49 | m_skip = (m_bl == 0xf); 50 | } 51 | void op_sbm() { m_bm |= 4; } 52 | void op_rbm() { m_bm &= ~4; } 53 | void op_comcb() { m_cb ^= 1; } 54 | void op_rtn0() { 55 | update_segments_state(); 56 | m_pc = m_a & m_prgmask; 57 | m_rsub = false; 58 | } 59 | void op_rtn1() { 60 | op_rtn0(); 61 | m_skip = true; 62 | } 63 | void op_ssr() { set_su(m_op & 0xf); } 64 | void op_tr() { 65 | m_pc = (m_pc & ~0x3f) | (m_op & 0x3f); 66 | if (!m_rsub) 67 | do_branch(m_cb, get_su(), m_pc & 0x3f); 68 | } 69 | void op_trs() { 70 | if (!m_rsub) { 71 | m_rsub = true; 72 | u8 su = get_su(); 73 | m_a = m_pc; 74 | do_branch(get_trs_field(), 0, m_op & 0x3f); 75 | if ((m_prev_op & 0xf0) == 0x70) 76 | do_branch(m_cb, su, m_pc & 0x3f); 77 | } else 78 | m_pc = (m_pc & ~0xff) | (m_op << 2 & 0xc0) | (m_op & 0xf); 79 | } 80 | void op_exc() { 81 | u8 a = m_acc; 82 | m_acc = ram_r(); 83 | ram_w(a); 84 | m_bm ^= (m_op & 3); 85 | } 86 | void op_exci() { 87 | op_exc(); 88 | op_incb(); 89 | } 90 | void op_excd() { 91 | op_exc(); 92 | op_decb(); 93 | } 94 | void op_atbp() { 95 | m_bp = m_acc & 1; 96 | m_cn = m_acc >> 3 & 1; 97 | } 98 | void op_ptw() { 99 | m_o[m_o_pins - 1] = m_ox[m_o_pins - 1]; 100 | m_o[m_o_pins - 2] = m_ox[m_o_pins - 2]; 101 | } 102 | void op_tw() { 103 | for (int i = 0; i < m_o_pins; i++) 104 | m_o[i] = m_ox[i]; 105 | } 106 | void op_pdtw() { 107 | m_ox[m_o_pins - 2] = m_ox[m_o_pins - 1]; 108 | m_ox[m_o_pins - 1] = get_digit(); 109 | } 110 | void op_dtw() { 111 | shift_w(); 112 | m_ox[m_o_pins - 1] = get_digit(); 113 | } 114 | void op_wr() { 115 | shift_w(); 116 | m_ox[m_o_pins - 1] = m_acc & 7; 117 | } 118 | void op_ws() { 119 | shift_w(); 120 | m_ox[m_o_pins - 1] = m_acc | 8; 121 | } 122 | void op_kta() { 123 | // printf("kta "); 124 | update_segments_state(); 125 | m_acc = readK(m_r_out & 0xf) & 0xf; 126 | } 127 | void op_exksa() {} 128 | void op_exkfa() {} 129 | void op_idiv() { m_div &= 0x3f; } 130 | void op_rmf() { 131 | m_mx = 0; 132 | m_acc = 0; 133 | } 134 | void op_smf() { m_mx = 1; } 135 | void op_comcn() { m_cn ^= 1; } 136 | void op_tal() { 137 | update_segments_state(); 138 | m_skip = (m_read_ba() != 0); 139 | } 140 | void op_tb() { 141 | update_segments_state(); 142 | m_skip = (m_read_b() != 0); 143 | } 144 | 145 | void op_lbl() { 146 | m_bl = m_param & 0xf; 147 | m_bm = (m_param & m_datamask) >> 4; 148 | } 149 | void op_exbla() { 150 | u8 a = m_acc; 151 | m_acc = m_bl; 152 | m_bl = a; 153 | } 154 | 155 | void op_lda() { 156 | m_acc = ram_r(); 157 | m_bm ^= (m_op & 3); 158 | } 159 | void op_lax() { 160 | if ((m_op & ~0xf) != (m_prev_op & ~0xf)) 161 | m_acc = m_op & 0xf; 162 | } 163 | void op_atr() { m_r = m_acc; } 164 | void op_add() { m_acc = (m_acc + ram_r()) & 0xf; } 165 | void op_add11() { 166 | m_acc += ram_r() + m_c; 167 | m_c = m_acc >> 4 & 1; 168 | m_skip = (m_c == 1); 169 | m_acc &= 0xf; 170 | } 171 | void op_adx() { 172 | m_acc += (m_op & 0xf); 173 | m_skip = ((m_op & 0xf) != 10 && (m_acc & 0x10) != 0); 174 | m_acc &= 0xf; 175 | } 176 | void op_coma() { m_acc ^= 0xf; } 177 | void op_rc() { m_c = 0; } 178 | void op_sc() { m_c = 1; } 179 | void op_tc() { m_skip = !m_c; } 180 | void op_tam() { m_skip = (m_acc == ram_r()); } 181 | void op_tmi() { m_skip = ((ram_r() & bitmask(m_op)) != 0); } 182 | void op_ta0() { m_skip = !m_acc; } 183 | void op_tabl() { m_skip = (m_acc == m_bl); } 184 | void op_tis() { 185 | m_skip = !m_1s; 186 | m_1s = false; 187 | } 188 | void op_rm() { ram_w(ram_r() & ~bitmask(m_op)); } 189 | void op_sm() { ram_w(ram_r() | bitmask(m_op)); } 190 | void op_skip() {} 191 | void op_cend() { m_halt = true; } 192 | void op_dta() { m_acc = m_div >> 11 & 0xf; } 193 | void op_illegal() { 194 | printf("unknown opcode $%02X at $%04X\n", m_op, m_prev_pc); 195 | } 196 | -------------------------------------------------------------------------------- /cpu/core.c: -------------------------------------------------------------------------------- 1 | #include "core.h" 2 | #include "../device/def.h" 3 | #include "../device/rom.h" 4 | #include "../device/system.h" 5 | #include "operations.h" 6 | 7 | u8 m_prgwidth = 11; 8 | u8 m_datawidth = 7; 9 | int m_prgmask; 10 | int m_datamask; 11 | 12 | un8 ram[128]; 13 | 14 | u16 m_pc, m_prev_pc, m_a; 15 | u8 m_cb; 16 | u8 m_c; 17 | u16 m_op, m_prev_op; 18 | u8 m_param; 19 | u8 m_acc; 20 | u8 m_bl; 21 | u8 m_bm; 22 | bool m_skip; 23 | u8 m_r, m_r_out; 24 | u8 m_ox[9]; 25 | u8 m_o[9]; 26 | u8 m_ox_state[9]; 27 | u8 m_o_state[9]; 28 | bool m_k_active; 29 | bool m_halt; 30 | int m_clk_div; 31 | u16 m_div; 32 | int m_icount; 33 | bool m_1s; 34 | u8 m_bp; 35 | bool m_bc; 36 | int m_o_pins; 37 | u8 m_cn; 38 | u8 m_mx; 39 | u8 trs_field; 40 | 41 | bool m_rsub; 42 | 43 | un8 readb(un8 ram_address) { return ram[ram_address]; } 44 | 45 | void writeb(un8 ram_address, u8 ram_data) { ram[ram_address] = ram_data; } 46 | 47 | u8 bitmask(u16 param) { return 1 << (param & 3); } 48 | 49 | un8 read_byte_program(un16 rom_address) { return *(program + rom_address); } 50 | 51 | void increment_pc() { 52 | int feed = ((m_pc >> 1 ^ m_pc) & 1) ? 0 : 0x20; 53 | m_pc = feed | (m_pc >> 1 & 0x1f) | (m_pc & ~0x3f); 54 | } 55 | 56 | u8 ram_r() { 57 | u8 address = (m_bm << 4 | m_bl) & m_datamask; 58 | if (address > 0x4f) 59 | address &= 0x4f; 60 | return readb(address) & 0xf; 61 | } 62 | void ram_w(u8 data) { 63 | u8 address = (m_bm << 4 | m_bl) & m_datamask; 64 | if (address > 0x4f) 65 | address &= 0x4f; 66 | writeb(address, data & 0xf); 67 | } 68 | 69 | void do_branch(u8 pu, u8 pm, u8 pl) { 70 | m_pc = ((pu << 10) | (pm << 6 & 0x3c0) | (pl & 0x03f)) & m_prgmask; 71 | } 72 | 73 | un8 m_read_ba() { return readBA(); } 74 | un8 m_read_b() { return readB(); } 75 | void m_write_r(un8 data) { writeR(data); } 76 | 77 | void clock_melody() { 78 | u8 out = (~m_r & 0xf); 79 | m_r_out = out; 80 | m_write_r(m_r_out); 81 | } 82 | 83 | bool wake_me_up() { 84 | if (m_k_active || m_1s) { 85 | m_halt = false; 86 | wakeup_vector(); 87 | return true; 88 | } else 89 | return false; 90 | } 91 | void div_timer_cb() { 92 | m_div = (m_div + 1) & 0x7fff; 93 | if (m_div == 0) { 94 | m_1s = true; 95 | if (m_halt) 96 | update_segments_state(); 97 | } 98 | clock_melody(); 99 | } 100 | void div_timer(int nb_inst) { 101 | if (nb_inst > 0) 102 | for (int toctoc = 0; toctoc < m_clk_div * nb_inst; toctoc++) 103 | div_timer_cb(); 104 | } 105 | void get_opcode_param() { 106 | if (m_op == 0x5e || m_op == 0x5f) { 107 | m_icount--; 108 | m_param = read_byte_program(m_pc); 109 | increment_pc(); 110 | } 111 | } 112 | 113 | void device_start() { 114 | memset(ram, 0, sizeof(ram)); 115 | memset(m_ox, 0, sizeof(m_ox)); 116 | memset(m_o, 0, sizeof(m_o)); 117 | memset(m_ox_state, 0, sizeof(m_ox_state)); 118 | memset(m_o_state, 0, sizeof(m_o_state)); 119 | 120 | m_pc = 0; 121 | m_prev_pc = 0; 122 | m_op = 0; 123 | m_prev_op = 0; 124 | m_param = 0; 125 | m_acc = 0; 126 | 127 | m_bl = 0; 128 | m_bm = 0; 129 | m_c = 0; 130 | m_skip = false; 131 | m_r = 0; 132 | m_r_out = 0; 133 | m_div = 0; 134 | m_1s = false; 135 | m_k_active = false; 136 | m_bp = 0; 137 | m_bc = false; 138 | m_halt = false; 139 | m_clk_div = 2; 140 | m_icount = 0; 141 | 142 | m_rsub = false; 143 | m_o_pins = 9; 144 | m_prgmask = (1 << m_prgwidth) - 1; 145 | m_datamask = (1 << m_datawidth) - 1; 146 | trs_field = 1; 147 | 148 | m_cn = 0; 149 | m_mx = 0; 150 | 151 | m_cb = 0; 152 | } 153 | void device_reset() { 154 | 155 | m_skip = false; 156 | m_halt = false; 157 | m_op = m_prev_op = 0; 158 | 159 | m_prev_pc = m_pc; 160 | m_bp = 1; 161 | m_bc = false; 162 | m_r = m_r_out = 0; 163 | reset_vector(); 164 | m_a = m_pc; 165 | op_idiv(); 166 | 167 | m_1s = true; 168 | m_cb = 0; 169 | m_rsub = false; 170 | m_r = 0xff; 171 | m_r_out = 0; 172 | } 173 | void execute_one() { 174 | switch (m_op & 0xf0) { 175 | case 0x20: 176 | op_lax(); 177 | break; 178 | case 0x30: 179 | op_adx(); 180 | break; 181 | case 0x40: 182 | op_lb(); 183 | break; 184 | case 0x70: 185 | op_ssr(); 186 | break; 187 | case 0x80: 188 | case 0x90: 189 | case 0xa0: 190 | case 0xb0: 191 | op_tr(); 192 | break; 193 | case 0xc0: 194 | case 0xd0: 195 | case 0xe0: 196 | case 0xf0: 197 | op_trs(); 198 | break; 199 | default: 200 | switch (m_op & 0xfc) { 201 | case 0x04: 202 | op_rm(); 203 | break; 204 | case 0x0c: 205 | op_sm(); 206 | break; 207 | case 0x10: 208 | op_exc(); 209 | break; 210 | case 0x14: 211 | op_exci(); 212 | break; 213 | case 0x18: 214 | op_lda(); 215 | break; 216 | case 0x1c: 217 | op_excd(); 218 | break; 219 | case 0x54: 220 | op_tmi(); 221 | break; 222 | default: 223 | switch (m_op) { 224 | case 0x00: 225 | op_skip(); 226 | break; 227 | case 0x01: 228 | op_atr(); 229 | break; 230 | case 0x02: 231 | op_sbm(); //? 232 | break; 233 | case 0x03: 234 | op_atbp(); 235 | break; 236 | case 0x08: 237 | op_add(); 238 | break; 239 | case 0x09: 240 | op_add11(); //? 241 | break; 242 | case 0x0a: 243 | op_coma(); 244 | break; 245 | case 0x0b: 246 | op_exbla(); 247 | break; 248 | case 0x50: 249 | op_tal(); 250 | break; 251 | case 0x51: 252 | op_tb(); 253 | break; 254 | case 0x52: 255 | op_tc(); 256 | break; 257 | case 0x53: 258 | op_tam(); 259 | break; 260 | case 0x58: 261 | op_tis(); //? 262 | break; 263 | case 0x59: 264 | op_ptw(); 265 | break; 266 | case 0x5a: 267 | op_ta0(); 268 | break; 269 | case 0x5b: 270 | op_tabl(); 271 | break; 272 | case 0x5c: 273 | op_tw(); 274 | break; 275 | case 0x5d: 276 | op_dtw(); 277 | break; 278 | case 0x5f: 279 | op_lbl(); 280 | break; 281 | case 0x60: 282 | op_comcn(); 283 | break; 284 | case 0x61: 285 | op_pdtw(); 286 | break; 287 | case 0x62: 288 | op_wr(); 289 | break; 290 | case 0x63: 291 | op_ws(); 292 | break; 293 | case 0x64: 294 | op_incb(); 295 | break; 296 | case 0x65: 297 | op_idiv(); 298 | break; 299 | case 0x66: 300 | op_rc(); 301 | break; 302 | case 0x67: 303 | op_sc(); 304 | break; 305 | case 0x68: 306 | op_rmf(); 307 | break; 308 | case 0x69: 309 | op_smf(); 310 | break; 311 | case 0x6a: 312 | op_kta(); 313 | break; 314 | case 0x6b: 315 | op_rbm(); //? 316 | break; 317 | case 0x6c: 318 | op_decb(); 319 | break; 320 | case 0x6d: 321 | op_comcb(); 322 | break; 323 | case 0x6e: 324 | op_rtn0(); 325 | break; 326 | case 0x6f: 327 | op_rtn1(); 328 | break; 329 | case 0x5e: 330 | m_op = m_op << 8 | m_param; 331 | switch (m_param) { 332 | case 0x00: 333 | op_cend(); 334 | break; 335 | case 0x04: 336 | op_dta(); 337 | break; 338 | default: 339 | op_illegal(); 340 | break; 341 | } 342 | break; 343 | default: 344 | op_illegal(); 345 | break; 346 | } 347 | break; 348 | } 349 | break; 350 | } 351 | } 352 | void device_run() { 353 | int remaining_icount = m_icount; 354 | 355 | while (m_icount > 0) { 356 | m_icount--; 357 | 358 | if (m_halt && !wake_me_up()) { 359 | div_timer(remaining_icount); 360 | m_icount = 0; 361 | return; 362 | } 363 | 364 | m_prev_op = m_op; 365 | m_prev_pc = m_pc; 366 | m_op = read_byte_program(m_pc); 367 | 368 | increment_pc(); 369 | get_opcode_param(); 370 | 371 | if (m_skip) { 372 | m_skip = false; 373 | m_op = 0; 374 | } else 375 | execute_one(); 376 | 377 | div_timer(remaining_icount - m_icount); 378 | remaining_icount = m_icount; 379 | } 380 | } 381 | --------------------------------------------------------------------------------