Skip to content

Commit ee05dc5

Browse files
author
Pedro Nogueira
committed
Entrega final do trabalho!
1 parent 7f2e377 commit ee05dc5

22 files changed

+1558
-2
lines changed

README.md

+61-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,61 @@
1-
# riscv-simulator
2-
start
1+
# OAC - Processador RiscV Monociclo em C++
2+
3+
Trabalho de Organização e Arquitetura de Computadores
4+
Pedro Nogueira - 14/0065032
5+
UnB - 2020/2
6+
7+
Projeto de um processador monociclo na arquitetura RISC-V na linguagem C++.
8+
O trabalho simula a arquitetura de um processador RISC-V na linguagem C++ como o programa [RARS](https://github.com/TheThirdOne/rars/releases) faz. Ele recebe um dump de dados de memória tanto de instrução quanto de memória em um arquivo externo que ele lê e roda cada instrução conforme.
9+
10+
## Especificações
11+
12+
### Plataforma
13+
14+
WSL2|Ubuntu em um Windows 10
15+
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
16+
VSCode
17+
18+
### Como rodar
19+
20+
O comando ```g++ -o ./main.exe -std=c++17 -Wall -Wno-overflow -pedantic -Wextra -g main.cpp``` compila o projeto todo, bastando depois rodar o executável main.exe resultante. O comando ```cppcheck . --enable=all --suppress=missingIncludeSystem``` funciona para checagem do projeto.
21+
22+
### PDF
23+
24+
O PDF do professor está na raiz do projeto.
25+
26+
### main.cpp
27+
28+
Código que começa o projeto, procurando na raiz os arquivos de dump.
29+
30+
### globals.h
31+
32+
Constantes e flags utilizadas pelo projeto inteiro.
33+
34+
### acessoMemoriaRV.c
35+
36+
Trabalho antigo contendo as funcionalidades para escrita e leitura na memória.
37+
38+
### riscvcommands.cpp
39+
40+
Comandos possíveis do projeto, cada um com sua função correspondente.
41+
42+
### riscv.cpp
43+
44+
Arquitetura completa do processador, unindo a ideia de cada funcionalidade na sequência lógica dos acontecimentos dentro da estrutura.
45+
A arquitetura é dividida em 3 pedaços de funcionamento:
46+
47+
- fetch: Fase em que cada instrução é reconhecida como uma instrução e carregada para o processador de uma em uma.
48+
- decode: Identificação da funcionalidade requisitada pela instrução pegada no fetch.
49+
- execute: Execução da funcionalidade reconhecida no decode.
50+
51+
### code.bin/data.bin
52+
53+
Arquivos de dump das instruções gerados pelo RARS. O arquivo code.bin contém as instruções (.text) enquanto o arquivo data.bin contém os dados (.data).
54+
55+
### Esse README.md
56+
57+
Vamos sempre atualizar, se atentando ao formato markdown dele. Inclusive os espaços no final das linhas!!!
58+
59+
### Estilo
60+
61+
Estilo Google nativo do VSCode.

README.txt

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Trabalho 2 - Organização e Arquitetura de Computadores
2+
Pedro Nogueira - 14/0065032
3+
UnB - 2020/2
4+
5+
WSL2|Ubuntu em um Windows 10
6+
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
7+
VSCode
8+
9+
comandos usados:
10+
cppcheck . --enable=all --suppress=missingIncludeSystem
11+
g++ -o ./main.exe -std=c++17 -Wall -Wno-overflow -pedantic -Wextra -g main.cpp

Simulador RISCV 2020_2.pdf

196 KB
Binary file not shown.

Testes ASM -20210323.zip

937 Bytes
Binary file not shown.

Trabalho_2_OAC.pdf

49 KB
Binary file not shown.

acessoMemoriaRV.c

+186
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/**
2+
* Trabalho 1 - Organização e Arquitetura de Computadores
3+
* UnB - 2020/2
4+
* @author Pedro Nogueira - 14/0065032
5+
*
6+
* Este trabalho consiste na simulação das instruções de acesso à memória do
7+
* RISCV RV32I em linguagem C.
8+
*/
9+
#include <stdbool.h>
10+
#include <stdint.h>
11+
#include <stdio.h>
12+
13+
// A memória é simulada como um arranjo de inteiros de 32 bits.
14+
// Ou seja, a memória é um arranjo de 4KWords, ou 16KBytes.
15+
#define MEM_SIZE 4096
16+
int32_t mem[MEM_SIZE];
17+
18+
typedef bool uint1_t; // somente usado para ints de 1 bit só
19+
20+
#define BYTE1AND 0x000000FF // 00000000 00000000 00000000 11111111
21+
#define BYTE2AND 0x0000FF00 // 00000000 00000000 11111111 00000000
22+
#define BYTE3AND 0x00FF0000 // 00000000 11111111 00000000 00000000
23+
#define BYTE4AND 0xFF000000 // 11111111 00000000 00000000 00000000
24+
25+
#define BYTE1OR 0xFFFFFF00 // 11111111 11111111 11111111 00000000
26+
#define BYTE2OR 0xFFFF00FF // 11111111 11111111 00000000 11111111
27+
#define BYTE3OR 0xFF00FFFF // 11111111 00000000 11111111 11111111
28+
#define BYTE4OR 0x00FFFFFF // 00000000 11111111 11111111 11111111
29+
30+
#define ALLONE 0xFFFFFFFF // 11111111 11111111 11111111 11111111
31+
32+
/**
33+
* Lê um inteiro alinhado - endereços múltiplos de 4.
34+
* A função calcula o endereço de memória somando os parâmetros:
35+
* Endereço palavra = address + kte
36+
* A função deve checar se o endereço é um múltiplo de 4 (%4 == 0).
37+
* Se não for, deve escrever uma mensagem de erro e retornar zero.
38+
* Se o endereço estiver correto, a função deve:
39+
* • Dividi-lo por 4 para obter o índice do vetor memória
40+
* • Retornar o o valor lido da memória
41+
*/
42+
int32_t lw(uint32_t address, int32_t kte) {
43+
if ((address + kte) % 4 != 0) {
44+
printf("Error reading the address in lw - address not multiple of 4!\n");
45+
return 0;
46+
}
47+
return mem[(address + kte) / 4];
48+
}
49+
50+
/**
51+
* Lê um byte do vetor memória e retorna-o, estendendo o sinal para 32 bits.
52+
* Lembrando que as palavras da memória tem 4 bytes cada, para acessar um byte
53+
* dentro da palavra pode-se:
54+
* • Ler a palavra que contém o byte e, por operações de mascaramento, extrair
55+
* byte endereçado, ou
56+
* • Criar um ponteiro para byte e fazer um type cast (coerção de tipo) do
57+
* endereço do vetor memória (int *) para byte (char *).
58+
*/
59+
int32_t lb(uint32_t address, int32_t kte) {
60+
uint1_t signal;
61+
int32_t word = mem[(address + kte) / 4];
62+
uint32_t byte = (address + kte) % 4;
63+
int32_t result;
64+
switch (byte) {
65+
case 0:
66+
result = (word & BYTE1AND);
67+
break;
68+
case 1:
69+
result = (word & BYTE2AND) >> 8;
70+
break;
71+
case 2:
72+
result = (word & BYTE3AND) >> 16;
73+
break;
74+
case 3:
75+
result = (word & BYTE4AND) >> 24;
76+
break;
77+
}
78+
signal = result >> 3;
79+
return signal ? (result | BYTE1OR) : result;
80+
}
81+
82+
/**
83+
* Lê um byte do vetor memória e retorna-o como um número positivo, ou seja,
84+
* todos os bits superiores devem ser zerados.
85+
*/
86+
int32_t lbu(uint32_t address, int32_t kte) {
87+
int32_t word = mem[(address + kte) / 4];
88+
uint32_t byte = (address + kte) % 4;
89+
int32_t result;
90+
switch (byte) {
91+
case 0:
92+
result = (word & BYTE1AND);
93+
break;
94+
case 1:
95+
result = (word & BYTE2AND) >> 8;
96+
break;
97+
case 2:
98+
result = (word & BYTE3AND) >> 16;
99+
break;
100+
case 3:
101+
result = (word & BYTE4AND) >> 24;
102+
break;
103+
}
104+
return result;
105+
}
106+
107+
/**
108+
* Escreve um inteiro alinhado na memória - endereços múltiplos de 4. O cálculo
109+
* do endereço é realizado da mesma forma que na operação lw().
110+
*/
111+
void sw(uint32_t address, int32_t kte, int32_t dado) {
112+
if ((address + kte) % 4 != 0) {
113+
printf("Error saving the word in sw - address not multiple of 4!\n");
114+
return;
115+
}
116+
mem[(address + kte) / 4] = dado;
117+
}
118+
119+
/**
120+
* Escreve um byte na memória. Caso utilize operações de mascaramento, a palavra
121+
* que contém o byte deve ser lida da memória, o byte deve ser posicionado
122+
* corretamente através de deslocamentos e a escrita ocorre utilizando máscaras.
123+
* Alternativamente pode-se utilizar a coerção para (char *) e escrever
124+
* diretamente na posição usando o endereço calculado como índice.
125+
*/
126+
void sb(uint32_t address, int32_t kte, int8_t dado) {
127+
int32_t word = mem[(address + kte) / 4];
128+
int32_t dado32bit = dado;
129+
dado32bit = dado32bit & BYTE1AND;
130+
int32_t byteMask = dado32bit << (kte * 8);
131+
int32_t result;
132+
switch (kte) {
133+
case 0:
134+
result = (word & BYTE1OR) | byteMask;
135+
break;
136+
case 1:
137+
result = (word & BYTE2OR) | byteMask;
138+
break;
139+
case 2:
140+
result = (word & BYTE3OR) | byteMask;
141+
break;
142+
case 3:
143+
result = (word & BYTE4OR) | byteMask;
144+
break;
145+
}
146+
mem[(address + kte) / 4] = result;
147+
}
148+
/*
149+
int main() {
150+
sb(0, 0, 0x04);
151+
sb(0, 1, 0x03);
152+
sb(0, 2, 0x02);
153+
sb(0, 3, 0x01);
154+
155+
sb(4, 0, 0xFF);
156+
sb(4, 2, 0xFD);
157+
sb(4, 3, 0xFC);
158+
159+
sw(12, 0, 0xFF);
160+
sw(16, 0, 0xFFFF);
161+
sw(20, 0, 0xFFFFFFFF);
162+
sw(24, 0, 0x80000000);
163+
164+
printf("mem[0] = %08x\n", mem[0]);
165+
printf("mem[1] = %08x\n", mem[1]);
166+
printf("mem[2] = %08x\n", mem[2]);
167+
printf("mem[3] = %08x\n", mem[3]);
168+
printf("mem[4] = %08x\n", mem[4]);
169+
printf("mem[5] = %08x\n", mem[5]);
170+
printf("mem[6] = %08x\n", mem[6]);
171+
172+
printf("lb(4,0) = %08x\n", lb(4, 0));
173+
printf("lb(4,1) = %08x\n", lb(4, 1));
174+
printf("lb(4,2) = %08x\n", lb(4, 2));
175+
printf("lb(4,3) = %08x\n", lb(4, 3));
176+
printf("lbu(4,0) = %08x\n", lbu(4, 0));
177+
printf("lbu(4,1) = %08x\n", lbu(4, 1));
178+
printf("lbu(4,2) = %08x\n", lbu(4, 2));
179+
printf("lbu(4,3) = %08x\n", lbu(4, 3));
180+
printf("lw(12,0) = %08x\n", lw(12, 0));
181+
printf("lw(16,0) = %08x\n", lw(16, 0));
182+
printf("lw(20,0) = %08x\n", lw(20, 0));
183+
184+
return 0;
185+
}
186+
*/

code.bin

176 Bytes
Binary file not shown.

data.bin

4 KB
Binary file not shown.

dumpEvenOdd_text.bin

60 Bytes
Binary file not shown.

dumpEvenOdd_text.txt

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
00000000010100000000100010010011 // addi x17, x0, 5
2+
00000000000000000000000001110011 // ecall
3+
00000000000101010111001010010011 // andi x5, x10, 1
4+
00000000000000101000110001100011 //
5+
00000000000000000010010100010111
6+
11111111011101010000010100010011
7+
00000000010000000000100010010011
8+
00000000000000000000000001110011
9+
00000001010000000000000001101111
10+
00000000000000000010010100010111
11+
11111101110001010000010100010011
12+
00000000010000000000100010010011
13+
00000000000000000000000001110011
14+
00000000101000000000100010010011
15+
00000000000000000000000001110011

dumpReadAddTwoPrint_text.bin

40 Bytes
Binary file not shown.

dumpReadAddTwoPrint_text.txt

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
0000000 00101 00000 000 10001 0010011 // addi x17, x0, 5
2+
0000000 00000 00000 000 00000 1110011 // ecall
3+
0000000 01010 00000 000 00101 0110011 // add x5, x0, x10
4+
0000000 00101 00000 000 10001 0010011 // addi x17, x0, 5
5+
0000000 00000 00000 000 00000 1110011 // ecall
6+
0000000 00101 01010 000 01010 0110011 // add x10, x10, x5
7+
0000000 00001 00000 000 10001 0010011 // addi x17, x0, 1
8+
0000000 00000 00000 000 00000 1110011 // ecall
9+
0000000 01010 00000 000 10001 0010011 // addi x17, x0, 10
10+
0000000 00000 00000 000 00000 1110011 // ecall

dumpteste1_text.txt

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
0000000 01010 00000 000 00101 0010011
2+
1111111 11011 00000 000 00110 0010011
3+
0000000 00001 00000 000 10001 0010011
4+
0000000 00110 00101 000 01010 0110011
5+
0000000 00000 00000 000 00000 1110011
6+
0000000 00110 00000 000 01010 0110011
7+
0000000 00000 00000 000 00000 1110011
8+
0000000 00110 00101 000 00110 0110011
9+
0000000 00110 00101 111 01010 0110011
10+
0000000 00000 00000 000 00000 1110011
11+
0000000 00110 00101 110 01010 0110011
12+
0000000 00000 00000 000 00000 1110011
13+
0000000 00011 00101 111 01010 0010011
14+
0000000 00000 00000 000 00000 1110011
15+
0000000 00001 00101 110 01010 0010011
16+
0000000 00000 00000 000 00000 1110011
17+
0100000 00110 00101 000 01010 0110011
18+
0000000 00000 00000 000 00000 1110011
19+
0100000 00101 00110 000 01010 0110011
20+
0000000 00000 00000 000 00000 1110011
21+
0000000 00101 00110 010 01010 0110011
22+
0000000 00000 00000 000 00000 1110011
23+
0000000 00110 00101 010 01010 0110011
24+
0000000 00000 00000 000 00000 1110011
25+
0000000 00101 00000 000 00111 0010011
26+
1111111 11011 00000 000 11100 0010011
27+
0000000 00111 11100 011 01010 0110011
28+
0000000 00000 00000 000 00000 1110011
29+
0000000 11100 00111 011 01010 0110011
30+
0000000 00000 00000 000 00000 1110011
31+
0000000 00110 00101 100 01010 0110011
32+
0000000 00000 00000 000 00000 1110011
33+
0000000 00010 00101 001 01010 0010011 // slli opcode = 19 funct3 = 1 funct7 = -------
34+
0000000 00000 00000 000 00000 1110011 // ecall
35+
1111111 11111 11101 001 00111 0110111 // lui
36+
1001000 00000 00111 000 00111 0010011 // addi
37+
0100000 01000 00111 101 01010 0010011 // srai
38+
0000000 00000 00000 000 00000 1110011 // ecall
39+
0000000 11000 00111 101 01010 0010011 // srli
40+
0000000 00000 00000 000 00000 1110011 // ecall
41+
0000000 00000 00000 001 01010 0110111 // lui
42+
0000000 00000 00000 000 00000 1110011 // ecall
43+
0000000 01010 00000 000 10001 0010011 // addi
44+
0000000 00000 00000 000 00000 1110011 // ecall

dumpteste3_text.txt

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
00200293
2+
00100893
3+
00100513
4+
00a00413
5+
00c000ef
6+
00a00893
7+
00000073
8+
00028a63
9+
00000073
10+
00150513
11+
00000293
12+
ff1ff06f
13+
00029a63
14+
00000073
15+
00150513
16+
fff00293
17+
ff1ff06f
18+
0002dc63
19+
00000073
20+
00150513
21+
00100293
22+
fff00413
23+
fedff06f
24+
0082fc63
25+
00000073
26+
00150513
27+
fff00293
28+
00000413
29+
fedff06f
30+
00804c63
31+
00000073
32+
00150513
33+
00100413
34+
00000293
35+
fedff06f
36+
00546a63
37+
00000073
38+
00150513
39+
fff00293
40+
ff1ff06f
41+
00000013
42+
00000013
43+
00008067

0 commit comments

Comments
 (0)