Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /******************************************************************************/
- /******************************************************************************/
- //"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<<KE_SHIFT_REPEAT ;will set zero flag if repeat bit is unset
- bzc #SUB_get_vkey_down ;try again if event is a repeat
- and.u32 r0, #KE_MASK_VKEY ;only observe the virtual key code
- .e: rts
- ;; draws score and the black bar at the bottom
- ;;
- ;; params: none
- ;; returns: none
- ;; clobbers: none
- FUN_draw_score:
- sph.u32 r0
- mov.u32 r0, #0xFF000000
- sys #SYSCALL_SETDRAWCOLOR
- mov.u32 r0, #0 ;x = 0 ;(previously an ext)
- mov.s32 r1, #SCREEN_H ;y = <last play area pixel> + 1
- mov.u32 r2, #SCREEN_W ;w
- mov.u32 r3, #144-SCREEN_H ;h = <total height>-<play area height>
- sys #SYSCALL_FILLRECT_S32
- mov.s32 r2, #CENTERED_TEXT ;x
- inc.s32 r1 ;y = <last play area pixel> + 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 <include_all.hpp>
- 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<dst_len; ++i){
- //clamp the samples so that they aren't out of bounds
- dst[i].l = CLAMP(dst[i].l, -1.0f, 1.0f);
- dst[i].r = CLAMP(dst[i].r, -1.0f, 1.0f);
- }
- return 0;
- }
- /******************************************************************************/
- /******************************************************************************/
- //"sokoban_and_kit32_2025-01-31\kit32\simulator\src\kit_32_cpu.cpp":
- #include <include_all.hpp>
- #include <cmath> //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)<<shift;
- value /= 10;
- shift += 4;
- }
- return result;
- }
- static inline u32 from_bcd(bcd value){
- u32 result;
- result = MIN(value.d0,9)/* 1*/;
- result += MIN(value.d1,9) * 10;
- result += MIN(value.d2,9) * 100;
- result += MIN(value.d3,9) * 1000;
- result += MIN(value.d4,9) * 10000;
- result += MIN(value.d5,9) * 100000;
- result += MIN(value.d6,9) * 1000000;
- result += MIN(value.d7,9) * 10000000;
- return result;
- }
- s32 cpu32::execute(){
- s32 result = EXERES_SUCCESS;
- reg32* src, *dst;
- //instructions are supposed to be memory-aligned to 4 bytes
- //(hence the "&(~0b11)"), however that behavior is undefined,
- //and the idiot check isn't strictly necessary.
- //maybe if i actually implement this on an fpga i'll enforce it
- //regs_pc &= ADDRESS_LIMIT&(~0b11);
- ins32 ins = *ADDR(ins32, regs_pc);
- regs_pc += sizeof(ins32);
- //if source is a normal register
- if(ins.src < OPADDR_IMM)
- {
- src = regs + ins.src;
- }
- //if ins.src == OPADDR_IMM, src will be set to either &ins.v_u16...
- else if((ins.op_dtype < 2) /*||
- (ins.op_type >= 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 */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement