/******************************************************************************/ /******************************************************************************/ //"sokoban_and_kit32_2025-01-31\kit32\snake\simple_text_editor.asm": #include "kit-32.asm" jmp #init ;r3 = char index ;r5 = temp indirection buffer ;other registers are scratch init: mov.u32 r0, #0xff000000 sys #SYSCALL_SETDRAWCOLOR mov.u32 r3, *#text_index loop: sys #SYSCALL_CLEAR jsr #get_char cmp.u8 r0, #0 beq #.draw_call ;if key is backspace cmp.u8 r0, #VKEY_BACKSPACE bne #.not_backspace jsr #rem_char bra #.draw_call .not_backspace: ;if key is newline cmp.u8 r0, #VKEY_RETURN bne #.not_newline mov.u8 r0, #"\n" ;convert '\r' to '\n' .not_newline: jsr #add_char .draw_call: mov.s32 r0, #1 mov.s32 r1, #1 jsr #draw_text mov.u32 r5, #text_index mov.u32 *r5, r3 sys #SYSCALL_PRESENT bra #loop ;puts new char for drawing into r0.u8, ;or 0 if there's nothing to pull from queue get_char: sys #SYSCALL_GETKEY cmp.u32 r0, #0 beq #.e ;skip if null bnc #get_char ;try again on key up ;try again if the key is just a keymod ;(aka, if r0.u8 >= VKEY_LCTRL && r0.u8 <= VKEY_RGUI) mov.u16 r4, r0 ;only observe stuff in vkey mask and.u16 r4, #KE_MASK_VKEY ;^^ cmp.u16 r4, #VKEY_LCTRL blt #.not_a_keymod cmp.u16 r4, #VKEY_RGUI ble #get_char .not_a_keymod: ;check if shift was being held mov.u32 r4, r0 shr.u32 r4, #KE_SHIFT_KEYMOD and.u16 r4, #KEYMOD_SHIFT bzs #.e ;if not, exit and.u8 r0, #0b11011111 ;unset bit 5 .e: rts ;adds r0.u8 to char buffer, or not if buffer is full add_char: cmp.u8 r0, #0 beq #.e ;exit if char is null cmp.u32 r3, #255 bge #.e ;exit if char buffer is full ;construct new char's address before dereferencing it mov.u32 r5, #text_buffer add.u32 r5, r3 mov.u8 *r5, r0 inc.u32 r3 ;new char was added; increment accordingly .e: rts rem_char: cmp.u32 r3, #0 beq #.e ;exit if there are no chars left to remove dec.u32 r3 .e: rts ;r0.s32, r1.s32 = x&y position of text in pixels ;r3 = the number of chars to draw (0 to skip drawing) draw_text: cmp.u32 r3, #0 beq #.e ;exit if there are no chars left to remove mov.u32 r2, #text_buffer sys #SYSCALL_DRAWTEXT .e: rts #addr 1024*1024*8 ;start of persistent memory text_index: #res 4 text_buffer: #res 256/******************************************************************************/ /******************************************************************************/ //"sokoban_and_kit32_2025-01-31\kit32\snake\snake.asm": #include "kit-32.asm" ;jmp #INIT SCREEN_W = (256) SCREEN_H = (144-8) ; -8 to account for score bar SCREEN_LEN = (SCREEN_W*SCREEN_H) ;0x24F -> 0x252 = the vkey events, in this order: DIR_RIGHT = 0 DIR_LEFT = 1 DIR_DOWN = 2 DIR_UP = 3 DIR_DEAD = 4 ;dead state INIT: ;code that executes only once ;(nothing currently) START: ;init stack pointer to first byte of persistent memory, ;so that it will enter the top of non-persistent memory when pushing mov.u32 sp, #1<<23 ;reset reserved memory mov.u32 r0, #RESERVED_START ;(previously an ext) mov.u8 r1, #0 mov.u32 r2, #RESERVED_LEN sys #SYSCALL_MEMSET ;set background color to a random one mov.u32 r0, #0 ;(previously an ext) jfn #FUN_set_bg sys #SYSCALL_CLEAR ;set score to -1, so that it rolls over to 0 next call to FUN_create_apple mov.u32 r3, #VAR_score dec.u32 *r3 ;(relies on *VAR_score previously being 0) ;set snake's start and end pointers mov.u32 r0, #ARR_snake_segments ;(previously an ext) mov.u32 r4, #VAR_snake_start ;(previously an ext) mov.u32 r5, #VAR_snake_end ;(previously an ext) mov.u32 *r4, r0 mov.u32 *r5, r0 ;set snake's position and direction, before adding the first segment ;(16-bit is used where possible) sys #SYSCALL_RAND_U16 mod.u16 r0, #SCREEN_LEN mov.u32 r5, #VAR_snake_pos ;(previously an ext) mov.u16 *r5, r0 mov.u16 r1, r0 ;for the call to FUN_snake_add ; and.u16 r0, #3 ;yes, this operates on the value given by the prev. rand.u16 mov.u32 r4, #VAR_snake_dir ;(previously an ext) mov.u16 *r4, r0 ; jfn #FUN_snake_add ;create first apple jfn #FUN_create_apple LOOP: jfn #FUN_handle_input ;move snake head mov.u32 r4, *#VAR_snake_dir shl.u16 r4, #1 ; *= 2 add.u16 r4, #.move_lookup ; mov.u32 r5, #VAR_snake_pos ;(previously an ext) add.s16 *r5, *r4 ;VAR_snake_pos += ARR_move_lookup[VAR_snake_dir] cmp.u16 *r5, #SCREEN_LEN blt #to_absolute(4) add.u16 *r5, #SCREEN_LEN mod.u16 *r5, #SCREEN_LEN ;check to see if snake died ;* mov.u16 r1, *#VAR_snake_pos jfn #FUN_get_screen_byte bzs #.dont_die mov.u32 r0, #0xFF00007F ;a shade of red sys #SYSCALL_SETDRAWCOLOR sys #SYSCALL_CLEAR jfn #FUN_draw_score mov.u16 r1, #60*3 jfn #FUN_wait bra #START .dont_die: *; ;add new segment mov.u16 r1, *r5 jfn #FUN_snake_add ;if snake is now touching the apple, increment score and generate a new one. ;otherwise, remove the last snake segment mov.u32 r4, #VAR_apple_pos ;(previously an ext) cmp.u16 *r4, *r5 bne #.not_on_apple jfn #FUN_create_apple bra #.dont_remove_segment .not_on_apple: jfn #FUN_snake_rem .dont_remove_segment: jfn #FUN_draw_score mov.u16 r1, #2 jfn #FUN_wait bra #LOOP .move_lookup: ;*right*; #d16 lend16( 1) ;*left *; #d16 lend16( -1) ;*down *; #d16 lend16( 256) ;*up *; #d16 lend16(-256) ;; add a snake segment to the queue, before painting in that segment ;; ;; params: r1.u16 = the segment to add ;; returns: none ;; clobbers: none FUN_snake_add: ;add segment to the queue mov.u32 r4, #VAR_snake_end ; r4 = &VAR_snake_end mov.u32 r5, *r4 ; r5 = VAR_snake_end mov.u16 *r5, r1 ; *VAR_snake_end = r1 ;snake segment added; set byte to 1 in screen mirror mov.u8 r2, #1 jfn #FUN_set_screen_byte ;(r1 = the segment) ;advance v_snake_end by 2, wrapping at the segment array boundary sub.s32 *r4, #(ARR_snake_segments-2) ;ptr to offset+2 mod.u32 *r4, #SCREEN_LEN*2 ; %= size of segments array add.u32 *r4, #ARR_snake_segments ;new offset back to ptr ;draw the new segment sph.u32 r0 mov.u32 r0, #0xFF00FF00 ; a shade of green sys #SYSCALL_SETDRAWCOLOR jfn #FUN_draw_segment ;r1 = the drawn segment spl.u32 r0 rfn ;; remove a snake segment from the queue, ;; before painting over that segment ;; ;; params: none ;; returns: none ;; clobbers: none FUN_snake_rem: mov.u32 r4, #VAR_snake_start ;(previously an ext) cmp.u16 *r4, *#VAR_snake_end beq #.e ;no sections to remove; exit early mov.u32 r5, *r4 ;r5 = *v_snake_start (ptr inside ARR_snake_segments) mov.u16 r1, *r5 ;r1 = first segment in queue ;(previously an ext) and.u32 r1, #U16_MAX ;^^ ;snake segment removed; set byte to 0 in screen mirror mov.u8 r2, #0 jfn #FUN_set_screen_byte ;(r1 = the segment) ;advance v_snake_start by 2, wrapping at the segment array boundary sub.s32 *r4, #(ARR_snake_segments-2) ;ptr to offset+2 mod.u32 *r4, #SCREEN_LEN*2 ; %= size of segments array add.u32 *r4, #ARR_snake_segments ;new offset back to ptr ;paint over the segment with the background color sph.u32 r0 jfn #FUN_get_bg jfn #FUN_draw_segment spl.u32 r0 .e: rfn ;; creates a new apple (will overwrite the previous one) ;; ;; params: none ;; returns: none ;; clobbers: none FUN_create_apple: sph.u32 r0 ;keep rolling for a new spot until one without a snake segment is found ;(lazy implementation, but it uses fewer bytes than the non-naive approach) .loop: sys #SYSCALL_RAND_U16 mod.u16 r0, #SCREEN_LEN ;= a random pixel offset mov.u16 r1, r0 jfn #FUN_get_screen_byte bzc #.loop ;set apple's position to the new value mov.u32 r5, #VAR_apple_pos ;(previously an ext) mov.u16 *r5, r1 ;increment score mov.u32 r3, #VAR_score inc.u32 *r3 ;draw the apple mov.u32 r0, #0xFF0000FF ; a shade of red sys #SYSCALL_SETDRAWCOLOR jfn #FUN_draw_segment spl.u32 r0 rfn ;; sets the byte r1.u16 of ARR_screen_mirror to r2.u8 ;; ;; params: r1.u16 = the byte to select ;; r2.u8 = the byte's new value ;; returns: none ;; clobbers: none FUN_set_screen_byte: mov.u32 r3, r1 ;(previously an ext) and.u32 r3, #U16_MAX ;^^ mod.u32 r3, #SCREEN_LEN add.u32 r3, #ARR_screen_mirror mov.u8 *r3, r2 rfn ;; gets the byte r1.u16 from ARR_screen_mirror ;; ;; params: r1.u16 = the byte to select ;; returns: r0.u8 = the byte's current value ;; clobbers: none ;; ;; remarks: the final "mov.u8" instruction will set the zero flag accordingly, ;; which means that a branch can be placed right after the jfn call FUN_get_screen_byte: mov.u32 r3, r1 ;(previously an ext) and.u32 r3, #U16_MAX ;^^ mod.u32 r3, #SCREEN_LEN add.u32 r3, #ARR_screen_mirror mov.u8 r0, *r3 rfn ;; set background color, or randomize it if r0 is equal to 0 ;; (will also set the draw color to the new background color!) ;; ;; params: r0.u32 = new color, or 0 for random ;; returns: r0.u32 = the new background color ;; clobbers: none FUN_set_bg: cmp.u32 r0, #0 bne #.dont_randomize sys #SYSCALL_RAND_U32 ior.u32 r0, #0xFF000000 ;make sure alpha is 255 ;make sure color intensity isn't too high, ;and prevent green from being used too much either and.u32 r0, #0xFF2F0F2F .dont_randomize: ;set background color mov.u32 r4, #VAR_bg_color ;(previously an ext) mov.u32 *r4, r0 ;(falls through to FUN_get_bg) ;; put background color into r0.u32, ;; while simultaneously setting the draw color ;; ;; params: none ;; returns: r0.u32 = the current background color ;; clobbers: none FUN_get_bg: mov.u32 r0, *#VAR_bg_color sys #SYSCALL_SETDRAWCOLOR rfn ;; takes in and acts on user input ;; ;; params: none ;; returns: none ;; clobbers: none FUN_handle_input: sph.u32 r0 mov.u32 r5, #VAR_snake_dir ;(previously an ext) mov.u32 r3, *r5 ;get original state of VAR_snake_dir, into r3 .loop: jsr #SUB_get_vkey_down bzs #.e ;break loop if key event is null cmp.u16 *r5, #DIR_DEAD beq #.loop ;if snake is dead, burn events until all are cleared ;convert an arrow's virtual key code to a snake direction sub.u16 r0, #0x24F ;0x24F = first arrow virtual key code cmp.u16 r0, #4 ;there are 4 arrow keys bge #.loop ;query next event if not an arrow key press ;query next event if new direction would be the opposite of the old one ;(this is to prevent immediately running into the last snake segment) mov.u32 r1, r0 ;no need for an ext, as r0 is guaranteed to be <=U16_MAX add.u16 r1, #.move_conflicts_lookup ;a lookup table is used, cmp.u8 *r1, *r5 ;and each entry is u8 beq #.loop ;set r3 to the new value, before querying another event mov.u16 r3, r0 bra #.loop .e: ;update v_snake_dir to new value (or the same one if it hasn't changed) mov.u16 *r5, r3 spl.u32 r0 rfn .move_conflicts_lookup: ;tiny lookup table :O #d8 1 ;opposite of right #d8 0 ;opposite of left #d8 3 ;opposite of down #d8 2 ;opposite of up ;; polls for key events until either a non-repeat vkey down event is found, ;; or if the event queue was cleared before returning anything valid ;; ;; params: none ;; returns: r0.u32 = vkey event, or 0 if nothing was found ;; clobbers: r1.u32 ;; ;; remarks: the zero flag will be set at the point of returning, ;; so a branch on zero immediately after the jsr is valid SUB_get_vkey_down: sys #SYSCALL_GETKEY cmp.u32 r0, #0 beq #.e ;break loop if event is null bnc #SUB_get_vkey_down ;try again if event is keyup mov.u32 r1, r0 and.u32 r1, #1< + 1 mov.u32 r2, #SCREEN_W ;w mov.u32 r3, #144-SCREEN_H ;h = - sys #SYSCALL_FILLRECT_S32 mov.s32 r2, #CENTERED_TEXT ;x inc.s32 r1 ;y = + 1 + 1 mov.u32 r3, *#VAR_score ;n ;this effectively calls FUN_draw_u32, without pushing r0 bra #to_absolute(4) ;; draws r3.u32 at (r2.s32,r1.s32), as text ;; ;; params: r1.s32 = y position ;; r2.s32 = x position ;; r3.u32 = number to draw ;; returns: none ;; clobbers: none FUN_draw_u32: sph.u32 r0 ;convert number to bcd, into r4 u2b r4, r3 ;preserve x, before setting r2 to last char of ARR_num_str +1 mov.u32 r0, r2 mov.u32 r2, #ARR_num_str+7 +1 .loop: dec.u32 r2 ;will *start* at last char ;construct digit char from low nybble of r4, into r3 mov.u8 r3, r4 and.u8 r3, #0b1111 add.u8 r3, #"0" mov.u8 *r2, r3 ;write that char to *r2 shr.u32 r4, #4 ;go to next nybble in bcd ;loop will break once r2 == ARR_num_str cmp.u32 r2, #ARR_num_str bne #.loop mov.u32 r3, #0 ;len = 0 (until null terminator is hit) ;(previously an ext) sys #SYSCALL_DRAWTEXT spl.u32 r0 rfn ;; draws and waits for r1.u16 frames ;; ;; params: r1.u16 = # of frames to wait ;; returns: none ;; clobbers: none FUN_wait: cmp.u16 r1, #0 beq #.e .loop: sys #SYSCALL_PRESENT dec.u16 r1 bzc #.loop .e: rfn ;; construct an x & y from a snake segment, ;; before drawing it as a point ;; ;; params: r1.u16 = segment to draw ;; returns: none ;; clobbers: none FUN_draw_segment: sph.u32 r0 and.u32 r1, #U16_MAX ;x mov.u32 r0, r1 and.u16 r0, #U8_MAX ;y shr.u16 r1, #8 mod.u16 r1, #SCREEN_H sys #SYSCALL_DRAWPOINT_S32 spl.u32 r0 rfn #align 32 RESERVED_START: ARR_num_str : #res 9 #align 32 ;should make 3 bytes of padding VAR_score : #res 4 VAR_bg_color : #res 4 VAR_apple_pos : #res 4 VAR_snake_pos : #res 4 VAR_snake_dir : #res 4 VAR_snake_start : #res 4 VAR_snake_end : #res 4 ARR_screen_mirror : #res SCREEN_LEN ;1 byte per pixel ARR_snake_segments: #res SCREEN_LEN*2 ;segment queue, each is 2 bytes RESERVED_END: RESERVED_LEN = RESERVED_END-RESERVED_START/******************************************************************************/ /******************************************************************************/ //"sokoban_and_kit32_2025-01-31\kit32\simulator\src\callbacks.cpp": #include using namespace kit; AudioDevice* audio = nullptr; bool audioIsReady = false; s32 cb_audio(void* _dst, const AudioDeviceInfo& info){ if(!audioIsReady) return 0; Stereo_f32* dst = (Stereo_f32*)_dst; u16 dst_len = info.sampleFrames; for(u16 i=0; i #include //for sqrtf, fmodf, and trig functions #define STACK_PUSH(_type) \ *ADDR(_type, regs_sp.u32-=sizeof(_type)) #define STACK_PULL(_type) \ *ADDR(_type, regs_sp.u32); regs_sp.u32 += sizeof(_type) #define STACK_GET(_type, _offset) \ *ADDR(_type, regs_sp.u32+(_offset)) #define BITSIZ(_value) (sizeof(_value)*8) #define SHIFTMOD(_value, _shift) ( (_shift)&(BITSIZ(_value)-1) ) #define GET_MSb(_value) ( 1<<(BITSIZ(_value)-1) ) #define SET_FLAGS_ZN(_value) \ flags_zero = (_value) == 0; \ flags_negative = ((_value)&GET_MSb(_value)) != 0 /* MISC. */ #define DO_MOV(_type) { \ dst->_type = src->_type; \ SET_FLAGS_ZN(dst->_type); } #define DO_CMP(_type) { \ flags_less = dst->_type < src->_type; \ flags_equal = dst->_type == src->_type; \ SET_FLAGS_ZN(dst->_type); } #define DO_JMP(_type) { \ regs_pc = (u32)(src->_type); } //(z&n are not set here) #define DO_JSR(_type) { \ STACK_PUSH(u32) = regs_pc; \ DO_JMP(_type); } //(z&n are not set here) #define DO_SLD(_type) { \ dst->_type = STACK_GET(_type, src->s16); \ SET_FLAGS_ZN(dst->_type); } #define DO_SST(_type) { \ STACK_GET(_type, src->s16) = dst->_type; } //(z&n are not set here) #define DO_SPH(_type) { \ STACK_PUSH(_type) = src->_type; } //(z&n are not set here) #define DO_SPL(_type) { \ dst->_type = STACK_PULL(_type); \ SET_FLAGS_ZN(dst->_type); } /* ARITHMETIC */ #define DO_INC(_type) { \ ++dst->_type; \ SET_FLAGS_ZN(dst->_type); } #define DO_DEC(_type) { \ --dst->_type; \ SET_FLAGS_ZN(dst->_type); } #define DO_ADD(_type) { \ dst->_type += src->_type; \ SET_FLAGS_ZN(dst->_type); } #define DO_SUB(_type) { \ dst->_type -= src->_type; \ SET_FLAGS_ZN(dst->_type); } #define DO_MUL(_type) { \ dst->_type *= src->_type; \ SET_FLAGS_ZN(dst->_type); } #define DO_DIV(_type) { \ dst->_type /= src->_type; \ SET_FLAGS_ZN(dst->_type); } #define DO_MOD(_type) { \ dst->_type %= src->_type; \ SET_FLAGS_ZN(dst->_type); } #define DO_NEG(_type) { \ dst->_type = -src->_type; \ SET_FLAGS_ZN(dst->_type); } /* BITWISE */ #define DO_NOT(_type) { \ dst->_type = ~src->_type; \ SET_FLAGS_ZN(dst->_type); } #define DO_NND(_type) { \ dst->_type = ~(dst->_type & src->_type); \ SET_FLAGS_ZN(dst->_type); } #define DO_AND(_type) { \ dst->_type &= src->_type; \ SET_FLAGS_ZN(dst->_type); } #define DO_NOR(_type) { \ dst->_type = ~(dst->_type | src->_type); \ SET_FLAGS_ZN(dst->_type); } #define DO_IOR(_type) { \ dst->_type |= src->_type; \ SET_FLAGS_ZN(dst->_type); } #define DO_XOR(_type) { \ dst->_type ^= src->_type; \ SET_FLAGS_ZN(dst->_type); } #define DO_SHL(_type) { \ dst->_type = ( dst->_type << SHIFTMOD(dst->_type, src->s16) ); \ SET_FLAGS_ZN(dst->_type); } #define DO_SHR(_type) { \ dst->_type = ( dst->_type >> SHIFTMOD(dst->_type, src->s16) ); \ SET_FLAGS_ZN(dst->_type); } #define DO_ROL(_type) { \ dst->_type = ( \ (dst->_type << SHIFTMOD(dst->_type, src->s16)) | \ (dst->_type >> (BITSIZ(dst->_type) - SHIFTMOD(dst->_type, src->s16))) ); \ SET_FLAGS_ZN(dst->_type); } #define DO_ROR(_type) { \ dst->_type = ( \ (dst->_type >> SHIFTMOD(dst->_type, src->s16)) | \ (dst->_type << (BITSIZ(dst->_type) - SHIFTMOD(dst->_type, src->s16))) ); \ SET_FLAGS_ZN(dst->_type); } #define DO_EXT(_type_from, _type_to) { \ dst->_type_to = (_type_to)src->_type_from; \ SET_FLAGS_ZN(dst->_type_to); } /* EXTRA */ #define DO_JFN(_type) { \ regs_sp.u32 -= sizeof(u32)*6; \ u32* stack = ADDR(u32, regs_sp.u32); \ stack[0] = regs_pc; \ stack[1] = regs_gp[5].u32; \ stack[2] = regs_gp[4].u32; \ stack[3] = regs_gp[3].u32; \ stack[4] = regs_gp[2].u32; \ stack[5] = regs_gp[1].u32; \ DO_JMP(_type); } //(z&n are not set here) namespace kit { union bcd { u32 v; struct { u32 d0:4, d1:4, d2:4, d3:4, d4:4, d5:4, d6:4, d7:4; }; inline bcd(u32 _v) : v(_v) {} }; static inline u32 to_bcd(u32 value){ u32 result = 0, shift = 0; value = MIN(value, 99999999); while(value > 0){ result |= (value%10)<= OPTYPE_SHL && ins.op_type <= OPTYPE_ROR)*/) { src = ADDR(reg32, regs_pc-2); } //...or the next 4 bytes after ins else { src = ADDR(reg32, regs_pc); regs_pc += sizeof(reg32); } //if source is indirect, and should be dereferenced as a memory address //(dereferencing an immediate value not of type u32 is undefined!) if(ins.src_ind) src = ADDR(reg32, src->u32); dst = regs + ins.dst; //if destination is indirect, and should be dereferenced as a memory address if(ins.dst_ind) dst = ADDR(reg32, dst->u32); switch(ins.op){ /*************** OPDATA_U8 ****************/ case OPCODE(U8,BRK): result = EXERES_BRK; break; case OPCODE(U8,MOV): DO_MOV(u8); break; case OPCODE(U8,CMP): DO_CMP(u8); break; case OPCODE(U8,JMP): DO_JMP(u8); break; case OPCODE(U8,JSR): DO_JSR(u8); break; case OPCODE(U8,SLD): DO_SLD(u8); break; case OPCODE(U8,SST): DO_SST(u8); break; case OPCODE(U8,SPH): DO_SPH(u8); break; case OPCODE(U8,SPL): DO_SPL(u8); break; case OPCODE(U8,INC): DO_INC(u8); break; case OPCODE(U8,DEC): DO_DEC(u8); break; case OPCODE(U8,ADD): DO_ADD(u8); break; case OPCODE(U8,SUB): DO_SUB(u8); break; case OPCODE(U8,MUL): DO_MUL(u8); break; case OPCODE(U8,DIV): DO_DIV(u8); break; case OPCODE(U8,MOD): DO_MOD(u8); break; case OPCODE(U8,NEG): DO_NEG(u8); break; case OPCODE(U8,NOT): DO_NOT(u8); break; case OPCODE(U8,NND): DO_NND(u8); break; case OPCODE(U8,AND): DO_AND(u8); break; case OPCODE(U8,NOR): DO_NOR(u8); break; case OPCODE(U8,IOR): DO_IOR(u8); break; case OPCODE(U8,XOR): DO_XOR(u8); break; case OPCODE(U8,SHL): DO_SHL(u8); break; case OPCODE(U8,SHR): DO_SHR(u8); break; case OPCODE(U8,ROL): DO_ROL(u8); break; case OPCODE(U8,ROR): DO_ROR(u8); break; case OPCODE(U8,EXT): DO_EXT(u8, u16); break; case OPCODE(U8,JFN): DO_JFN(u8); break; /*************** OPDATA_S8 ****************/ case OPCODE(S8,BRK): result = EXERES_BRK; break; case OPCODE(S8,MOV): DO_MOV(s8); break; case OPCODE(S8,CMP): DO_CMP(s8); break; case OPCODE(S8,JMP): DO_JMP(s8); break; case OPCODE(S8,JSR): DO_JSR(s8); break; case OPCODE(S8,SLD): DO_SLD(s8); break; case OPCODE(S8,SST): DO_SST(s8); break; case OPCODE(S8,SPH): DO_SPH(s8); break; case OPCODE(S8,SPL): DO_SPL(s8); break; case OPCODE(S8,INC): DO_INC(s8); break; case OPCODE(S8,DEC): DO_DEC(s8); break; case OPCODE(S8,ADD): DO_ADD(s8); break; case OPCODE(S8,SUB): DO_SUB(s8); break; case OPCODE(S8,MUL): DO_MUL(s8); break; case OPCODE(S8,DIV): DO_DIV(s8); break; case OPCODE(S8,MOD): DO_MOD(s8); break; case OPCODE(S8,NEG): DO_NEG(s8); break; case OPCODE(S8,NOT): DO_NOT(s8); break; case OPCODE(S8,NND): DO_NND(s8); break; case OPCODE(S8,AND): DO_AND(s8); break; case OPCODE(S8,NOR): DO_NOR(s8); break; case OPCODE(S8,IOR): DO_IOR(s8); break; case OPCODE(S8,XOR): DO_XOR(s8); break; case OPCODE(S8,SHL): DO_SHL(s8); break; case OPCODE(S8,SHR): DO_SHR(s8); break; case OPCODE(S8,ROL): DO_ROL(s8); break; case OPCODE(S8,ROR): DO_ROR(s8); break; case OPCODE(S8,EXT): DO_EXT(s8, s16); break; case OPCODE(S8,JFN): DO_JFN(s8); break; /*************** OPDATA_U16 ****************/ case OPCODE(U16,BRK): result = EXERES_BRK; break; case OPCODE(U16,MOV): DO_MOV(u16); break; case OPCODE(U16,CMP): DO_CMP(u16); break; case OPCODE(U16,JMP): DO_JMP(u16); break; case OPCODE(U16,JSR): DO_JSR(u16); break; case OPCODE(U16,SLD): DO_SLD(u16); break; case OPCODE(U16,SST): DO_SST(u16); break; case OPCODE(U16,SPH): DO_SPH(u16); break; case OPCODE(U16,SPL): DO_SPL(u16); break; case OPCODE(U16,INC): DO_INC(u16); break; case OPCODE(U16,DEC): DO_DEC(u16); break; case OPCODE(U16,ADD): DO_ADD(u16); break; case OPCODE(U16,SUB): DO_SUB(u16); break; case OPCODE(U16,MUL): DO_MUL(u16); break; case OPCODE(U16,DIV): DO_DIV(u16); break; case OPCODE(U16,MOD): DO_MOD(u16); break; case OPCODE(U16,NEG): DO_NEG(u16); break; case OPCODE(U16,NOT): DO_NOT(u16); break; case OPCODE(U16,NND): DO_NND(u16); break; case OPCODE(U16,AND): DO_AND(u16); break; case OPCODE(U16,NOR): DO_NOR(u16); break; case OPCODE(U16,IOR): DO_IOR(u16); break; case OPCODE(U16,XOR): DO_XOR(u16); break; case OPCODE(U16,SHL): DO_SHL(u16); break; case OPCODE(U16,SHR): DO_SHR(u16); break; case OPCODE(U16,ROL): DO_ROL(u16); break; case OPCODE(U16,ROR): DO_ROR(u16); break; case OPCODE(U16,EXT): DO_EXT(u16, u32); break; case OPCODE(U16,JFN): DO_JFN(u16); break; /*************** OPDATA_S16 ****************/ case OPCODE(S16,BRK): result = EXERES_BRK; break; case OPCODE(S16,MOV): DO_MOV(s16); break; case OPCODE(S16,CMP): DO_CMP(s16); break; case OPCODE(S16,JMP): DO_JMP(s16); break; case OPCODE(S16,JSR): DO_JSR(s16); break; case OPCODE(S16,SLD): DO_SLD(s16); break; case OPCODE(S16,SST): DO_SST(s16); break; case OPCODE(S16,SPH): DO_SPH(s16); break; case OPCODE(S16,SPL): DO_SPL(s16); break; case OPCODE(S16,INC): DO_INC(s16); break; case OPCODE(S16,DEC): DO_DEC(s16); break; case OPCODE(S16,ADD): DO_ADD(s16); break; case OPCODE(S16,SUB): DO_SUB(s16); break; case OPCODE(S16,MUL): DO_MUL(s16); break; case OPCODE(S16,DIV): DO_DIV(s16); break; case OPCODE(S16,MOD): DO_MOD(s16); break; case OPCODE(S16,NEG): DO_NEG(s16); break; case OPCODE(S16,NOT): DO_NOT(s16); break; case OPCODE(S16,NND): DO_NND(s16); break; case OPCODE(S16,AND): DO_AND(s16); break; case OPCODE(S16,NOR): DO_NOR(s16); break; case OPCODE(S16,IOR): DO_IOR(s16); break; case OPCODE(S16,XOR): DO_XOR(s16); break; case OPCODE(S16,SHL): DO_SHL(s16); break; case OPCODE(S16,SHR): DO_SHR(s16); break; case OPCODE(S16,ROL): DO_ROL(s16); break; case OPCODE(S16,ROR): DO_ROR(s16); break; case OPCODE(S16,EXT): DO_EXT(s16, s32); break; case OPCODE(S16,JFN): DO_JFN(s16); break; /*************** OPDATA_U32 ****************/ case OPCODE(U32,BRK): result = EXERES_BRK; break; case OPCODE(U32,MOV): DO_MOV(u32); break; case OPCODE(U32,CMP): DO_CMP(u32); break; case OPCODE(U32,JMP): DO_JMP(u32); break; case OPCODE(U32,JSR): DO_JSR(u32); break; case OPCODE(U32,SLD): DO_SLD(u32); break; case OPCODE(U32,SST): DO_SST(u32); break; case OPCODE(U32,SPH): DO_SPH(u32); break; case OPCODE(U32,SPL): DO_SPL(u32); break; case OPCODE(U32,INC): DO_INC(u32); break; case OPCODE(U32,DEC): DO_DEC(u32); break; case OPCODE(U32,ADD): DO_ADD(u32); break; case OPCODE(U32,SUB): DO_SUB(u32); break; case OPCODE(U32,MUL): DO_MUL(u32); break; case OPCODE(U32,DIV): DO_DIV(u32); break; case OPCODE(U32,MOD): DO_MOD(u32); break; case OPCODE(U32,NEG): DO_NEG(u32); break; case OPCODE(U32,NOT): DO_NOT(u32); break; case OPCODE(U32,NND): DO_NND(u32); break; case OPCODE(U32,AND): DO_AND(u32); break; case OPCODE(U32,NOR): DO_NOR(u32); break; case OPCODE(U32,IOR): DO_IOR(u32); break; case OPCODE(U32,XOR): DO_XOR(u32); break; case OPCODE(U32,SHL): DO_SHL(u32); break; case OPCODE(U32,SHR): DO_SHR(u32); break; case OPCODE(U32,ROL): DO_ROL(u32); break; case OPCODE(U32,ROR): DO_ROR(u32); break; case OPCODE(U32,EXT): goto _lbl_NOP; //can't extend past 32b case OPCODE(U32,JFN): DO_JFN(u32); break; /*************** OPDATA_S32 ****************/ case OPCODE(S32,BRK): result = EXERES_BRK; break; case OPCODE(S32,MOV): DO_MOV(s32); break; case OPCODE(S32,CMP): DO_CMP(s32); break; case OPCODE(S32,JMP): DO_JMP(s32); break; case OPCODE(S32,JSR): DO_JSR(s32); break; case OPCODE(S32,SLD): DO_SLD(s32); break; case OPCODE(S32,SST): DO_SST(s32); break; case OPCODE(S32,SPH): DO_SPH(s32); break; case OPCODE(S32,SPL): DO_SPL(s32); break; case OPCODE(S32,INC): DO_INC(s32); break; case OPCODE(S32,DEC): DO_DEC(s32); break; case OPCODE(S32,ADD): DO_ADD(s32); break; case OPCODE(S32,SUB): DO_SUB(s32); break; case OPCODE(S32,MUL): DO_MUL(s32); break; case OPCODE(S32,DIV): DO_DIV(s32); break; case OPCODE(S32,MOD): DO_MOD(s32); break; case OPCODE(S32,NEG): DO_NEG(s32); break; case OPCODE(S32,NOT): DO_NOT(s32); break; case OPCODE(S32,NND): DO_NND(s32); break; case OPCODE(S32,AND): DO_AND(s32); break; case OPCODE(S32,NOR): DO_NOR(s32); break; case OPCODE(S32,IOR): DO_IOR(s32); break; case OPCODE(S32,XOR): DO_XOR(s32); break; case OPCODE(S32,SHL): DO_SHL(s32); break; case OPCODE(S32,SHR): DO_SHR(s32); break; case OPCODE(S32,ROL): DO_ROL(s32); break; case OPCODE(S32,ROR): DO_ROR(s32); break; case OPCODE(S32,EXT): goto _lbl_NOP; //can't extend past 32b case OPCODE(S32,JFN): DO_JFN(s32); break; /*************** OPDATA_IMP ****************/ #define ZN_U32 SET_FLAGS_ZN(dst->u32); #define ZN_S32 SET_FLAGS_ZN(dst->s32); #define ZN_F32 { \ flags_zero = dst->f32 == 0.0f; \ flags_negative = dst->f32 < 0.0f; } //(branches have -4 applied to them when src is immediate, //because OPDATA_IMP defaults to 32-bits when using an //immediate value, even though branches only use s16) #define src_imm16 s16 src_s16; { \ if(ins.src == OPADDR_IMM){ src_s16 = *(((s16*)src)-1); regs_pc-=4; } \ else { src_s16 = * ((s16*)src) ; } } #define src_imm16_u u16 src_u16; { \ if(ins.src == OPADDR_IMM){ src_u16 = *(((u16*)src)-1); regs_pc-=4; } \ else { src_u16 = * ((u16*)src) ; } } case OPCODE(IMP,NOP): _lbl_NOP: { result = EXERES_NOP; #ifdef _DEBUG kit_LogInfo( "\ r0=0x%08X, r1=0x%08X, r2=0x%08X, r3=0x%08X, r4=0x%08X, r5=0x%08X, sp=0x%08X, flg=0b%08X, pc=0x%08X\ ", regs[0].u32, regs[1].u32, regs[2].u32, regs[3].u32, regs[4].u32, regs[5].u32, regs_sp.u32, bin_hex(regs_flags.u8), regs_pc ); #endif /* _DEBUG */ } break; case OPCODE(IMP,SRT): { dst->f32 = sqrtf(src->f32); ZN_F32 } break; case OPCODE(IMP,CPU): { src_imm16_u cpuid(src_u16); } break; case OPCODE(IMP,SYS): { src_imm16_u syscall(src_u16); } break; case OPCODE(IMP,BNC): { src_imm16 if(!flags_negative){ regs_pc += src_s16; } } break; case OPCODE(IMP,BNS): { src_imm16 if( flags_negative){ regs_pc += src_s16; } } break; case OPCODE(IMP,BZC): { src_imm16 if(!flags_zero ){ regs_pc += src_s16; } } break; case OPCODE(IMP,BZS): { src_imm16 if( flags_zero ){ regs_pc += src_s16; } } break; case OPCODE(IMP,BLT): { src_imm16 if(CMP_LT){ regs_pc += src_s16; } } break; case OPCODE(IMP,BGT): { src_imm16 if(CMP_GT){ regs_pc += src_s16; } } break; case OPCODE(IMP,BLE): { src_imm16 if(CMP_LE){ regs_pc += src_s16; } } break; case OPCODE(IMP,BGE): { src_imm16 if(CMP_GE){ regs_pc += src_s16; } } break; case OPCODE(IMP,BNE): { src_imm16 if(CMP_NE){ regs_pc += src_s16; } } break; case OPCODE(IMP,BEQ): { src_imm16 if(CMP_EQ){ regs_pc += src_s16; } } break; case OPCODE(IMP,JNC): { if(!flags_negative){ regs_pc = src->u32; } } break; case OPCODE(IMP,JNS): { if( flags_negative){ regs_pc = src->u32; } } break; case OPCODE(IMP,JZC): { if(!flags_zero ){ regs_pc = src->u32; } } break; case OPCODE(IMP,JZS): { if( flags_zero ){ regs_pc = src->u32; } } break; case OPCODE(IMP,JLT): { if(CMP_LT){ regs_pc = src->u32; } } break; case OPCODE(IMP,JGT): { if(CMP_GT){ regs_pc = src->u32; } } break; case OPCODE(IMP,JLE): { if(CMP_LE){ regs_pc = src->u32; } } break; case OPCODE(IMP,JGE): { if(CMP_GE){ regs_pc = src->u32; } } break; case OPCODE(IMP,JNE): { if(CMP_NE){ regs_pc = src->u32; } } break; case OPCODE(IMP,JEQ): { if(CMP_EQ){ regs_pc = src->u32; } } break; case OPCODE(IMP,U2B): { dst->u32 = to_bcd(src->u32); ZN_U32 } break; case OPCODE(IMP,B2U): { dst->u32 = from_bcd(src->u32); ZN_U32 } break; case OPCODE(IMP,I2F): { dst->f32 = (f32)src->s32; ZN_F32 } break; case OPCODE(IMP,F2I): { dst->s32 = (s32)src->f32; ZN_S32 } break; case OPCODE(IMP,RTS): { regs_pc = STACK_PULL(u32); } break; case OPCODE(IMP,BRA): { src_imm16 regs_pc += src_s16; } break; case OPCODE(IMP,RSI): { src_imm16 regs_pc = *ADDR(u32, regs_sp.u32); regs_sp.u32 += src_s16; } break; case OPCODE(IMP,RFN): { u32* stack = ADDR(u32, regs_sp.u32); regs_pc = stack[0]; regs_gp[5].u32 = stack[1]; regs_gp[4].u32 = stack[2]; regs_gp[3].u32 = stack[3]; regs_gp[2].u32 = stack[4]; regs_gp[1].u32 = stack[5]; regs_sp.u32 += sizeof(u32)*6; } break; /*************** OPDATA_F32 ****************/ #undef SET_FLAGS_ZN #define SET_FLAGS_ZN(_) ZN_F32 #define DO_MOD_F32 { dst->f32 = fmodf(dst->f32, src->f32); ZN_F32 } case OPCODE(F32,BRK): result = EXERES_BRK; break; case OPCODE(F32,MOV): DO_MOV(f32); break; case OPCODE(F32,CMP): DO_CMP(f32); break; case OPCODE(F32,JMP): DO_JMP(f32); break; case OPCODE(F32,JSR): DO_JSR(f32); break; case OPCODE(F32,SLD): DO_SLD(f32); break; case OPCODE(F32,SST): DO_SST(f32); break; case OPCODE(F32,SPH): DO_SPH(f32); break; case OPCODE(F32,SPL): DO_SPL(f32); break; case OPCODE(F32,INC): DO_INC(f32); break; case OPCODE(F32,DEC): DO_DEC(f32); break; case OPCODE(F32,ADD): DO_ADD(f32); break; case OPCODE(F32,SUB): DO_SUB(f32); break; case OPCODE(F32,MUL): DO_MUL(f32); break; case OPCODE(F32,DIV): DO_DIV(f32); break; case OPCODE(F32,MOD): DO_MOD_F32 ; break; case OPCODE(F32,NEG): DO_NEG(f32); break; case OPCODE(F32,NOT): ATTR_FALLTHROUGH; case OPCODE(F32,NND): ATTR_FALLTHROUGH; case OPCODE(F32,AND): ATTR_FALLTHROUGH; case OPCODE(F32,NOR): ATTR_FALLTHROUGH; case OPCODE(F32,IOR): ATTR_FALLTHROUGH; case OPCODE(F32,XOR): ATTR_FALLTHROUGH; case OPCODE(F32,SHL): ATTR_FALLTHROUGH; case OPCODE(F32,SHR): ATTR_FALLTHROUGH; case OPCODE(F32,ROL): ATTR_FALLTHROUGH; case OPCODE(F32,ROR): ATTR_FALLTHROUGH; case OPCODE(F32,EXT): goto _lbl_NOP; case OPCODE(F32,JFN): DO_JFN(f32); break; default: result = EXERES_ILLEGAL; break; } return result; } void cpu32::cpuid(u16 type){ (void)type; //tbd } }; /* namespace kit */