Memory interface is now MMIO-capable
This commit is contained in:
		@@ -4,7 +4,6 @@
 | 
				
			|||||||
#include "devices/sbi/sbi.h"
 | 
					#include "devices/sbi/sbi.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "memory/memory.h"
 | 
					#include "memory/memory.h"
 | 
				
			||||||
#include "memory/mmu/mmu.h"
 | 
					 | 
				
			||||||
#include "vriscv.h"
 | 
					#include "vriscv.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
@@ -210,27 +209,27 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction)
 | 
				
			|||||||
			{
 | 
								{
 | 
				
			||||||
				case FUNC3_LB:
 | 
									case FUNC3_LB:
 | 
				
			||||||
					// Load Byte (8-bits)
 | 
										// Load Byte (8-bits)
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = memory[mmu_translate(address)];
 | 
										cpu->regs.x[instruction->rd] = mem_read8(address);
 | 
				
			||||||
					// Sign extend from 8 bits to 32 bits
 | 
										// Sign extend from 8 bits to 32 bits
 | 
				
			||||||
					cpu->regs.x[instruction->rd] |= (cpu->regs.x[instruction->rd] & 0x80 ? 0xFFFFFF00 : 0);
 | 
										cpu->regs.x[instruction->rd] |= (cpu->regs.x[instruction->rd] & 0x80 ? 0xFFFFFF00 : 0);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC3_LH:
 | 
									case FUNC3_LH:
 | 
				
			||||||
					// Load Halfword (16-bits)
 | 
										// Load Halfword (16-bits)
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = *((uint16_t*) &memory[mmu_translate(address)]);
 | 
										cpu->regs.x[instruction->rd] = mem_read16(address);
 | 
				
			||||||
					// Sign extend from 16 bits to 32 bits
 | 
										// Sign extend from 16 bits to 32 bits
 | 
				
			||||||
					cpu->regs.x[instruction->rd] |= (cpu->regs.x[instruction->rd] & 0x8000 ? 0xFFFF0000 : 0);
 | 
										cpu->regs.x[instruction->rd] |= (cpu->regs.x[instruction->rd] & 0x8000 ? 0xFFFF0000 : 0);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC3_LW:
 | 
									case FUNC3_LW:
 | 
				
			||||||
					// Load Word (32-bits)
 | 
										// Load Word (32-bits)
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = *((uint32_t*) &memory[mmu_translate(address)]);
 | 
										cpu->regs.x[instruction->rd] = mem_read32(address);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC3_LBU:
 | 
									case FUNC3_LBU:
 | 
				
			||||||
					// Load Byte Unsigned (8-bits)
 | 
										// Load Byte Unsigned (8-bits)
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = memory[mmu_translate(address)];
 | 
										cpu->regs.x[instruction->rd] = mem_read8(address);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC3_LHU:
 | 
									case FUNC3_LHU:
 | 
				
			||||||
					// Load Halfword Unsigned (16-bits)
 | 
										// Load Halfword Unsigned (16-bits)
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = *((uint16_t*) &memory[mmu_translate(address)]);
 | 
										cpu->regs.x[instruction->rd] = mem_read16(address);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
					fprintf(stderr, "FATAL: Unknown func3 0x%x for load instruction, could not execute\n", instruction->func3);
 | 
										fprintf(stderr, "FATAL: Unknown func3 0x%x for load instruction, could not execute\n", instruction->func3);
 | 
				
			||||||
@@ -250,15 +249,15 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction)
 | 
				
			|||||||
			{
 | 
								{
 | 
				
			||||||
				case FUNC3_SB:
 | 
									case FUNC3_SB:
 | 
				
			||||||
					// Store Byte (8-bits)
 | 
										// Store Byte (8-bits)
 | 
				
			||||||
					memory[mmu_translate(address)] = cpu->regs.x[instruction->rs2] & 0xFF;
 | 
										mem_write8(address, cpu->regs.x[instruction->rs2] & 0xFF);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC3_SH:
 | 
									case FUNC3_SH:
 | 
				
			||||||
					// Store Halfword (16-bits)
 | 
										// Store Halfword (16-bits)
 | 
				
			||||||
					*((uint16_t*) &memory[mmu_translate(address)]) = cpu->regs.x[instruction->rs2] & 0xFFFF;
 | 
										mem_write16(address, cpu->regs.x[instruction->rs2] & 0xFFFF);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC3_SW:
 | 
									case FUNC3_SW:
 | 
				
			||||||
					// Store Word (32-bits)
 | 
										// Store Word (32-bits)
 | 
				
			||||||
					*((uint32_t*) &memory[mmu_translate(address)]) = cpu->regs.x[instruction->rs2];
 | 
										mem_write32(address, cpu->regs.x[instruction->rs2]);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
					fprintf(stderr, "FATAL: Unknown func3 0x%x for store instruction, could not execute\n", instruction->func3);
 | 
										fprintf(stderr, "FATAL: Unknown func3 0x%x for store instruction, could not execute\n", instruction->func3);
 | 
				
			||||||
@@ -588,77 +587,76 @@ static void cpu_execute(rv32_cpu_t* cpu, instruction_t* instruction)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			// FUNC7 contains 2 flag bits in lower part ; ignore them, we look for func7_5
 | 
								// FUNC7 contains 2 flag bits in lower part ; ignore them, we look for func7_5
 | 
				
			||||||
			uint32_t address = cpu->regs.x[instruction->rs1];
 | 
								uint32_t address = cpu->regs.x[instruction->rs1];
 | 
				
			||||||
			uint32_t* ptr = ((uint32_t*) &memory[mmu_translate(address)]);
 | 
					 | 
				
			||||||
			switch(instruction->func7 >> 2)
 | 
								switch(instruction->func7 >> 2)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				case FUNC75_LRW:
 | 
									case FUNC75_LRW:
 | 
				
			||||||
					// Load-Reserved Word
 | 
										// Load-Reserved Word
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = *ptr;
 | 
										cpu->regs.x[instruction->rd] = mem_read32(address);
 | 
				
			||||||
					// TODO register reservation set that subsumes the bytes in word
 | 
										// TODO register reservation set that subsumes the bytes in word
 | 
				
			||||||
					fprintf(stderr, "LR.W\n");
 | 
										fprintf(stderr, "LR.W\n");
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC75_SCW:
 | 
									case FUNC75_SCW:
 | 
				
			||||||
					// Store-Conditional Word
 | 
										// Store-Conditional Word
 | 
				
			||||||
					// TODO succeed only if the reservation is still valid and the reservation set contains the bytes written
 | 
										// TODO succeed only if the reservation is still valid and the reservation set contains the bytes written
 | 
				
			||||||
					*ptr = cpu->regs.x[instruction->rs2];
 | 
										mem_write32(address, cpu->regs.x[instruction->rs2]);
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = 0; // TODO write 1 in rd on failure
 | 
										cpu->regs.x[instruction->rd] = 0; // TODO write 1 in rd on failure
 | 
				
			||||||
					fprintf(stderr, "SC.W\n");
 | 
										fprintf(stderr, "SC.W\n");
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC75_AMOSWAPW:
 | 
									case FUNC75_AMOSWAPW:
 | 
				
			||||||
					// Atomic Memory Operation SWAP Word
 | 
										// Atomic Memory Operation SWAP Word
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = *ptr;
 | 
										cpu->regs.x[instruction->rd] = mem_read32(address);
 | 
				
			||||||
					// Put in RS1 addr the value of RS2
 | 
										// Put in RS1 addr the value of RS2
 | 
				
			||||||
					*ptr = cpu->regs.x[instruction->rs2];
 | 
										mem_write32(address, cpu->regs.x[instruction->rs2]);
 | 
				
			||||||
					// Put in RS2 the value of RS1 addr (which is in RD)
 | 
										// Put in RS2 the value of RS1 addr (which is in RD)
 | 
				
			||||||
					cpu->regs.x[instruction->rs2] = cpu->regs.x[instruction->rd];
 | 
										cpu->regs.x[instruction->rs2] = cpu->regs.x[instruction->rd];
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC75_AMOADDW:
 | 
									case FUNC75_AMOADDW:
 | 
				
			||||||
					// Atomic Memory Operation ADD Word
 | 
										// Atomic Memory Operation ADD Word
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = *ptr;
 | 
										cpu->regs.x[instruction->rd] = mem_read32(address);
 | 
				
			||||||
					// Add rs1 addr and value of rs2
 | 
										// Add rs1 addr and value of rs2
 | 
				
			||||||
					*ptr = cpu->regs.x[instruction->rd] + cpu->regs.x[instruction->rs2];
 | 
										mem_write32(address, cpu->regs.x[instruction->rd] + cpu->regs.x[instruction->rs2]);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC75_AMOXORW:
 | 
									case FUNC75_AMOXORW:
 | 
				
			||||||
					// Atomic Memory Operation XOR Word
 | 
										// Atomic Memory Operation XOR Word
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = *ptr;
 | 
										cpu->regs.x[instruction->rd] = mem_read32(address);
 | 
				
			||||||
					// Xor rs1 addr and value of rs2
 | 
										// Xor rs1 addr and value of rs2
 | 
				
			||||||
					*ptr = cpu->regs.x[instruction->rd] ^ cpu->regs.x[instruction->rs2];
 | 
										mem_write32(address, cpu->regs.x[instruction->rd] ^ cpu->regs.x[instruction->rs2]);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC75_AMOANDW:
 | 
									case FUNC75_AMOANDW:
 | 
				
			||||||
					// Atomic Memory Operation AND Word
 | 
										// Atomic Memory Operation AND Word
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = *ptr;
 | 
										cpu->regs.x[instruction->rd] = mem_read32(address);
 | 
				
			||||||
					// AND rs1 addr and value of rs2
 | 
										// AND rs1 addr and value of rs2
 | 
				
			||||||
					*ptr = cpu->regs.x[instruction->rd] & cpu->regs.x[instruction->rs2];
 | 
										mem_write32(address, cpu->regs.x[instruction->rd] & cpu->regs.x[instruction->rs2]);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC75_AMOORW:
 | 
									case FUNC75_AMOORW:
 | 
				
			||||||
					// Atomic Memory Operation OR Word
 | 
										// Atomic Memory Operation OR Word
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = *ptr;
 | 
										cpu->regs.x[instruction->rd] = mem_read32(address);
 | 
				
			||||||
					// Or rs1 addr and value of rs2
 | 
										// Or rs1 addr and value of rs2
 | 
				
			||||||
					*ptr = cpu->regs.x[instruction->rd] | cpu->regs.x[instruction->rs2];
 | 
										mem_write32(address, cpu->regs.x[instruction->rd] | cpu->regs.x[instruction->rs2]);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC75_AMOMINW:
 | 
									case FUNC75_AMOMINW:
 | 
				
			||||||
					// Atomic Memory Operation MIN Word
 | 
										// Atomic Memory Operation MIN Word
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = *ptr;
 | 
										cpu->regs.x[instruction->rd] = mem_read32(address);
 | 
				
			||||||
					// Min rs1 addr and value of rs2
 | 
										// Min rs1 addr and value of rs2
 | 
				
			||||||
					*ptr = ((int32_t) cpu->regs.x[instruction->rd]) < ((int32_t) cpu->regs.x[instruction->rs2]) ? cpu->regs.x[instruction->rd] : cpu->regs.x[instruction->rs2];
 | 
										mem_write32(address, ((int32_t) cpu->regs.x[instruction->rd]) < ((int32_t) cpu->regs.x[instruction->rs2]) ? cpu->regs.x[instruction->rd] : cpu->regs.x[instruction->rs2]);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC75_AMOMAXW:
 | 
									case FUNC75_AMOMAXW:
 | 
				
			||||||
					// Atomic Memory Operation MAX Word
 | 
										// Atomic Memory Operation MAX Word
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = *ptr;
 | 
										cpu->regs.x[instruction->rd] = mem_read32(address);
 | 
				
			||||||
					// Max rs1 addr and value of rs2
 | 
										// Max rs1 addr and value of rs2
 | 
				
			||||||
					*ptr = ((int32_t) cpu->regs.x[instruction->rd]) > ((int32_t) cpu->regs.x[instruction->rs2]) ? cpu->regs.x[instruction->rd] : cpu->regs.x[instruction->rs2];
 | 
										mem_write32(address, ((int32_t) cpu->regs.x[instruction->rd]) > ((int32_t) cpu->regs.x[instruction->rs2]) ? cpu->regs.x[instruction->rd] : cpu->regs.x[instruction->rs2]);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC75_AMOMINUW:
 | 
									case FUNC75_AMOMINUW:
 | 
				
			||||||
					// Atomic Memory Operation MIN Unsigned Word
 | 
										// Atomic Memory Operation MIN Unsigned Word
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = *ptr;
 | 
										cpu->regs.x[instruction->rd] = mem_read32(address);
 | 
				
			||||||
					// Min rs1 addr and value of rs2
 | 
										// Min rs1 addr and value of rs2
 | 
				
			||||||
					*ptr = cpu->regs.x[instruction->rd] < cpu->regs.x[instruction->rs2] ? cpu->regs.x[instruction->rd] : cpu->regs.x[instruction->rs2];
 | 
										mem_write32(address, cpu->regs.x[instruction->rd] < cpu->regs.x[instruction->rs2] ? cpu->regs.x[instruction->rd] : cpu->regs.x[instruction->rs2]);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case FUNC75_AMOMAXUW:
 | 
									case FUNC75_AMOMAXUW:
 | 
				
			||||||
					// Atomic Memory Operation MAX Unsigned Word
 | 
										// Atomic Memory Operation MAX Unsigned Word
 | 
				
			||||||
					cpu->regs.x[instruction->rd] = *ptr;
 | 
										cpu->regs.x[instruction->rd] = mem_read32(address);
 | 
				
			||||||
					// Max rs1 addr and value of rs2
 | 
										// Max rs1 addr and value of rs2
 | 
				
			||||||
					*ptr = cpu->regs.x[instruction->rd] > cpu->regs.x[instruction->rs2] ? cpu->regs.x[instruction->rd] : cpu->regs.x[instruction->rs2];
 | 
										mem_write32(address, cpu->regs.x[instruction->rd] > cpu->regs.x[instruction->rs2] ? cpu->regs.x[instruction->rd] : cpu->regs.x[instruction->rs2]);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
					fprintf(stderr, "FATAL: Unknown func7 0x%x for ATOMIC/0x2 instruction, could not execute\n", instruction->func7);
 | 
										fprintf(stderr, "FATAL: Unknown func7 0x%x for ATOMIC/0x2 instruction, could not execute\n", instruction->func7);
 | 
				
			||||||
@@ -688,7 +686,7 @@ void cpu_loop(rv32_cpu_t* cpu)
 | 
				
			|||||||
		while(!cpu->sim_ticks_left)
 | 
							while(!cpu->sim_ticks_left)
 | 
				
			||||||
			pthread_cond_wait(&cpu0->sim_condition, &cpu0_mutex);
 | 
								pthread_cond_wait(&cpu0->sim_condition, &cpu0_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pthread_mutex_lock(&memory_mutex);
 | 
							// pthread_mutex_lock(&memory_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Fetch
 | 
							// Fetch
 | 
				
			||||||
		raw_instruction_t raw_instruction;
 | 
							raw_instruction_t raw_instruction;
 | 
				
			||||||
@@ -723,7 +721,7 @@ void cpu_loop(rv32_cpu_t* cpu)
 | 
				
			|||||||
			cpu->sim_ticks_left--;
 | 
								cpu->sim_ticks_left--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Let go of cpu and memory mutex
 | 
							// Let go of cpu and memory mutex
 | 
				
			||||||
		pthread_mutex_unlock(&memory_mutex);
 | 
							// pthread_mutex_unlock(&memory_mutex);
 | 
				
			||||||
		pthread_mutex_unlock(&cpu0_mutex);
 | 
							pthread_mutex_unlock(&cpu0_mutex);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "cpu/rv32cpu.h"
 | 
					#include "cpu/rv32cpu.h"
 | 
				
			||||||
#include "memory/memory.h"
 | 
					#include "memory/memory.h"
 | 
				
			||||||
#include "memory/mmu/mmu.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
@@ -259,19 +258,13 @@ void gdbstub_thread_gdb()
 | 
				
			|||||||
			uint32_t length;
 | 
								uint32_t length;
 | 
				
			||||||
			sscanf(packet + 1, "%x,%x", &address, &length);
 | 
								sscanf(packet + 1, "%x,%x", &address, &length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Aquire memory mutex
 | 
					 | 
				
			||||||
			pthread_mutex_lock(&memory_mutex);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			char data[length * 2 + 1];
 | 
								char data[length * 2 + 1];
 | 
				
			||||||
			for(size_t i = 0; i < length; i++)
 | 
								for(size_t i = 0; i < length; i++)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				uint32_t value = memory[mmu_translate(address + i)];
 | 
									uint32_t value = mem_read32(address + i);
 | 
				
			||||||
				snprintf(data + i * 2, 3, "%02x", value);
 | 
									snprintf(data + i * 2, 3, "%02x", value);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Let go of memory mutex
 | 
					 | 
				
			||||||
			pthread_mutex_unlock(&memory_mutex);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			gdbstub_send_packet(data, length * 2);
 | 
								gdbstub_send_packet(data, length * 2);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else if(packet[0] == 'M')
 | 
							else if(packet[0] == 'M')
 | 
				
			||||||
@@ -286,19 +279,13 @@ void gdbstub_thread_gdb()
 | 
				
			|||||||
				data_start++;
 | 
									data_start++;
 | 
				
			||||||
			data_start++;
 | 
								data_start++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Aquire memory mutex
 | 
					 | 
				
			||||||
			pthread_mutex_lock(&memory_mutex);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			for(size_t i = 0; i < length; i++)
 | 
								for(size_t i = 0; i < length; i++)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				uint32_t value;
 | 
									uint32_t value;
 | 
				
			||||||
				sscanf(packet + data_start + i * 2, "%02x", &value);
 | 
									sscanf(packet + data_start + i * 2, "%02x", &value);
 | 
				
			||||||
				memory[mmu_translate(address + i)] = value;
 | 
									mem_write32(address + i, value);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Let go of memory mutex
 | 
					 | 
				
			||||||
			pthread_mutex_unlock(&memory_mutex);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			gdbstub_send_packet("OK", 2);
 | 
								gdbstub_send_packet("OK", 2);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else if(packet[0] == 's')
 | 
							else if(packet[0] == 's')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,8 +4,209 @@
 | 
				
			|||||||
uint8_t* memory;
 | 
					uint8_t* memory;
 | 
				
			||||||
pthread_mutex_t memory_mutex;
 | 
					pthread_mutex_t memory_mutex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MMIO_INSIDE(io, addr) (addr >= io->address && addr < io->address + (io->reg_size * io->reg_count))
 | 
				
			||||||
 | 
					struct MMIO_ENTRY
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint32_t address;
 | 
				
			||||||
 | 
						uint32_t reg_size;
 | 
				
			||||||
 | 
						uint32_t reg_count;
 | 
				
			||||||
 | 
						void* fn_write;
 | 
				
			||||||
 | 
						void* fn_read;
 | 
				
			||||||
 | 
						struct MMIO_ENTRY* next;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					struct MMIO_ENTRY* mmio = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mem_init()
 | 
					void mem_init()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	memory = malloc(memory_size);
 | 
						memory = malloc(memory_size);
 | 
				
			||||||
	pthread_mutex_init(&memory_mutex, 0);
 | 
						pthread_mutex_init(&memory_mutex, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mem_register_mmio(uint32_t address, uint32_t reg_size, uint32_t reg_count, void* fn_write, void* fn_read)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct MMIO_ENTRY** current = &mmio;
 | 
				
			||||||
 | 
						while(*current)
 | 
				
			||||||
 | 
							current = &(*current)->next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*current = malloc(sizeof(struct MMIO_ENTRY));
 | 
				
			||||||
 | 
						(*current)->address = address;
 | 
				
			||||||
 | 
						(*current)->reg_count = reg_count;
 | 
				
			||||||
 | 
						(*current)->reg_size = reg_size;
 | 
				
			||||||
 | 
						(*current)->fn_write = fn_write;
 | 
				
			||||||
 | 
						(*current)->fn_read = fn_read;
 | 
				
			||||||
 | 
						(*current)->next = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mem_write8(uint32_t address, uint8_t value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// Look wether we are on an MMIO region
 | 
				
			||||||
 | 
						struct MMIO_ENTRY* io = mmio;
 | 
				
			||||||
 | 
						while(io)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if(MMIO_INSIDE(io, address))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if(io->reg_size == 1)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
					                void (*fn_write)(uint32_t, uint8_t) = io->fn_write;
 | 
				
			||||||
 | 
									fn_write(address, value);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									fprintf(stderr, "MEMORY: Invalid MMIO access of size 1 in a mapping of %u-sized registers\n", io->reg_size);
 | 
				
			||||||
 | 
									exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							io = io->next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Proceed with memory write
 | 
				
			||||||
 | 
						pthread_mutex_lock(&memory_mutex);
 | 
				
			||||||
 | 
						memory[address] = value;
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&memory_mutex);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mem_write16(uint32_t address, uint16_t value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// Look wether we are on an MMIO region
 | 
				
			||||||
 | 
						struct MMIO_ENTRY* io = mmio;
 | 
				
			||||||
 | 
						while(io)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if(MMIO_INSIDE(io, address))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if(io->reg_size == 2)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
					                void (*fn_write)(uint32_t, uint16_t) = io->fn_write;
 | 
				
			||||||
 | 
									fn_write(address, value);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									fprintf(stderr, "MEMORY: Invalid MMIO access of size 2 in a mapping of %u-sized registers\n", io->reg_size);
 | 
				
			||||||
 | 
									exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							io = io->next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Proceed with memory write
 | 
				
			||||||
 | 
						pthread_mutex_lock(&memory_mutex);
 | 
				
			||||||
 | 
						*((uint16_t*) &memory[address]) = value;
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&memory_mutex);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mem_write32(uint32_t address, uint32_t value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// Look wether we are on an MMIO region
 | 
				
			||||||
 | 
						struct MMIO_ENTRY* io = mmio;
 | 
				
			||||||
 | 
						while(io)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if(MMIO_INSIDE(io, address))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if(io->reg_size == 4)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
					                void (*fn_write)(uint32_t, uint32_t) = io->fn_write;
 | 
				
			||||||
 | 
									fn_write(address, value);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									fprintf(stderr, "MEMORY: Invalid MMIO access of size 4 in a mapping of %u-sized registers\n", io->reg_size);
 | 
				
			||||||
 | 
									exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							io = io->next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Proceed with memory write
 | 
				
			||||||
 | 
						pthread_mutex_lock(&memory_mutex);
 | 
				
			||||||
 | 
						*((uint32_t*) &memory[address]) = value;
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&memory_mutex);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t mem_read8(uint32_t address)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Look wether we are on an MMIO region
 | 
				
			||||||
 | 
						struct MMIO_ENTRY* io = mmio;
 | 
				
			||||||
 | 
						while(io)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if(MMIO_INSIDE(io, address))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if(io->reg_size == 1)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
					                uint8_t (*fn_read)(uint32_t) = io->fn_read;
 | 
				
			||||||
 | 
									return fn_read(address);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									fprintf(stderr, "MEMORY: Invalid MMIO access of size 1 in a mapping of %u-sized registers\n", io->reg_size);
 | 
				
			||||||
 | 
									exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							io = io->next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Proceed with memory read
 | 
				
			||||||
 | 
						pthread_mutex_lock(&memory_mutex);
 | 
				
			||||||
 | 
						uint8_t tr = memory[address];
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&memory_mutex);
 | 
				
			||||||
 | 
					    return tr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint16_t mem_read16(uint32_t address)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Look wether we are on an MMIO region
 | 
				
			||||||
 | 
						struct MMIO_ENTRY* io = mmio;
 | 
				
			||||||
 | 
						while(io)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if(MMIO_INSIDE(io, address))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if(io->reg_size == 2)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
					                uint16_t (*fn_read)(uint32_t) = io->fn_read;
 | 
				
			||||||
 | 
									return fn_read(address);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									fprintf(stderr, "MEMORY: Invalid MMIO access of size 2 in a mapping of %u-sized registers\n", io->reg_size);
 | 
				
			||||||
 | 
									exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							io = io->next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Proceed with memory read
 | 
				
			||||||
 | 
						pthread_mutex_lock(&memory_mutex);
 | 
				
			||||||
 | 
						uint16_t tr = *((uint16_t*) &memory[address]);
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&memory_mutex);
 | 
				
			||||||
 | 
					    return tr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t mem_read32(uint32_t address)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Look wether we are on an MMIO region
 | 
				
			||||||
 | 
						struct MMIO_ENTRY* io = mmio;
 | 
				
			||||||
 | 
						while(io)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if(MMIO_INSIDE(io, address))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if(io->reg_size == 4)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
					                uint32_t (*fn_read)(uint32_t) = io->fn_read;
 | 
				
			||||||
 | 
									return fn_read(address);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									fprintf(stderr, "MEMORY: Invalid MMIO access of size 4 in a mapping of %u-sized registers\n", io->reg_size);
 | 
				
			||||||
 | 
									exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							io = io->next;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Proceed with memory read
 | 
				
			||||||
 | 
						pthread_mutex_lock(&memory_mutex);
 | 
				
			||||||
 | 
						uint32_t tr = *((uint32_t*) &memory[address]);
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&memory_mutex);
 | 
				
			||||||
 | 
					    return tr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,8 +5,14 @@
 | 
				
			|||||||
#include <pthread.h>
 | 
					#include <pthread.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern uint8_t* memory;
 | 
					extern uint8_t* memory;
 | 
				
			||||||
extern pthread_mutex_t memory_mutex;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mem_init();
 | 
					void mem_init();
 | 
				
			||||||
 | 
					void mem_register_mmio(uint32_t address, uint32_t size, uint32_t reg_size, void* fn_write, void* fn_read);
 | 
				
			||||||
 | 
					void mem_write8(uint32_t address, uint8_t value);
 | 
				
			||||||
 | 
					void mem_write16(uint32_t address, uint16_t value);
 | 
				
			||||||
 | 
					void mem_write32(uint32_t address, uint32_t value);
 | 
				
			||||||
 | 
					uint8_t mem_read8(uint32_t address);
 | 
				
			||||||
 | 
					uint16_t mem_read16(uint32_t address);
 | 
				
			||||||
 | 
					uint32_t mem_read32(uint32_t address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +0,0 @@
 | 
				
			|||||||
#ifndef MMU_H
 | 
					 | 
				
			||||||
#define MMU_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define mmu_translate(vaddr) (vaddr)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user