mirror of
				https://github.com/RetroDECK/Duckstation.git
				synced 2025-04-10 19:15:14 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			145 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			145 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # Biscuit: RISC-V Runtime Code Generation Library
 | |
| 
 | |
| *RISC it for the biscuit*
 | |
| 
 | |
| ## About
 | |
| 
 | |
| An experimental runtime code generator for RISC-V.
 | |
| 
 | |
| This allows for runtime code generation of RISC-V instructions. Similar
 | |
| to how [Xbyak](https://github.com/herumi/xbyak) allows for runtime code generation of x86 instructions.
 | |
| 
 | |
| 
 | |
| ## Implemented ISA Features
 | |
| 
 | |
| Includes both 32-bit and 64-bit instructions in the following:
 | |
| 
 | |
| | Feature   | Version |
 | |
| |:----------|:-------:|
 | |
| | A         | 2.1     |
 | |
| | B         | 1.0     |
 | |
| | C         | 2.0     |
 | |
| | D         | 2.2     |
 | |
| | F         | 2.2     |
 | |
| | H         | 1.0 RC  |
 | |
| | K         | 1.0.1   |
 | |
| | M         | 2.0     |
 | |
| | N         | 1.1     |
 | |
| | Q         | 2.2     |
 | |
| | RV32I     | 2.1     |
 | |
| | RV64I     | 2.1     |
 | |
| | S         | 1.12    |
 | |
| | V         | 1.0     |
 | |
| | Sstc      | 0.5.4   |
 | |
| | Zfh       | 1.0     |
 | |
| | Zfhmin    | 1.0     |
 | |
| | Zicbom    | 1.0     |
 | |
| | Zicbop    | 1.0     |
 | |
| | Zicboz    | 1.0     |
 | |
| | Zicsr     | 2.0     |
 | |
| | Zifencei  | 2.0     |
 | |
| | Zihintntl | 0.2     |
 | |
| 
 | |
| Note that usually only extensions considered ratified will be implemented
 | |
| as non-ratified documents are considerably more likely to have
 | |
| large changes made to them, which makes maintaining instruction
 | |
| APIs a little annoying.
 | |
| 
 | |
| 
 | |
| ## Dependencies
 | |
| 
 | |
| Biscuit requires no external dependencies for its library other than the C++ standard library. 
 | |
| The tests, however, use the Catch2 testing library. This is included in tree so there's no need
 | |
| to worry about installing it yourself if you wish to run said tests.
 | |
| 
 | |
| 
 | |
| ## Building Biscuit
 | |
| 
 | |
| 1. Generate the build files for the project with CMake
 | |
| 2. Hit the build button in your IDE of choice, or run the relevant console command to build for the CMake generator you've chosen.
 | |
| 3. Done.
 | |
| 
 | |
| 
 | |
| ## Running Tests
 | |
| 
 | |
| 1. Generate the build files for the project with CMake
 | |
| 2. Build the tests
 | |
| 3. Run the test executable directly, or enter `ctest` into your terminal.
 | |
| 
 | |
| 
 | |
| ## License
 | |
| 
 | |
| The library is licensed under the MIT license.
 | |
| 
 | |
| While it's not a requirement whatsoever, it'd be pretty neat if you told me that you found the library useful :-)
 | |
| 
 | |
| 
 | |
| ## Example
 | |
| 
 | |
| The following is an adapted equivalent of the `strlen` implementation within the RISC-V bit manipulation extension specification.
 | |
| For brevity, it has been condensed to only handle little-endian platforms.
 | |
| 
 | |
| ```cpp
 | |
| // We prepare some contiguous buffer and give the pointer to the beginning
 | |
| // of the data and the total size of the buffer in bytes to the assembler.
 | |
| 
 | |
| void strlen_example(uint8_t* buffer, size_t buffer_size) {
 | |
|     using namespace biscuit;
 | |
| 
 | |
|     constexpr int ptrlog = 3;
 | |
|     constexpr int szreg  = 8;
 | |
| 
 | |
|     Assembler as(buffer, buffer_size);
 | |
|     Label done;
 | |
|     Label loop;
 | |
| 
 | |
|     as.ANDI(a3, a0, szreg - 1); // Offset
 | |
|     as.ANDI(a1, a0, 0xFF8);     // Align pointer
 | |
| 
 | |
|     as.LI(a4, szreg);
 | |
|     as.SUB(a4, a4, a3);         // XLEN - offset
 | |
|     as.SLLI(a3, a3, ptrlog);    // offset * 8
 | |
|     as.LD(a2, 0, a1);           // Chunk
 | |
| 
 | |
|     //
 | |
|     // Shift the partial/unaligned chunk we loaded to remove the bytes
 | |
|     // from before the start of the string, adding NUL bytes at the end.
 | |
|     //
 | |
|     as.SRL(a2, a2, a3);         // chunk >> (offset * 8)
 | |
|     as.ORCB(a2, a2);
 | |
|     as.NOT(a2, a2);
 | |
| 
 | |
|     // Non-NUL bytes in the string have been expanded to 0x00, while
 | |
|     // NUL bytes have become 0xff. Search for the first set bit
 | |
|     // (corresponding to a NUL byte in the original chunk).
 | |
|     as.CTZ(a2, a2);
 | |
| 
 | |
|     // The first chunk is special: compare against the number of valid
 | |
|     // bytes in this chunk.
 | |
|     as.SRLI(a0, a2, 3);
 | |
|     as.BGTU(a4, a0, &done);
 | |
|     as.ADDI(a3, a1, szreg);
 | |
|     as.LI(a4, -1);
 | |
| 
 | |
|     // Our critical loop is 4 instructions and processes data in 4 byte
 | |
|     // or 8 byte chunks.
 | |
|     as.Bind(&loop);
 | |
| 
 | |
|     as.LD(a2, szreg, a1);
 | |
|     as.ADDI(a1, a1, szreg);
 | |
|     as.ORCB(a2, a2);
 | |
|     as.BEQ(a2, a4, &loop);
 | |
| 
 | |
|     as.NOT(a2, a2);
 | |
|     as.CTZ(a2, a2);
 | |
|     as.SUB(a1, a1, a3);
 | |
|     as.ADD(a0, a0, a1);
 | |
|     as.SRLI(a2, a2, 3);
 | |
|     as.ADD(a0, a0, a2);
 | |
| 
 | |
|     as.Bind(&done);
 | |
| 
 | |
|     as.RET();
 | |
| }
 | |
| ```
 | 
